topological_inventory-providers-common 1.0.6 → 1.0.7

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: aafb37efd571f568a887c8c11b31bc87a6141a556ae06b970bf4acfcbdea3d08
4
- data.tar.gz: 2d1024891611a96df454a56819a5f6f921e195605d3867ca05c595c336f9a699
3
+ metadata.gz: 868c8f764cd11d9888ed99698a309cc199fdf92823963f4e5cae71208d506ff7
4
+ data.tar.gz: 39c352e8b1306bdb87675bf0ccc1fe08f02b0c13555b2466c4c38d7a76979aca
5
5
  SHA512:
6
- metadata.gz: daff9b2dc2388297dba831994c74e048d608256c9fd3aadc06446c16abfa4143f5fcbed2e6dd3eff66cb6fbb9e6637abe8f47c1eda452b99d5557c9424c20849
7
- data.tar.gz: ece193799a908c7ca96aee73de80e9a6dc7cf17346b549ebf2d802cd3ed42b11aec7b46837a4078c1569fe608ef0241f7ac64a7daf43bd2905df1d53e21c8e01
6
+ metadata.gz: c2a8af390114548a89c7dc5bb43f1a6e3784a5a59ebd2ce1c7451c15726015df1353e3dcbc3755d7637d696707b0d6db93e5d4907920a1c4b09d3f6410130a77
7
+ data.tar.gz: 46e6596954367336de4049f8024da8b5e63e5be4c60636c77f91f22c3e407229b38aca604137907d1f5cd6411201d9c3b57e4ad5bab2cfb749b2c04e9ca8eeab
@@ -4,6 +4,11 @@ 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
+ ## [1.0.7] - 2020-07-27
8
+ Update operations/source model for receptor-enabled availability checks #36
9
+ Add check for Application subresource under a Source during Availability check #40
10
+ Remove infinite loop in error messages #43
11
+
7
12
  ## [1.0.6] - 2020-07-06
8
13
  Add some error handling if Sources does not have endpoints/authentications for a source #38
9
14
  Specs for Collector #35
@@ -38,7 +43,8 @@ manageiq-loggers to >= 0.4.2 #20
38
43
  ## [1.0.0] - 2020-03-19
39
44
  ### Initial release to rubygems.org
40
45
 
41
- [Unreleased]: https://github.com/RedHatInsights/topological_inventory-providers-common/compare/v1.0.6...HEAD
46
+ [Unreleased]: https://github.com/RedHatInsights/topological_inventory-providers-common/compare/v1.0.7...HEAD
47
+ [1.0.6]: https://github.com/RedHatInsights/topological_inventory-providers-common/compare/v1.0.6...v1.0.7
42
48
  [1.0.6]: https://github.com/RedHatInsights/topological_inventory-providers-common/compare/v1.0.5...v1.0.6
43
49
  [1.0.5]: https://github.com/RedHatInsights/topological_inventory-providers-common/compare/v1.0.4...v1.0.5
44
50
  [1.0.4]: https://github.com/RedHatInsights/topological_inventory-providers-common/compare/v1.0.3...v1.0.4
@@ -12,18 +12,20 @@ module TopologicalInventory
12
12
  STATUS_AVAILABLE, STATUS_UNAVAILABLE = %w[available unavailable].freeze
13
13
 
14
14
  ERROR_MESSAGES = {
15
- :authentication_not_found => "Authentication not found in Sources API",
16
- :endpoint_not_found => "Endpoint not found in Sources API",
15
+ :authentication_not_found => "Authentication not found in Sources API",
16
+ :endpoint_or_application_not_found => "Endpoint or Application not found in Sources API",
17
17
  }.freeze
18
18
 
19
19
  LAST_CHECKED_AT_THRESHOLD = 5.minutes.freeze
20
+ AUTH_NOT_NECESSARY = "n/a".freeze
20
21
 
21
- attr_accessor :params, :request_context, :source_id
22
+ attr_accessor :params, :request_context, :source_id, :account_number
22
23
 
23
24
  def initialize(params = {}, request_context = nil)
24
25
  self.params = params
25
26
  self.request_context = request_context
26
27
  self.source_id = params['source_id']
28
+ self.account_number = params['external_tenant']
27
29
  end
28
30
 
29
31
  def availability_check
@@ -33,7 +35,7 @@ module TopologicalInventory
33
35
 
34
36
  status, error_message = connection_status
35
37
 
36
- update_source_and_endpoint(status, error_message)
38
+ update_source_and_subresources(status, error_message)
37
39
 
38
40
  logger.availability_check("Completed: Source #{source_id} is #{status}")
39
41
  end
@@ -57,32 +59,57 @@ module TopologicalInventory
57
59
  end
58
60
 
59
61
  def checked_recently?
60
- return false if endpoint.nil?
62
+ checked_recently = if endpoint.present?
63
+ endpoint.last_checked_at.present? && endpoint.last_checked_at >= LAST_CHECKED_AT_THRESHOLD.ago
64
+ elsif application.present?
65
+ application.last_checked_at.present? && application.last_checked_at >= LAST_CHECKED_AT_THRESHOLD.ago
66
+ end
61
67
 
62
- checked_recently = endpoint.last_checked_at.present? && endpoint.last_checked_at >= LAST_CHECKED_AT_THRESHOLD.ago
63
- logger.availability_check("Skipping, last check at #{endpoint.last_checked_at} [Source ID: #{source_id}] ") if checked_recently
68
+ logger.availability_check("Skipping, last check at #{endpoint.last_checked_at || application.last_checked_at} [Source ID: #{source_id}] ") if checked_recently
64
69
 
65
70
  checked_recently
66
71
  end
67
72
 
68
73
  def connection_status
69
- return [STATUS_UNAVAILABLE, ERROR_MESSAGES[:endpoint_not_found]] unless endpoint
70
- return [STATUS_UNAVAILABLE, ERROR_MESSAGES[:authentication_not_found]] unless authentication
74
+ # we need either an endpoint or application to check the source.
75
+ return [STATUS_UNAVAILABLE, ERROR_MESSAGES[:endpoint_or_application_not_found]] unless endpoint || application
71
76
 
72
77
  check_time
78
+ if endpoint
79
+ endpoint_connection_check
80
+ elsif application
81
+ application_connection_check
82
+ end
83
+ end
84
+
85
+ def endpoint_connection_check
86
+ return [STATUS_UNAVAILABLE, ERROR_MESSAGES[:authentication_not_found]] unless authentication
87
+
88
+ # call down into the operations pod implementation of `Source#connection_check`
73
89
  connection_check
74
90
  end
75
91
 
92
+ def application_connection_check
93
+ case application.availability_status
94
+ when "available"
95
+ [STATUS_AVAILABLE, nil]
96
+ when "unavailable"
97
+ [STATUS_UNAVAILABLE, "Application id #{application.id} unavailable"]
98
+ end
99
+ end
100
+
76
101
  # @return [Array<String, String|nil] - STATUS_[UN]AVAILABLE, error message
77
102
  def connection_check
78
103
  raise NotImplementedError, "#{__method__} must be implemented in a subclass"
79
104
  end
80
105
 
81
- def update_source_and_endpoint(status, error_message = nil)
106
+ def update_source_and_subresources(status, error_message = nil)
82
107
  logger.availability_check("Updating source [#{source_id}] status [#{status}] message [#{error_message}]")
83
108
 
84
109
  update_source(status)
85
- update_endpoint(status, error_message)
110
+
111
+ update_endpoint(status, error_message) if endpoint
112
+ update_application(status) if application
86
113
  end
87
114
 
88
115
  def update_source(status)
@@ -114,18 +141,36 @@ module TopologicalInventory
114
141
  logger.availability_check("Failed to update Endpoint(ID: #{endpoint.id}) - #{e.message}", :error)
115
142
  end
116
143
 
144
+ def update_application(status)
145
+ application_update = ::SourcesApiClient::Application.new
146
+ application_update.last_checked_at = check_time
147
+ application_update.last_available_at = check_time if status == STATUS_AVAILABLE
148
+
149
+ api_client.update_application(application.id, application_update)
150
+ rescue ::SourcesApiClient::ApiError => e
151
+ logger.availability_check("Failed to update Application id: #{application.id} - #{e.message}", :error)
152
+ end
153
+
117
154
  def endpoint
118
155
  @endpoint ||= api_client.fetch_default_endpoint(source_id)
119
- rescue StandardError => e
120
- logger.availability_check("Failed to fetch Endpoint for Source #{source_id}, Endpoint #{endpoint}: #{e.message}", :error)
121
- return
156
+ rescue e
157
+ logger.availability_check("Failed to fetch Endpoint for Source #{source_id}: #{e.message}", :error)
122
158
  end
123
159
 
124
160
  def authentication
125
- @authentication ||= api_client.fetch_authentication(source_id, endpoint)
126
- rescue StandardError => e
127
- logger.availability_check("Failed to fetch Authentication for Source #{source_id}, Endpoint #{endpoint}: #{e.message}", :error)
128
- return
161
+ @authentication ||= if endpoint.receptor_node.present?
162
+ AUTH_NOT_NECESSARY
163
+ else
164
+ api_client.fetch_authentication(source_id, endpoint)
165
+ end
166
+ rescue e
167
+ logger.availability_check("Failed to fetch Authentication for Source #{source_id}: #{e.message}", :error)
168
+ end
169
+
170
+ def application
171
+ @application ||= api_client.fetch_application(source_id)
172
+ rescue e
173
+ logger.availability_check("Failed to fetch Application for Source #{source_id}: #{e.message}", :error)
129
174
  end
130
175
 
131
176
  def check_time
@@ -133,7 +178,7 @@ module TopologicalInventory
133
178
  end
134
179
 
135
180
  def identity
136
- @identity ||= {"x-rh-identity" => Base64.strict_encode64({"identity" => {"account_number" => params["external_tenant"], "user" => {"is_org_admin" => true}}}.to_json)}
181
+ @identity ||= {"x-rh-identity" => Base64.strict_encode64({"identity" => {"account_number" => account_number, "user" => {"is_org_admin" => true}}}.to_json)}
137
182
  end
138
183
 
139
184
  def api_client
@@ -5,7 +5,7 @@ module TopologicalInventory
5
5
  module Common
6
6
  module Operations
7
7
  class SourcesApiClient < ::SourcesApiClient::ApiClient
8
- delegate :update_source, :update_endpoint, :to => :api
8
+ delegate :update_source, :update_endpoint, :update_application, :to => :api
9
9
 
10
10
  INTERNAL_API_PATH = '//internal/v1.0'.freeze
11
11
 
@@ -25,6 +25,11 @@ module TopologicalInventory
25
25
  endpoints.find(&:default)
26
26
  end
27
27
 
28
+ def fetch_application(source_id)
29
+ applications = api.list_source_applications(source_id)&.data || []
30
+ applications.first
31
+ end
32
+
28
33
  def fetch_authentication(source_id, default_endpoint = nil, authtype = nil)
29
34
  endpoint = default_endpoint || fetch_default_endpoint(source_id)
30
35
  return if endpoint.nil?
@@ -1,7 +1,7 @@
1
1
  module TopologicalInventory
2
2
  module Providers
3
3
  module Common
4
- VERSION = "1.0.6"
4
+ VERSION = "1.0.7"
5
5
  end
6
6
  end
7
7
  end
@@ -11,6 +11,7 @@ RSpec.shared_examples "availability_check" do
11
11
  let(:headers) { {'Content-Type' => 'application/json'}.merge(identity) }
12
12
  let(:source_id) { '123' }
13
13
  let(:endpoint_id) { '234' }
14
+ let(:application_id) { '345' }
14
15
  let(:authentication_id) { '345' }
15
16
  let(:payload) do
16
17
  {
@@ -26,6 +27,8 @@ RSpec.shared_examples "availability_check" do
26
27
  let(:list_endpoint_authentications_response) { "{\"data\":[{\"authtype\":\"username_password\",\"id\":\"#{authentication_id}\",\"resource_id\":\"#{endpoint_id}\",\"resource_type\":\"Endpoint\",\"username\":\"admin\",\"tenant\":\"#{external_tenant}\"}]}" }
27
28
  let(:list_endpoint_authentications_response_empty) { "{\"data\":[]}" }
28
29
  let(:internal_api_authentication_response) { "{\"authtype\":\"username_password\",\"id\":\"#{authentication_id}\",\"resource_id\":\"#{endpoint_id}\",\"resource_type\":\"Endpoint\",\"username\":\"admin\",\"tenant\":\"#{external_tenant}\",\"password\":\"xxx\"}" }
30
+ let(:list_applications_response) { {:data => [{:id => "345", :availability_status => "available"}]}.to_json }
31
+ let(:list_applications_unavailable_response) { {:data => [{:id => "345", :availability_status => "unavailable"}]}.to_json }
29
32
 
30
33
  subject { described_class.new(payload["params"]) }
31
34
 
@@ -39,6 +42,7 @@ RSpec.shared_examples "availability_check" do
39
42
  stub_get(:endpoint, list_endpoints_response)
40
43
  stub_get(:authentication, list_endpoint_authentications_response)
41
44
  stub_get(:password, internal_api_authentication_response)
45
+ stub_get(:application, "[]")
42
46
 
43
47
  # PATCH
44
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
@@ -61,6 +65,7 @@ RSpec.shared_examples "availability_check" do
61
65
  stub_get(:endpoint, list_endpoints_response)
62
66
  stub_get(:authentication, list_endpoint_authentications_response)
63
67
  stub_get(:password, internal_api_authentication_response)
68
+ stub_get(:application, "[]")
64
69
 
65
70
  # PATCH
66
71
  connection_error_message = "Some connection error"
@@ -82,6 +87,7 @@ RSpec.shared_examples "availability_check" do
82
87
  it "updates only Source to 'unavailable' status if Endpoint not found" do
83
88
  # GET
84
89
  stub_get(:endpoint, '')
90
+ stub_get(:application, "[]")
85
91
 
86
92
  # PATCH
87
93
  source_patch_body = {'availability_status' => described_class::STATUS_UNAVAILABLE, 'last_checked_at' => subject.send(:check_time)}.to_json
@@ -100,6 +106,7 @@ RSpec.shared_examples "availability_check" do
100
106
  # GET
101
107
  stub_get(:endpoint, list_endpoints_response)
102
108
  stub_get(:authentication, list_endpoint_authentications_response_empty)
109
+ stub_get(:application, "[]")
103
110
 
104
111
  # PATCH
105
112
  source_patch_body = {'availability_status' => described_class::STATUS_UNAVAILABLE, 'last_checked_at' => subject.send(:check_time)}.to_json
@@ -131,6 +138,49 @@ RSpec.shared_examples "availability_check" do
131
138
  end
132
139
  end
133
140
 
141
+ context "when there is an application" do
142
+ context "when it is available" do
143
+ it "updates the availability status to available" do
144
+ # GET
145
+ stub_get(: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
150
+
151
+ stub_patch(:source, source_patch_body)
152
+ stub_patch(:application, application_patch_body)
153
+
154
+ # Check
155
+ expect(subject).not_to receive(:connection_check)
156
+ subject.availability_check
157
+
158
+ assert_patch(:source, source_patch_body)
159
+ assert_patch(:application, application_patch_body)
160
+ end
161
+ end
162
+
163
+ context "when it is unavailable" do
164
+ it "updates the availability status to unavailable" do
165
+ # GET
166
+ stub_get(: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
171
+
172
+ stub_patch(:source, source_patch_body)
173
+ stub_patch(:application, application_patch_body)
174
+
175
+ # Check
176
+ expect(subject).not_to receive(:connection_check)
177
+ subject.availability_check
178
+
179
+ assert_patch(:source, source_patch_body)
180
+ assert_patch(:application, application_patch_body)
181
+ end
182
+ end
183
+ end
134
184
 
135
185
  def stub_get(object_type, response)
136
186
  case object_type
@@ -146,6 +196,10 @@ RSpec.shared_examples "availability_check" do
146
196
  stub_request(:get, "#{host_url}#{sources_internal_api_path}/authentications/#{authentication_id}?expose_encrypted_attribute%5B%5D=password")
147
197
  .with(:headers => headers)
148
198
  .to_return(:status => 200, :body => response, :headers => {})
199
+ when :application
200
+ stub_request(:get, "#{sources_api_url}/sources/#{source_id}/applications")
201
+ .with(:headers => headers)
202
+ .to_return(:status => 200, :body => response, :headers => {})
149
203
  end
150
204
  end
151
205
 
@@ -159,6 +213,10 @@ RSpec.shared_examples "availability_check" do
159
213
  stub_request(:patch, "#{sources_api_url}/endpoints/#{endpoint_id}")
160
214
  .with(:body => data, :headers => headers)
161
215
  .to_return(:status => 200, :body => "", :headers => {})
216
+ when :application
217
+ stub_request(:patch, "#{sources_api_url}/applications/#{application_id}")
218
+ .with(:body => data, :headers => headers)
219
+ .to_return(:status => 200, :body => "", :headers => {})
162
220
  end
163
221
  end
164
222
 
@@ -166,10 +224,13 @@ RSpec.shared_examples "availability_check" do
166
224
  case object_type
167
225
  when :source
168
226
  expect(WebMock).to have_requested(:patch, "#{sources_api_url}/sources/#{source_id}")
169
- .with(:body => data, :headers => headers).once
227
+ .with(:body => data, :headers => headers).once
170
228
  when :endpoint
171
229
  expect(WebMock).to have_requested(:patch, "#{sources_api_url}/endpoints/#{endpoint_id}")
172
- .with(:body => data, :headers => headers).once
230
+ .with(:body => data, :headers => headers).once
231
+ when :application
232
+ expect(WebMock).to have_requested(:patch, "#{sources_api_url}/applications/#{application_id}")
233
+ .with(:body => data, :headers => headers).once
173
234
  end
174
235
  end
175
236
  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: 1.0.6
4
+ version: 1.0.7
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-07-09 00:00:00.000000000 Z
11
+ date: 2020-07-28 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activesupport