topological_inventory-providers-common 1.0.6 → 1.0.7
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/CHANGELOG.md +7 -1
- data/lib/topological_inventory/providers/common/operations/source.rb +64 -19
- data/lib/topological_inventory/providers/common/operations/sources_api_client.rb +6 -1
- data/lib/topological_inventory/providers/common/version.rb +1 -1
- data/spec/support/shared/availability_check.rb +63 -2
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 868c8f764cd11d9888ed99698a309cc199fdf92823963f4e5cae71208d506ff7
|
4
|
+
data.tar.gz: 39c352e8b1306bdb87675bf0ccc1fe08f02b0c13555b2466c4c38d7a76979aca
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: c2a8af390114548a89c7dc5bb43f1a6e3784a5a59ebd2ce1c7451c15726015df1353e3dcbc3755d7637d696707b0d6db93e5d4907920a1c4b09d3f6410130a77
|
7
|
+
data.tar.gz: 46e6596954367336de4049f8024da8b5e63e5be4c60636c77f91f22c3e407229b38aca604137907d1f5cd6411201d9c3b57e4ad5bab2cfb749b2c04e9ca8eeab
|
data/CHANGELOG.md
CHANGED
@@ -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.
|
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
|
16
|
-
:
|
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
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
70
|
-
return [STATUS_UNAVAILABLE, ERROR_MESSAGES[:
|
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
|
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
|
-
|
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
|
120
|
-
logger.availability_check("Failed to fetch Endpoint for Source #{source_id}
|
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 ||=
|
126
|
-
|
127
|
-
|
128
|
-
|
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" =>
|
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?
|
@@ -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
|
-
|
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
|
-
|
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.
|
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-
|
11
|
+
date: 2020-07-28 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: activesupport
|