foreman_rh_cloud 12.2.13 → 13.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.
- checksums.yaml +4 -4
- data/app/assets/javascripts/foreman_rh_cloud/locale/fr/foreman_rh_cloud.js +24 -78
- data/app/assets/javascripts/foreman_rh_cloud/locale/ja/foreman_rh_cloud.js +24 -78
- data/app/assets/javascripts/foreman_rh_cloud/locale/ka/foreman_rh_cloud.js +23 -77
- data/app/assets/javascripts/foreman_rh_cloud/locale/ko/foreman_rh_cloud.js +23 -77
- data/app/assets/javascripts/foreman_rh_cloud/locale/zh_CN/foreman_rh_cloud.js +23 -77
- data/app/controllers/concerns/insights_cloud/package_profile_upload_extensions.rb +3 -2
- data/app/models/insights_hit.rb +1 -1
- data/app/services/foreman_rh_cloud/cert_auth.rb +3 -13
- data/app/services/foreman_rh_cloud/gateway_request.rb +26 -0
- data/app/services/foreman_rh_cloud/insights_api_forwarder.rb +1 -3
- data/app/services/foreman_rh_cloud/tags_auth.rb +1 -2
- data/lib/foreman_inventory_upload/async/generate_report_job.rb +8 -13
- data/lib/foreman_inventory_upload/async/queue_for_upload_job.rb +4 -4
- data/lib/foreman_inventory_upload/async/upload_report_job.rb +5 -6
- data/lib/foreman_inventory_upload/generators/fact_helpers.rb +2 -2
- data/lib/foreman_inventory_upload/generators/slice.rb +3 -3
- data/lib/foreman_inventory_upload/scripts/uploader.sh.erb +1 -7
- data/lib/foreman_inventory_upload.rb +2 -6
- data/lib/foreman_rh_cloud/engine.rb +15 -34
- data/lib/foreman_rh_cloud/plugin.rb +9 -9
- data/lib/foreman_rh_cloud/version.rb +1 -1
- data/lib/tasks/rh_cloud_inventory.rake +31 -14
- data/locale/foreman_rh_cloud.pot +157 -261
- data/locale/fr/LC_MESSAGES/foreman_rh_cloud.mo +0 -0
- data/locale/fr/foreman_rh_cloud.po +26 -79
- data/locale/ja/LC_MESSAGES/foreman_rh_cloud.mo +0 -0
- data/locale/ja/foreman_rh_cloud.po +26 -79
- data/locale/ka/LC_MESSAGES/foreman_rh_cloud.mo +0 -0
- data/locale/ka/foreman_rh_cloud.po +24 -77
- data/locale/ko/LC_MESSAGES/foreman_rh_cloud.mo +0 -0
- data/locale/ko/foreman_rh_cloud.po +25 -78
- data/locale/zh_CN/LC_MESSAGES/foreman_rh_cloud.mo +0 -0
- data/locale/zh_CN/foreman_rh_cloud.po +25 -78
- data/package.json +1 -1
- data/test/jobs/cloud_connector_announce_task_test.rb +2 -3
- data/test/jobs/connector_playbook_execution_reporter_task_test.rb +20 -32
- data/test/jobs/exponential_backoff_test.rb +8 -9
- data/test/jobs/insights_client_status_aging_test.rb +2 -3
- data/test/jobs/insights_full_sync_test.rb +7 -13
- data/test/jobs/insights_resolutions_sync_test.rb +5 -9
- data/test/jobs/insights_rules_sync_test.rb +3 -5
- data/test/jobs/inventory_full_sync_test.rb +5 -9
- data/test/jobs/inventory_hosts_sync_test.rb +6 -11
- data/test/jobs/inventory_scheduled_sync_test.rb +6 -10
- data/test/jobs/inventory_self_host_sync_test.rb +1 -1
- data/test/jobs/remove_insights_hosts_job_test.rb +15 -14
- data/test/jobs/upload_report_job_test.rb +5 -7
- data/test/unit/fact_helpers_test.rb +0 -47
- data/test/unit/slice_generator_test.rb +0 -57
- data/webpack/ForemanRhCloudFills.js +2 -6
- data/webpack/ForemanRhCloudHelpers.js +0 -4
- data/webpack/InsightsHostDetailsTab/InsightsTab.scss +0 -4
- data/webpack/InsightsHostDetailsTab/InsightsTotalRiskChart.js +23 -59
- data/webpack/InsightsHostDetailsTab/NewHostDetailsTab.js +16 -3
- data/webpack/InsightsVulnerabilityHostIndexExtensions/CVECountCell.js +2 -8
- data/webpack/InsightsVulnerabilityHostIndexExtensions/__tests__/CVECountCell.test.js +2 -48
- data/webpack/__tests__/ForemanRhCloudHelpers.test.js +1 -16
- data/webpack/__tests__/__snapshots__/ForemanRhCloudHelpers.test.js.snap +0 -6
- metadata +4 -23
- data/app/controllers/concerns/foreman_rh_cloud/registration_manager_extensions.rb +0 -39
- data/lib/foreman_inventory_upload/async/create_missing_insights_facets.rb +0 -30
- data/lib/foreman_inventory_upload/async/generate_host_report.rb +0 -20
- data/lib/foreman_inventory_upload/async/host_inventory_report_job.rb +0 -39
- data/lib/foreman_inventory_upload/async/single_host_report_job.rb +0 -20
- data/test/jobs/create_missing_insights_facets_test.rb +0 -151
- data/test/jobs/generate_host_report_test.rb +0 -100
- data/test/jobs/generate_report_job_test.rb +0 -146
- data/test/jobs/host_inventory_report_job_test.rb +0 -244
- data/test/jobs/queue_for_upload_job_test.rb +0 -65
- data/test/jobs/single_host_report_job_test.rb +0 -155
- data/test/unit/lib/foreman_rh_cloud/registration_manager_extensions_test.rb +0 -192
- data/webpack/InsightsHostDetailsTab/__tests__/InsightsTotalRiskChart.test.js +0 -194
|
@@ -2,7 +2,7 @@ require 'test_plugin_helper'
|
|
|
2
2
|
require 'foreman_tasks/test_helpers'
|
|
3
3
|
|
|
4
4
|
class InventoryHostsSyncTest < ActiveSupport::TestCase
|
|
5
|
-
include
|
|
5
|
+
include ForemanTasks::TestHelpers::WithInThreadExecutor
|
|
6
6
|
include MockCerts
|
|
7
7
|
include KatelloCVEHelper
|
|
8
8
|
|
|
@@ -302,8 +302,7 @@ class InventoryHostsSyncTest < ActiveSupport::TestCase
|
|
|
302
302
|
|
|
303
303
|
@host2.build_insights.save
|
|
304
304
|
|
|
305
|
-
|
|
306
|
-
run_action(action)
|
|
305
|
+
ForemanTasks.sync_task(InventorySync::Async::InventoryHostsSync, [@host1.organization, @host2.organization])
|
|
307
306
|
|
|
308
307
|
@host2.reload
|
|
309
308
|
|
|
@@ -318,8 +317,7 @@ class InventoryHostsSyncTest < ActiveSupport::TestCase
|
|
|
318
317
|
InventorySync::Async::InventoryHostsSync.any_instance.stubs(:candlepin_id_cert)
|
|
319
318
|
end
|
|
320
319
|
|
|
321
|
-
|
|
322
|
-
run_action(action)
|
|
320
|
+
ForemanTasks.sync_task(InventorySync::Async::InventoryHostsSync, [@host1.organization, @host2.organization])
|
|
323
321
|
|
|
324
322
|
@host2.reload
|
|
325
323
|
|
|
@@ -338,8 +336,7 @@ class InventoryHostsSyncTest < ActiveSupport::TestCase
|
|
|
338
336
|
|
|
339
337
|
assert_nil @host2.insights
|
|
340
338
|
|
|
341
|
-
|
|
342
|
-
run_action(action)
|
|
339
|
+
ForemanTasks.sync_task(InventorySync::Async::InventoryHostsSync, [@host1.organization, @host2.organization])
|
|
343
340
|
|
|
344
341
|
@host2.reload
|
|
345
342
|
|
|
@@ -356,8 +353,7 @@ class InventoryHostsSyncTest < ActiveSupport::TestCase
|
|
|
356
353
|
InventorySync::Async::InventoryHostsSync.any_instance.stubs(:candlepin_id_cert)
|
|
357
354
|
end
|
|
358
355
|
|
|
359
|
-
|
|
360
|
-
run_action(action)
|
|
356
|
+
ForemanTasks.sync_task(InventorySync::Async::InventoryHostsSync, [org])
|
|
361
357
|
|
|
362
358
|
assert_equal 3, InsightsMissingHost.count
|
|
363
359
|
end
|
|
@@ -374,8 +370,7 @@ class InventoryHostsSyncTest < ActiveSupport::TestCase
|
|
|
374
370
|
InventorySync::Async::InventoryHostsSync.any_instance.stubs(:candlepin_id_cert)
|
|
375
371
|
end
|
|
376
372
|
|
|
377
|
-
|
|
378
|
-
run_action(action)
|
|
373
|
+
ForemanTasks.sync_task(InventorySync::Async::InventoryHostsSync, [org])
|
|
379
374
|
|
|
380
375
|
assert_equal 3, InsightsMissingHost.count
|
|
381
376
|
end
|
|
@@ -2,7 +2,7 @@ require 'test_plugin_helper'
|
|
|
2
2
|
require 'foreman_tasks/test_helpers'
|
|
3
3
|
|
|
4
4
|
class InventoryScheduledSyncTest < ActiveSupport::TestCase
|
|
5
|
-
include
|
|
5
|
+
include ForemanTasks::TestHelpers::WithInThreadExecutor
|
|
6
6
|
|
|
7
7
|
test 'Schedules an execution if auto upload is enabled' do
|
|
8
8
|
Setting[:allow_auto_inventory_upload] = true
|
|
@@ -11,8 +11,7 @@ class InventoryScheduledSyncTest < ActiveSupport::TestCase
|
|
|
11
11
|
InventorySync::Async::InventoryScheduledSync.any_instance.expects(:plan_org_sync).times(Organization.unscoped.count)
|
|
12
12
|
InventorySync::Async::InventoryScheduledSync.any_instance.expects(:plan_remove_insights_hosts).times(Organization.unscoped.count)
|
|
13
13
|
|
|
14
|
-
|
|
15
|
-
run_action(action)
|
|
14
|
+
ForemanTasks.sync_task(InventorySync::Async::InventoryScheduledSync)
|
|
16
15
|
end
|
|
17
16
|
|
|
18
17
|
test 'Skips execution if with_iop_smart_proxy? is true' do
|
|
@@ -20,9 +19,8 @@ class InventoryScheduledSyncTest < ActiveSupport::TestCase
|
|
|
20
19
|
|
|
21
20
|
InventorySync::Async::InventoryScheduledSync.any_instance.expects(:plan_org_sync).never
|
|
22
21
|
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
status = action.output[:status].to_s
|
|
22
|
+
task = ForemanTasks.sync_task(InventorySync::Async::InventoryScheduledSync)
|
|
23
|
+
status = task.output[:status].to_s
|
|
26
24
|
assert_match(/Foreman is configured with a local IoP Smart Proxy/, status)
|
|
27
25
|
end
|
|
28
26
|
|
|
@@ -31,8 +29,7 @@ class InventoryScheduledSyncTest < ActiveSupport::TestCase
|
|
|
31
29
|
|
|
32
30
|
InventorySync::Async::InventoryScheduledSync.any_instance.expects(:plan_org_sync).never
|
|
33
31
|
|
|
34
|
-
|
|
35
|
-
run_action(action)
|
|
32
|
+
ForemanTasks.sync_task(InventorySync::Async::InventoryScheduledSync)
|
|
36
33
|
end
|
|
37
34
|
|
|
38
35
|
test 'Skips mismatch deletion if the setting is disabled' do
|
|
@@ -42,7 +39,6 @@ class InventoryScheduledSyncTest < ActiveSupport::TestCase
|
|
|
42
39
|
InventorySync::Async::InventoryScheduledSync.any_instance.expects(:plan_org_sync).times(Organization.unscoped.count)
|
|
43
40
|
InventorySync::Async::InventoryScheduledSync.any_instance.expects(:plan_remove_insights_hosts).never
|
|
44
41
|
|
|
45
|
-
|
|
46
|
-
run_action(action)
|
|
42
|
+
ForemanTasks.sync_task(InventorySync::Async::InventoryScheduledSync)
|
|
47
43
|
end
|
|
48
44
|
end
|
|
@@ -2,7 +2,7 @@ require 'test_plugin_helper'
|
|
|
2
2
|
require 'foreman_tasks/test_helpers'
|
|
3
3
|
|
|
4
4
|
class RemoveInsightsHostJobTest < ActiveSupport::TestCase
|
|
5
|
-
include
|
|
5
|
+
include ForemanTasks::TestHelpers::WithInThreadExecutor
|
|
6
6
|
|
|
7
7
|
setup do
|
|
8
8
|
User.current = User.find_by(login: 'secret_admin')
|
|
@@ -18,10 +18,10 @@ class RemoveInsightsHostJobTest < ActiveSupport::TestCase
|
|
|
18
18
|
|
|
19
19
|
FactoryBot.create(:insights_missing_host, organization: @org)
|
|
20
20
|
|
|
21
|
-
|
|
22
|
-
run_action(action)
|
|
21
|
+
task = ForemanTasks.sync_task(ForemanInventoryUpload::Async::RemoveInsightsHostsJob, '', @org.id)
|
|
23
22
|
|
|
24
23
|
assert_equal 0, InsightsMissingHost.count
|
|
24
|
+
assert_equal 'success', task.result
|
|
25
25
|
end
|
|
26
26
|
|
|
27
27
|
test 'Does not delete hosts on cloud failure' do
|
|
@@ -31,13 +31,14 @@ class RemoveInsightsHostJobTest < ActiveSupport::TestCase
|
|
|
31
31
|
|
|
32
32
|
FactoryBot.create(:insights_missing_host, organization: @org)
|
|
33
33
|
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
34
|
+
begin
|
|
35
|
+
ForemanTasks.sync_task(ForemanInventoryUpload::Async::RemoveInsightsHostsJob, '', @org.id)
|
|
36
|
+
rescue ForemanTasks::TaskError => ex
|
|
37
|
+
task = ex.task
|
|
38
38
|
end
|
|
39
39
|
|
|
40
40
|
assert_equal 1, InsightsMissingHost.count
|
|
41
|
+
assert_equal 'error', task.result
|
|
41
42
|
end
|
|
42
43
|
|
|
43
44
|
test 'Paginates the hosts list' do
|
|
@@ -53,12 +54,12 @@ class RemoveInsightsHostJobTest < ActiveSupport::TestCase
|
|
|
53
54
|
FactoryBot.create(:insights_missing_host, organization: @org)
|
|
54
55
|
FactoryBot.create(:insights_missing_host, organization: @org)
|
|
55
56
|
|
|
56
|
-
|
|
57
|
-
action = run_action(action)
|
|
57
|
+
task = ForemanTasks.sync_task(ForemanInventoryUpload::Async::RemoveInsightsHostsJob, '', @org.id)
|
|
58
58
|
|
|
59
59
|
assert_equal 0, InsightsMissingHost.count
|
|
60
|
-
assert_equal '
|
|
61
|
-
assert_equal '
|
|
60
|
+
assert_equal 'success', task.result
|
|
61
|
+
assert_equal 'response1', task.output[:response_page1]
|
|
62
|
+
assert_equal 'response2', task.output[:response_page2]
|
|
62
63
|
end
|
|
63
64
|
|
|
64
65
|
test 'Uses scoped_search to select hosts' do
|
|
@@ -72,12 +73,12 @@ class RemoveInsightsHostJobTest < ActiveSupport::TestCase
|
|
|
72
73
|
FactoryBot.create(:insights_missing_host, name: 'test a', organization: @org)
|
|
73
74
|
FactoryBot.create(:insights_missing_host, name: 'test b', organization: @org)
|
|
74
75
|
|
|
75
|
-
|
|
76
|
-
action = run_action(action)
|
|
76
|
+
task = ForemanTasks.sync_task(ForemanInventoryUpload::Async::RemoveInsightsHostsJob, 'name ~ b', @org.id)
|
|
77
77
|
|
|
78
78
|
assert_equal 1, InsightsMissingHost.count
|
|
79
79
|
assert_equal 'test a', InsightsMissingHost.first.name
|
|
80
|
-
assert_equal '
|
|
80
|
+
assert_equal 'success', task.result
|
|
81
|
+
assert_equal 'response1', task.output[:response_page1]
|
|
81
82
|
end
|
|
82
83
|
|
|
83
84
|
def mock_response(code: 200, body: '')
|
|
@@ -2,7 +2,8 @@ require 'test_plugin_helper'
|
|
|
2
2
|
require 'foreman_tasks/test_helpers'
|
|
3
3
|
|
|
4
4
|
class UploadReportJobTest < ActiveSupport::TestCase
|
|
5
|
-
include
|
|
5
|
+
include ForemanTasks::TestHelpers::WithInThreadExecutor
|
|
6
|
+
include FolderIsolation
|
|
6
7
|
|
|
7
8
|
test 'returns aborted state when disconnected' do
|
|
8
9
|
organization = FactoryBot.create(:organization)
|
|
@@ -13,13 +14,11 @@ class UploadReportJobTest < ActiveSupport::TestCase
|
|
|
13
14
|
)
|
|
14
15
|
ForemanInventoryUpload::Async::UploadReportJob.any_instance.expects(:content_disconnected?).returns(true)
|
|
15
16
|
|
|
16
|
-
|
|
17
|
-
run_action(action)
|
|
17
|
+
ForemanTasks.sync_task(ForemanInventoryUpload::Async::UploadReportJob, '', organization.id)
|
|
18
18
|
|
|
19
19
|
label = ForemanInventoryUpload::Async::UploadReportJob.output_label(organization.id)
|
|
20
20
|
progress_output = ForemanInventoryUpload::Async::ProgressOutput.get(label)
|
|
21
|
-
assert_match(/
|
|
22
|
-
assert_match(/Report location:/, progress_output.full_output)
|
|
21
|
+
assert_match(/Upload canceled/, progress_output.full_output)
|
|
23
22
|
assert_match(/exit 1/, progress_output.status)
|
|
24
23
|
end
|
|
25
24
|
|
|
@@ -27,8 +26,7 @@ class UploadReportJobTest < ActiveSupport::TestCase
|
|
|
27
26
|
organization = FactoryBot.create(:organization)
|
|
28
27
|
Organization.any_instance.expects(:owner_details).returns(nil)
|
|
29
28
|
|
|
30
|
-
|
|
31
|
-
run_action(action)
|
|
29
|
+
ForemanTasks.sync_task(ForemanInventoryUpload::Async::UploadReportJob, '', organization.id)
|
|
32
30
|
|
|
33
31
|
label = ForemanInventoryUpload::Async::UploadReportJob.output_label(organization.id)
|
|
34
32
|
progress_output = ForemanInventoryUpload::Async::ProgressOutput.get(label)
|
|
@@ -313,51 +313,4 @@ class FactHelpersTest < ActiveSupport::TestCase
|
|
|
313
313
|
assert_equal '10.230.230.3', ip3
|
|
314
314
|
end
|
|
315
315
|
end
|
|
316
|
-
|
|
317
|
-
describe 'IoP smart proxy checks' do
|
|
318
|
-
test 'obfuscate_hostname? returns false when global setting is enabled but IoP is present' do
|
|
319
|
-
Setting.expects(:[]).with(:obfuscate_inventory_hostnames).returns(true)
|
|
320
|
-
ForemanRhCloud.expects(:with_iop_smart_proxy?).returns(true)
|
|
321
|
-
host = mock('host')
|
|
322
|
-
# When IoP is present, it falls back to checking host-specific facts
|
|
323
|
-
@instance.expects(:fact_value).with(host, 'insights_client::obfuscate_hostname_enabled').returns(nil)
|
|
324
|
-
|
|
325
|
-
result = @instance.obfuscate_hostname?(host)
|
|
326
|
-
|
|
327
|
-
refute result
|
|
328
|
-
end
|
|
329
|
-
|
|
330
|
-
test 'obfuscate_hostname? returns true when global setting is enabled and IoP is not present' do
|
|
331
|
-
Setting.expects(:[]).with(:obfuscate_inventory_hostnames).returns(true)
|
|
332
|
-
ForemanRhCloud.expects(:with_iop_smart_proxy?).returns(false)
|
|
333
|
-
host = mock('host')
|
|
334
|
-
|
|
335
|
-
result = @instance.obfuscate_hostname?(host)
|
|
336
|
-
|
|
337
|
-
assert result
|
|
338
|
-
end
|
|
339
|
-
|
|
340
|
-
test 'obfuscate_ips? returns false when global setting is enabled but IoP is present' do
|
|
341
|
-
Setting.expects(:[]).with(:obfuscate_inventory_ips).returns(true)
|
|
342
|
-
ForemanRhCloud.expects(:with_iop_smart_proxy?).returns(true)
|
|
343
|
-
host = mock('host')
|
|
344
|
-
# When IoP is present, it falls back to checking host-specific facts
|
|
345
|
-
@instance.expects(:fact_value).with(host, 'insights_client::obfuscate_ipv4_enabled').returns(nil)
|
|
346
|
-
@instance.expects(:fact_value).with(host, 'insights_client::obfuscate_ipv6_enabled').returns(nil)
|
|
347
|
-
|
|
348
|
-
result = @instance.obfuscate_ips?(host)
|
|
349
|
-
|
|
350
|
-
refute result
|
|
351
|
-
end
|
|
352
|
-
|
|
353
|
-
test 'obfuscate_ips? returns true when global setting is enabled and IoP is not present' do
|
|
354
|
-
Setting.expects(:[]).with(:obfuscate_inventory_ips).returns(true)
|
|
355
|
-
ForemanRhCloud.expects(:with_iop_smart_proxy?).returns(false)
|
|
356
|
-
host = mock('host')
|
|
357
|
-
|
|
358
|
-
result = @instance.obfuscate_ips?(host)
|
|
359
|
-
|
|
360
|
-
assert result
|
|
361
|
-
end
|
|
362
|
-
end
|
|
363
316
|
end
|
|
@@ -107,36 +107,6 @@ class SliceGeneratorTest < ActiveSupport::TestCase
|
|
|
107
107
|
assert_equal 'test_nic1', actual_nic['name']
|
|
108
108
|
end
|
|
109
109
|
|
|
110
|
-
test 'does not generate a report with minimal data collection when iop is present' do
|
|
111
|
-
Setting[:insights_minimal_data_collection] = true
|
|
112
|
-
ForemanRhCloud.stubs(:with_iop_smart_proxy?).returns(true)
|
|
113
|
-
|
|
114
|
-
batch = Host.where(id: @host.id).in_batches.first
|
|
115
|
-
generator = create_generator(batch)
|
|
116
|
-
|
|
117
|
-
json_str = generator.render
|
|
118
|
-
actual = JSON.parse(json_str.join("\n"))
|
|
119
|
-
|
|
120
|
-
assert_equal '00000000-0000-0000-0000-000000000000', actual['report_slice_id']
|
|
121
|
-
assert_not_nil(actual_host = actual['hosts'].first)
|
|
122
|
-
assert_nil actual_host['ip_addresses']
|
|
123
|
-
assert_nil actual_host['mac_addresses']
|
|
124
|
-
assert_equal @host.fqdn, actual_host['fqdn']
|
|
125
|
-
assert_equal '1234', actual_host['account']
|
|
126
|
-
assert_equal 1, generator.hosts_count
|
|
127
|
-
assert_not_nil(actual_system_profile = actual_host['system_profile'])
|
|
128
|
-
assert_nil actual_system_profile['number_of_cpus']
|
|
129
|
-
assert_nil actual_system_profile['number_of_sockets']
|
|
130
|
-
assert_nil actual_system_profile['cores_per_socket']
|
|
131
|
-
assert_nil actual_system_profile['system_memory_bytes']
|
|
132
|
-
assert_nil actual_system_profile['os_release']
|
|
133
|
-
assert_not_nil(actual_network_interfaces = actual_system_profile['network_interfaces'])
|
|
134
|
-
assert_not_nil(actual_nic = actual_network_interfaces.first)
|
|
135
|
-
refute actual_nic.key?('mtu')
|
|
136
|
-
refute actual_nic.key?('mac_address')
|
|
137
|
-
assert_equal 'test_nic1', actual_nic['name']
|
|
138
|
-
end
|
|
139
|
-
|
|
140
110
|
test 'generates a report with minimal data collection' do
|
|
141
111
|
Setting[:insights_minimal_data_collection] = true
|
|
142
112
|
create_fact_values(@host,
|
|
@@ -960,33 +930,6 @@ class SliceGeneratorTest < ActiveSupport::TestCase
|
|
|
960
930
|
assert_equal 'alibaba', actual_profile['cloud_provider']
|
|
961
931
|
end
|
|
962
932
|
|
|
963
|
-
test 'do not exclude packages when iop is present' do
|
|
964
|
-
Setting[:exclude_installed_packages] = true
|
|
965
|
-
ForemanRhCloud.stubs(:with_iop_smart_proxy?).returns(true)
|
|
966
|
-
installed_package = ::Katello::InstalledPackage.create(name: 'test-package', nvrea: 'test-package-1.0.x86_64', nvra: 'test-package-1.0.x86_64')
|
|
967
|
-
|
|
968
|
-
another_host = FactoryBot.create(
|
|
969
|
-
:host,
|
|
970
|
-
:with_subscription,
|
|
971
|
-
:with_content,
|
|
972
|
-
content_view: @host.content_views.first,
|
|
973
|
-
lifecycle_environment: @host.lifecycle_environments.first,
|
|
974
|
-
organization: @host.organization,
|
|
975
|
-
installed_packages: [installed_package]
|
|
976
|
-
)
|
|
977
|
-
|
|
978
|
-
batch = Host.where(id: another_host.id).in_batches.first
|
|
979
|
-
generator = create_generator(batch)
|
|
980
|
-
|
|
981
|
-
json_str = generator.render
|
|
982
|
-
actual = JSON.parse(json_str.join("\n"))
|
|
983
|
-
|
|
984
|
-
assert_equal '00000000-0000-0000-0000-000000000000', actual['report_slice_id']
|
|
985
|
-
assert_not_nil(actual_host = actual['hosts'].first)
|
|
986
|
-
assert_not_nil(actual_profile = actual_host['system_profile'])
|
|
987
|
-
assert_not_nil(actual_profile['installed_packages'])
|
|
988
|
-
end
|
|
989
|
-
|
|
990
933
|
test 'include packages installed in the report' do
|
|
991
934
|
Setting[:exclude_installed_packages] = false
|
|
992
935
|
installed_package = ::Katello::InstalledPackage.create(name: 'test-package', nvrea: 'test-package-1.0.x86_64', nvra: 'test-package-1.0.x86_64')
|
|
@@ -4,11 +4,7 @@ import { translate as __ } from 'foremanReact/common/I18n';
|
|
|
4
4
|
import InventoryAutoUploadSwitcher from './ForemanInventoryUpload/SubscriptionsPageExtension/InventoryAutoUpload';
|
|
5
5
|
import NewHostDetailsTab from './InsightsHostDetailsTab/NewHostDetailsTab';
|
|
6
6
|
import { InsightsTotalRiskChartWrapper } from './InsightsHostDetailsTab/InsightsTotalRiskChartWrapper';
|
|
7
|
-
import {
|
|
8
|
-
isNotRhelHost,
|
|
9
|
-
vulnerabilityDisabled,
|
|
10
|
-
hasNoInsightsFacet,
|
|
11
|
-
} from './ForemanRhCloudHelpers';
|
|
7
|
+
import { isNotRhelHost, vulnerabilityDisabled } from './ForemanRhCloudHelpers';
|
|
12
8
|
import CVEsHostDetailsTabWrapper from './CVEsHostDetailsTab/CVEsHostDetailsTab';
|
|
13
9
|
|
|
14
10
|
const fills = [
|
|
@@ -24,7 +20,7 @@ const fills = [
|
|
|
24
20
|
component: props => <NewHostDetailsTab {...props} />,
|
|
25
21
|
weight: 400,
|
|
26
22
|
metadata: {
|
|
27
|
-
hideTab:
|
|
23
|
+
hideTab: isNotRhelHost,
|
|
28
24
|
title: __('Recommendations'),
|
|
29
25
|
},
|
|
30
26
|
},
|
|
@@ -14,7 +14,3 @@ export const isNotRhelHost = ({ hostDetails }) =>
|
|
|
14
14
|
|
|
15
15
|
export const vulnerabilityDisabled = ({ hostDetails }) =>
|
|
16
16
|
isNotRhelHost({ hostDetails }) || !hostDetails?.vulnerability?.enabled;
|
|
17
|
-
|
|
18
|
-
export const hasNoInsightsFacet = ({ response, hostDetails }) =>
|
|
19
|
-
// eslint-disable-next-line camelcase
|
|
20
|
-
!(response?.insights_attributes || hostDetails?.insights_attributes);
|
|
@@ -3,7 +3,8 @@ import PropTypes from 'prop-types';
|
|
|
3
3
|
import { useDispatch } from 'react-redux';
|
|
4
4
|
import { push } from 'connected-react-router';
|
|
5
5
|
import { useHistory } from 'react-router-dom';
|
|
6
|
-
import { Bullseye,
|
|
6
|
+
import { Bullseye, Title } from '@patternfly/react-core';
|
|
7
|
+
import { DropdownItem } from '@patternfly/react-core/deprecated';
|
|
7
8
|
import {
|
|
8
9
|
ChartDonut,
|
|
9
10
|
ChartLegend,
|
|
@@ -18,67 +19,36 @@ import SkeletonLoader from 'foremanReact/components/common/SkeletonLoader';
|
|
|
18
19
|
import { insightsCloudUrl } from '../InsightsCloudSync/InsightsCloudSyncHelpers';
|
|
19
20
|
import { getInitialRisks, theme } from './InsightsTabConstants';
|
|
20
21
|
|
|
21
|
-
const InsightsTotalRiskCard = ({ hostDetails }) => {
|
|
22
|
-
const { id, insights_attributes: insightsFacet } = hostDetails;
|
|
23
|
-
const uuid = insightsFacet?.uuid;
|
|
24
|
-
// eslint-disable-next-line camelcase
|
|
25
|
-
const isIop = insightsFacet?.use_iop_mode;
|
|
22
|
+
const InsightsTotalRiskCard = ({ hostDetails: { id } }) => {
|
|
26
23
|
const [totalRisks, setTotalRisks] = useState(getInitialRisks());
|
|
27
24
|
const hashHistory = useHistory();
|
|
28
25
|
const dispatch = useDispatch();
|
|
29
26
|
const API_KEY = `HOST_${id}_RECOMMENDATIONS`;
|
|
30
27
|
const API_OPTIONS = useMemo(() => ({ key: API_KEY }), [API_KEY]);
|
|
28
|
+
const url = id && insightsCloudUrl(`hits/${id}`); // This will keep the API call from being triggered if there's no host id.
|
|
29
|
+
const {
|
|
30
|
+
status = STATUS.PENDING,
|
|
31
|
+
response: { hits = [] },
|
|
32
|
+
} = useAPI('get', url, API_OPTIONS);
|
|
31
33
|
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
: id && insightsCloudUrl(`hits/${id}`);
|
|
36
|
-
const { status = STATUS.PENDING, response } = useAPI('get', url, API_OPTIONS);
|
|
37
|
-
|
|
38
|
-
const checkRisks = useMemo(() => {
|
|
39
|
-
if (!response || status !== STATUS.RESOLVED) {
|
|
40
|
-
return getInitialRisks();
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
const risks = getInitialRisks();
|
|
44
|
-
if (isIop) {
|
|
45
|
-
const {
|
|
46
|
-
low_hits: lowHits = 0,
|
|
47
|
-
moderate_hits: moderateHits = 0,
|
|
48
|
-
important_hits: importantHits = 0,
|
|
49
|
-
critical_hits: criticalHits = 0,
|
|
50
|
-
hits = 0,
|
|
51
|
-
} = response;
|
|
52
|
-
|
|
53
|
-
risks[1].value += lowHits;
|
|
54
|
-
risks[2].value += moderateHits;
|
|
55
|
-
risks[3].value += importantHits;
|
|
56
|
-
risks[4].value += criticalHits;
|
|
57
|
-
risks.total = hits;
|
|
58
|
-
} else {
|
|
59
|
-
const { hits = [] } = response;
|
|
34
|
+
useEffect(() => {
|
|
35
|
+
if (status === STATUS.RESOLVED) {
|
|
36
|
+
const risks = getInitialRisks();
|
|
60
37
|
hits.forEach(({ total_risk: risk }) => {
|
|
61
38
|
risks[risk].value += 1;
|
|
62
39
|
});
|
|
63
40
|
risks.total = hits.length;
|
|
41
|
+
setTotalRisks(risks);
|
|
64
42
|
}
|
|
65
|
-
|
|
66
|
-
}, [response, status, isIop]);
|
|
67
|
-
|
|
68
|
-
useEffect(() => {
|
|
69
|
-
setTotalRisks(checkRisks);
|
|
70
|
-
}, [checkRisks]);
|
|
71
|
-
|
|
72
|
-
if (!insightsFacet) return null;
|
|
43
|
+
}, [hits, status]);
|
|
73
44
|
|
|
74
45
|
const onChartClick = (evt, { index }) => {
|
|
75
46
|
hashHistory.push(`/Insights`);
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
);
|
|
47
|
+
dispatch(
|
|
48
|
+
push({
|
|
49
|
+
search: `search=total_risk+%3D+${index + 1}`,
|
|
50
|
+
})
|
|
51
|
+
);
|
|
82
52
|
};
|
|
83
53
|
|
|
84
54
|
const onChartHover = (evt, { index }) => [
|
|
@@ -92,16 +62,11 @@ const InsightsTotalRiskCard = ({ hostDetails }) => {
|
|
|
92
62
|
const { 1: low, 2: moderate, 3: important, 4: critical, total } = totalRisks;
|
|
93
63
|
|
|
94
64
|
// eslint-disable-next-line react/prop-types
|
|
95
|
-
const LegendLabel = ({ index, ...rest }) =>
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
<a key={index} onClick={() => onChartClick(null, { index })}>
|
|
101
|
-
<ChartLabel {...rest} />
|
|
102
|
-
</a>
|
|
103
|
-
);
|
|
104
|
-
};
|
|
65
|
+
const LegendLabel = ({ index, ...rest }) => (
|
|
66
|
+
<a key={index} onClick={() => onChartClick(null, { index })}>
|
|
67
|
+
<ChartLabel {...rest} />
|
|
68
|
+
</a>
|
|
69
|
+
);
|
|
105
70
|
|
|
106
71
|
const legend = (
|
|
107
72
|
<ChartLegend
|
|
@@ -162,7 +127,6 @@ const InsightsTotalRiskCard = ({ hostDetails }) => {
|
|
|
162
127
|
return (
|
|
163
128
|
<CardTemplate
|
|
164
129
|
header={__('Total risks')}
|
|
165
|
-
overrideDropdownProps={{ id: 'total-risks-dropdown-container' }}
|
|
166
130
|
dropdownItems={[
|
|
167
131
|
<DropdownItem
|
|
168
132
|
key="insights-tab"
|
|
@@ -131,15 +131,28 @@ const IopInsightsTabWrapped = props => (
|
|
|
131
131
|
);
|
|
132
132
|
|
|
133
133
|
const InsightsTab = props => {
|
|
134
|
-
const
|
|
134
|
+
const { response } = props;
|
|
135
|
+
const isLocalAdvisorEngine =
|
|
136
|
+
// eslint-disable-next-line camelcase
|
|
137
|
+
response?.insights_attributes?.use_iop_mode;
|
|
135
138
|
|
|
136
|
-
return
|
|
139
|
+
return isLocalAdvisorEngine ? (
|
|
137
140
|
<IopInsightsTabWrapped {...props} />
|
|
138
141
|
) : (
|
|
139
142
|
<NewHostDetailsTab {...props} />
|
|
140
143
|
);
|
|
141
144
|
};
|
|
142
145
|
|
|
143
|
-
InsightsTab.
|
|
146
|
+
InsightsTab.propTypes = {
|
|
147
|
+
response: PropTypes.shape({
|
|
148
|
+
insights_attributes: {
|
|
149
|
+
use_iop_mode: PropTypes.bool,
|
|
150
|
+
},
|
|
151
|
+
}),
|
|
152
|
+
};
|
|
153
|
+
|
|
154
|
+
InsightsTab.defaultProps = {
|
|
155
|
+
response: {},
|
|
156
|
+
};
|
|
144
157
|
|
|
145
158
|
export default InsightsTab;
|
|
@@ -3,31 +3,25 @@ import PropTypes from 'prop-types';
|
|
|
3
3
|
import { UnknownIcon } from '@patternfly/react-icons';
|
|
4
4
|
import { Link } from 'react-router-dom';
|
|
5
5
|
import { useAPI } from 'foremanReact/common/hooks/API/APIHooks';
|
|
6
|
+
|
|
6
7
|
import { insightsCloudUrl } from '../InsightsCloudSync/InsightsCloudSyncHelpers';
|
|
7
|
-
import { useAdvisorEngineConfig } from '../common/Hooks/ConfigHooks';
|
|
8
8
|
|
|
9
9
|
const vulnerabilityApiPath = path =>
|
|
10
10
|
insightsCloudUrl(`api/vulnerability/v1/${path}`);
|
|
11
11
|
|
|
12
12
|
export const CVECountCell = ({ hostDetails }) => {
|
|
13
|
-
const isIopEnabled = useAdvisorEngineConfig();
|
|
14
|
-
|
|
15
13
|
// eslint-disable-next-line camelcase
|
|
16
14
|
const uuid = hostDetails?.subscription_facet_attributes?.uuid;
|
|
17
15
|
|
|
18
16
|
const key = `HOST_CVE_COUNT_${uuid}`;
|
|
19
17
|
const response = useAPI(
|
|
20
|
-
|
|
18
|
+
uuid ? 'get' : null,
|
|
21
19
|
vulnerabilityApiPath(`systems?uuid=${uuid}`),
|
|
22
20
|
{
|
|
23
21
|
key,
|
|
24
22
|
}
|
|
25
23
|
);
|
|
26
24
|
|
|
27
|
-
if (!isIopEnabled) {
|
|
28
|
-
return <UnknownIcon />;
|
|
29
|
-
}
|
|
30
|
-
|
|
31
25
|
if (uuid === undefined) {
|
|
32
26
|
return <UnknownIcon />;
|
|
33
27
|
}
|
|
@@ -2,11 +2,8 @@ import React from 'react';
|
|
|
2
2
|
import { render, screen } from '@testing-library/react';
|
|
3
3
|
import { API } from 'foremanReact/redux/API';
|
|
4
4
|
import { CVECountCell } from '../CVECountCell';
|
|
5
|
-
import * as ConfigHooks from '../../common/Hooks/ConfigHooks';
|
|
6
5
|
|
|
7
6
|
jest.mock('foremanReact/redux/API');
|
|
8
|
-
jest.mock('../../common/Hooks/ConfigHooks');
|
|
9
|
-
|
|
10
7
|
API.get.mockImplementation(async () => ({
|
|
11
8
|
data: [
|
|
12
9
|
{
|
|
@@ -17,58 +14,15 @@ API.get.mockImplementation(async () => ({
|
|
|
17
14
|
],
|
|
18
15
|
}));
|
|
19
16
|
|
|
20
|
-
const hostDetailsMock = {
|
|
21
|
-
name: 'test-host.example.com',
|
|
22
|
-
subscription_facet_attributes: {
|
|
23
|
-
uuid: 'test-uuid-123',
|
|
24
|
-
},
|
|
25
|
-
};
|
|
26
|
-
|
|
27
17
|
describe('CVECountCell', () => {
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
});
|
|
31
|
-
|
|
32
|
-
afterEach(() => {
|
|
33
|
-
jest.clearAllMocks();
|
|
34
|
-
});
|
|
35
|
-
|
|
36
|
-
it('renders an empty cves count column when no subscription UUID', () => {
|
|
37
|
-
const hostDetailsMockIoP = {
|
|
18
|
+
it('renders an empty cves count column', () => {
|
|
19
|
+
const hostDetailsMock = {
|
|
38
20
|
name: 'test-host.example.com',
|
|
39
21
|
subscription_facet_attributes: {
|
|
40
22
|
uuid: null, // no subscription
|
|
41
23
|
},
|
|
42
24
|
};
|
|
43
|
-
render(<CVECountCell hostDetails={hostDetailsMockIoP} />);
|
|
44
|
-
expect(screen.getByRole('img', { hidden: true })).toBeTruthy();
|
|
45
|
-
});
|
|
46
|
-
|
|
47
|
-
it('renders UnknownIcon when IoP is not enabled', () => {
|
|
48
|
-
ConfigHooks.useAdvisorEngineConfig.mockReturnValue(false);
|
|
49
|
-
render(<CVECountCell hostDetails={hostDetailsMock} />);
|
|
50
|
-
expect(screen.getByRole('img', { hidden: true })).toBeTruthy();
|
|
51
|
-
expect(ConfigHooks.useAdvisorEngineConfig).toHaveBeenCalled();
|
|
52
|
-
});
|
|
53
|
-
|
|
54
|
-
it('renders UnknownIcon when IoP is enabled but CVE API call fails', () => {
|
|
55
|
-
// Mock successful IoP config
|
|
56
|
-
ConfigHooks.useAdvisorEngineConfig.mockReturnValue(true);
|
|
57
|
-
// Mock CVE API failure - override the global mock for this test
|
|
58
|
-
API.get.mockImplementationOnce(async () => {
|
|
59
|
-
throw new Error('CVE API call failed');
|
|
60
|
-
});
|
|
61
|
-
|
|
62
|
-
render(<CVECountCell hostDetails={hostDetailsMock} />);
|
|
63
|
-
// Should render UnknownIcon when CVE API fails
|
|
64
|
-
expect(screen.getByRole('img', { hidden: true })).toBeTruthy();
|
|
65
|
-
expect(ConfigHooks.useAdvisorEngineConfig).toHaveBeenCalled();
|
|
66
|
-
});
|
|
67
|
-
|
|
68
|
-
it('renders UnknownIcon when IoP is undefined (API call pending)', () => {
|
|
69
|
-
ConfigHooks.useAdvisorEngineConfig.mockReturnValue(undefined);
|
|
70
25
|
render(<CVECountCell hostDetails={hostDetailsMock} />);
|
|
71
26
|
expect(screen.getByRole('img', { hidden: true })).toBeTruthy();
|
|
72
|
-
expect(ConfigHooks.useAdvisorEngineConfig).toHaveBeenCalled();
|
|
73
27
|
});
|
|
74
28
|
});
|