foreman_rh_cloud 13.0.6 → 13.0.8
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/controllers/concerns/foreman_rh_cloud/registration_manager_extensions.rb +39 -0
- data/lib/foreman_inventory_upload/async/create_missing_insights_facets.rb +3 -2
- data/lib/foreman_inventory_upload/scripts/uploader.sh.erb +1 -1
- data/lib/foreman_inventory_upload.rb +6 -2
- data/lib/foreman_rh_cloud/engine.rb +1 -0
- data/lib/foreman_rh_cloud/plugin.rb +4 -0
- data/lib/foreman_rh_cloud/version.rb +1 -1
- data/lib/tasks/rh_cloud_inventory.rake +11 -1
- data/package.json +1 -1
- data/test/jobs/cloud_connector_announce_task_test.rb +3 -2
- data/test/jobs/connector_playbook_execution_reporter_task_test.rb +32 -20
- data/test/jobs/create_missing_insights_facets_test.rb +151 -0
- data/test/jobs/exponential_backoff_test.rb +9 -8
- data/test/jobs/generate_host_report_test.rb +100 -0
- data/test/jobs/generate_report_job_test.rb +146 -0
- data/test/jobs/host_inventory_report_job_test.rb +244 -0
- data/test/jobs/insights_client_status_aging_test.rb +3 -2
- data/test/jobs/insights_full_sync_test.rb +13 -7
- data/test/jobs/insights_resolutions_sync_test.rb +9 -5
- data/test/jobs/insights_rules_sync_test.rb +5 -3
- data/test/jobs/inventory_full_sync_test.rb +9 -5
- data/test/jobs/inventory_hosts_sync_test.rb +11 -6
- data/test/jobs/inventory_scheduled_sync_test.rb +10 -6
- data/test/jobs/inventory_self_host_sync_test.rb +1 -1
- data/test/jobs/queue_for_upload_job_test.rb +9 -7
- data/test/jobs/remove_insights_hosts_job_test.rb +14 -15
- data/test/jobs/single_host_report_job_test.rb +155 -0
- data/test/jobs/upload_report_job_test.rb +5 -4
- data/test/unit/lib/foreman_rh_cloud/registration_manager_extensions_test.rb +192 -0
- data/webpack/ForemanColumnExtensions/index.js +2 -0
- data/webpack/InsightsCloudSync/Components/InsightsSettings/InsightsSettings.js +3 -3
- data/webpack/InsightsCloudSync/Components/InsightsTable/InsightsTable.js +3 -9
- data/webpack/InsightsCloudSync/Components/InsightsTable/__tests__/InsightsTable.test.js +13 -0
- data/webpack/InsightsCloudSync/Components/RemediationModal/RemediationModal.js +2 -2
- data/webpack/InsightsCloudSync/Components/ToolbarDropdown.js +3 -3
- data/webpack/InsightsCloudSync/InsightsCloudSync.js +3 -3
- data/webpack/InsightsCloudSync/InsightsCloudSync.test.js +10 -0
- data/webpack/InsightsCloudSync/__snapshots__/InsightsCloudSync.test.js.snap +1 -1
- data/webpack/InsightsHostDetailsTab/NewHostDetailsTab.js +5 -5
- data/webpack/InsightsVulnerabilityHostIndexExtensions/CVECountCell.js +2 -2
- data/webpack/InsightsVulnerabilityHostIndexExtensions/__tests__/CVECountCell.test.js +7 -7
- data/webpack/common/Hooks/ConfigHooks.js +3 -16
- metadata +14 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: aba47c451526fd85b565ba8fdcb17d6b7d643cd3c6fbea186a40943a6a4887bc
|
|
4
|
+
data.tar.gz: 16357a50048143a026497016cd38533b34d211c6ea61fccf55bd2a298852766e
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: c863fed43a17edb0cfdb465e4b26b529e9a09460ab9677cea6e94bc3fea6c560c8fdf01c691ea4ea2d495c7ab715db90cbee5c3bf87217e3aae135c9b29b5e2f
|
|
7
|
+
data.tar.gz: c1d61f3f092e87829a28fd1ac237f46c29772aeae926d2a3c65cba440d3233844aa8dd40eb38a18ff56a09c68f9578aaf83a142d37d1aff06679d0ba6b87c904
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
module ForemanRhCloud
|
|
2
|
+
module RegistrationManagerExtensions
|
|
3
|
+
include ForemanRhCloud::CertAuth
|
|
4
|
+
|
|
5
|
+
def logger
|
|
6
|
+
Rails.logger
|
|
7
|
+
end
|
|
8
|
+
|
|
9
|
+
def unregister_host(host, options = {})
|
|
10
|
+
organization_destroy = options.fetch(:organization_destroy, false)
|
|
11
|
+
|
|
12
|
+
# Reload to ensure we have fresh association data
|
|
13
|
+
host.reload
|
|
14
|
+
|
|
15
|
+
# Only delete from HBI in IoP mode (hosted mode uses async job for cleanup)
|
|
16
|
+
hbi_host_destroy(host) if ForemanRhCloud.with_iop_smart_proxy? && !organization_destroy && host.insights_facet&.uuid&.presence
|
|
17
|
+
host.insights&.destroy!
|
|
18
|
+
super(host, options)
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
def hbi_host_destroy(host)
|
|
22
|
+
uuid = host.insights_facet.uuid
|
|
23
|
+
logger.debug "Unregistering host #{uuid} from HBI"
|
|
24
|
+
execute_cloud_request(
|
|
25
|
+
organization: host.organization,
|
|
26
|
+
method: :delete,
|
|
27
|
+
url: ForemanInventoryUpload.host_by_id_url(uuid),
|
|
28
|
+
headers: {
|
|
29
|
+
content_type: :json,
|
|
30
|
+
}
|
|
31
|
+
)
|
|
32
|
+
rescue RestClient::NotFound
|
|
33
|
+
Rails.logger.warn(_("Attempted to destroy HBI host %s, but host does not exist in HBI") % uuid)
|
|
34
|
+
rescue StandardError => e
|
|
35
|
+
# TODO: Improve error handling - don't break registration if HBI delete fails
|
|
36
|
+
Rails.logger.error(format(_("Failed to destroy HBI host %s: %s"), uuid, e.message))
|
|
37
|
+
end
|
|
38
|
+
end
|
|
39
|
+
end
|
|
@@ -8,7 +8,7 @@ module ForemanInventoryUpload
|
|
|
8
8
|
def run
|
|
9
9
|
organization = ::Organization.find(input[:organization_id])
|
|
10
10
|
hosts_without_facets = ::ForemanInventoryUpload::Generators::Queries.for_org(organization, hosts_query: 'null? insights_uuid')
|
|
11
|
-
facet_count =
|
|
11
|
+
facet_count = 0
|
|
12
12
|
hosts_without_facets.each do |batch|
|
|
13
13
|
facets = batch.pluck(:id, 'katello_subscription_facets.uuid').map do |host_id, uuid|
|
|
14
14
|
{
|
|
@@ -20,9 +20,10 @@ module ForemanInventoryUpload
|
|
|
20
20
|
# rubocop:disable Rails/SkipsModelValidations
|
|
21
21
|
InsightsFacet.upsert_all(facets, unique_by: :host_id) unless facets.empty?
|
|
22
22
|
# rubocop:enable Rails/SkipsModelValidations
|
|
23
|
+
facet_count += facets.size
|
|
23
24
|
end
|
|
24
25
|
output[:result] = facet_count.zero? ? _("There were no missing Insights facets") : format(_("Missing Insights facets created: %s"), facet_count)
|
|
25
|
-
Rails.logger.
|
|
26
|
+
Rails.logger.debug output[:result]
|
|
26
27
|
end
|
|
27
28
|
end
|
|
28
29
|
end
|
|
@@ -88,8 +88,12 @@ module ForemanInventoryUpload
|
|
|
88
88
|
inventory_base_url + "?hostname_or_id=#{ForemanRhCloud.foreman_host.fqdn}"
|
|
89
89
|
end
|
|
90
90
|
|
|
91
|
-
def self.
|
|
92
|
-
|
|
91
|
+
def self.host_by_id_url(host_uuid)
|
|
92
|
+
"#{inventory_base_url}/#{host_uuid}"
|
|
93
|
+
end
|
|
94
|
+
|
|
95
|
+
def self.hosts_by_ids_url(host_uuids)
|
|
96
|
+
host_ids_string = host_uuids.join(',')
|
|
93
97
|
"#{inventory_base_url}/#{host_ids_string}"
|
|
94
98
|
end
|
|
95
99
|
end
|
|
@@ -40,6 +40,7 @@ module ForemanRhCloud
|
|
|
40
40
|
::Host::Managed.include RhCloudHost
|
|
41
41
|
|
|
42
42
|
::Katello::Api::Rhsm::CandlepinDynflowProxyController.include InsightsCloud::PackageProfileUploadExtensions
|
|
43
|
+
::Katello::RegistrationManager.singleton_class.prepend ::ForemanRhCloud::RegistrationManagerExtensions
|
|
43
44
|
end
|
|
44
45
|
end
|
|
45
46
|
|
|
@@ -146,6 +146,10 @@ module ForemanRhCloud
|
|
|
146
146
|
end
|
|
147
147
|
end
|
|
148
148
|
|
|
149
|
+
::Foreman::Plugin.app_metadata_registry.register(:foreman_rh_cloud, {
|
|
150
|
+
iop: ForemanRhCloud.with_iop_smart_proxy?,
|
|
151
|
+
})
|
|
152
|
+
|
|
149
153
|
extend_template_helpers ForemanRhCloud::TemplateRendererHelper
|
|
150
154
|
allowed_template_helpers :remediations_playbook, :download_rh_playbook
|
|
151
155
|
end
|
|
@@ -39,13 +39,23 @@ namespace :rh_cloud_inventory do
|
|
|
39
39
|
|
|
40
40
|
User.as_anonymous_admin do
|
|
41
41
|
organization_ids.each do |organization_id|
|
|
42
|
-
ForemanTasks.sync_task(
|
|
42
|
+
task = ForemanTasks.sync_task(
|
|
43
43
|
ForemanInventoryUpload::Async::HostInventoryReportJob,
|
|
44
44
|
base_folder,
|
|
45
45
|
organization_id,
|
|
46
46
|
filter,
|
|
47
47
|
false # don't upload; the user ran report:generate and not report:generate_upload
|
|
48
48
|
)
|
|
49
|
+
|
|
50
|
+
if task.result == 'success'
|
|
51
|
+
unless Setting[:subscription_connection_enabled]
|
|
52
|
+
target_file = File.join(base_folder, ForemanInventoryUpload.facts_archive_name(organization_id, filter))
|
|
53
|
+
puts "Generated #{target_file} for organization id #{organization_id}"
|
|
54
|
+
end
|
|
55
|
+
else
|
|
56
|
+
puts "Failed to generate report for organization id #{organization_id}. Task result: #{task.result}"
|
|
57
|
+
puts "Check task #{task.id} in the Tasks dashboard for error details."
|
|
58
|
+
end
|
|
49
59
|
end
|
|
50
60
|
puts "Check the Uploading tab for report uploading status." if Setting[:subscription_connection_enabled]
|
|
51
61
|
end
|
data/package.json
CHANGED
|
@@ -4,7 +4,7 @@ require 'foreman_tasks/test_helpers'
|
|
|
4
4
|
require "#{ForemanTasks::Engine.root}/test/support/dummy_dynflow_action"
|
|
5
5
|
|
|
6
6
|
class CloudConnectorAnnounceTaskTest < ActiveSupport::TestCase
|
|
7
|
-
include
|
|
7
|
+
include Dynflow::Testing::Factories
|
|
8
8
|
|
|
9
9
|
setup do
|
|
10
10
|
RemoteExecutionFeature.register(
|
|
@@ -23,7 +23,8 @@ class CloudConnectorAnnounceTaskTest < ActiveSupport::TestCase
|
|
|
23
23
|
test 'It executes cloud presence announcer' do
|
|
24
24
|
ForemanRhCloud::CloudPresence.any_instance.expects(:announce_to_sources).times(Organization.unscoped.count)
|
|
25
25
|
|
|
26
|
-
|
|
26
|
+
action = create_and_plan_action(InsightsCloud::Async::CloudConnectorAnnounceTask, @job_invocation)
|
|
27
|
+
finalize_action(action)
|
|
27
28
|
end
|
|
28
29
|
|
|
29
30
|
private
|
|
@@ -4,7 +4,7 @@ require 'foreman_tasks/test_helpers'
|
|
|
4
4
|
require "#{ForemanTasks::Engine.root}/test/support/dummy_dynflow_action"
|
|
5
5
|
|
|
6
6
|
class ConnectorPlaybookExecutionReporterTaskTest < ActiveSupport::TestCase
|
|
7
|
-
include
|
|
7
|
+
include Dynflow::Testing::Factories
|
|
8
8
|
|
|
9
9
|
# override default send behavior for the test
|
|
10
10
|
class TestConnectorPlaybookExecutionReporterTask < InsightsCloud::Async::ConnectorPlaybookExecutionReporterTask
|
|
@@ -35,17 +35,19 @@ class ConnectorPlaybookExecutionReporterTaskTest < ActiveSupport::TestCase
|
|
|
35
35
|
|
|
36
36
|
TestConnectorPlaybookExecutionReporterTask.any_instance.stubs(:job_finished?).returns(true)
|
|
37
37
|
|
|
38
|
-
|
|
38
|
+
action = create_and_plan_action(TestConnectorPlaybookExecutionReporterTask, @job_invocation)
|
|
39
|
+
action = run_action(action)
|
|
39
40
|
|
|
40
|
-
|
|
41
|
+
saved_reports = action.output[:saved_reports]
|
|
42
|
+
actual_report = saved_reports.first.to_s
|
|
41
43
|
|
|
42
|
-
assert_equal 1,
|
|
44
|
+
assert_equal 1, saved_reports.size
|
|
43
45
|
assert_not_nil actual_report
|
|
44
46
|
actual_jsonl = read_jsonl(actual_report)
|
|
45
47
|
|
|
46
|
-
assert_equal true,
|
|
47
|
-
assert_equal 0,
|
|
48
|
-
assert_equal 0,
|
|
48
|
+
assert_equal true, action.output['task']['invocation_status']['task_state']['task_done_reported']
|
|
49
|
+
assert_equal 0, action.output['task']['invocation_status']['hosts_state']['TEST_UUID1']['exit_status']
|
|
50
|
+
assert_equal 0, action.output['task']['invocation_status']['hosts_state']['TEST_UUID2']['exit_status']
|
|
49
51
|
|
|
50
52
|
assert_equal true, @job_invocation.finished?
|
|
51
53
|
assert_equal 'stopped', @job_invocation.sub_task_for_host(Host.where(name: 'host1').first)['state']
|
|
@@ -77,20 +79,25 @@ class ConnectorPlaybookExecutionReporterTaskTest < ActiveSupport::TestCase
|
|
|
77
79
|
|
|
78
80
|
ArrangeTestHost.any_instance.stubs(:job_finished?).returns(false, true)
|
|
79
81
|
|
|
80
|
-
|
|
82
|
+
action = create_and_plan_action(ArrangeTestHost, @job_invocation)
|
|
83
|
+
action = run_action(action)
|
|
81
84
|
|
|
82
|
-
|
|
83
|
-
|
|
85
|
+
# Process polling cycles - manually trigger Poll events until done
|
|
86
|
+
action = run_action(action, Dynflow::Action::Polling::Poll) until action.done?
|
|
84
87
|
|
|
85
|
-
|
|
88
|
+
saved_reports = action.output[:saved_reports]
|
|
89
|
+
actual_report1 = saved_reports.first.to_s
|
|
90
|
+
actual_report2 = saved_reports.second.to_s
|
|
91
|
+
|
|
92
|
+
assert_equal 2, saved_reports.size
|
|
86
93
|
assert_not_nil actual_report1
|
|
87
94
|
assert_not_nil actual_report2
|
|
88
95
|
|
|
89
96
|
actual_json1 = read_jsonl(actual_report1)
|
|
90
97
|
actual_json2 = read_jsonl(actual_report2)
|
|
91
98
|
|
|
92
|
-
assert_equal true,
|
|
93
|
-
assert_equal 0,
|
|
99
|
+
assert_equal true, action.output['task']['invocation_status']['task_state']['task_done_reported']
|
|
100
|
+
assert_equal 0, action.output['task']['invocation_status']['hosts_state']['TEST_UUID1']['exit_status']
|
|
94
101
|
|
|
95
102
|
assert_equal 'stopped', @job_invocation.sub_task_for_host(Host.where(name: 'host1').first)['state']
|
|
96
103
|
|
|
@@ -141,13 +148,18 @@ class ConnectorPlaybookExecutionReporterTaskTest < ActiveSupport::TestCase
|
|
|
141
148
|
|
|
142
149
|
ArrangeTestHostTwo.any_instance.stubs(:job_finished?).returns(false, false, true)
|
|
143
150
|
|
|
144
|
-
|
|
151
|
+
action = create_and_plan_action(ArrangeTestHostTwo, @job_invocation)
|
|
152
|
+
action = run_action(action)
|
|
153
|
+
|
|
154
|
+
# Process polling cycles - manually trigger Poll events until done
|
|
155
|
+
action = run_action(action, Dynflow::Action::Polling::Poll) until action.done?
|
|
145
156
|
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
157
|
+
saved_reports = action.output[:saved_reports]
|
|
158
|
+
actual_report1 = saved_reports.first.to_s
|
|
159
|
+
actual_report2 = saved_reports.second.to_s
|
|
160
|
+
actual_report3 = saved_reports.third.to_s
|
|
149
161
|
|
|
150
|
-
assert_equal 3,
|
|
162
|
+
assert_equal 3, saved_reports.size
|
|
151
163
|
assert_not_nil actual_report1
|
|
152
164
|
assert_not_nil actual_report2
|
|
153
165
|
assert_not_nil actual_report3
|
|
@@ -156,8 +168,8 @@ class ConnectorPlaybookExecutionReporterTaskTest < ActiveSupport::TestCase
|
|
|
156
168
|
actual_json2 = read_jsonl(actual_report2)
|
|
157
169
|
actual_json3 = read_jsonl(actual_report3)
|
|
158
170
|
|
|
159
|
-
assert_equal true,
|
|
160
|
-
assert_equal 0,
|
|
171
|
+
assert_equal true, action.output['task']['invocation_status']['task_state']['task_done_reported']
|
|
172
|
+
assert_equal 0, action.output['task']['invocation_status']['hosts_state']['TEST_UUID1']['exit_status']
|
|
161
173
|
|
|
162
174
|
assert_not_nil actual_report_updated = actual_json1.find { |l| l['type'] == 'playbook_run_update' && l['host'] == 'TEST_UUID1' }
|
|
163
175
|
assert_equal 'TEST_CORRELATION', actual_report_updated['correlation_id']
|
|
@@ -0,0 +1,151 @@
|
|
|
1
|
+
require 'test_plugin_helper'
|
|
2
|
+
require 'foreman_tasks/test_helpers'
|
|
3
|
+
|
|
4
|
+
class CreateMissingInsightsFacetsTest < ActiveSupport::TestCase
|
|
5
|
+
include Dynflow::Testing::Factories
|
|
6
|
+
include KatelloCVEHelper
|
|
7
|
+
|
|
8
|
+
setup do
|
|
9
|
+
User.current = User.find_by(login: 'secret_admin')
|
|
10
|
+
@cve = make_cve
|
|
11
|
+
@env = @cve.lifecycle_environment
|
|
12
|
+
@organization = @env.organization
|
|
13
|
+
|
|
14
|
+
# Create a host with subscription facet but no insights facet
|
|
15
|
+
@host_without_facet = FactoryBot.create(
|
|
16
|
+
:host,
|
|
17
|
+
:with_subscription,
|
|
18
|
+
:with_content,
|
|
19
|
+
content_view: @cve.content_view,
|
|
20
|
+
lifecycle_environment: @env,
|
|
21
|
+
organization: @organization
|
|
22
|
+
)
|
|
23
|
+
|
|
24
|
+
# Create a host with both subscription and insights facets
|
|
25
|
+
@host_with_facet = FactoryBot.create(
|
|
26
|
+
:host,
|
|
27
|
+
:with_subscription,
|
|
28
|
+
:with_content,
|
|
29
|
+
content_view: @cve.content_view,
|
|
30
|
+
lifecycle_environment: @env,
|
|
31
|
+
organization: @organization
|
|
32
|
+
)
|
|
33
|
+
@host_with_facet.build_insights(uuid: @host_with_facet.subscription_facet.uuid)
|
|
34
|
+
@host_with_facet.insights.save!
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
test 'creates insights facets for hosts without them' do
|
|
38
|
+
assert_nil @host_without_facet.insights
|
|
39
|
+
|
|
40
|
+
action = create_and_plan_action(
|
|
41
|
+
ForemanInventoryUpload::Async::CreateMissingInsightsFacets,
|
|
42
|
+
@organization.id
|
|
43
|
+
)
|
|
44
|
+
action = run_action(action)
|
|
45
|
+
|
|
46
|
+
@host_without_facet.reload
|
|
47
|
+
assert_not_nil @host_without_facet.insights
|
|
48
|
+
assert_equal @host_without_facet.subscription_facet.uuid, @host_without_facet.insights.uuid
|
|
49
|
+
assert_match(/Missing Insights facets created: 1/, action.output[:result])
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
test 'does not create duplicate facets for hosts that already have them' do
|
|
53
|
+
original_uuid = @host_with_facet.insights.uuid
|
|
54
|
+
original_id = @host_with_facet.insights.id
|
|
55
|
+
|
|
56
|
+
action = create_and_plan_action(
|
|
57
|
+
ForemanInventoryUpload::Async::CreateMissingInsightsFacets,
|
|
58
|
+
@organization.id
|
|
59
|
+
)
|
|
60
|
+
run_action(action)
|
|
61
|
+
|
|
62
|
+
@host_with_facet.reload
|
|
63
|
+
assert_equal original_id, @host_with_facet.insights.id
|
|
64
|
+
assert_equal original_uuid, @host_with_facet.insights.uuid
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
test 'handles organization with no missing facets' do
|
|
68
|
+
# Create insights facet for the host that was missing one
|
|
69
|
+
@host_without_facet.build_insights(uuid: @host_without_facet.subscription_facet.uuid)
|
|
70
|
+
@host_without_facet.insights.save!
|
|
71
|
+
|
|
72
|
+
action = create_and_plan_action(
|
|
73
|
+
ForemanInventoryUpload::Async::CreateMissingInsightsFacets,
|
|
74
|
+
@organization.id
|
|
75
|
+
)
|
|
76
|
+
action = run_action(action)
|
|
77
|
+
|
|
78
|
+
assert_match(/There were no missing Insights facets/, action.output[:result])
|
|
79
|
+
end
|
|
80
|
+
|
|
81
|
+
test 'creates multiple facets when multiple hosts are missing them' do
|
|
82
|
+
# Remove the insights facet from the host that has one
|
|
83
|
+
@host_with_facet.insights.destroy
|
|
84
|
+
@host_with_facet.reload
|
|
85
|
+
|
|
86
|
+
assert_nil @host_without_facet.insights
|
|
87
|
+
assert_nil @host_with_facet.insights
|
|
88
|
+
|
|
89
|
+
action = create_and_plan_action(
|
|
90
|
+
ForemanInventoryUpload::Async::CreateMissingInsightsFacets,
|
|
91
|
+
@organization.id
|
|
92
|
+
)
|
|
93
|
+
action = run_action(action)
|
|
94
|
+
|
|
95
|
+
@host_without_facet.reload
|
|
96
|
+
@host_with_facet.reload
|
|
97
|
+
assert_not_nil @host_without_facet.insights
|
|
98
|
+
assert_not_nil @host_with_facet.insights
|
|
99
|
+
# After the bug fix, the count should correctly show 2 hosts
|
|
100
|
+
assert_match(/Missing Insights facets created: 2/, action.output[:result])
|
|
101
|
+
end
|
|
102
|
+
|
|
103
|
+
test 'logs result message' do
|
|
104
|
+
Rails.logger.expects(:debug).with(regexp_matches(/Missing Insights facets created/))
|
|
105
|
+
|
|
106
|
+
action = create_and_plan_action(
|
|
107
|
+
ForemanInventoryUpload::Async::CreateMissingInsightsFacets,
|
|
108
|
+
@organization.id
|
|
109
|
+
)
|
|
110
|
+
run_action(action)
|
|
111
|
+
end
|
|
112
|
+
|
|
113
|
+
test 'correctly counts facets across multiple batches' do
|
|
114
|
+
# Remove existing insights facet
|
|
115
|
+
@host_with_facet.insights.destroy
|
|
116
|
+
@host_with_facet.reload
|
|
117
|
+
|
|
118
|
+
# Stub the batch size to force multiple batches with just 2 hosts
|
|
119
|
+
ForemanInventoryUpload.stubs(:slice_size).returns(1)
|
|
120
|
+
|
|
121
|
+
assert_nil @host_without_facet.insights
|
|
122
|
+
assert_nil @host_with_facet.insights
|
|
123
|
+
|
|
124
|
+
action = create_and_plan_action(
|
|
125
|
+
ForemanInventoryUpload::Async::CreateMissingInsightsFacets,
|
|
126
|
+
@organization.id
|
|
127
|
+
)
|
|
128
|
+
action = run_action(action)
|
|
129
|
+
|
|
130
|
+
@host_without_facet.reload
|
|
131
|
+
@host_with_facet.reload
|
|
132
|
+
assert_not_nil @host_without_facet.insights
|
|
133
|
+
assert_not_nil @host_with_facet.insights
|
|
134
|
+
# Count should be 2 even though processed in 2 separate batches
|
|
135
|
+
assert_match(/Missing Insights facets created: 2/, action.output[:result])
|
|
136
|
+
end
|
|
137
|
+
|
|
138
|
+
test 'handles error when InsightsFacet.upsert_all fails' do
|
|
139
|
+
# Stub upsert_all to raise an exception
|
|
140
|
+
InsightsFacet.stubs(:upsert_all).raises(StandardError.new('upsert failed'))
|
|
141
|
+
|
|
142
|
+
action = create_and_plan_action(
|
|
143
|
+
ForemanInventoryUpload::Async::CreateMissingInsightsFacets,
|
|
144
|
+
@organization.id
|
|
145
|
+
)
|
|
146
|
+
|
|
147
|
+
assert_raises(StandardError) do
|
|
148
|
+
run_action(action)
|
|
149
|
+
end
|
|
150
|
+
end
|
|
151
|
+
end
|
|
@@ -2,7 +2,7 @@ require 'test_plugin_helper'
|
|
|
2
2
|
require 'foreman_tasks/test_helpers'
|
|
3
3
|
|
|
4
4
|
class ExponentialBackoffTest < ActiveSupport::TestCase
|
|
5
|
-
include
|
|
5
|
+
include Dynflow::Testing::Factories
|
|
6
6
|
|
|
7
7
|
class TestAction < ::Actions::EntryAction
|
|
8
8
|
include ::ForemanRhCloud::Async::ExponentialBackoff
|
|
@@ -19,28 +19,29 @@ class ExponentialBackoffTest < ActiveSupport::TestCase
|
|
|
19
19
|
test 'executes an action once' do
|
|
20
20
|
TestAction.any_instance.expects(:action_callback).returns(->(instance) { instance.done! })
|
|
21
21
|
|
|
22
|
-
|
|
22
|
+
action = create_and_plan_action(TestAction)
|
|
23
|
+
run_action(action)
|
|
23
24
|
end
|
|
24
25
|
|
|
25
26
|
test 'fails after a single excution if done was called' do
|
|
26
27
|
TestAction.any_instance.expects(:action_callback).returns(
|
|
27
28
|
lambda do |instance|
|
|
28
29
|
instance.done!
|
|
29
|
-
raise
|
|
30
|
+
raise StandardError.new('Foo')
|
|
30
31
|
end
|
|
31
32
|
)
|
|
32
33
|
|
|
33
|
-
|
|
34
|
+
action = create_and_plan_action(TestAction)
|
|
35
|
+
run_action(action)
|
|
34
36
|
end
|
|
35
37
|
|
|
36
38
|
test 'executes the task three times before failing it' do
|
|
37
39
|
# speed up the execution
|
|
38
40
|
TestAction.any_instance.stubs(:poll_intervals).returns([0, 0, 0])
|
|
39
41
|
|
|
40
|
-
TestAction.any_instance.expects(:action_callback).raises(
|
|
42
|
+
TestAction.any_instance.expects(:action_callback).raises(StandardError.new('Foo')).at_least_once
|
|
41
43
|
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
assert ex.aggregated_message =~ /Foo/
|
|
44
|
+
action = create_and_plan_action(TestAction)
|
|
45
|
+
run_action(action)
|
|
45
46
|
end
|
|
46
47
|
end
|
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
require 'test_plugin_helper'
|
|
2
|
+
require 'foreman_tasks/test_helpers'
|
|
3
|
+
|
|
4
|
+
class GenerateHostReportTest < ActiveSupport::TestCase
|
|
5
|
+
include Dynflow::Testing::Factories
|
|
6
|
+
include FolderIsolation
|
|
7
|
+
|
|
8
|
+
let(:organization) { FactoryBot.create(:organization) }
|
|
9
|
+
let(:base_folder) { @tmpdir }
|
|
10
|
+
let(:filter) { '' }
|
|
11
|
+
|
|
12
|
+
setup do
|
|
13
|
+
# Stub the ArchivedReport generator
|
|
14
|
+
@mock_generator = mock('archived_report_generator')
|
|
15
|
+
@mock_generator.stubs(:render)
|
|
16
|
+
ForemanInventoryUpload::Generators::ArchivedReport.stubs(:new).returns(@mock_generator)
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
test 'plan sets target path correctly' do
|
|
20
|
+
expected_archive_name = ForemanInventoryUpload.facts_archive_name(organization.id, filter)
|
|
21
|
+
expected_target = File.join(base_folder, expected_archive_name)
|
|
22
|
+
|
|
23
|
+
action = create_and_plan_action(
|
|
24
|
+
ForemanInventoryUpload::Async::GenerateHostReport,
|
|
25
|
+
base_folder,
|
|
26
|
+
organization.id,
|
|
27
|
+
filter
|
|
28
|
+
)
|
|
29
|
+
|
|
30
|
+
assert_equal expected_target, action.input[:target]
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
test 'run generates report archive' do
|
|
34
|
+
expected_target = File.join(base_folder, ForemanInventoryUpload.facts_archive_name(organization.id, filter))
|
|
35
|
+
|
|
36
|
+
ForemanInventoryUpload::Generators::ArchivedReport.expects(:new).with(expected_target).returns(@mock_generator)
|
|
37
|
+
@mock_generator.expects(:render).with(organization: organization.id, filter: filter)
|
|
38
|
+
|
|
39
|
+
action = create_and_plan_action(
|
|
40
|
+
ForemanInventoryUpload::Async::GenerateHostReport,
|
|
41
|
+
base_folder,
|
|
42
|
+
organization.id,
|
|
43
|
+
filter
|
|
44
|
+
)
|
|
45
|
+
action = run_action(action)
|
|
46
|
+
|
|
47
|
+
assert_match(/Generated #{Regexp.escape(expected_target)} for organization id #{organization.id}/, action.output[:result])
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
test 'generates report with filter' do
|
|
51
|
+
filter_value = 'id=123'
|
|
52
|
+
expected_target = File.join(base_folder, ForemanInventoryUpload.facts_archive_name(organization.id, filter_value))
|
|
53
|
+
|
|
54
|
+
ForemanInventoryUpload::Generators::ArchivedReport.expects(:new).with(expected_target).returns(@mock_generator)
|
|
55
|
+
@mock_generator.expects(:render).with(organization: organization.id, filter: filter_value)
|
|
56
|
+
|
|
57
|
+
action = create_and_plan_action(
|
|
58
|
+
ForemanInventoryUpload::Async::GenerateHostReport,
|
|
59
|
+
base_folder,
|
|
60
|
+
organization.id,
|
|
61
|
+
filter_value
|
|
62
|
+
)
|
|
63
|
+
action = run_action(action)
|
|
64
|
+
|
|
65
|
+
assert_match(/organization id #{organization.id}/, action.output[:result])
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
test 'stores organization_id and filter in input' do
|
|
69
|
+
filter_value = 'name~test'
|
|
70
|
+
|
|
71
|
+
action = create_and_plan_action(
|
|
72
|
+
ForemanInventoryUpload::Async::GenerateHostReport,
|
|
73
|
+
base_folder,
|
|
74
|
+
organization.id,
|
|
75
|
+
filter_value
|
|
76
|
+
)
|
|
77
|
+
|
|
78
|
+
assert_equal organization.id, action.input[:organization_id]
|
|
79
|
+
assert_equal filter_value, action.input[:filter]
|
|
80
|
+
assert_equal base_folder, action.input[:base_folder]
|
|
81
|
+
end
|
|
82
|
+
|
|
83
|
+
test 'handles ArchivedReport generator failure' do
|
|
84
|
+
expected_target = File.join(base_folder, ForemanInventoryUpload.facts_archive_name(organization.id, filter))
|
|
85
|
+
|
|
86
|
+
ForemanInventoryUpload::Generators::ArchivedReport.expects(:new).with(expected_target).returns(@mock_generator)
|
|
87
|
+
@mock_generator.expects(:render).with(organization: organization.id, filter: filter).raises(StandardError.new('Report generation failed'))
|
|
88
|
+
|
|
89
|
+
action = create_and_plan_action(
|
|
90
|
+
ForemanInventoryUpload::Async::GenerateHostReport,
|
|
91
|
+
base_folder,
|
|
92
|
+
organization.id,
|
|
93
|
+
filter
|
|
94
|
+
)
|
|
95
|
+
|
|
96
|
+
assert_raises(StandardError) do
|
|
97
|
+
run_action(action)
|
|
98
|
+
end
|
|
99
|
+
end
|
|
100
|
+
end
|