foreman_rh_cloud 12.1.2 → 12.1.4
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/README.md +3 -5
- data/app/controllers/concerns/insights_cloud/package_profile_upload_extensions.rb +33 -0
- data/app/controllers/insights_cloud/api/machine_telemetries_controller.rb +1 -1
- data/app/services/foreman_rh_cloud/cert_auth.rb +9 -1
- data/app/services/foreman_rh_cloud/cloud_request_forwarder.rb +8 -3
- data/app/views/api/v2/hosts/insights/base.rabl +6 -0
- data/db/seeds.d/200_features.rb +4 -0
- data/lib/foreman_inventory_upload/async/generate_report_job.rb +11 -5
- data/lib/foreman_inventory_upload/async/upload_report_job.rb +15 -4
- data/lib/foreman_inventory_upload/generators/archived_report.rb +2 -2
- data/lib/foreman_inventory_upload/generators/fact_helpers.rb +65 -13
- data/lib/foreman_inventory_upload/generators/queries.rb +7 -5
- data/lib/foreman_inventory_upload/generators/slice.rb +0 -1
- data/lib/foreman_inventory_upload/generators/tags.rb +4 -1
- data/lib/foreman_inventory_upload.rb +2 -2
- data/lib/foreman_rh_cloud/engine.rb +31 -2
- data/lib/foreman_rh_cloud/version.rb +1 -1
- data/lib/inventory_sync/async/inventory_hosts_sync.rb +2 -0
- data/lib/tasks/hybrid_cloud.rake +105 -37
- data/lib/tasks/rh_cloud_inventory.rake +3 -2
- data/package.json +1 -1
- data/test/controllers/insights_cloud/api/cloud_request_controller_test.rb +1 -2
- data/test/unit/archived_report_generator_test.rb +1 -1
- data/test/unit/fact_helpers_test.rb +267 -2
- data/test/unit/rh_cloud_http_proxy_test.rb +8 -0
- data/test/unit/services/foreman_rh_cloud/cloud_request_forwarder_test.rb +19 -2
- data/test/unit/slice_generator_test.rb +69 -10
- data/test/unit/tags_generator_test.rb +1 -0
- data/webpack/ForemanColumnExtensions/index.js +41 -0
- data/webpack/global_index.js +3 -0
- metadata +4 -1
data/lib/tasks/hybrid_cloud.rake
CHANGED
@@ -1,64 +1,132 @@
|
|
1
1
|
require 'io/console'
|
2
|
+
require 'uri'
|
2
3
|
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
4
|
+
def logger
|
5
|
+
@logger ||= Logger.new(STDOUT)
|
6
|
+
end
|
7
|
+
|
8
|
+
namespace :rh_cloud do
|
9
|
+
desc 'Register Satellite Organization with Hybrid Cloud API.'
|
10
|
+
# This task registers the Satellite Organization with the Hybrid Cloud API.
|
11
|
+
# It requires the user to input their organization ID, Insights URL, and token.
|
12
|
+
# The task will then send a POST request to the Hybrid Cloud API to register the organization.
|
13
|
+
# The response will be logged, and any errors will be caught and logged as well.
|
14
|
+
# The task will exit with an error message if the organization does not have a manifest imported or if the token is not entered.
|
15
|
+
# The task will also log a warning if the custom URL is not set and the default one is used.
|
7
16
|
task hybridcloud_register: [:environment] do
|
8
17
|
include ::ForemanRhCloud::CertAuth
|
9
18
|
include ::InsightsCloud::CandlepinCache
|
10
19
|
|
11
|
-
def
|
12
|
-
|
20
|
+
def default_registrations_url
|
21
|
+
URI.join(ForemanRhCloud.base_url, '/api/identity/certificate/registrations').to_s
|
13
22
|
end
|
14
23
|
|
15
|
-
|
16
|
-
|
17
|
-
|
24
|
+
# Helper method to get the registrations URL, with a warning for default usage
|
25
|
+
def registrations_url(custom_url)
|
26
|
+
if custom_url.empty?
|
27
|
+
logger.warn("Custom url is not set, using the default one: #{default_registrations_url}")
|
28
|
+
default_registrations_url
|
29
|
+
else
|
30
|
+
if URI(custom_url).scheme.nil?
|
31
|
+
logger.warn("Custom URL lacks a scheme; prepending https:// prefix.")
|
32
|
+
custom_url = "https://" + custom_url
|
33
|
+
end
|
34
|
+
custom_url
|
35
|
+
end
|
18
36
|
end
|
19
37
|
|
20
|
-
|
21
|
-
|
22
|
-
|
38
|
+
def get_organization(user_org_id)
|
39
|
+
maybe_organization = Organization.find_by(id: user_org_id)
|
40
|
+
if maybe_organization.nil?
|
41
|
+
logger.error("Organization with ID '#{user_org_id}' not found.")
|
42
|
+
exit(1)
|
43
|
+
end
|
44
|
+
maybe_organization
|
23
45
|
end
|
24
46
|
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
logger.error('Token was not entered.') + exit(1) if @token.empty?
|
33
|
-
|
34
|
-
def headers
|
35
|
-
{
|
36
|
-
Authorization: "Bearer #{@token}",
|
37
|
-
}
|
47
|
+
def get_uid(organization)
|
48
|
+
maybe_uid = cp_owner_id(organization)
|
49
|
+
if maybe_uid.nil?
|
50
|
+
logger.error("Organization '#{organization}' does not have a manifest imported.")
|
51
|
+
exit(1)
|
52
|
+
end
|
53
|
+
maybe_uid
|
38
54
|
end
|
39
55
|
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
56
|
+
# --- Input Collection ---
|
57
|
+
puts "Paste in your organization ID, this can be retrieved with the command: hammer organization list"
|
58
|
+
loop do
|
59
|
+
input = STDIN.gets.chomp
|
60
|
+
if input.match?(/^\d+$/) # Checks if input consists only of digits
|
61
|
+
@user_org_id = input.to_i
|
62
|
+
break
|
63
|
+
else
|
64
|
+
puts "Invalid input. Please enter a numeric organization ID."
|
65
|
+
end
|
45
66
|
end
|
46
67
|
|
47
|
-
|
48
|
-
|
68
|
+
puts "\n" + "-" * 50 + "\n\n"
|
69
|
+
puts "Paste in your custom Insights URL. If nothing is entered, the default will be used (#{default_registrations_url})."
|
70
|
+
insights_user_input = STDIN.gets.chomp
|
71
|
+
|
72
|
+
puts "\n" + "-" * 50 + "\n\n"
|
73
|
+
puts 'Paste in your Hybrid Cloud API token, output will be hidden.'
|
74
|
+
puts 'This token can be retrieved from the Hybrid Cloud console.'
|
75
|
+
token = STDIN.noecho(&:gets).chomp
|
76
|
+
if token.empty?
|
77
|
+
logger.error('Token was not entered.')
|
78
|
+
exit(1)
|
49
79
|
end
|
50
80
|
|
81
|
+
# --- Data Preparation ---
|
82
|
+
|
83
|
+
organization = get_organization(@user_org_id)
|
84
|
+
uid = get_uid(organization)
|
85
|
+
hostname = ForemanRhCloud.foreman_host_name
|
86
|
+
insights_url = registrations_url(insights_user_input)
|
87
|
+
|
88
|
+
# --- API Request ---
|
89
|
+
|
90
|
+
headers = {
|
91
|
+
Authorization: "Bearer #{token}",
|
92
|
+
}
|
93
|
+
|
94
|
+
payload = {
|
95
|
+
'uid': uid,
|
96
|
+
"display_name": "#{hostname}+#{organization.label}",
|
97
|
+
}
|
98
|
+
|
51
99
|
begin
|
52
100
|
response = execute_cloud_request(
|
53
|
-
organization:
|
54
|
-
method:
|
55
|
-
url:
|
101
|
+
organization: organization,
|
102
|
+
method: :post,
|
103
|
+
url: insights_url,
|
56
104
|
headers: headers,
|
57
105
|
payload: payload.to_json
|
58
106
|
)
|
59
|
-
logger.debug(response)
|
107
|
+
logger.debug("Cloud request completed: status=#{response.code}, body_preview=#{response.body&.slice(0, 200)}")
|
108
|
+
rescue RestClient::Unauthorized => _ex
|
109
|
+
# Add a more specific rescue for 401 Unauthorized errors
|
110
|
+
logger.error('Registration failed: Your token is invalid or unauthorized. Please check your token and try again.')
|
111
|
+
# Optionally, you can still log the full debug info if helpful for advanced troubleshooting
|
112
|
+
# logger.debug(ex.backtrace.join("\n"))
|
113
|
+
exit(1)
|
114
|
+
rescue RestClient::ExceptionWithResponse => ex
|
115
|
+
# This catches any RestClient exception that has a response (like 400, 403, 404, 500, etc.)
|
116
|
+
status_code = begin
|
117
|
+
ex.response.code
|
118
|
+
rescue StandardError
|
119
|
+
"unknown"
|
120
|
+
end
|
121
|
+
logger.error("Registration failed with HTTP status #{status_code}: #{ex.message}")
|
122
|
+
logger.debug("Response body (if available): #{ex.response.body}")
|
123
|
+
exit(1)
|
60
124
|
rescue StandardError => ex
|
61
|
-
|
125
|
+
# This is the catch-all for any other unexpected errors
|
126
|
+
logger.error("An unexpected error occurred during registration: #{ex.message}")
|
127
|
+
exit(1)
|
62
128
|
end
|
129
|
+
|
130
|
+
logger.info("Satellite Organization '#{organization.label}' (ID: #{@user_org_id}) successfully registered.")
|
63
131
|
end
|
64
132
|
end
|
@@ -26,6 +26,7 @@ namespace :rh_cloud_inventory do
|
|
26
26
|
task generate: :environment do
|
27
27
|
organizations = [ENV['organization_id']]
|
28
28
|
base_folder = ENV['target'] || Dir.pwd
|
29
|
+
filter = ENV['hosts_filter']
|
29
30
|
|
30
31
|
unless File.writable?(base_folder)
|
31
32
|
puts "#{base_folder} is not writable by the current process"
|
@@ -40,9 +41,9 @@ namespace :rh_cloud_inventory do
|
|
40
41
|
|
41
42
|
User.as_anonymous_admin do
|
42
43
|
organizations.each do |organization|
|
43
|
-
target = File.join(base_folder, ForemanInventoryUpload.facts_archive_name(organization))
|
44
|
+
target = File.join(base_folder, ForemanInventoryUpload.facts_archive_name(organization, filter))
|
44
45
|
archived_report_generator = ForemanInventoryUpload::Generators::ArchivedReport.new(target, Logger.new(STDOUT))
|
45
|
-
archived_report_generator.render(organization: organization)
|
46
|
+
archived_report_generator.render(organization: organization, filter: filter)
|
46
47
|
puts "Successfully generated #{target} for organization id #{organization}"
|
47
48
|
end
|
48
49
|
end
|
data/package.json
CHANGED
@@ -51,8 +51,7 @@ module InsightsCloud::Api
|
|
51
51
|
mock_composer = mock('composer')
|
52
52
|
::JobInvocationComposer.expects(:for_feature).with do |feature, host_ids, params|
|
53
53
|
feature == :rh_cloud_connector_run_playbook &&
|
54
|
-
host_ids.
|
55
|
-
host_ids.last == host2.id
|
54
|
+
host_ids.sort == [host1.id, host2.id].sort
|
56
55
|
end.returns(mock_composer)
|
57
56
|
mock_composer.expects(:trigger!)
|
58
57
|
mock_composer.expects(:job_invocation)
|
@@ -50,7 +50,7 @@ class ArchivedReportGeneratorTest < ActiveSupport::TestCase
|
|
50
50
|
batches = Host.where(id: @host.id).in_batches
|
51
51
|
test_org = FactoryBot.create(:organization)
|
52
52
|
|
53
|
-
ForemanInventoryUpload::Generators::Queries.expects(:for_org).with(test_org.id).returns(batches)
|
53
|
+
ForemanInventoryUpload::Generators::Queries.expects(:for_org).with(test_org.id, hosts_query: '').returns(batches)
|
54
54
|
ForemanInventoryUpload::Generators::Slice.any_instance.stubs(:golden_ticket?).returns(false)
|
55
55
|
Dir.mktmpdir do |tmpdir|
|
56
56
|
target = File.join(tmpdir, 'test.tar.gz')
|
@@ -1,4 +1,5 @@
|
|
1
1
|
require 'test_plugin_helper'
|
2
|
+
require 'digest'
|
2
3
|
|
3
4
|
class FactHelpersTest < ActiveSupport::TestCase
|
4
5
|
class FactsHelpersTestStub
|
@@ -29,7 +30,7 @@ class FactHelpersTest < ActiveSupport::TestCase
|
|
29
30
|
|
30
31
|
test 'obfuscates ips with insights-client data' do
|
31
32
|
host = mock('host')
|
32
|
-
@instance.expects(:fact_value).with(host, 'insights_client::
|
33
|
+
@instance.expects(:fact_value).with(host, 'insights_client::obfuscated_ipv4').returns(
|
33
34
|
'[{"obfuscated": "10.230.230.1", "original": "224.0.0.1"}, {"obfuscated": "10.230.230.255", "original": "224.0.0.251"}]'
|
34
35
|
)
|
35
36
|
|
@@ -41,11 +42,275 @@ class FactHelpersTest < ActiveSupport::TestCase
|
|
41
42
|
|
42
43
|
test 'obfuscates ips without insights-client data' do
|
43
44
|
host = mock('host')
|
44
|
-
@instance.expects(:fact_value).with(host, 'insights_client::
|
45
|
+
@instance.expects(:fact_value).with(host, 'insights_client::obfuscated_ipv4').returns(nil)
|
45
46
|
|
46
47
|
actual = @instance.obfuscated_ips(host)
|
47
48
|
|
48
49
|
assert_equal '10.230.230.1', actual['224.0.0.1']
|
49
50
|
assert_equal '10.230.230.2', actual['224.0.0.2']
|
50
51
|
end
|
52
|
+
|
53
|
+
describe 'obfuscate_hostname?' do
|
54
|
+
test 'returns true when global setting is enabled' do
|
55
|
+
Setting.expects(:[]).with(:obfuscate_inventory_hostnames).returns(true)
|
56
|
+
host = mock('host')
|
57
|
+
|
58
|
+
result = @instance.obfuscate_hostname?(host)
|
59
|
+
|
60
|
+
assert result
|
61
|
+
end
|
62
|
+
|
63
|
+
test 'returns false when global setting is disabled and no host-specific setting' do
|
64
|
+
Setting.expects(:[]).with(:obfuscate_inventory_hostnames).returns(false)
|
65
|
+
host = mock('host')
|
66
|
+
@instance.expects(:fact_value).with(host, 'insights_client::obfuscate_hostname_enabled').returns(nil)
|
67
|
+
|
68
|
+
result = @instance.obfuscate_hostname?(host)
|
69
|
+
|
70
|
+
refute result
|
71
|
+
end
|
72
|
+
|
73
|
+
test 'returns true when host-specific setting is enabled' do
|
74
|
+
Setting.expects(:[]).with(:obfuscate_inventory_hostnames).returns(false)
|
75
|
+
host = mock('host')
|
76
|
+
@instance.expects(:fact_value).with(host, 'insights_client::obfuscate_hostname_enabled').returns('true')
|
77
|
+
|
78
|
+
result = @instance.obfuscate_hostname?(host)
|
79
|
+
|
80
|
+
assert result
|
81
|
+
end
|
82
|
+
|
83
|
+
test 'returns false when host-specific setting is disabled' do
|
84
|
+
Setting.expects(:[]).with(:obfuscate_inventory_hostnames).returns(false)
|
85
|
+
host = mock('host')
|
86
|
+
@instance.expects(:fact_value).with(host, 'insights_client::obfuscate_hostname_enabled').returns('false')
|
87
|
+
|
88
|
+
result = @instance.obfuscate_hostname?(host)
|
89
|
+
|
90
|
+
refute result
|
91
|
+
end
|
92
|
+
end
|
93
|
+
|
94
|
+
describe 'fqdn' do
|
95
|
+
test 'returns original fqdn when obfuscation is disabled' do
|
96
|
+
host = mock('host')
|
97
|
+
host.expects(:fqdn).returns('test.example.com')
|
98
|
+
@instance.expects(:obfuscate_hostname?).with(host).returns(false)
|
99
|
+
|
100
|
+
result = @instance.fqdn(host)
|
101
|
+
|
102
|
+
assert_equal 'test.example.com', result
|
103
|
+
end
|
104
|
+
|
105
|
+
test 'returns obfuscated hostname from insights_client fact when available' do
|
106
|
+
host = mock('host')
|
107
|
+
host.expects(:fqdn).returns('test.example.com').once
|
108
|
+
@instance.expects(:obfuscate_hostname?).with(host).returns(true)
|
109
|
+
@instance.expects(:fact_value).with(host, 'insights_client::obfuscated_hostname').returns(
|
110
|
+
'[{"original": "test.example.com", "obfuscated": "abc123.example.com"}]'
|
111
|
+
)
|
112
|
+
|
113
|
+
result = @instance.fqdn(host)
|
114
|
+
|
115
|
+
assert_equal 'abc123.example.com', result
|
116
|
+
end
|
117
|
+
|
118
|
+
test 'returns dynamically obfuscated hostname when insights_client fact is not available' do
|
119
|
+
host = mock('host')
|
120
|
+
host.stubs(:fqdn).returns('test.example.com')
|
121
|
+
@instance.expects(:obfuscate_hostname?).with(host).returns(true)
|
122
|
+
@instance.expects(:fact_value).with(host, 'insights_client::obfuscated_hostname').returns(nil)
|
123
|
+
|
124
|
+
result = @instance.fqdn(host)
|
125
|
+
|
126
|
+
expected = "#{Digest::SHA1.hexdigest('test.example.com')}.example.com"
|
127
|
+
assert_equal expected, result
|
128
|
+
end
|
129
|
+
|
130
|
+
test 'returns dynamically obfuscated hostname when insights_client fact does not contain matching host' do
|
131
|
+
host = mock('host')
|
132
|
+
host.expects(:fqdn).returns('test.example.com').twice
|
133
|
+
@instance.expects(:obfuscate_hostname?).with(host).returns(true)
|
134
|
+
@instance.expects(:fact_value).with(host, 'insights_client::obfuscated_hostname').returns(
|
135
|
+
'[{"original": "other.example.com", "obfuscated": "abc123.example.com"}]'
|
136
|
+
)
|
137
|
+
@instance.expects(:obfuscate_fqdn).with('test.example.com').returns('dynamically_obfuscated.example.com')
|
138
|
+
|
139
|
+
result = @instance.fqdn(host)
|
140
|
+
|
141
|
+
assert_equal 'dynamically_obfuscated.example.com', result
|
142
|
+
end
|
143
|
+
|
144
|
+
test 'handles invalid JSON in insights_client fact gracefully' do
|
145
|
+
host = mock('host')
|
146
|
+
host.stubs(:fqdn).returns('test.example.com')
|
147
|
+
@instance.expects(:obfuscate_hostname?).with(host).returns(true)
|
148
|
+
@instance.expects(:fact_value).with(host, 'insights_client::obfuscated_hostname').returns('invalid json')
|
149
|
+
|
150
|
+
result = @instance.fqdn(host)
|
151
|
+
|
152
|
+
expected = "#{Digest::SHA1.hexdigest('test.example.com')}.example.com"
|
153
|
+
assert_equal expected, result
|
154
|
+
end
|
155
|
+
|
156
|
+
test 'handles empty insights_client fact' do
|
157
|
+
host = mock('host')
|
158
|
+
host.stubs(:fqdn).returns('test.example.com')
|
159
|
+
@instance.expects(:obfuscate_hostname?).with(host).returns(true)
|
160
|
+
@instance.expects(:fact_value).with(host, 'insights_client::obfuscated_hostname').returns('[]')
|
161
|
+
|
162
|
+
result = @instance.fqdn(host)
|
163
|
+
|
164
|
+
expected = "#{Digest::SHA1.hexdigest('test.example.com')}.example.com"
|
165
|
+
assert_equal expected, result
|
166
|
+
end
|
167
|
+
end
|
168
|
+
|
169
|
+
describe 'obfuscate_ips?' do
|
170
|
+
test 'returns true when global setting is enabled' do
|
171
|
+
Setting.expects(:[]).with(:obfuscate_inventory_ips).returns(true)
|
172
|
+
host = mock('host')
|
173
|
+
|
174
|
+
result = @instance.obfuscate_ips?(host)
|
175
|
+
|
176
|
+
assert result
|
177
|
+
end
|
178
|
+
|
179
|
+
test 'returns false when global setting is disabled and no host-specific settings' do
|
180
|
+
Setting.expects(:[]).with(:obfuscate_inventory_ips).returns(false)
|
181
|
+
host = mock('host')
|
182
|
+
@instance.expects(:fact_value).with(host, 'insights_client::obfuscate_ipv4_enabled').returns(nil)
|
183
|
+
@instance.expects(:fact_value).with(host, 'insights_client::obfuscate_ipv6_enabled').returns(nil)
|
184
|
+
|
185
|
+
result = @instance.obfuscate_ips?(host)
|
186
|
+
|
187
|
+
refute result
|
188
|
+
end
|
189
|
+
|
190
|
+
test 'returns true when host-specific IPv4 setting is enabled' do
|
191
|
+
Setting.expects(:[]).with(:obfuscate_inventory_ips).returns(false)
|
192
|
+
host = mock('host')
|
193
|
+
@instance.expects(:fact_value).with(host, 'insights_client::obfuscate_ipv4_enabled').returns('true')
|
194
|
+
@instance.expects(:fact_value).with(host, 'insights_client::obfuscate_ipv6_enabled').returns(nil)
|
195
|
+
|
196
|
+
result = @instance.obfuscate_ips?(host)
|
197
|
+
|
198
|
+
assert result
|
199
|
+
end
|
200
|
+
|
201
|
+
test 'returns true when host-specific IPv6 setting is enabled' do
|
202
|
+
Setting.expects(:[]).with(:obfuscate_inventory_ips).returns(false)
|
203
|
+
host = mock('host')
|
204
|
+
@instance.expects(:fact_value).with(host, 'insights_client::obfuscate_ipv4_enabled').returns(nil)
|
205
|
+
@instance.expects(:fact_value).with(host, 'insights_client::obfuscate_ipv6_enabled').returns('true')
|
206
|
+
|
207
|
+
result = @instance.obfuscate_ips?(host)
|
208
|
+
|
209
|
+
assert result
|
210
|
+
end
|
211
|
+
|
212
|
+
test 'returns true when both IPv4 and IPv6 settings are enabled' do
|
213
|
+
Setting.expects(:[]).with(:obfuscate_inventory_ips).returns(false)
|
214
|
+
host = mock('host')
|
215
|
+
@instance.expects(:fact_value).with(host, 'insights_client::obfuscate_ipv4_enabled').returns('true')
|
216
|
+
@instance.expects(:fact_value).with(host, 'insights_client::obfuscate_ipv6_enabled').returns('true')
|
217
|
+
|
218
|
+
result = @instance.obfuscate_ips?(host)
|
219
|
+
|
220
|
+
assert result
|
221
|
+
end
|
222
|
+
|
223
|
+
test 'returns false when both IPv4 and IPv6 settings are disabled' do
|
224
|
+
Setting.expects(:[]).with(:obfuscate_inventory_ips).returns(false)
|
225
|
+
host = mock('host')
|
226
|
+
@instance.expects(:fact_value).with(host, 'insights_client::obfuscate_ipv4_enabled').returns('false')
|
227
|
+
@instance.expects(:fact_value).with(host, 'insights_client::obfuscate_ipv6_enabled').returns('false')
|
228
|
+
|
229
|
+
result = @instance.obfuscate_ips?(host)
|
230
|
+
|
231
|
+
refute result
|
232
|
+
end
|
233
|
+
end
|
234
|
+
|
235
|
+
describe 'obfuscate_ip' do
|
236
|
+
test 'generates first IP when no existing obfuscated IPs' do
|
237
|
+
ips_dict = {}
|
238
|
+
|
239
|
+
result = @instance.obfuscate_ip('192.168.1.1', ips_dict)
|
240
|
+
|
241
|
+
assert_equal '10.230.230.1', result
|
242
|
+
end
|
243
|
+
|
244
|
+
test 'generates next sequential IP when existing obfuscated IPs present' do
|
245
|
+
ips_dict = { '192.168.1.1' => '10.230.230.5', '192.168.1.2' => '10.230.230.10' }
|
246
|
+
|
247
|
+
result = @instance.obfuscate_ip('192.168.1.3', ips_dict)
|
248
|
+
|
249
|
+
assert_equal '10.230.230.11', result
|
250
|
+
end
|
251
|
+
|
252
|
+
test 'handles mixed IP ranges correctly' do
|
253
|
+
ips_dict = { '192.168.1.1' => '10.230.230.255', '192.168.1.2' => '10.230.230.1' }
|
254
|
+
|
255
|
+
result = @instance.obfuscate_ip('192.168.1.3', ips_dict)
|
256
|
+
|
257
|
+
assert_equal '10.230.231.0', result
|
258
|
+
end
|
259
|
+
|
260
|
+
test 'generates valid IP addresses' do
|
261
|
+
ips_dict = {}
|
262
|
+
|
263
|
+
result = @instance.obfuscate_ip('any.ip.address', ips_dict)
|
264
|
+
|
265
|
+
assert_match(/\A\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}\z/, result)
|
266
|
+
assert_nothing_raised { IPAddr.new(result) }
|
267
|
+
end
|
268
|
+
end
|
269
|
+
|
270
|
+
describe 'obfuscated_ips' do
|
271
|
+
test 'handles invalid JSON in insights_client fact gracefully' do
|
272
|
+
host = mock('host')
|
273
|
+
@instance.expects(:fact_value).with(host, 'insights_client::obfuscated_ipv4').returns('invalid json')
|
274
|
+
|
275
|
+
result = @instance.obfuscated_ips(host)
|
276
|
+
|
277
|
+
assert_equal '10.230.230.1', result['192.168.1.1']
|
278
|
+
end
|
279
|
+
|
280
|
+
test 'handles empty insights_client fact' do
|
281
|
+
host = mock('host')
|
282
|
+
@instance.expects(:fact_value).with(host, 'insights_client::obfuscated_ipv4').returns('[]')
|
283
|
+
|
284
|
+
result = @instance.obfuscated_ips(host)
|
285
|
+
|
286
|
+
assert_equal '10.230.230.1', result['192.168.1.1']
|
287
|
+
end
|
288
|
+
|
289
|
+
test 'preserves existing obfuscated IPs and generates new ones' do
|
290
|
+
host = mock('host')
|
291
|
+
@instance.expects(:fact_value).with(host, 'insights_client::obfuscated_ipv4').returns(
|
292
|
+
'[{"original": "192.168.1.1", "obfuscated": "10.230.230.5"}]'
|
293
|
+
)
|
294
|
+
|
295
|
+
result = @instance.obfuscated_ips(host)
|
296
|
+
|
297
|
+
assert_equal '10.230.230.5', result['192.168.1.1']
|
298
|
+
assert_equal '10.230.230.6', result['192.168.1.2']
|
299
|
+
end
|
300
|
+
|
301
|
+
test 'default_proc generates unique sequential IPs' do
|
302
|
+
host = mock('host')
|
303
|
+
@instance.expects(:fact_value).with(host, 'insights_client::obfuscated_ipv4').returns(nil)
|
304
|
+
|
305
|
+
result = @instance.obfuscated_ips(host)
|
306
|
+
|
307
|
+
ip1 = result['192.168.1.1']
|
308
|
+
ip2 = result['192.168.1.2']
|
309
|
+
ip3 = result['192.168.1.3']
|
310
|
+
|
311
|
+
assert_equal '10.230.230.1', ip1
|
312
|
+
assert_equal '10.230.230.2', ip2
|
313
|
+
assert_equal '10.230.230.3', ip3
|
314
|
+
end
|
315
|
+
end
|
51
316
|
end
|
@@ -4,6 +4,7 @@ class RhCloudHttpProxyTest < ActiveSupport::TestCase
|
|
4
4
|
setup do
|
5
5
|
@global_content_proxy_mock = 'http://global:content@localhost:80'
|
6
6
|
@global_foreman_proxy_mock = 'http://global:foreman@localhost:80'
|
7
|
+
ForemanRhCloud.stubs(:with_local_advisor_engine?).returns(false)
|
7
8
|
end
|
8
9
|
|
9
10
|
test 'selects global content proxy' do
|
@@ -18,6 +19,13 @@ class RhCloudHttpProxyTest < ActiveSupport::TestCase
|
|
18
19
|
assert_equal @global_foreman_proxy_mock, ForemanRhCloud.proxy_setting
|
19
20
|
end
|
20
21
|
|
22
|
+
test 'returns empty string in on-prem setup' do
|
23
|
+
ForemanRhCloud.unstub(:with_local_advisor_engine?)
|
24
|
+
ForemanRhCloud.stubs(:with_local_advisor_engine?).returns(true)
|
25
|
+
|
26
|
+
assert_empty ForemanRhCloud.proxy_setting
|
27
|
+
end
|
28
|
+
|
21
29
|
def setup_global_content_proxy
|
22
30
|
http_proxy = FactoryBot.create(:http_proxy, url: @global_content_proxy_mock)
|
23
31
|
HttpProxy.stubs(:default_global_content_proxy).returns(http_proxy)
|
@@ -3,6 +3,7 @@ require 'puma/null_io'
|
|
3
3
|
|
4
4
|
class CloudRequestForwarderTest < ActiveSupport::TestCase
|
5
5
|
include MockCerts
|
6
|
+
include KatelloCVEHelper
|
6
7
|
|
7
8
|
setup do
|
8
9
|
@forwarder = ::ForemanRhCloud::CloudRequestForwarder.new
|
@@ -10,6 +11,22 @@ class CloudRequestForwarderTest < ActiveSupport::TestCase
|
|
10
11
|
ForemanRhCloud.stubs(:base_url).returns('https://cloud.example.com')
|
11
12
|
ForemanRhCloud.stubs(:cert_base_url).returns('https://cert.cloud.example.com')
|
12
13
|
ForemanRhCloud.stubs(:legacy_insights_url).returns('https://cert-api.access.example.com')
|
14
|
+
|
15
|
+
UpstreamOnlySettingsTestHelper.set_if_available('allow_multiple_content_views')
|
16
|
+
env = FactoryBot.create(:katello_k_t_environment)
|
17
|
+
env2 = FactoryBot.create(:katello_k_t_environment, organization: env.organization)
|
18
|
+
|
19
|
+
@host = FactoryBot.create(
|
20
|
+
:host,
|
21
|
+
:with_subscription,
|
22
|
+
:with_content,
|
23
|
+
:with_hostgroup,
|
24
|
+
:with_parameter,
|
25
|
+
content_view_environments: [make_cve(lifecycle_environment: env), make_cve(lifecycle_environment: env2)],
|
26
|
+
organization: env.organization
|
27
|
+
)
|
28
|
+
|
29
|
+
@host.subscription_facet.pools << FactoryBot.create(:katello_pool, account_number: '5678', cp_id: 1)
|
13
30
|
end
|
14
31
|
|
15
32
|
test 'should prepare correct cloud url' do
|
@@ -150,7 +167,7 @@ class CloudRequestForwarderTest < ActiveSupport::TestCase
|
|
150
167
|
'action_dispatch.request.query_parameters' => params
|
151
168
|
)
|
152
169
|
|
153
|
-
actual = @forwarder.prepare_request_opts(req, 'TEST PAYLOAD', params, generate_certs_hash)
|
170
|
+
actual = @forwarder.prepare_request_opts(req, 'TEST PAYLOAD', params, generate_certs_hash, @host)
|
154
171
|
|
155
172
|
assert_match /foo/, actual[:headers][:user_agent]
|
156
173
|
assert_match /bar/, actual[:headers][:user_agent]
|
@@ -175,7 +192,7 @@ class CloudRequestForwarderTest < ActiveSupport::TestCase
|
|
175
192
|
'action_dispatch.request.query_parameters' => params
|
176
193
|
)
|
177
194
|
|
178
|
-
actual = @forwarder.prepare_request_opts(req, 'TEST PAYLOAD', params, generate_certs_hash)
|
195
|
+
actual = @forwarder.prepare_request_opts(req, 'TEST PAYLOAD', params, generate_certs_hash, @host)
|
179
196
|
|
180
197
|
assert_match /text\/html/, actual[:headers][:content_type]
|
181
198
|
end
|