connectors_service 8.6.0.4.pre.20221114T233727Z → 8.6.0.4.pre.20221116T024501Z

Sign up to get free protection for your applications and to get access to all the features.
Files changed (33) hide show
  1. checksums.yaml +4 -4
  2. data/config/connectors.yml +4 -4
  3. data/lib/app/app.rb +4 -0
  4. data/lib/app/dispatcher.rb +30 -17
  5. data/lib/connectors/base/advanced_snippet_against_schema_validator.rb +173 -0
  6. data/lib/connectors/base/advanced_snippet_validator.rb +34 -0
  7. data/lib/connectors/base/connector.rb +27 -5
  8. data/lib/connectors/example/connector.rb +3 -12
  9. data/lib/connectors/example/example_advanced_snippet_validator.rb +35 -0
  10. data/lib/connectors/gitlab/connector.rb +3 -12
  11. data/lib/connectors/gitlab/gitlab_advanced_snippet_validator.rb +35 -0
  12. data/lib/connectors/mongodb/connector.rb +9 -24
  13. data/lib/connectors/mongodb/mongo_advanced_snippet_against_schema_validator.rb +22 -0
  14. data/lib/connectors/mongodb/mongo_advanced_snippet_schema.rb +292 -0
  15. data/lib/connectors/sync_status.rb +6 -1
  16. data/lib/connectors/tolerable_error_helper.rb +43 -0
  17. data/lib/core/connector_job.rb +96 -23
  18. data/lib/core/connector_settings.rb +29 -6
  19. data/lib/core/elastic_connector_actions.rb +77 -55
  20. data/lib/core/filtering/validation_job_runner.rb +1 -1
  21. data/lib/core/ingestion/es_sink.rb +68 -9
  22. data/lib/core/ingestion.rb +0 -1
  23. data/lib/core/jobs/consumer.rb +114 -0
  24. data/lib/core/jobs/producer.rb +26 -0
  25. data/lib/core/single_scheduler.rb +1 -1
  26. data/lib/core/sync_job_runner.rb +20 -12
  27. data/lib/core.rb +2 -0
  28. data/lib/utility/error_monitor.rb +108 -0
  29. data/lib/utility/errors.rb +0 -12
  30. data/lib/utility/logger.rb +0 -1
  31. data/lib/utility.rb +6 -0
  32. metadata +12 -3
  33. data/lib/core/ingestion/ingester.rb +0 -90
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 8f69f05260d34b07ce34d569ce7c41fdd10349b33121823697ebbb6a4ebf9206
4
- data.tar.gz: a2957118c80d0e2bc9ea6a8046307485c11e4f809efb01cabbb96e341dc947c2
3
+ metadata.gz: 9a610999d9c34543392e1dd9b7b9ab136557992cc1503fa5aa5973186d17af9e
4
+ data.tar.gz: '086282a4a15ce1b168e6a0add5f78646e1fe89c336b8a257677826cce3677635'
5
5
  SHA512:
6
- metadata.gz: 63775eded9d9953b41950edd7ca86176200c4ae7510564f6f7995c336d6e78bbe40d494cb0a152a984b14b45055e7b7847a2779888d70905d4956b8c78d4bda1
7
- data.tar.gz: 52b00d122ef43fc5afa0b4cb50bbe428111e7fe2cb7cee437dd2d2b6b32516cbd01c5803b0a11609a5021e85605a2e6bd2b30973807df3cae1420864e2fcb185
6
+ metadata.gz: bf0a0a22ea96074bcbb904000ec489a591fc8491bc2d91759bc1a097c60e31c2abad7b118bb97d16bbe80c5b00dbe08f7c65653710c2d6a77d3356607d87e045
7
+ data.tar.gz: 67ff773ed2ae3f869897b5fb3a2c0dc3fc55c5922c602e032ed5bafa800043bd4b7f4af90fdd055e575ea877f3cf3b9e308d91c58bad59cd6c63dd5eb8ab98f4
@@ -1,10 +1,10 @@
1
1
  # general metadata
2
- version: 8.6.0.4-20221114T233727Z
2
+ version: 8.6.0.4-20221116T024501Z
3
3
  repository: git@github.com:elastic/ent-search-connectors.git
4
- revision: f506d5e5ebedfb0c6058d347d8ce22adc42e2cc0
4
+ revision: b3cc1332879a38930a272a63f8c6be1847578204
5
5
  elasticsearch:
6
6
  hosts: http://localhost:9200
7
- api_key: WXNYeWQ0UUJ4Y3ZQV3ctbjVibnU6REx4eE8tbFhUMU94N2JoU2hIeVFMQQ==
7
+ api_key: MDJyaGZZUUJ1ZXdOLTB1ZnQ5aXQ6a2IwQURWSjVUc1NPcjVsOFBuVDBzZw==
8
8
  retry_on_failure: 3
9
9
  request_timeout: 120
10
10
  disable_warnings: true
@@ -20,5 +20,5 @@ poll_interval: 3
20
20
  termination_timeout: 60
21
21
  heartbeat_interval: 1800
22
22
  native_mode: false
23
- connector_id: YcXyd4QBxcvPWw-n2bkA
23
+ connector_id: 0mrhfYQBuewN-0ufptgN
24
24
  service_type: mongodb
data/lib/app/app.rb CHANGED
@@ -17,6 +17,10 @@ require 'utility/logger'
17
17
  module App
18
18
  Utility::Environment.set_execution_environment(App::Config) do
19
19
  App::PreflightCheck.run!
20
+
21
+ # set exit hook
22
+ Kernel.at_exit { App::Dispatcher.shutdown! }
23
+
20
24
  App::Dispatcher.start!
21
25
  rescue App::PreflightCheck::CheckFailure => e
22
26
  Utility::Logger.error("Preflight check failed: #{e.message}")
@@ -28,6 +28,10 @@ module App
28
28
  def start!
29
29
  running!
30
30
  Utility::Logger.info("Starting connector service in #{App::Config.native_mode ? 'native' : 'non-native'} mode...")
31
+
32
+ # start sync jobs consumer
33
+ start_consumer!
34
+
31
35
  start_polling_jobs!
32
36
  end
33
37
 
@@ -37,6 +41,8 @@ module App
37
41
  scheduler.shutdown
38
42
  pool.shutdown
39
43
  pool.wait_for_termination(TERMINATION_TIMEOUT)
44
+
45
+ stop_consumer!
40
46
  end
41
47
 
42
48
  private
@@ -68,7 +74,10 @@ module App
68
74
  scheduler.when_triggered do |connector_settings, task|
69
75
  case task
70
76
  when :sync
71
- start_sync_task(connector_settings)
77
+ # update connector sync_now flag
78
+ Core::ElasticConnectorActions.update_connector_sync_now(connector_settings.id, false)
79
+
80
+ Core::Jobs::Producer.enqueue_job(job_type: :sync, connector_settings: connector_settings)
72
81
  when :heartbeat
73
82
  start_heartbeat_task(connector_settings)
74
83
  when :configuration
@@ -83,22 +92,6 @@ module App
83
92
  Utility::ExceptionTracking.log_exception(e, 'The connector service failed due to unexpected error.')
84
93
  end
85
94
 
86
- def start_sync_task(connector_settings)
87
- start_heartbeat_task(connector_settings)
88
- pool.post do
89
- Utility::Logger.info("Initiating a sync job for #{connector_settings.formatted}...")
90
- Core::ElasticConnectorActions.ensure_content_index_exists(connector_settings.index_name)
91
- job_runner = Core::SyncJobRunner.new(connector_settings)
92
- job_runner.execute
93
- rescue Core::JobAlreadyRunningError
94
- Utility::Logger.info("Sync job for #{connector_settings.formatted} is already running, skipping.")
95
- rescue Core::ConnectorVersionChangedError => e
96
- Utility::Logger.info("Could not start the job because #{connector_settings.formatted} has been updated externally. Message: #{e.message}")
97
- rescue StandardError => e
98
- Utility::ExceptionTracking.log_exception(e, "Sync job for #{connector_settings.formatted} failed due to unexpected error.")
99
- end
100
- end
101
-
102
95
  def start_heartbeat_task(connector_settings)
103
96
  pool.post do
104
97
  Utility::Logger.info("Sending heartbeat for #{connector_settings.formatted}...")
@@ -132,6 +125,26 @@ module App
132
125
  Utility::ExceptionTracking.log_exception(e, "Filter validation task for #{connector_settings.formatted} failed due to unexpected error.")
133
126
  end
134
127
  end
128
+
129
+ def start_consumer!
130
+ @consumer = Core::Jobs::Consumer.new(
131
+ poll_interval: POLL_INTERVAL,
132
+ termination_timeout: TERMINATION_TIMEOUT,
133
+ min_threads: MIN_THREADS,
134
+ max_threads: MAX_THREADS,
135
+ max_queue: MAX_QUEUE,
136
+ scheduler: scheduler
137
+ )
138
+
139
+ @consumer.subscribe!(index_name: Utility::Constants::JOB_INDEX)
140
+ end
141
+
142
+ def stop_consumer!
143
+ return if @consumer.nil?
144
+ return unless @consumer.running?
145
+
146
+ @consumer.shutdown!
147
+ end
135
148
  end
136
149
  end
137
150
  end
@@ -0,0 +1,173 @@
1
+ #
2
+ # Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
3
+ # or more contributor license agreements. Licensed under the Elastic License;
4
+ # you may not use this file except in compliance with the Elastic License.
5
+ #
6
+ # frozen_string_literal: true
7
+
8
+ require 'active_support/core_ext/hash'
9
+ require 'utility/logger'
10
+ require 'connectors/base/advanced_snippet_validator'
11
+ require 'core/filtering/validation_status'
12
+
13
+ module Connectors
14
+ module Base
15
+ class AdvancedSnippetAgainstSchemaValidator < Connectors::Base::AdvancedSnippetValidator
16
+
17
+ MAX_RECURSION_DEPTH = 50
18
+ ADVANCED_SNIPPET_ID = 'advanced_snippet'
19
+
20
+ def initialize(advanced_snippet, schema)
21
+ super(advanced_snippet)
22
+ @schema = schema
23
+ end
24
+
25
+ def is_snippet_valid?
26
+ validation_result = validate_against_schema(@schema, @advanced_snippet)
27
+ log_validation_result(validation_result)
28
+ validation_result
29
+ end
30
+
31
+ private
32
+
33
+ def validate_against_schema(config_schema, advanced_snippet, recursion_depth = 0)
34
+ # Prevent unintentional/intentional SystemStackErrors/crashes
35
+ return unexpected_error if exceeded_recursion_depth?(recursion_depth)
36
+
37
+ return valid_snippet if config_schema.nil? || config_schema.empty?
38
+
39
+ schema_fields = config_schema[:fields].is_a?(Hash) ? config_schema.dig(:fields, :values) : config_schema[:fields]
40
+ snippet_field_names = advanced_snippet&.keys&.map(&:to_s)
41
+ schema_field_names = schema_fields.map { |field| field[:name] }
42
+
43
+ return unexpected_field(schema_field_names, snippet_field_names) if unexpected_field_present?(snippet_field_names, schema_field_names)
44
+
45
+ return fields_constraint_violation(config_schema[:fields]) if fields_constraints_violated?(config_schema, advanced_snippet)
46
+
47
+ schema_fields.each do |field|
48
+ name = field[:name]
49
+ type = field[:type]
50
+ optional = field[:optional] || false
51
+
52
+ snippet_field_value = advanced_snippet.with_indifferent_access[name]
53
+
54
+ next if optional && (snippet_field_value.nil? || !snippet_field_value.present?)
55
+
56
+ return wrong_names(snippet_field_names, name) unless snippet_field_names.include?(name)
57
+
58
+ return wrong_type(name, type, snippet_field_value) if type_error_present?(type, snippet_field_value)
59
+
60
+ if field[:fields].present?
61
+ validation_result = validate_against_schema(field, snippet_field_value, recursion_depth + 1)
62
+
63
+ return validation_result unless validation_result[:is_valid]
64
+ end
65
+ end
66
+
67
+ valid_snippet
68
+ end
69
+
70
+ def fields_constraints_violated?(config_schema, advanced_snippet)
71
+ return false unless config_schema[:fields].is_a?(Hash)
72
+
73
+ constraints = config_schema.dig(:fields, :constraints)
74
+ constraints = constraints.is_a?(Array) ? constraints : [constraints]
75
+
76
+ constraints.each do |constraint|
77
+ return true unless constraint.call(advanced_snippet)
78
+ end
79
+
80
+ false
81
+ end
82
+
83
+ def type_error_present?(schema_type, snippet_value)
84
+ return !schema_type.call(snippet_value) if schema_type.is_a?(Proc)
85
+
86
+ !snippet_value.is_a?(schema_type)
87
+ end
88
+
89
+ def exceeded_recursion_depth?(recursion_depth)
90
+ if recursion_depth >= MAX_RECURSION_DEPTH
91
+ Utility::Logger.warn("Recursion depth for filtering validation exceeded. (Max recursion depth: #{MAX_RECURSION_DEPTH})")
92
+ return true
93
+ end
94
+
95
+ false
96
+ end
97
+
98
+ def unexpected_field_present?(actual_field_names, expected_field_names)
99
+ difference = actual_field_names - expected_field_names
100
+
101
+ # we have field names, which we didn't expect
102
+ !difference.empty?
103
+ end
104
+
105
+ def valid_snippet
106
+ {
107
+ :state => Core::Filtering::ValidationStatus::VALID,
108
+ :errors => []
109
+ }
110
+ end
111
+
112
+ def unexpected_field(expected_fields, actual_fields)
113
+ {
114
+ :state => Core::Filtering::ValidationStatus::INVALID,
115
+ :errors => [
116
+ {
117
+ :ids => [ADVANCED_SNIPPET_ID],
118
+ :messages => ["Encountered unexpected fields '#{actual_fields}'. Expected: '#{expected_fields}'."]
119
+ }
120
+ ]
121
+ }
122
+ end
123
+
124
+ def wrong_type(field_name, expected_type, actual_value)
125
+ {
126
+ :state => Core::Filtering::ValidationStatus::INVALID,
127
+ :errors => [
128
+ {
129
+ :ids => [ADVANCED_SNIPPET_ID],
130
+ :messages => ["Expected field type '#{expected_type.is_a?(Proc) ? 'custom matcher' : expected_type}' for field '#{field_name}', but got value '#{actual_value.inspect}' of type '#{actual_value.class}'."]
131
+ }
132
+ ]
133
+ }
134
+ end
135
+
136
+ def wrong_names(actual_field_names, expected_field_name)
137
+ {
138
+ :state => Core::Filtering::ValidationStatus::INVALID,
139
+ :errors => [
140
+ {
141
+ :ids => [ADVANCED_SNIPPET_ID],
142
+ :messages => ["Expected field name '#{expected_field_name}', but got #{actual_field_names}."]
143
+ }
144
+ ]
145
+ }
146
+ end
147
+
148
+ def fields_constraint_violation(fields)
149
+ {
150
+ :state => Core::Filtering::ValidationStatus::INVALID,
151
+ :errors => [
152
+ {
153
+ :ids => [ADVANCED_SNIPPET_ID],
154
+ :messages => ["A fields constraint was violated for fields: '#{fields[:values].map { |v| v[:name] }}'. Check advanced snippet field constraints."]
155
+ }
156
+ ]
157
+ }
158
+ end
159
+
160
+ def unexpected_error
161
+ {
162
+ :state => Core::Filtering::ValidationStatus::INVALID,
163
+ :errors => [
164
+ {
165
+ :ids => [ADVANCED_SNIPPET_ID],
166
+ :messages => ['Unexpected error. Check logs for details.']
167
+ }
168
+ ]
169
+ }
170
+ end
171
+ end
172
+ end
173
+ end
@@ -0,0 +1,34 @@
1
+ #
2
+ # Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
3
+ # or more contributor license agreements. Licensed under the Elastic License;
4
+ # you may not use this file except in compliance with the Elastic License.
5
+ #
6
+ # frozen_string_literal: true
7
+
8
+ require 'utility/logger'
9
+
10
+ module Connectors
11
+ module Base
12
+ class AdvancedSnippetValidator
13
+
14
+ def initialize(advanced_snippet)
15
+ @advanced_snippet = advanced_snippet || {}
16
+ end
17
+
18
+ def is_snippet_valid?
19
+ raise 'Advanced Snippet validation not implemented'
20
+ end
21
+
22
+ private
23
+
24
+ def log_validation_result(validation_result)
25
+ Utility::Logger.info("Filtering Advanced Configuration validation result: #{validation_result[:state]}")
26
+ if validation_result[:errors].present?
27
+ validation_result[:errors].each do |error|
28
+ Utility::Logger.warn("Validation error for: '#{error[:ids]}': '#{error[:messages]}'")
29
+ end
30
+ end
31
+ end
32
+ end
33
+ end
34
+ end
@@ -6,12 +6,15 @@
6
6
 
7
7
  # frozen_string_literal: true
8
8
 
9
+ require 'active_support/core_ext/hash/indifferent_access'
10
+ require 'app/config'
9
11
  require 'bson'
12
+ require 'connectors/base/advanced_snippet_validator'
10
13
  require 'core/ingestion'
14
+ require 'connectors/tolerable_error_helper'
15
+ require 'core/filtering/validation_status'
11
16
  require 'utility'
12
17
  require 'utility/filtering'
13
- require 'app/config'
14
- require 'active_support/core_ext/hash/indifferent_access'
15
18
 
16
19
  module Connectors
17
20
  module Base
@@ -40,24 +43,43 @@ module Connectors
40
43
  ]
41
44
  end
42
45
 
43
- def self.validate_filtering(_filtering = {})
44
- raise 'Not implemented for this connector'
46
+ def self.advanced_snippet_validator
47
+ AdvancedSnippetValidator
48
+ end
49
+
50
+ def self.validate_filtering(filtering = {})
51
+ # nothing to validate
52
+ return { :state => Core::Filtering::ValidationStatus::VALID, :errors => [] } unless filtering.present?
53
+
54
+ filter = Utility::Filtering.extract_filter(filtering)
55
+ advanced_snippet = filter.dig(:advanced_snippet, :value)
56
+
57
+ snippet_validator_instance = advanced_snippet_validator.new(advanced_snippet)
58
+
59
+ snippet_validator_instance.is_snippet_valid?
45
60
  end
46
61
 
47
62
  attr_reader :rules, :advanced_filter_config
48
63
 
49
64
  def initialize(configuration: {}, job_description: {})
65
+ error_monitor = Utility::ErrorMonitor.new
66
+ @tolerable_error_helper = Connectors::TolerableErrorHelper.new(error_monitor)
67
+
50
68
  @configuration = configuration.dup || {}
51
69
  @job_description = job_description&.dup || {}
52
70
 
53
71
  filtering = Utility::Filtering.extract_filter(@job_description.dig(:connector, :filtering))
54
72
 
55
73
  @rules = filtering[:rules] || []
56
- @advanced_filter_config = filtering[:advanced_snippet] || {}
74
+ @advanced_filter_config = filtering.dig(:advanced_snippet, :value) || {}
57
75
  end
58
76
 
59
77
  def yield_documents; end
60
78
 
79
+ def yield_with_handling_tolerable_errors(identifier: nil, &block)
80
+ @tolerable_error_helper.yield_single_document(identifier: identifier, &block)
81
+ end
82
+
61
83
  def do_health_check
62
84
  raise 'Not implemented for this connector'
63
85
  end
@@ -7,6 +7,7 @@
7
7
  # frozen_string_literal: true
8
8
 
9
9
  require 'connectors/base/connector'
10
+ require 'connectors/example/example_advanced_snippet_validator'
10
11
  require 'core/filtering/validation_status'
11
12
  require 'utility'
12
13
 
@@ -46,18 +47,8 @@ module Connectors
46
47
  # raise 'something went wrong'
47
48
  end
48
49
 
49
- def self.validate_filtering(filtering = {})
50
- # TODO: real filtering validation will follow later
51
- errors = [
52
- {
53
- :ids => ['missing-implementation'],
54
- :messages => ['Filtering is not implemented yet for the example connector']
55
- }
56
- ]
57
-
58
- return { :state => Core::Filtering::ValidationStatus::INVALID, :errors => errors } if filtering.present?
59
-
60
- { :state => Core::Filtering::ValidationStatus::VALID, :errors => [] }
50
+ def self.advanced_snippet_validator
51
+ ExampleAdvancedSnippetValidator
61
52
  end
62
53
 
63
54
  def yield_documents
@@ -0,0 +1,35 @@
1
+ #
2
+ # Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
3
+ # or more contributor license agreements. Licensed under the Elastic License;
4
+ # you may not use this file except in compliance with the Elastic License.
5
+ #
6
+
7
+ # frozen_string_literal: true
8
+
9
+ require 'connectors/base/advanced_snippet_validator'
10
+
11
+ module Connectors
12
+ module Example
13
+ class ExampleAdvancedSnippetValidator < Connectors::Base::AdvancedSnippetValidator
14
+
15
+ def is_snippet_valid?
16
+ # TODO: real filtering validation will follow later
17
+ errors = [
18
+ {
19
+ :ids => ['missing-implementation'],
20
+ :messages => ['Filtering is not implemented yet for the example connector']
21
+ }
22
+ ]
23
+
24
+ validation_result = if @advanced_snippet.present? && !@advanced_snippet.empty?
25
+ { :state => Core::Filtering::ValidationStatus::INVALID, :errors => errors }
26
+ else
27
+ { :state => Core::Filtering::ValidationStatus::VALID, :errors => [] }
28
+ end
29
+ log_validation_result(validation_result)
30
+ validation_result
31
+ end
32
+
33
+ end
34
+ end
35
+ end
@@ -11,6 +11,7 @@ require 'connectors/base/connector'
11
11
  require 'connectors/gitlab/extractor'
12
12
  require 'connectors/gitlab/custom_client'
13
13
  require 'connectors/gitlab/adapter'
14
+ require 'connectors/gitlab/gitlab_advanced_snippet_validator'
14
15
  require 'core/ingestion'
15
16
 
16
17
  module Connectors
@@ -36,18 +37,8 @@ module Connectors
36
37
  }
37
38
  end
38
39
 
39
- def self.validate_filtering(filtering = {})
40
- # TODO: real filtering validation will follow later
41
- errors = [
42
- {
43
- :ids => ['missing-implementation'],
44
- :messages => ['Filtering is not implemented yet for the GitLab connector']
45
- }
46
- ]
47
-
48
- return { :state => Core::Filtering::ValidationStatus::INVALID, :errors => errors } if filtering.present?
49
-
50
- { :state => Core::Filtering::ValidationStatus::VALID, :errors => [] }
40
+ def self.advanced_snippet_validator
41
+ GitLabAdvancedSnippetValidator
51
42
  end
52
43
 
53
44
  def initialize(configuration: {}, job_description: {})
@@ -0,0 +1,35 @@
1
+ #
2
+ # Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
3
+ # or more contributor license agreements. Licensed under the Elastic License;
4
+ # you may not use this file except in compliance with the Elastic License.
5
+ #
6
+
7
+ # frozen_string_literal: true
8
+
9
+ require 'connectors/base/advanced_snippet_validator'
10
+
11
+ module Connectors
12
+ module GitLab
13
+ class GitLabAdvancedSnippetValidator < Connectors::Base::AdvancedSnippetValidator
14
+
15
+ def is_snippet_valid?
16
+ # TODO: real filtering validation will follow later
17
+ errors = [
18
+ {
19
+ :ids => ['missing-implementation'],
20
+ :messages => ['Filtering is not implemented yet for the GitLab connector']
21
+ }
22
+ ]
23
+
24
+ validation_result = if @advanced_snippet.present? && !@advanced_snippet.empty?
25
+ { :state => Core::Filtering::ValidationStatus::INVALID, :errors => errors }
26
+ else
27
+ { :state => Core::Filtering::ValidationStatus::VALID, :errors => [] }
28
+ end
29
+ log_validation_result(validation_result)
30
+ validation_result
31
+ end
32
+
33
+ end
34
+ end
35
+ end
@@ -9,6 +9,7 @@
9
9
  require 'connectors/base/connector'
10
10
  require 'core/filtering/validation_status'
11
11
  require 'connectors/mongodb/mongo_rules_parser'
12
+ require 'connectors/mongodb/mongo_advanced_snippet_against_schema_validator'
12
13
  require 'mongo'
13
14
  require 'utility'
14
15
 
@@ -51,23 +52,8 @@ module Connectors
51
52
  }
52
53
  end
53
54
 
54
- def self.validate_filtering(filtering = {})
55
- valid_filtering = { :state => Core::Filtering::ValidationStatus::VALID, :errors => [] }
56
-
57
- return valid_filtering unless filtering.present?
58
-
59
- filter = Utility::Filtering.extract_filter(filtering)
60
-
61
- advanced_filter_config = filter[:advanced_snippet] || {}
62
- filter_keys = advanced_filter_config&.keys
63
-
64
- if !filter_keys&.empty? && (filter_keys.size != 1 || !ALLOWED_TOP_LEVEL_FILTER_KEYS.include?(filter_keys[0]&.to_s))
65
- return { :state => Core::Filtering::ValidationStatus::INVALID,
66
- :errors => [{ :ids => ['wrong-keys'],
67
- :messages => ["Only one of #{ALLOWED_TOP_LEVEL_FILTER_KEYS} is allowed in the filtering object. Keys present: '#{filter_keys}'."] }] }
68
- end
69
-
70
- valid_filtering
55
+ def self.advanced_snippet_validator
56
+ MongoAdvancedSnippetAgainstSchemaValidator
71
57
  end
72
58
 
73
59
  def initialize(configuration: {}, job_description: {})
@@ -111,13 +97,12 @@ module Connectors
111
97
  Utility::Logger.info("Requesting #{PAGE_SIZE} documents from MongoDB (Starting at #{skip})")
112
98
  view = cursor.skip(skip).limit(PAGE_SIZE)
113
99
  view.each do |document|
114
- yield serialize(document)
115
-
116
- found_in_page += 1
117
- found_overall += 1
118
-
119
- overall_limit_reached = found_overall >= overall_limit && overall_limit != Float::INFINITY
120
-
100
+ yield_with_handling_tolerable_errors do
101
+ yield serialize(document)
102
+ found_in_page += 1
103
+ found_overall += 1
104
+ overall_limit_reached = found_overall >= overall_limit && overall_limit != Float::INFINITY
105
+ end
121
106
  break if overall_limit_reached
122
107
  end
123
108
 
@@ -0,0 +1,22 @@
1
+ #
2
+ # Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
3
+ # or more contributor license agreements. Licensed under the Elastic License;
4
+ # you may not use this file except in compliance with the Elastic License.
5
+ #
6
+
7
+ # frozen_string_literal: true
8
+
9
+ require 'connectors/base/advanced_snippet_against_schema_validator'
10
+ require 'connectors/mongodb/mongo_advanced_snippet_schema'
11
+
12
+ module Connectors
13
+ module MongoDB
14
+ class MongoAdvancedSnippetAgainstSchemaValidator < Connectors::Base::AdvancedSnippetAgainstSchemaValidator
15
+
16
+ def initialize(advanced_snippet, schema = Connectors::MongoDB::AdvancedSnippet::SCHEMA)
17
+ super
18
+ end
19
+
20
+ end
21
+ end
22
+ end