topological_inventory-providers-common 1.0.8 → 2.0.0

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.
Files changed (24) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +22 -2
  3. data/lib/topological_inventory/providers/common.rb +1 -2
  4. data/lib/topological_inventory/providers/common/collector.rb +12 -4
  5. data/lib/topological_inventory/providers/common/collectors_pool.rb +2 -1
  6. data/lib/topological_inventory/providers/common/logging.rb +10 -4
  7. data/lib/topological_inventory/providers/common/mixins/sources_api.rb +58 -0
  8. data/lib/topological_inventory/providers/common/mixins/topology_api.rb +26 -0
  9. data/lib/topological_inventory/providers/common/mixins/x_rh_headers.rb +24 -0
  10. data/lib/topological_inventory/providers/common/operations/async_worker.rb +56 -0
  11. data/lib/topological_inventory/providers/common/operations/health_check.rb +15 -0
  12. data/lib/topological_inventory/providers/common/operations/source.rb +119 -144
  13. data/lib/topological_inventory/providers/common/sources_api_client.rb +92 -0
  14. data/lib/topological_inventory/providers/common/topology_api_client.rb +43 -0
  15. data/lib/topological_inventory/providers/common/version.rb +1 -1
  16. data/spec/support/shared/availability_check.rb +1 -1
  17. data/spec/topological_inventory/providers/common/operations/async_worker_spec.rb +36 -0
  18. data/topological_inventory-providers-common.gemspec +1 -1
  19. metadata +16 -7
  20. data/lib/topological_inventory/providers/common/operations/endpoint_client.rb +0 -65
  21. data/lib/topological_inventory/providers/common/operations/processor.rb +0 -135
  22. data/lib/topological_inventory/providers/common/operations/sources_api_client.rb +0 -94
  23. data/lib/topological_inventory/providers/common/operations/topology_api_client.rb +0 -28
  24. data/spec/topological_inventory/providers/common/operations/processor_spec.rb +0 -102
@@ -0,0 +1,92 @@
1
+ require "sources-api-client"
2
+
3
+ module TopologicalInventory
4
+ module Providers
5
+ module Common
6
+ class SourcesApiClient < ::SourcesApiClient::ApiClient
7
+ delegate :update_source, :update_endpoint, :update_application, :to => :api
8
+
9
+ INTERNAL_API_PATH = '//internal/v1.0'.freeze
10
+
11
+ def initialize(identity = nil)
12
+ super(::SourcesApiClient::Configuration.default)
13
+ self.identity = identity
14
+ self.api = init_default_api
15
+ end
16
+
17
+ def init_default_api
18
+ default_headers.merge!(identity) if identity.present?
19
+ ::SourcesApiClient::DefaultApi.new(self)
20
+ end
21
+
22
+ def fetch_default_endpoint(source_id)
23
+ endpoints = api.list_source_endpoints(source_id)&.data || []
24
+ endpoints.find(&:default)
25
+ end
26
+
27
+ def fetch_application(source_id)
28
+ applications = api.list_source_applications(source_id)&.data || []
29
+ applications.first
30
+ end
31
+
32
+ def fetch_authentication(source_id, default_endpoint = nil, authtype = nil)
33
+ endpoint = default_endpoint || fetch_default_endpoint(source_id)
34
+ return if endpoint.nil?
35
+
36
+ endpoint_authentications = api.list_endpoint_authentications(endpoint.id.to_s).data || []
37
+ return if endpoint_authentications.empty?
38
+
39
+ auth_id = if authtype.nil?
40
+ endpoint_authentications.first&.id
41
+ else
42
+ endpoint_authentications.detect { |a| a.authtype = authtype }&.id
43
+ end
44
+ return if auth_id.nil?
45
+
46
+ fetch_authentication_with_password(auth_id)
47
+ end
48
+
49
+ private
50
+
51
+ attr_accessor :identity, :api, :custom_base_path
52
+
53
+ def fetch_authentication_with_password(auth_id)
54
+ on_internal_api do
55
+ local_var_path = "/authentications/#{auth_id}"
56
+
57
+ query_params = "expose_encrypted_attribute[]=password"
58
+
59
+ header_params = {'Accept' => select_header_accept(['application/json'])}
60
+ return_type = 'Authentication'
61
+ data, _, _ = call_api(:GET, local_var_path,
62
+ :header_params => header_params,
63
+ :query_params => query_params,
64
+ :auth_names => ['UserSecurity'],
65
+ :return_type => return_type)
66
+ data
67
+ end
68
+ end
69
+
70
+ def build_request_url(path)
71
+ # Add leading and trailing slashes to path
72
+ path = "/#{path}".gsub(/\/+/, '/')
73
+ URI.encode((custom_base_url || @config.base_url) + path)
74
+ end
75
+
76
+ def custom_base_url
77
+ return nil if custom_base_path.nil?
78
+
79
+ url = "#{@config.scheme}://#{[@config.host, custom_base_path].join('/').gsub(/\/+/, '/')}".sub(/\/+\z/, '')
80
+ URI.encode(url)
81
+ end
82
+
83
+ def on_internal_api
84
+ self.custom_base_path = INTERNAL_API_PATH
85
+ yield
86
+ ensure
87
+ self.custom_base_path = nil
88
+ end
89
+ end
90
+ end
91
+ end
92
+ end
@@ -0,0 +1,43 @@
1
+ require "topological_inventory-api-client"
2
+
3
+ module TopologicalInventory
4
+ module Providers
5
+ module Common
6
+ class TopologyApiClient < ::TopologicalInventoryApiClient::ApiClient
7
+ attr_accessor :api
8
+
9
+ def initialize(identity = nil)
10
+ super(::TopologicalInventoryApiClient::Configuration.default)
11
+
12
+ self.identity = identity
13
+ self.api = init_default_api
14
+ end
15
+
16
+ def init_default_api
17
+ default_headers.merge!(identity) if identity.present?
18
+ ::TopologicalInventoryApiClient::DefaultApi.new(self)
19
+ end
20
+
21
+ def update_task(task_id, source_id: nil, state:, status:, target_type: nil, target_source_ref: nil, context: nil)
22
+ params = {'state' => state,
23
+ 'status' => status}
24
+ params['context'] = context if context
25
+ params['source_id'] = source_id if source_id
26
+ params['target_type'] = target_type if target_type
27
+ params['target_source_ref'] = target_source_ref if target_source_ref
28
+ task = TopologicalInventoryApiClient::Task.new(params)
29
+ api.update_task(task_id, task)
30
+ end
31
+
32
+ def svc_instance_url(service_instance)
33
+ rest_api_path = '/service_instances/{id}'.sub('{' + 'id' + '}', service_instance&.id.to_s)
34
+ build_request(:GET, rest_api_path).url
35
+ end
36
+
37
+ private
38
+
39
+ attr_accessor :identity
40
+ end
41
+ end
42
+ end
43
+ end
@@ -1,7 +1,7 @@
1
1
  module TopologicalInventory
2
2
  module Providers
3
3
  module Common
4
- VERSION = "1.0.8"
4
+ VERSION = "2.0.0".freeze
5
5
  end
6
6
  end
7
7
  end
@@ -94,7 +94,7 @@ RSpec.shared_examples "availability_check" do
94
94
  stub_patch(:source, source_patch_body)
95
95
 
96
96
  # Check
97
- api_client = subject.send(:api_client)
97
+ api_client = subject.send(:sources_api)
98
98
  expect(api_client).not_to receive(:update_endpoint)
99
99
 
100
100
  subject.availability_check
@@ -0,0 +1,36 @@
1
+ require "topological_inventory/providers/common/operations/async_worker"
2
+
3
+ describe TopologicalInventory::Providers::Common::Operations::AsyncWorker do
4
+ let(:queue) { double }
5
+ let(:impl) { double }
6
+ let(:msg) { double }
7
+ subject { described_class.new(impl, queue) }
8
+
9
+ before do
10
+ allow(queue).to receive(:length).and_return(0)
11
+ allow(msg).to receive(:message).and_return("Source.availability_check")
12
+ end
13
+
14
+ context "when the message is able to be processed" do
15
+ before do
16
+ allow(impl).to receive(:process!).with(msg)
17
+ allow(msg).to receive(:ack)
18
+ end
19
+
20
+ it "drains messages that are added to the queue" do
21
+ expect(impl).to receive(:process!).with(msg).once
22
+ subject.send(:process_message, msg)
23
+ end
24
+ end
25
+
26
+ context "when the message results in an error" do
27
+ before do
28
+ allow(impl).to receive(:process!).with(msg).and_raise(StandardError.new("boom!"))
29
+ end
30
+
31
+ it "ack's the message on failure" do
32
+ expect(msg).to receive(:ack).once
33
+ subject.send(:process_message, msg)
34
+ end
35
+ end
36
+ end
@@ -29,7 +29,7 @@ Gem::Specification.new do |spec|
29
29
  spec.add_runtime_dependency "manageiq-loggers", ">= 0.4.2"
30
30
  spec.add_runtime_dependency "sources-api-client", "~> 3.0"
31
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"
32
+ spec.add_runtime_dependency "topological_inventory-ingress_api-client", "~> 1.0", ">= 1.0.3"
33
33
 
34
34
  spec.add_development_dependency "bundler", "~> 2.0"
35
35
  spec.add_development_dependency "rake", ">= 12.3.3"
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: 1.0.8
4
+ version: 2.0.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-08-12 00:00:00.000000000 Z
11
+ date: 2020-10-20 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activesupport
@@ -113,6 +113,9 @@ dependencies:
113
113
  - - "~>"
114
114
  - !ruby/object:Gem::Version
115
115
  version: '1.0'
116
+ - - ">="
117
+ - !ruby/object:Gem::Version
118
+ version: 1.0.3
116
119
  type: :runtime
117
120
  prerelease: false
118
121
  version_requirements: !ruby/object:Gem::Requirement
@@ -120,6 +123,9 @@ dependencies:
120
123
  - - "~>"
121
124
  - !ruby/object:Gem::Version
122
125
  version: '1.0'
126
+ - - ">="
127
+ - !ruby/object:Gem::Version
128
+ version: 1.0.3
123
129
  - !ruby/object:Gem::Dependency
124
130
  name: bundler
125
131
  requirement: !ruby/object:Gem::Requirement
@@ -246,13 +252,16 @@ files:
246
252
  - lib/topological_inventory/providers/common/collector/parser.rb
247
253
  - lib/topological_inventory/providers/common/collectors_pool.rb
248
254
  - lib/topological_inventory/providers/common/logging.rb
249
- - lib/topological_inventory/providers/common/operations/endpoint_client.rb
250
- - lib/topological_inventory/providers/common/operations/processor.rb
255
+ - lib/topological_inventory/providers/common/mixins/sources_api.rb
256
+ - lib/topological_inventory/providers/common/mixins/topology_api.rb
257
+ - lib/topological_inventory/providers/common/mixins/x_rh_headers.rb
258
+ - lib/topological_inventory/providers/common/operations/async_worker.rb
259
+ - lib/topological_inventory/providers/common/operations/health_check.rb
251
260
  - lib/topological_inventory/providers/common/operations/source.rb
252
- - lib/topological_inventory/providers/common/operations/sources_api_client.rb
253
- - lib/topological_inventory/providers/common/operations/topology_api_client.rb
254
261
  - lib/topological_inventory/providers/common/save_inventory/exception.rb
255
262
  - lib/topological_inventory/providers/common/save_inventory/saver.rb
263
+ - lib/topological_inventory/providers/common/sources_api_client.rb
264
+ - lib/topological_inventory/providers/common/topology_api_client.rb
256
265
  - lib/topological_inventory/providers/common/version.rb
257
266
  - spec/spec_helper.rb
258
267
  - spec/support/inventory_helper.rb
@@ -262,7 +271,7 @@ files:
262
271
  - spec/topological_inventory/providers/common/collectors/inventory_collection_wrapper_spec.rb
263
272
  - spec/topological_inventory/providers/common/collectors_pool_spec.rb
264
273
  - spec/topological_inventory/providers/common/logger_spec.rb
265
- - spec/topological_inventory/providers/common/operations/processor_spec.rb
274
+ - spec/topological_inventory/providers/common/operations/async_worker_spec.rb
266
275
  - spec/topological_inventory/providers/common/operations/source_spec.rb
267
276
  - spec/topological_inventory/providers/common/save_inventory/saver_spec.rb
268
277
  - spec/topological_inventory/providers/common_spec.rb
@@ -1,65 +0,0 @@
1
- require "topological_inventory/providers/common/operations/topology_api_client"
2
- require "topological_inventory/providers/common/operations/sources_api_client"
3
-
4
- module TopologicalInventory
5
- module Providers
6
- module Common
7
- module Operations
8
- class EndpointClient
9
- include TopologyApiClient
10
-
11
- def initialize(source_id, task_id, identity = nil)
12
- self.identity = identity
13
- self.source_id = source_id
14
- self.task_id = task_id
15
- end
16
-
17
- def order_service(service_offering, service_plan, order_params)
18
- raise NotImplementedError, "#{__method__} must be implemented in a subclass"
19
- end
20
-
21
- def source_ref_of(endpoint_svc_instance)
22
- raise NotImplementedError, "#{__method__} must be implemented in a subclass"
23
- end
24
-
25
- def wait_for_provision_complete(source_id, endpoint_svc_instance, context = {})
26
- raise NotImplementedError, "#{__method__} must be implemented in a subclass"
27
- end
28
-
29
- def provisioned_successfully?(endpoint_svc_instance)
30
- raise NotImplementedError, "#{__method__} must be implemented in a subclass"
31
- end
32
-
33
- # Endpoint for conversion of provisioned service's status to
34
- # TopologicalInventory Task's status
35
- def task_status_for(endpoint_svc_instance)
36
- raise NotImplementedError, "#{__method__} must be implemented in a subclass"
37
- end
38
-
39
- private
40
-
41
- attr_accessor :identity, :task_id, :source_id
42
-
43
- def sources_api
44
- @sources_api ||= SourcesApiClient.new(identity)
45
- end
46
-
47
- def default_endpoint
48
- @default_endpoint ||= sources_api.fetch_default_endpoint(source_id)
49
- raise "Sources API: Endpoint not found! (source id: #{source_id})" if @default_endpoint.nil?
50
-
51
- @default_endpoint
52
- end
53
-
54
- def authentication
55
- @authentication ||= sources_api.fetch_authentication(source_id, default_endpoint)
56
- end
57
-
58
- def verify_ssl_mode
59
- default_endpoint.verify_ssl ? OpenSSL::SSL::VERIFY_PEER : OpenSSL::SSL::VERIFY_NONE
60
- end
61
- end
62
- end
63
- end
64
- end
65
- end
@@ -1,135 +0,0 @@
1
- require "topological_inventory/providers/common/operations/topology_api_client"
2
-
3
- module TopologicalInventory
4
- module Providers
5
- module Common
6
- module Operations
7
- class Processor
8
- include Logging
9
- include TopologyApiClient
10
-
11
- SLEEP_POLL = 10
12
- POLL_TIMEOUT = 1800
13
-
14
- def self.process!(message)
15
- model, method = message.headers['message_type'].to_s.split(".")
16
- new(model, method, message.payload).process
17
- end
18
-
19
- # @param payload [Hash] https://github.com/ManageIQ/topological_inventory-api/blob/master/app/controllers/api/v0/service_plans_controller.rb#L32-L41
20
- def initialize(model, method, payload, metrics = nil)
21
- self.model = model
22
- self.method = method
23
- self.params = payload["params"]
24
- self.identity = payload["request_context"]
25
- self.metrics = metrics
26
- end
27
-
28
- def process
29
- logger.info("Processing #{model}##{method} [#{params}]...")
30
- result = order_service(params)
31
- logger.info("Processing #{model}##{method} [#{params}]...Complete")
32
-
33
- result
34
- end
35
-
36
- private
37
-
38
- attr_accessor :identity, :model, :method, :metrics, :params
39
-
40
- def endpoint_client(source_id, task_id, identity)
41
- raise NotImplementedError, "#{__method__} must be implemented in a subclass as kind of TopologicalInventory::Providers::Common::EndpointClient class"
42
- end
43
-
44
- def order_service(params)
45
- task_id, service_offering_id, service_plan_id, order_params = params.values_at("task_id", "service_offering_id", "service_plan_id", "order_params")
46
-
47
- service_plan = topology_api_client.show_service_plan(service_plan_id) if service_plan_id.present?
48
- service_offering_id = service_plan.service_offering_id if service_offering_id.nil? && service_plan.present?
49
- service_offering = topology_api_client.show_service_offering(service_offering_id)
50
-
51
- source_id = service_offering.source_id
52
- client = endpoint_client(source_id, task_id, identity)
53
-
54
- logger.info("Ordering #{service_offering.name}...")
55
- remote_service_instance = client.order_service(service_offering, service_plan.presence, order_params)
56
- logger.info("Ordering #{service_offering.name}...Complete")
57
-
58
- poll_order_complete_thread(task_id, source_id, remote_service_instance)
59
- rescue StandardError => err
60
- metrics&.record_error
61
- logger.error("[Task #{task_id}] Ordering error: #{err}\n#{err.backtrace.join("\n")}")
62
- update_task(task_id, :state => "completed", :status => "error", :context => {:error => err.to_s})
63
- end
64
-
65
- def poll_order_complete_thread(task_id, source_id, remote_svc_instance)
66
- Thread.new do
67
- begin
68
- poll_order_complete(task_id, source_id, remote_svc_instance)
69
- rescue StandardError => err
70
- logger.error("[Task #{task_id}] Waiting for complete: #{err}\n#{err.backtrace.join("\n")}")
71
- update_task(task_id, :state => "completed", :status => "warn", :context => {:error => err.to_s})
72
- end
73
- end
74
- end
75
-
76
- def poll_order_complete(task_id, source_id, remote_svc_instance)
77
- client = endpoint_client(source_id, task_id, identity)
78
-
79
- context = {
80
- :service_instance => {
81
- :source_id => source_id,
82
- :source_ref => client.source_ref_of(remote_svc_instance)
83
- }
84
- }
85
-
86
- remote_svc_instance = client.wait_for_provision_complete(task_id, remote_svc_instance, context)
87
-
88
- if client.provisioned_successfully?(remote_svc_instance)
89
- if (service_instance = load_topological_svc_instance(source_id, client.source_ref_of(remote_svc_instance))).present?
90
- context[:service_instance][:id] = service_instance.id
91
- context[:service_instance][:url] = svc_instance_url(service_instance)
92
- else
93
- logger.warn("Failed to get service_instance API URL (endpoint's service instance: #{remote_svc_instance.inspect})")
94
- end
95
- end
96
- update_task(task_id, :state => "completed", :status => client.task_status_for(remote_svc_instance), :context => context)
97
- end
98
-
99
- def load_topological_svc_instance(source_id, source_ref)
100
- api = topology_api_client.api_client
101
-
102
- count = 0
103
- timeout_count = POLL_TIMEOUT / SLEEP_POLL
104
-
105
- header_params = { 'Accept' => api.select_header_accept(['application/json']) }
106
- query_params = { :'source_id' => source_id, :'source_ref' => source_ref }
107
- return_type = 'ServiceInstancesCollection'
108
-
109
- service_instance = nil
110
- loop do
111
- data, _status_code, _headers = api.call_api(:GET, "/service_instances",
112
- :header_params => header_params,
113
- :query_params => query_params,
114
- :auth_names => ['UserSecurity'],
115
- :return_type => return_type)
116
-
117
- service_instance = data.data&.first if data.meta.count > 0
118
- break if service_instance.present?
119
-
120
- break if (count += 1) >= timeout_count
121
-
122
- sleep(SLEEP_POLL) # seconds
123
- end
124
-
125
- if service_instance.nil?
126
- logger.error("Failed to find service_instance by source_id [#{source_id}] source_ref [#{source_ref}]")
127
- end
128
-
129
- service_instance
130
- end
131
- end
132
- end
133
- end
134
- end
135
- end