topological_inventory-providers-common 2.0.0 → 2.1.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 134e945b201072b8bdd7fc6af73b04a6f60698da831ef3989ab973453a1a5159
4
- data.tar.gz: 20e4f260c411551572b557f4e4454fdc03c9e3b2ac9c8f5997e6600780298c1a
3
+ metadata.gz: aad209b97efea9bb19ce488782adb1dabfa8d650c12f8637e2b348ed4ec95a15
4
+ data.tar.gz: 69b9bbed6a2d725990206ab3bfc7b13ec25b10f7e0c1a979b48c61b67e53fd0d
5
5
  SHA512:
6
- metadata.gz: 0a847566f6fb20e9518faef660c626788e6afd20d26cec28a5899e645c68cedd7c017974d0cb1c3c2524253007386b9728a1bb67a0f0a9101fe62bd388f03ccb
7
- data.tar.gz: 6e786659b1bf913fe1e22d9c0618986d03dc4bc169d782e446ecd089b97a136b639f83be85c562006dccde83a8d025b102863b565aa571746767fa292e4dae89
6
+ metadata.gz: 45722b70f009a764d8cd804424157cc98b1a225b72326b8b8971fecd093fa6260446777db76bc3502e487d27dc82b2b4325959302f4a1abe13fbbf8c015c1d54
7
+ data.tar.gz: b1a6de8e2eb93b2b26d4b609f17a1a518cf4b318dbcf117c6225fe297bb3ec97f870b944e151786977ad90f42c16746eeeadf6a3d113b648921e278cb831aadd
@@ -0,0 +1,31 @@
1
+ ---
2
+ version: '2'
3
+ prepare:
4
+ fetch:
5
+ - url: https://raw.githubusercontent.com/RedHatInsights/insights-api-common-rails/master/.rubocop_base.yml
6
+ path: ".rubocop_base.yml"
7
+ - url: https://raw.githubusercontent.com/RedHatInsights/insights-api-common-rails/master/.rubocop_cc_base.yml
8
+ path: ".rubocop_cc_base.yml"
9
+ checks:
10
+ argument-count:
11
+ enabled: false
12
+ complex-logic:
13
+ enabled: false
14
+ file-lines:
15
+ enabled: false
16
+ method-complexity:
17
+ config:
18
+ threshold: 11
19
+ method-count:
20
+ enabled: false
21
+ method-lines:
22
+ enabled: false
23
+ nested-control-flow:
24
+ enabled: false
25
+ return-statements:
26
+ enabled: false
27
+ plugins:
28
+ rubocop:
29
+ enabled: true
30
+ config: ".rubocop_cc.yml"
31
+ channel: rubocop-1-0
@@ -1,3 +1,3 @@
1
1
  inherit_from:
2
- - https://raw.githubusercontent.com/ManageIQ/guides/master/.rubocop_base.yml
2
+ - https://raw.githubusercontent.com/RedHatInsights/insights-api-common-rails/master/.rubocop_base.yml
3
3
  - .rubocop_local.yml
@@ -0,0 +1,8 @@
1
+ ---
2
+ ignore: |
3
+
4
+ extends: relaxed
5
+
6
+ rules:
7
+ line-length:
8
+ max: 120
@@ -4,7 +4,12 @@ All notable changes to this project will be documented in this file.
4
4
  The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
5
5
  and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
6
6
 
7
- ## [2.0.0]
7
+ ## [2.1.0]
8
+ Add Availability checks for sources via Kafka #54
9
+ Common Metrics exporter #57
10
+ Rubocop rules from insights-api-common + yamllint #59
11
+
12
+ ## [2.0.0] - 2020-10-20
8
13
  Operations/API clients refactoring
9
14
 
10
15
  ## [1.0.12] - 2020-10-01
@@ -62,7 +67,8 @@ manageiq-loggers to >= 0.4.2 #20
62
67
  ## [1.0.0] - 2020-03-19
63
68
  ### Initial release to rubygems.org
64
69
 
65
- [Unreleased]: https://github.com/RedHatInsights/topological_inventory-providers-common/compare/v2.0.0...HEAD
70
+ [Unreleased]: https://github.com/RedHatInsights/topological_inventory-providers-common/compare/v2.1.0...HEAD
71
+ [2.1.0]: https://github.com/RedHatInsights/topological_inventory-providers-common/compare/v2.0.0...v2.1.0
66
72
  [2.0.0]: https://github.com/RedHatInsights/topological_inventory-providers-common/compare/v1.0.12...v2.0.0
67
73
  [1.0.12]: https://github.com/RedHatInsights/topological_inventory-providers-common/compare/v1.0.11...v1.0.12
68
74
  [1.0.11]: https://github.com/RedHatInsights/topological_inventory-providers-common/compare/v1.0.10...v1.0.11
@@ -3,6 +3,7 @@ require "topological_inventory/providers/common/logging"
3
3
  require "topological_inventory/providers/common/operations/health_check"
4
4
  require "topological_inventory/providers/common/collectors_pool"
5
5
  require "topological_inventory/providers/common/collector"
6
+ require "topological_inventory/providers/common/metrics"
6
7
 
7
8
  module TopologicalInventory
8
9
  module Providers
@@ -0,0 +1,40 @@
1
+ require "more_core_extensions/core_ext/module/cache_with_timeout"
2
+ require "manageiq-messaging"
3
+
4
+ module TopologicalInventory
5
+ module Providers
6
+ module Common
7
+ class MessagingClient
8
+ # Kafka host name
9
+ attr_accessor :queue_host
10
+ # Kafka port
11
+ attr_accessor :queue_port
12
+
13
+ def initialize
14
+ @queue_host = ENV['QUEUE_HOST'] || 'localhost'
15
+ @queue_port = (ENV['QUEUE_PORT'] || 9092).to_i
16
+ end
17
+
18
+ def self.default
19
+ @@default ||= new
20
+ end
21
+
22
+ def self.configure
23
+ if block_given?
24
+ yield(default)
25
+ else
26
+ default
27
+ end
28
+ end
29
+
30
+ cache_with_timeout(:client) do
31
+ ManageIQ::Messaging::Client.open(:protocol => :Kafka, :host => @queue_host, :port => @queue_port)
32
+ end
33
+
34
+ def client
35
+ self.class.client
36
+ end
37
+ end
38
+ end
39
+ end
40
+ end
@@ -0,0 +1,84 @@
1
+ require "benchmark"
2
+ require "prometheus_exporter"
3
+ require "prometheus_exporter/server"
4
+ require "prometheus_exporter/client"
5
+ require "prometheus_exporter/instrumentation"
6
+
7
+ module TopologicalInventory
8
+ module Providers
9
+ module Common
10
+ class Metrics
11
+ ERROR_COUNTER_MESSAGE = "total number of errors".freeze
12
+
13
+ def initialize(port = 9394)
14
+ return if port == 0
15
+
16
+ configure_server(port)
17
+ configure_metrics
18
+ end
19
+
20
+ def stop_server
21
+ @server&.stop
22
+ end
23
+
24
+ def record_error(type = :general)
25
+ @error_counter&.observe(1, :type => type.to_s)
26
+ end
27
+
28
+ def record_operation(name, labels = {})
29
+ @status_counter&.observe(1, (labels || {}).merge(:name => name))
30
+ end
31
+
32
+ def record_operation_time(name, labels = {}, &block)
33
+ record_time(@duration_seconds, (labels || {}).merge(:name => name), &block)
34
+ end
35
+
36
+ # Common method for gauge
37
+ def record_gauge(metric, opt, value: nil, labels: {})
38
+ case opt
39
+ when :set then
40
+ metric&.observe(value.to_i, labels)
41
+ when :add then
42
+ metric&.increment(labels)
43
+ when :remove then
44
+ metric&.decrement(labels)
45
+ end
46
+ end
47
+
48
+ # Common method for histogram
49
+ def record_time(metric, labels = {})
50
+ result = nil
51
+ time = Benchmark.realtime { result = yield }
52
+ metric&.observe(time, labels)
53
+ result
54
+ end
55
+
56
+ private
57
+
58
+ def configure_server(port)
59
+ @server = PrometheusExporter::Server::WebServer.new(:port => port)
60
+ @server.start
61
+
62
+ PrometheusExporter::Client.default = PrometheusExporter::LocalClient.new(:collector => @server.collector)
63
+ end
64
+
65
+ def configure_metrics
66
+ PrometheusExporter::Instrumentation::Process.start
67
+ PrometheusExporter::Metric::Base.default_prefix = default_prefix
68
+
69
+ @duration_seconds = PrometheusExporter::Metric::Histogram.new('duration_seconds', 'Duration of processed operation')
70
+ @error_counter = PrometheusExporter::Metric::Counter.new("error", ERROR_COUNTER_MESSAGE)
71
+ @status_counter = PrometheusExporter::Metric::Counter.new('status_counter', 'number of processed operations')
72
+
73
+ [@duration_seconds, @error_counter, @status_counter].each do |metric|
74
+ @server.collector.register_metric(metric)
75
+ end
76
+ end
77
+
78
+ def default_prefix
79
+ raise NotImplementedError, "#{__method__} must be implemented in a subclass"
80
+ end
81
+ end
82
+ end
83
+ end
84
+ end
@@ -14,6 +14,7 @@ module TopologicalInventory
14
14
  def endpoint
15
15
  @endpoint ||= sources_api.fetch_default_endpoint(source_id)
16
16
  rescue => e
17
+ metrics&.record_error(:sources_api)
17
18
  logger.error_ext(operation, "Failed to fetch Endpoint for Source #{source_id}: #{e.message}")
18
19
  nil
19
20
  end
@@ -25,6 +26,7 @@ module TopologicalInventory
25
26
  sources_api.fetch_authentication(source_id, endpoint)
26
27
  end
27
28
  rescue => e
29
+ metrics&.record_error(:sources_api)
28
30
  logger.error_ext(operation, "Failed to fetch Authentication for Source #{source_id}: #{e.message}")
29
31
  nil
30
32
  end
@@ -32,6 +34,7 @@ module TopologicalInventory
32
34
  def application
33
35
  @application ||= sources_api.fetch_application(source_id)
34
36
  rescue => e
37
+ metrics&.record_error(:sources_api)
35
38
  logger.error_ext(operation, "Failed to fetch Application for Source #{source_id}: #{e.message}")
36
39
  nil
37
40
  end
@@ -0,0 +1,19 @@
1
+ module TopologicalInventory
2
+ module Providers
3
+ module Common
4
+ module Mixins
5
+ module Statuses
6
+ def operation_status
7
+ return @statuses if @statuses.present?
8
+
9
+ @statuses = {}
10
+ %i[success error skipped not_implemented].each do |status|
11
+ @statuses[status] = status.to_s
12
+ end
13
+ @statuses
14
+ end
15
+ end
16
+ end
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,77 @@
1
+ require "topological_inventory/providers/common/logging"
2
+ require "topological_inventory/providers/common/mixins/statuses"
3
+ require "topological_inventory/providers/common/mixins/topology_api"
4
+
5
+ module TopologicalInventory
6
+ module Providers
7
+ module Common
8
+ module Operations
9
+ class Processor
10
+ include Logging
11
+ include Mixins::Statuses
12
+ include Mixins::TopologyApi
13
+
14
+ def self.process!(message, metrics)
15
+ new(message, metrics).process
16
+ end
17
+
18
+ def initialize(message, metrics)
19
+ self.message = message
20
+ self.metrics = metrics
21
+ self.model, self.method = message.message.split(".")
22
+
23
+ self.params = message.payload["params"]
24
+ self.identity = message.payload["request_context"]
25
+ end
26
+
27
+ def process
28
+ logger.info(status_log_msg)
29
+ impl = operation_class&.new(params, identity, metrics)
30
+ if impl&.respond_to?(method)
31
+ with_time_measure do
32
+ result = impl.send(method)
33
+
34
+ logger.info(status_log_msg("Complete"))
35
+ result
36
+ end
37
+ else
38
+ logger.warn(status_log_msg("Not Implemented!"))
39
+ complete_task("not implemented") if params["task_id"]
40
+ operation_status[:not_implemented]
41
+ end
42
+ rescue StandardError, NotImplementedError => e
43
+ complete_task(e.message) if params["task_id"]
44
+ raise
45
+ end
46
+
47
+ private
48
+
49
+ attr_accessor :message, :identity, :model, :method, :metrics, :params
50
+
51
+ def operation_class
52
+ raise NotImplementedError, "#{__method__} must be implemented in a subclass"
53
+ end
54
+
55
+ def with_time_measure
56
+ if metrics.present?
57
+ metrics.record_operation_time(message.message) { yield }
58
+ else
59
+ yield
60
+ end
61
+ end
62
+
63
+ def complete_task(msg, status = "error")
64
+ update_task(params["task_id"],
65
+ :state => "completed",
66
+ :status => status,
67
+ :context => {:error => "#{model}##{method} - #{msg}"})
68
+ end
69
+
70
+ def status_log_msg(status = nil)
71
+ "Processing #{model}##{method} [#{params}]...#{status}"
72
+ end
73
+ end
74
+ end
75
+ end
76
+ end
77
+ end
@@ -1,7 +1,9 @@
1
1
  require "topological_inventory/providers/common/logging"
2
2
  require "active_support/core_ext/numeric/time"
3
3
  require "topological_inventory/providers/common/mixins/sources_api"
4
+ require "topological_inventory/providers/common/mixins/statuses"
4
5
  require "topological_inventory/providers/common/mixins/x_rh_headers"
6
+ require "topological_inventory/providers/common/messaging_client"
5
7
 
6
8
  module TopologicalInventory
7
9
  module Providers
@@ -11,8 +13,11 @@ module TopologicalInventory
11
13
  include Logging
12
14
  include Mixins::SourcesApi
13
15
  include Mixins::XRhHeaders
16
+ include Mixins::Statuses
14
17
 
15
18
  STATUS_AVAILABLE, STATUS_UNAVAILABLE = %w[available unavailable].freeze
19
+ EVENT_AVAILABILITY_STATUS = "availability_status".freeze
20
+ SERVICE_NAME = "platform.sources.status".freeze
16
21
 
17
22
  ERROR_MESSAGES = {
18
23
  :authentication_not_found => "Authentication not found in Sources API",
@@ -20,36 +25,41 @@ module TopologicalInventory
20
25
  }.freeze
21
26
 
22
27
  LAST_CHECKED_AT_THRESHOLD = 5.minutes.freeze
23
- AUTH_NOT_NECESSARY = "n/a".freeze
28
+ AUTH_NOT_NECESSARY = "n/a".freeze
24
29
 
25
30
  attr_accessor :identity, :operation, :params, :request_context, :source_id, :account_number
26
31
 
27
- def initialize(params = {}, request_context = nil)
28
- self.operation = 'Source'
29
- self.params = params
30
- self.request_context = request_context
31
- self.source_id = params['source_id']
32
-
33
- self.account_number = params['external_tenant']
34
- self.identity = identity_by_account_number(account_number)
32
+ def initialize(params = {}, request_context = nil, metrics = nil)
33
+ self.metrics = metrics
34
+ self.operation = 'Source'
35
+ self.params = params
36
+ self.request_context = request_context
37
+ self.source_id = params['source_id']
38
+ self.account_number = params['external_tenant']
39
+ self.updates_via_kafka = ENV['UPDATE_SOURCES_VIA_API'].blank?
40
+ self.identity = identity_by_account_number(account_number)
35
41
  end
36
42
 
37
43
  def availability_check
38
44
  self.operation += '#availability_check'
39
45
 
40
- return if params_missing?
46
+ return operation_status[:error] if params_missing?
41
47
 
42
- return if checked_recently?
48
+ return operation_status[:skipped] if checked_recently?
43
49
 
44
50
  status, error_message = connection_status
45
51
 
46
52
  update_source_and_subresources(status, error_message)
47
53
 
48
54
  logger.availability_check("Completed: Source #{source_id} is #{status}")
55
+
56
+ operation_status[:success]
49
57
  end
50
58
 
51
59
  private
52
60
 
61
+ attr_accessor :metrics, :updates_via_kafka
62
+
53
63
  def required_params
54
64
  %w[source_id]
55
65
  end
@@ -114,10 +124,15 @@ module TopologicalInventory
114
124
  def update_source_and_subresources(status, error_message = nil)
115
125
  logger.availability_check("Updating source [#{source_id}] status [#{status}] message [#{error_message}]")
116
126
 
117
- update_source(status)
118
-
119
- update_endpoint(status, error_message) if endpoint
120
- update_application(status) if application
127
+ if updates_via_kafka
128
+ update_source_by_kafka(status)
129
+ update_endpoint_by_kafka(status, error_message) if endpoint
130
+ update_application_by_kafka(status) if application
131
+ else
132
+ update_source(status)
133
+ update_endpoint(status, error_message) if endpoint
134
+ update_application(status) if application
135
+ end
121
136
  end
122
137
 
123
138
  def update_source(status)
@@ -128,9 +143,18 @@ module TopologicalInventory
128
143
 
129
144
  sources_api.update_source(source_id, source)
130
145
  rescue ::SourcesApiClient::ApiError => e
146
+ metrics&.record_error(:sources_api)
131
147
  logger.availability_check("Failed to update Source id:#{source_id} - #{e.message}", :error)
132
148
  end
133
149
 
150
+ def update_source_by_kafka(status)
151
+ availability_status_message(
152
+ :resource_type => "Source",
153
+ :resource_id => source_id,
154
+ :status => status
155
+ )
156
+ end
157
+
134
158
  def update_endpoint(status, error_message)
135
159
  if endpoint.nil?
136
160
  logger.availability_check("Failed to update Endpoint for Source id:#{source_id}. Endpoint not found", :error)
@@ -146,19 +170,59 @@ module TopologicalInventory
146
170
 
147
171
  sources_api.update_endpoint(endpoint.id, endpoint_update)
148
172
  rescue ::SourcesApiClient::ApiError => e
173
+ metrics&.record_error(:sources_api)
149
174
  logger.availability_check("Failed to update Endpoint(ID: #{endpoint.id}) - #{e.message}", :error)
150
175
  end
151
176
 
177
+ def update_endpoint_by_kafka(status, error_message)
178
+ if endpoint.nil?
179
+ logger.availability_check("Failed to update Endpoint for Source id:#{source_id}. Endpoint not found", :error)
180
+ return
181
+ end
182
+
183
+ availability_status_message(
184
+ :resource_type => "Endpoint",
185
+ :resource_id => endpoint.id,
186
+ :status => status,
187
+ :error => error_message
188
+ )
189
+ end
190
+
152
191
  def update_application(status)
153
- application_update = ::SourcesApiClient::Application.new
154
- application_update.last_checked_at = check_time
155
- application_update.last_available_at = check_time if status == STATUS_AVAILABLE
192
+ application_update = ::SourcesApiClient::Application.new
193
+ application_update.last_checked_at = check_time
194
+ application_update.last_available_at = check_time if status == STATUS_AVAILABLE
156
195
 
157
196
  sources_api.update_application(application.id, application_update)
158
197
  rescue ::SourcesApiClient::ApiError => e
198
+ metrics&.record_error(:sources_api)
159
199
  logger.availability_check("Failed to update Application id: #{application.id} - #{e.message}", :error)
160
200
  end
161
201
 
202
+ def update_application_by_kafka(status)
203
+ availability_status_message(
204
+ :resource_type => "Application",
205
+ :resource_id => application.id,
206
+ :status => status
207
+ )
208
+ end
209
+
210
+ def availability_status_message(payload)
211
+ messaging_client.publish_message(
212
+ :service => SERVICE_NAME,
213
+ :message => EVENT_AVAILABILITY_STATUS,
214
+ :payload => payload.to_json
215
+ )
216
+ rescue => err
217
+ logger.availability_check("Failed to update Application id: #{application.id} - #{err.message}", :error)
218
+ ensure
219
+ messaging_client&.close
220
+ end
221
+
222
+ def messaging_client
223
+ TopologicalInventory::Providers::Common::MessagingClient.default.client
224
+ end
225
+
162
226
  def check_time
163
227
  @check_time ||= Time.now.utc
164
228
  end
@@ -1,7 +1,7 @@
1
1
  module TopologicalInventory
2
2
  module Providers
3
3
  module Common
4
- VERSION = "2.0.0".freeze
4
+ VERSION = "2.1.0".freeze
5
5
  end
6
6
  end
7
7
  end
@@ -7,8 +7,12 @@ RSpec.shared_examples "availability_check" do
7
7
  let(:sources_api_url) { "#{host_url}#{sources_api_path}" }
8
8
 
9
9
  let(:external_tenant) { '11001' }
10
+ let(:kafka_client) { TopologicalInventory::Providers::Common::MessagingClient.default.client }
10
11
  let(:identity) { {'x-rh-identity' => Base64.strict_encode64({'identity' => {'account_number' => external_tenant, 'user' => {'is_org_admin' => true}}}.to_json)} }
11
12
  let(:headers) { {'Content-Type' => 'application/json'}.merge(identity) }
13
+ let(:status_available) { described_class::STATUS_AVAILABLE }
14
+ let(:status_unavailable) { described_class::STATUS_UNAVAILABLE }
15
+ let(:error_message) { 'error_message' }
12
16
  let(:source_id) { '123' }
13
17
  let(:endpoint_id) { '234' }
14
18
  let(:application_id) { '345' }
@@ -32,101 +36,208 @@ RSpec.shared_examples "availability_check" do
32
36
 
33
37
  subject { described_class.new(payload["params"]) }
34
38
 
39
+ def kafka_message(resource_type, resource_id, status, error_message = nil)
40
+ res = {
41
+ :service => described_class::SERVICE_NAME,
42
+ :message => described_class::EVENT_AVAILABILITY_STATUS,
43
+ :payload => {
44
+ :resource_type => resource_type,
45
+ :resource_id => resource_id,
46
+ :status => status
47
+ }
48
+ }
49
+ res[:payload][:error] = error_message if error_message
50
+ res[:payload] = res[:payload].to_json
51
+ res
52
+ end
53
+
54
+ before do
55
+ allow(subject).to receive(:messaging_client).and_return(kafka_client)
56
+ end
57
+
35
58
  context "when not checked recently" do
36
59
  before do
37
60
  allow(subject).to receive(:checked_recently?).and_return(false)
38
61
  end
39
62
 
40
- it "updates Source and Endpoint when available" do
41
- # GET
42
- stub_get(:endpoint, list_endpoints_response)
43
- stub_get(:authentication, list_endpoint_authentications_response)
44
- stub_get(:password, internal_api_authentication_response)
45
- stub_not_found(:application)
63
+ context 'kafka' do
64
+ it 'updates Source and Endpoint when available' do
65
+ stub_get(:endpoint, list_endpoints_response)
66
+ stub_get(:application, list_applications_response)
46
67
 
47
- # PATCH
48
- source_patch_body = {'availability_status' => described_class::STATUS_AVAILABLE, 'last_available_at' => subject.send(:check_time), 'last_checked_at' => subject.send(:check_time)}.to_json
49
- endpoint_patch_body = {'availability_status' => described_class::STATUS_AVAILABLE, 'availability_status_error' => '', 'last_available_at' => subject.send(:check_time), 'last_checked_at' => subject.send(:check_time)}.to_json
68
+ expect(subject).to receive(:connection_status).and_return([status_available, ''])
50
69
 
51
- stub_patch(:source, source_patch_body)
52
- stub_patch(:endpoint, endpoint_patch_body)
70
+ expect(kafka_client).to receive(:publish_message).with(
71
+ kafka_message("Source", source_id, status_available)
72
+ )
53
73
 
54
- # Check ---
55
- expect(subject).to receive(:connection_check).and_return([described_class::STATUS_AVAILABLE, nil])
74
+ expect(kafka_client).to receive(:publish_message).with(
75
+ kafka_message("Endpoint", endpoint_id, status_available, '')
76
+ )
56
77
 
57
- subject.availability_check
78
+ expect(kafka_client).to receive(:publish_message).with(
79
+ kafka_message("Application", application_id, status_available)
80
+ )
58
81
 
59
- assert_patch(:source, source_patch_body)
60
- assert_patch(:endpoint, endpoint_patch_body)
61
- end
82
+ subject.availability_check
83
+ end
62
84
 
63
- it "updates Source and Endpoint when unavailable" do
64
- # GET
65
- stub_get(:endpoint, list_endpoints_response)
66
- stub_get(:authentication, list_endpoint_authentications_response)
67
- stub_get(:password, internal_api_authentication_response)
68
- stub_not_found(:application)
69
85
 
70
- # PATCH
71
- connection_error_message = "Some connection error"
72
- source_patch_body = {'availability_status' => described_class::STATUS_UNAVAILABLE, 'last_checked_at' => subject.send(:check_time)}.to_json
73
- endpoint_patch_body = {'availability_status' => described_class::STATUS_UNAVAILABLE, 'availability_status_error' => connection_error_message, 'last_checked_at' => subject.send(:check_time)}.to_json
86
+ it "updates Source and Endpoint when unavailable" do
87
+ stub_get(:endpoint, list_endpoints_response)
88
+ stub_get(:application, list_applications_response)
74
89
 
75
- stub_patch(:source, source_patch_body)
76
- stub_patch(:endpoint, endpoint_patch_body)
90
+ expect(subject).to receive(:connection_status).and_return([status_unavailable, error_message])
77
91
 
78
- # Check ---
79
- expect(subject).to receive(:connection_check).and_return([described_class::STATUS_UNAVAILABLE, connection_error_message])
92
+ expect(kafka_client).to receive(:publish_message).with(
93
+ kafka_message("Source", source_id, status_unavailable)
94
+ )
80
95
 
81
- subject.availability_check
96
+ expect(kafka_client).to receive(:publish_message).with(
97
+ kafka_message("Endpoint", endpoint_id, status_unavailable, error_message)
98
+ )
82
99
 
83
- assert_patch(:source, source_patch_body)
84
- assert_patch(:endpoint, endpoint_patch_body)
85
- end
100
+ expect(kafka_client).to receive(:publish_message).with(
101
+ kafka_message("Application", application_id, status_unavailable)
102
+ )
86
103
 
87
- it "updates only Source to 'unavailable' status if Endpoint not found" do
88
- # GET
89
- stub_not_found(:endpoint)
90
- stub_not_found(:application)
104
+ subject.availability_check
105
+ end
91
106
 
92
- # PATCH
93
- source_patch_body = {'availability_status' => described_class::STATUS_UNAVAILABLE, 'last_checked_at' => subject.send(:check_time)}.to_json
94
- stub_patch(:source, source_patch_body)
107
+ it "updates only Source to 'unavailable' status if Endpoint not found" do
108
+ stub_not_found(:endpoint)
109
+ stub_not_found(:application)
95
110
 
96
- # Check
97
- api_client = subject.send(:sources_api)
98
- expect(api_client).not_to receive(:update_endpoint)
111
+ expect(subject).to receive(:connection_status).and_return([status_unavailable, error_message])
99
112
 
100
- subject.availability_check
113
+ expect(kafka_client).to receive(:publish_message).with(
114
+ kafka_message("Source", source_id, status_unavailable)
115
+ )
116
+
117
+ expect(subject.logger).to receive(:availability_check).with("Updating source [#{source_id}] status [#{status_unavailable}] message [#{error_message}]")
118
+ expect(subject.logger).to receive(:availability_check).with("Completed: Source #{source_id} is #{status_unavailable}")
119
+
120
+ subject.availability_check
121
+ end
122
+
123
+ it "updates Source and Endpoint to 'unavailable' if Authentication not found" do
124
+ stub_get(:endpoint, list_endpoints_response)
125
+ stub_not_found(:application)
126
+
127
+ expect(subject).to receive(:connection_status).and_return([status_unavailable, error_message])
128
+
129
+ expect(kafka_client).to receive(:publish_message).with(
130
+ kafka_message("Source", source_id, status_unavailable)
131
+ )
132
+
133
+ expect(kafka_client).to receive(:publish_message).with(
134
+ kafka_message("Endpoint", endpoint_id, status_unavailable, error_message)
135
+ )
101
136
 
102
- assert_patch(:source, source_patch_body)
137
+ expect(subject.logger).to receive(:availability_check).with("Updating source [#{source_id}] status [#{status_unavailable}] message [#{error_message}]")
138
+ expect(subject.logger).to receive(:availability_check).with("Completed: Source #{source_id} is #{status_unavailable}")
139
+
140
+ subject.availability_check
141
+ end
103
142
  end
104
143
 
105
- it "updates Source and Endpoint to 'unavailable' if Authentication not found" do
106
- # GET
107
- stub_get(:endpoint, list_endpoints_response)
108
- stub_get(:authentication, list_endpoint_authentications_response_empty)
109
- stub_not_found(:application)
144
+ context 'sources_api' do
145
+ before do
146
+ subject.send(:updates_via_kafka=, false)
147
+ end
110
148
 
111
- # PATCH
112
- source_patch_body = {'availability_status' => described_class::STATUS_UNAVAILABLE, 'last_checked_at' => subject.send(:check_time)}.to_json
113
- endpoint_patch_body = {'availability_status' => described_class::STATUS_UNAVAILABLE, 'availability_status_error' => described_class::ERROR_MESSAGES[:authentication_not_found], 'last_checked_at' => subject.send(:check_time)}.to_json
149
+ it "updates Source and Endpoint when available" do
150
+ # GET
151
+ stub_get(:endpoint, list_endpoints_response)
152
+ stub_get(:authentication, list_endpoint_authentications_response)
153
+ stub_get(:password, internal_api_authentication_response)
154
+ stub_not_found(:application)
114
155
 
115
- stub_patch(:source, source_patch_body)
116
- stub_patch(:endpoint, endpoint_patch_body)
156
+ # PATCH
157
+ source_patch_body = {'availability_status' => described_class::STATUS_AVAILABLE, 'last_available_at' => subject.send(:check_time), 'last_checked_at' => subject.send(:check_time)}.to_json
158
+ endpoint_patch_body = {'availability_status' => described_class::STATUS_AVAILABLE, 'availability_status_error' => '', 'last_available_at' => subject.send(:check_time), 'last_checked_at' => subject.send(:check_time)}.to_json
117
159
 
118
- # Check
119
- expect(subject).not_to receive(:connection_check)
120
- subject.availability_check
160
+ stub_patch(:source, source_patch_body)
161
+ stub_patch(:endpoint, endpoint_patch_body)
162
+
163
+ # Check ---
164
+ expect(subject).to receive(:connection_check).and_return([described_class::STATUS_AVAILABLE, nil])
165
+
166
+ subject.availability_check
167
+
168
+ assert_patch(:source, source_patch_body)
169
+ assert_patch(:endpoint, endpoint_patch_body)
170
+ end
171
+
172
+ it "updates Source and Endpoint when unavailable" do
173
+ # GET
174
+ stub_get(:endpoint, list_endpoints_response)
175
+ stub_get(:authentication, list_endpoint_authentications_response)
176
+ stub_get(:password, internal_api_authentication_response)
177
+ stub_not_found(:application)
178
+
179
+ # PATCH
180
+ connection_error_message = "Some connection error"
181
+ source_patch_body = {'availability_status' => described_class::STATUS_UNAVAILABLE, 'last_checked_at' => subject.send(:check_time)}.to_json
182
+ endpoint_patch_body = {'availability_status' => described_class::STATUS_UNAVAILABLE, 'availability_status_error' => connection_error_message, 'last_checked_at' => subject.send(:check_time)}.to_json
183
+
184
+ stub_patch(:source, source_patch_body)
185
+ stub_patch(:endpoint, endpoint_patch_body)
186
+
187
+ # Check ---
188
+ expect(subject).to receive(:connection_check).and_return([described_class::STATUS_UNAVAILABLE, connection_error_message])
189
+
190
+ subject.availability_check
191
+
192
+ assert_patch(:source, source_patch_body)
193
+ assert_patch(:endpoint, endpoint_patch_body)
194
+ end
195
+
196
+ it "updates only Source to 'unavailable' status if Endpoint not found" do
197
+ # GET
198
+ stub_not_found(:endpoint)
199
+ stub_not_found(:application)
200
+
201
+ # PATCH
202
+ source_patch_body = {'availability_status' => described_class::STATUS_UNAVAILABLE, 'last_checked_at' => subject.send(:check_time)}.to_json
203
+ stub_patch(:source, source_patch_body)
204
+
205
+ # Check
206
+ api_client = subject.send(:sources_api)
207
+ expect(api_client).not_to receive(:update_endpoint)
208
+
209
+ subject.availability_check
210
+
211
+ assert_patch(:source, source_patch_body)
212
+ end
213
+
214
+ it "updates Source and Endpoint to 'unavailable' if Authentication not found" do
215
+ # GET
216
+ stub_get(:endpoint, list_endpoints_response)
217
+ stub_get(:authentication, list_endpoint_authentications_response_empty)
218
+ stub_not_found(:application)
121
219
 
122
- assert_patch(:source, source_patch_body)
123
- assert_patch(:endpoint, endpoint_patch_body)
220
+ # PATCH
221
+ source_patch_body = {'availability_status' => described_class::STATUS_UNAVAILABLE, 'last_checked_at' => subject.send(:check_time)}.to_json
222
+ endpoint_patch_body = {'availability_status' => described_class::STATUS_UNAVAILABLE, 'availability_status_error' => described_class::ERROR_MESSAGES[:authentication_not_found], 'last_checked_at' => subject.send(:check_time)}.to_json
223
+
224
+ stub_patch(:source, source_patch_body)
225
+ stub_patch(:endpoint, endpoint_patch_body)
226
+
227
+ # Check
228
+ expect(subject).not_to receive(:connection_check)
229
+ subject.availability_check
230
+
231
+ assert_patch(:source, source_patch_body)
232
+ assert_patch(:endpoint, endpoint_patch_body)
233
+ end
124
234
  end
125
235
  end
126
236
 
127
237
  context "when checked recently" do
128
238
  before do
129
239
  allow(subject).to receive(:checked_recently?).and_return(true)
240
+ subject.send(:updates_via_kafka=, false)
130
241
  end
131
242
 
132
243
  it "doesn't do connection check" do
@@ -140,44 +251,97 @@ RSpec.shared_examples "availability_check" do
140
251
 
141
252
  context "when there is an application" do
142
253
  context "when it is available" do
143
- it "updates the availability status to available" do
144
- # GET
145
- stub_not_found(:endpoint)
146
- stub_get(:application, list_applications_response)
147
- # PATCH
148
- application_patch_body = {'last_available_at' => subject.send(:check_time), 'last_checked_at' => subject.send(:check_time)}.to_json
149
- source_patch_body = {'availability_status' => described_class::STATUS_AVAILABLE, 'last_available_at' => subject.send(:check_time), 'last_checked_at' => subject.send(:check_time)}.to_json
254
+ context 'kafka' do
255
+ it "updates the availability status to available" do
256
+ stub_not_found(:endpoint)
257
+ stub_get(:application, list_applications_response)
150
258
 
151
- stub_patch(:source, source_patch_body)
152
- stub_patch(:application, application_patch_body)
259
+ expect(subject).to receive(:connection_status).and_return([status_available, ''])
153
260
 
154
- # Check
155
- expect(subject).not_to receive(:connection_check)
156
- subject.availability_check
261
+ expect(kafka_client).to receive(:publish_message).with(
262
+ kafka_message("Source", source_id, status_available)
263
+ )
157
264
 
158
- assert_patch(:source, source_patch_body)
159
- assert_patch(:application, application_patch_body)
265
+ expect(kafka_client).to receive(:publish_message).with(
266
+ kafka_message("Application", application_id, status_available)
267
+ )
268
+
269
+ expect(subject.logger).to receive(:availability_check).with("Updating source [#{source_id}] status [#{status_available}] message []")
270
+ expect(subject.logger).to receive(:availability_check).with("Completed: Source #{source_id} is #{status_available}")
271
+
272
+ subject.availability_check
273
+ end
274
+ end
275
+
276
+ context 'sources_api' do
277
+ before do
278
+ subject.send(:updates_via_kafka=, false)
279
+ end
280
+
281
+ it "updates the availability status to available" do
282
+ # GET
283
+ stub_not_found(:endpoint)
284
+ stub_get(:application, list_applications_response)
285
+ # PATCH
286
+ application_patch_body = {'last_available_at' => subject.send(:check_time), 'last_checked_at' => subject.send(:check_time)}.to_json
287
+ source_patch_body = {'availability_status' => described_class::STATUS_AVAILABLE, 'last_available_at' => subject.send(:check_time), 'last_checked_at' => subject.send(:check_time)}.to_json
288
+
289
+ stub_patch(:source, source_patch_body)
290
+ stub_patch(:application, application_patch_body)
291
+
292
+ # Check
293
+ expect(subject).not_to receive(:connection_check)
294
+ subject.availability_check
295
+
296
+ assert_patch(:source, source_patch_body)
297
+ assert_patch(:application, application_patch_body)
298
+ end
160
299
  end
161
300
  end
162
301
 
163
302
  context "when it is unavailable" do
164
- it "updates the availability status to unavailable" do
165
- # GET
166
- stub_not_found(:endpoint)
167
- stub_get(:application, list_applications_unavailable_response)
168
- # PATCH
169
- application_patch_body = {'last_checked_at' => subject.send(:check_time)}.to_json
170
- source_patch_body = {'availability_status' => described_class::STATUS_UNAVAILABLE, 'last_checked_at' => subject.send(:check_time)}.to_json
303
+ context 'kafka' do
304
+ it "updates the availability status to unavailable" do
305
+ stub_not_found(:endpoint)
306
+ stub_get(:application, list_applications_unavailable_response)
171
307
 
172
- stub_patch(:source, source_patch_body)
173
- stub_patch(:application, application_patch_body)
308
+ expect(subject).to receive(:connection_status).and_return([status_unavailable, error_message])
174
309
 
175
- # Check
176
- expect(subject).not_to receive(:connection_check)
177
- subject.availability_check
310
+ expect(kafka_client).to receive(:publish_message).with(
311
+ kafka_message("Source", source_id, status_unavailable)
312
+ )
178
313
 
179
- assert_patch(:source, source_patch_body)
180
- assert_patch(:application, application_patch_body)
314
+ expect(kafka_client).to receive(:publish_message).with(
315
+ kafka_message("Application", application_id, status_unavailable)
316
+ )
317
+
318
+ subject.availability_check
319
+ end
320
+ end
321
+
322
+ context 'sources_api' do
323
+ before do
324
+ subject.send(:updates_via_kafka=, false)
325
+ end
326
+
327
+ it "updates the availability status to unavailable" do
328
+ # GET
329
+ stub_not_found(:endpoint)
330
+ stub_get(:application, list_applications_unavailable_response)
331
+ # PATCH
332
+ application_patch_body = {'last_checked_at' => subject.send(:check_time)}.to_json
333
+ source_patch_body = {'availability_status' => described_class::STATUS_UNAVAILABLE, 'last_checked_at' => subject.send(:check_time)}.to_json
334
+
335
+ stub_patch(:source, source_patch_body)
336
+ stub_patch(:application, application_patch_body)
337
+
338
+ # Check
339
+ expect(subject).not_to receive(:connection_check)
340
+ subject.availability_check
341
+
342
+ assert_patch(:source, source_patch_body)
343
+ assert_patch(:application, application_patch_body)
344
+ end
181
345
  end
182
346
  end
183
347
  end
@@ -0,0 +1,71 @@
1
+ require "topological_inventory/providers/common/operations/processor"
2
+
3
+ RSpec.describe TopologicalInventory::Providers::Common::Operations::Processor do
4
+ let(:operation_name) { 'Source.availability_check' }
5
+ let(:params) { {'source_id' => 1, 'external_tenant' => '12345'} }
6
+ let(:payload) { {"params" => params, "request_context" => double('request_context')} }
7
+ let(:message) { double("ManageIQ::Messaging::ReceivedMessage", :message => operation_name, :payload => payload) }
8
+
9
+ subject { described_class.new(message, nil) }
10
+
11
+ describe "#process" do
12
+ it "starts the operation if class and method exists" do
13
+ result = double('result')
14
+
15
+ klass = TopologicalInventory::Providers::Common::Operations::Source
16
+ allow(subject).to receive(:operation_class).and_return(klass)
17
+
18
+ source = klass.new(params, payload['request_context'], nil)
19
+ expect(klass).to receive(:new).with(params, payload['request_context'], nil).and_return(source)
20
+ expect(source).to receive(:availability_check).and_return(result)
21
+
22
+ expect(subject.process).to eq(result)
23
+ end
24
+
25
+ it "returns 'not_implemented' if class of method doesn't exist" do
26
+ allow(subject).to receive(:operation_class).and_return(nil)
27
+ allow(subject).to receive(:method).and_return('awesome')
28
+
29
+ expect(subject.process).to eq(subject.operation_status[:not_implemented])
30
+ end
31
+
32
+ it "updates task if not_implemented" do
33
+ allow(subject).to receive(:operation_class).and_return(nil)
34
+ allow(subject).to receive(:method).and_return('awesome')
35
+
36
+ subject.send(:params)['task_id'] = '1'
37
+ expect(subject).to(receive(:update_task).with('1',
38
+ :state => "completed",
39
+ :status => "error",
40
+ :context => anything))
41
+ subject.process
42
+ end
43
+
44
+ it "updates task if exception raised" do
45
+ subject.send(:params)['task_id'] = '1'
46
+ expect(subject).to(receive(:update_task).with('1',
47
+ :state => "completed",
48
+ :status => "error",
49
+ :context => anything))
50
+ expect { subject.process }.to raise_exception(NotImplementedError)
51
+ end
52
+ end
53
+
54
+ describe "#with_time_measure" do
55
+ let(:metrics) { double("Metrics") }
56
+
57
+ it "records time and yields if metrics provided" do
58
+ allow(subject).to receive(:metrics).and_return(metrics)
59
+
60
+ expect(metrics).to receive(:record_operation_time).with(operation_name).and_yield
61
+
62
+ expect(subject.send(:with_time_measure) { 42 }).to eq(42)
63
+ end
64
+
65
+ it "only yields if metrics not present" do
66
+ expect(metrics).not_to receive(:record_operation_time)
67
+
68
+ expect(subject.send(:with_time_measure) { 42 }).to eq(42)
69
+ end
70
+ end
71
+ end
@@ -26,16 +26,20 @@ Gem::Specification.new do |spec|
26
26
  spec.add_runtime_dependency 'activesupport', '~> 5.2.4.3'
27
27
  spec.add_runtime_dependency 'config', '~> 1.7', '>= 1.7.2'
28
28
  spec.add_runtime_dependency 'json', '~> 2.3'
29
- spec.add_runtime_dependency "manageiq-loggers", ">= 0.4.2"
30
- spec.add_runtime_dependency "sources-api-client", "~> 3.0"
31
- spec.add_runtime_dependency "topological_inventory-api-client", "~> 3.0", ">= 3.0.1"
32
- spec.add_runtime_dependency "topological_inventory-ingress_api-client", "~> 1.0", ">= 1.0.3"
29
+ spec.add_runtime_dependency 'manageiq-loggers', '>= 0.4.2'
30
+ spec.add_runtime_dependency 'manageiq-messaging', '~> 1.0.0'
31
+ spec.add_runtime_dependency 'more_core_extensions'
32
+ spec.add_runtime_dependency 'prometheus_exporter', '~> 0.4.17'
33
+ spec.add_runtime_dependency 'sources-api-client', '~> 3.0'
34
+ spec.add_runtime_dependency 'topological_inventory-api-client', '~> 3.0', '>= 3.0.1'
35
+ spec.add_runtime_dependency 'topological_inventory-ingress_api-client', '~> 1.0', '>= 1.0.3'
33
36
 
34
- spec.add_development_dependency "bundler", "~> 2.0"
35
- spec.add_development_dependency "rake", ">= 12.3.3"
36
- spec.add_development_dependency "rspec", "~> 3.0"
37
- spec.add_development_dependency 'rubocop', '~>0.69.0'
38
- spec.add_development_dependency 'rubocop-performance', '~>1.3'
39
- spec.add_development_dependency "simplecov", "~> 0.17.1"
37
+ spec.add_development_dependency 'bundler', '~> 2.0'
38
+ spec.add_development_dependency 'rake', '>= 12.3.3'
39
+ spec.add_development_dependency 'rspec', '~> 3.0'
40
+ spec.add_development_dependency 'rubocop', '~> 1.0.0'
41
+ spec.add_development_dependency 'rubocop-performance', '~> 1.8'
42
+ spec.add_development_dependency 'rubocop-rails', '~> 2.8'
43
+ spec.add_development_dependency 'simplecov', '~> 0.17.1'
40
44
  spec.add_development_dependency 'webmock'
41
45
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: topological_inventory-providers-common
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.0.0
4
+ version: 2.1.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Martin Slemr
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2020-10-20 00:00:00.000000000 Z
11
+ date: 2020-11-02 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activesupport
@@ -72,6 +72,48 @@ dependencies:
72
72
  - - ">="
73
73
  - !ruby/object:Gem::Version
74
74
  version: 0.4.2
75
+ - !ruby/object:Gem::Dependency
76
+ name: manageiq-messaging
77
+ requirement: !ruby/object:Gem::Requirement
78
+ requirements:
79
+ - - "~>"
80
+ - !ruby/object:Gem::Version
81
+ version: 1.0.0
82
+ type: :runtime
83
+ prerelease: false
84
+ version_requirements: !ruby/object:Gem::Requirement
85
+ requirements:
86
+ - - "~>"
87
+ - !ruby/object:Gem::Version
88
+ version: 1.0.0
89
+ - !ruby/object:Gem::Dependency
90
+ name: more_core_extensions
91
+ requirement: !ruby/object:Gem::Requirement
92
+ requirements:
93
+ - - ">="
94
+ - !ruby/object:Gem::Version
95
+ version: '0'
96
+ type: :runtime
97
+ prerelease: false
98
+ version_requirements: !ruby/object:Gem::Requirement
99
+ requirements:
100
+ - - ">="
101
+ - !ruby/object:Gem::Version
102
+ version: '0'
103
+ - !ruby/object:Gem::Dependency
104
+ name: prometheus_exporter
105
+ requirement: !ruby/object:Gem::Requirement
106
+ requirements:
107
+ - - "~>"
108
+ - !ruby/object:Gem::Version
109
+ version: 0.4.17
110
+ type: :runtime
111
+ prerelease: false
112
+ version_requirements: !ruby/object:Gem::Requirement
113
+ requirements:
114
+ - - "~>"
115
+ - !ruby/object:Gem::Version
116
+ version: 0.4.17
75
117
  - !ruby/object:Gem::Dependency
76
118
  name: sources-api-client
77
119
  requirement: !ruby/object:Gem::Requirement
@@ -174,28 +216,42 @@ dependencies:
174
216
  requirements:
175
217
  - - "~>"
176
218
  - !ruby/object:Gem::Version
177
- version: 0.69.0
219
+ version: 1.0.0
178
220
  type: :development
179
221
  prerelease: false
180
222
  version_requirements: !ruby/object:Gem::Requirement
181
223
  requirements:
182
224
  - - "~>"
183
225
  - !ruby/object:Gem::Version
184
- version: 0.69.0
226
+ version: 1.0.0
185
227
  - !ruby/object:Gem::Dependency
186
228
  name: rubocop-performance
187
229
  requirement: !ruby/object:Gem::Requirement
188
230
  requirements:
189
231
  - - "~>"
190
232
  - !ruby/object:Gem::Version
191
- version: '1.3'
233
+ version: '1.8'
234
+ type: :development
235
+ prerelease: false
236
+ version_requirements: !ruby/object:Gem::Requirement
237
+ requirements:
238
+ - - "~>"
239
+ - !ruby/object:Gem::Version
240
+ version: '1.8'
241
+ - !ruby/object:Gem::Dependency
242
+ name: rubocop-rails
243
+ requirement: !ruby/object:Gem::Requirement
244
+ requirements:
245
+ - - "~>"
246
+ - !ruby/object:Gem::Version
247
+ version: '2.8'
192
248
  type: :development
193
249
  prerelease: false
194
250
  version_requirements: !ruby/object:Gem::Requirement
195
251
  requirements:
196
252
  - - "~>"
197
253
  - !ruby/object:Gem::Version
198
- version: '1.3'
254
+ version: '2.8'
199
255
  - !ruby/object:Gem::Dependency
200
256
  name: simplecov
201
257
  requirement: !ruby/object:Gem::Requirement
@@ -231,6 +287,7 @@ executables: []
231
287
  extensions: []
232
288
  extra_rdoc_files: []
233
289
  files:
290
+ - ".codeclimate.yml"
234
291
  - ".github/workflows/gem-push.yml"
235
292
  - ".gitignore"
236
293
  - ".rspec"
@@ -238,6 +295,7 @@ files:
238
295
  - ".rubocop_cc.yml"
239
296
  - ".rubocop_local.yml"
240
297
  - ".travis.yml"
298
+ - ".yamllint"
241
299
  - CHANGELOG.md
242
300
  - Gemfile
243
301
  - LICENSE.txt
@@ -252,11 +310,15 @@ files:
252
310
  - lib/topological_inventory/providers/common/collector/parser.rb
253
311
  - lib/topological_inventory/providers/common/collectors_pool.rb
254
312
  - lib/topological_inventory/providers/common/logging.rb
313
+ - lib/topological_inventory/providers/common/messaging_client.rb
314
+ - lib/topological_inventory/providers/common/metrics.rb
255
315
  - lib/topological_inventory/providers/common/mixins/sources_api.rb
316
+ - lib/topological_inventory/providers/common/mixins/statuses.rb
256
317
  - lib/topological_inventory/providers/common/mixins/topology_api.rb
257
318
  - lib/topological_inventory/providers/common/mixins/x_rh_headers.rb
258
319
  - lib/topological_inventory/providers/common/operations/async_worker.rb
259
320
  - lib/topological_inventory/providers/common/operations/health_check.rb
321
+ - lib/topological_inventory/providers/common/operations/processor.rb
260
322
  - lib/topological_inventory/providers/common/operations/source.rb
261
323
  - lib/topological_inventory/providers/common/save_inventory/exception.rb
262
324
  - lib/topological_inventory/providers/common/save_inventory/saver.rb
@@ -272,6 +334,7 @@ files:
272
334
  - spec/topological_inventory/providers/common/collectors_pool_spec.rb
273
335
  - spec/topological_inventory/providers/common/logger_spec.rb
274
336
  - spec/topological_inventory/providers/common/operations/async_worker_spec.rb
337
+ - spec/topological_inventory/providers/common/operations/processor_spec.rb
275
338
  - spec/topological_inventory/providers/common/operations/source_spec.rb
276
339
  - spec/topological_inventory/providers/common/save_inventory/saver_spec.rb
277
340
  - spec/topological_inventory/providers/common_spec.rb