connectors_service 8.6.0.4.pre.20221114T233727Z → 8.6.0.4.pre.20221116T024501Z
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/config/connectors.yml +4 -4
- data/lib/app/app.rb +4 -0
- data/lib/app/dispatcher.rb +30 -17
- data/lib/connectors/base/advanced_snippet_against_schema_validator.rb +173 -0
- data/lib/connectors/base/advanced_snippet_validator.rb +34 -0
- data/lib/connectors/base/connector.rb +27 -5
- data/lib/connectors/example/connector.rb +3 -12
- data/lib/connectors/example/example_advanced_snippet_validator.rb +35 -0
- data/lib/connectors/gitlab/connector.rb +3 -12
- data/lib/connectors/gitlab/gitlab_advanced_snippet_validator.rb +35 -0
- data/lib/connectors/mongodb/connector.rb +9 -24
- data/lib/connectors/mongodb/mongo_advanced_snippet_against_schema_validator.rb +22 -0
- data/lib/connectors/mongodb/mongo_advanced_snippet_schema.rb +292 -0
- data/lib/connectors/sync_status.rb +6 -1
- data/lib/connectors/tolerable_error_helper.rb +43 -0
- data/lib/core/connector_job.rb +96 -23
- data/lib/core/connector_settings.rb +29 -6
- data/lib/core/elastic_connector_actions.rb +77 -55
- data/lib/core/filtering/validation_job_runner.rb +1 -1
- data/lib/core/ingestion/es_sink.rb +68 -9
- data/lib/core/ingestion.rb +0 -1
- data/lib/core/jobs/consumer.rb +114 -0
- data/lib/core/jobs/producer.rb +26 -0
- data/lib/core/single_scheduler.rb +1 -1
- data/lib/core/sync_job_runner.rb +20 -12
- data/lib/core.rb +2 -0
- data/lib/utility/error_monitor.rb +108 -0
- data/lib/utility/errors.rb +0 -12
- data/lib/utility/logger.rb +0 -1
- data/lib/utility.rb +6 -0
- metadata +12 -3
- data/lib/core/ingestion/ingester.rb +0 -90
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 9a610999d9c34543392e1dd9b7b9ab136557992cc1503fa5aa5973186d17af9e
|
4
|
+
data.tar.gz: '086282a4a15ce1b168e6a0add5f78646e1fe89c336b8a257677826cce3677635'
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: bf0a0a22ea96074bcbb904000ec489a591fc8491bc2d91759bc1a097c60e31c2abad7b118bb97d16bbe80c5b00dbe08f7c65653710c2d6a77d3356607d87e045
|
7
|
+
data.tar.gz: 67ff773ed2ae3f869897b5fb3a2c0dc3fc55c5922c602e032ed5bafa800043bd4b7f4af90fdd055e575ea877f3cf3b9e308d91c58bad59cd6c63dd5eb8ab98f4
|
data/config/connectors.yml
CHANGED
@@ -1,10 +1,10 @@
|
|
1
1
|
# general metadata
|
2
|
-
version: 8.6.0.4-
|
2
|
+
version: 8.6.0.4-20221116T024501Z
|
3
3
|
repository: git@github.com:elastic/ent-search-connectors.git
|
4
|
-
revision:
|
4
|
+
revision: b3cc1332879a38930a272a63f8c6be1847578204
|
5
5
|
elasticsearch:
|
6
6
|
hosts: http://localhost:9200
|
7
|
-
api_key:
|
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:
|
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}")
|
data/lib/app/dispatcher.rb
CHANGED
@@ -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
|
-
|
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.
|
44
|
-
|
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
|
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.
|
50
|
-
|
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.
|
40
|
-
|
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.
|
55
|
-
|
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
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
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
|