foreman_rh_cloud 13.0.7 → 13.0.9
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/app/controllers/foreman_inventory_upload/accounts_controller.rb +1 -1
- data/app/controllers/foreman_inventory_upload/uploads_controller.rb +1 -1
- data/lib/foreman_inventory_upload/async/create_missing_insights_facets.rb +3 -2
- data/lib/foreman_inventory_upload/async/queue_for_upload_job.rb +1 -23
- data/lib/foreman_inventory_upload/async/upload_report_direct_job.rb +200 -0
- data/lib/foreman_inventory_upload.rb +6 -6
- 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/inventory_sync/async/inventory_hosts_sync.rb +0 -2
- data/lib/tasks/rh_cloud_inventory.rake +11 -1
- data/package.json +1 -1
- data/test/controllers/accounts_controller_test.rb +1 -1
- data/test/controllers/uploads_controller_test.rb +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 +10 -19
- 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_direct_job_test.rb +399 -0
- data/test/unit/lib/foreman_rh_cloud/registration_manager_extensions_test.rb +192 -0
- data/webpack/ForemanColumnExtensions/index.js +2 -0
- data/webpack/ForemanInventoryUpload/Components/AccountList/AccountList.js +1 -1
- data/webpack/ForemanInventoryUpload/Components/AccountList/Components/ListItem/ListItem.fixtures.js +4 -5
- data/webpack/ForemanInventoryUpload/Components/AccountList/Components/ListItem/ListItem.js +4 -2
- data/webpack/ForemanInventoryUpload/Components/AccountList/Components/ListItem/__tests__/__snapshots__/ListItem.test.js.snap +9 -10
- data/webpack/ForemanInventoryUpload/Components/Dashboard/Dashboard.js +4 -1
- data/webpack/ForemanInventoryUpload/Components/PageHeader/PageHeader.js +24 -17
- data/webpack/ForemanInventoryUpload/Components/PageHeader/__tests__/PageHeader.test.js +178 -8
- data/webpack/ForemanInventoryUpload/Components/PageHeader/components/ToolbarButtons/ToolbarButtons.js +3 -1
- data/webpack/ForemanInventoryUpload/Components/PageHeader/components/ToolbarButtons/__tests__/ToolbarButtons.test.js +69 -51
- 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 +12 -7
- 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 +77 -22
- data/webpack/common/Hooks/ConfigHooks.js +3 -16
- metadata +17 -8
- data/lib/foreman_inventory_upload/async/upload_report_job.rb +0 -97
- data/lib/foreman_inventory_upload/scripts/uploader.sh.erb +0 -55
- data/test/jobs/upload_report_job_test.rb +0 -37
- data/webpack/ForemanInventoryUpload/Components/PageHeader/__tests__/__snapshots__/PageHeader.test.js.snap +0 -36
- data/webpack/InsightsCloudSync/Components/InsightsTable/__tests__/__snapshots__/InsightsTable.test.js.snap +0 -112
- data/webpack/__mocks__/foremanReact/common/hooks/API/APIHooks.js +0 -3
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 9d818ad6b4142546fe8d3b8c0e54f49600ed30915f6b22f142bc1861938c5dba
|
|
4
|
+
data.tar.gz: 3d0e310b2cf587243c64623713af21e164c87e87e21a5edeee556f16613ae8fc
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: ae35c83c6c45af99a891a3ff243d10f7f7616891facecab5f6afa34287f2282eb3c0175680537bb0a17b62352ea42b43d1e1d4365a517f6086c3e1d82fbd725b
|
|
7
|
+
data.tar.gz: f9e14d6356e65f5649b3c4a2f57ef381539aa296e12fbbe7c0e5fcc28c47e855bd9ad8e1ab3a9ca739319b9c9882e41de9d578244be2f1fcbd83ca8d1c4160de
|
|
@@ -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
|
|
@@ -7,7 +7,7 @@ module ForemanInventoryUpload
|
|
|
7
7
|
accounts = Hash[
|
|
8
8
|
labels.map do |id, label|
|
|
9
9
|
generate_report_status = status_for(id, ForemanInventoryUpload::Async::GenerateReportJob)
|
|
10
|
-
upload_report_status = status_for(id, ForemanInventoryUpload::Async::
|
|
10
|
+
upload_report_status = status_for(id, ForemanInventoryUpload::Async::UploadReportDirectJob)
|
|
11
11
|
report_file_paths = ForemanInventoryUpload.report_file_paths(id)
|
|
12
12
|
|
|
13
13
|
[
|
|
@@ -6,7 +6,7 @@ module ForemanInventoryUpload
|
|
|
6
6
|
before_action :require_non_iop_smart_proxy, only: [:enable_cloud_connector]
|
|
7
7
|
|
|
8
8
|
def last
|
|
9
|
-
label = ForemanInventoryUpload::Async::
|
|
9
|
+
label = ForemanInventoryUpload::Async::UploadReportDirectJob.output_label(params[:organization_id])
|
|
10
10
|
output = ForemanInventoryUpload::Async::ProgressOutput.get(label)&.full_output
|
|
11
11
|
|
|
12
12
|
render json: {
|
|
@@ -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
|
|
@@ -9,7 +9,6 @@ module ForemanInventoryUpload
|
|
|
9
9
|
def run
|
|
10
10
|
logger.debug('Ensuring objects')
|
|
11
11
|
ensure_ouput_folder
|
|
12
|
-
ensure_output_script
|
|
13
12
|
logger.debug("Copying #{report_file} to #{uploads_folder}")
|
|
14
13
|
enqueued_file_name = File.join(uploads_folder, report_file)
|
|
15
14
|
FileUtils.mv(File.join(base_folder, report_file), enqueued_file_name)
|
|
@@ -22,31 +21,10 @@ module ForemanInventoryUpload
|
|
|
22
21
|
@uploads_folder ||= ForemanInventoryUpload.uploads_folder
|
|
23
22
|
end
|
|
24
23
|
|
|
25
|
-
def script_file
|
|
26
|
-
@script_file ||= File.join(uploads_folder, ForemanInventoryUpload.upload_script_file)
|
|
27
|
-
end
|
|
28
|
-
|
|
29
24
|
def ensure_ouput_folder
|
|
30
25
|
FileUtils.mkdir_p(uploads_folder)
|
|
31
26
|
end
|
|
32
27
|
|
|
33
|
-
def ensure_output_script
|
|
34
|
-
return if File.exist?(script_file)
|
|
35
|
-
|
|
36
|
-
script_source = File.join(ForemanRhCloud::Engine.root, 'lib/foreman_inventory_upload/scripts/uploader.sh.erb')
|
|
37
|
-
|
|
38
|
-
template_src = Foreman::Renderer::Source::String.new(content: File.read(script_source))
|
|
39
|
-
scope = Foreman::Renderer::Scope::Base.new(
|
|
40
|
-
source: template_src,
|
|
41
|
-
variables: {
|
|
42
|
-
upload_url: ForemanInventoryUpload.upload_url,
|
|
43
|
-
}
|
|
44
|
-
)
|
|
45
|
-
script_source = Foreman::Renderer.render(template_src, scope)
|
|
46
|
-
File.write(script_file, script_source)
|
|
47
|
-
FileUtils.chmod('+x', script_file)
|
|
48
|
-
end
|
|
49
|
-
|
|
50
28
|
def logger
|
|
51
29
|
Foreman::Logging.logger('background')
|
|
52
30
|
end
|
|
@@ -60,7 +38,7 @@ module ForemanInventoryUpload
|
|
|
60
38
|
end
|
|
61
39
|
|
|
62
40
|
def plan_upload_report(enqueued_file_name, organization_id)
|
|
63
|
-
plan_action(
|
|
41
|
+
plan_action(UploadReportDirectJob, enqueued_file_name, organization_id)
|
|
64
42
|
end
|
|
65
43
|
end
|
|
66
44
|
end
|
|
@@ -0,0 +1,200 @@
|
|
|
1
|
+
require 'tempfile'
|
|
2
|
+
require 'rest-client'
|
|
3
|
+
|
|
4
|
+
module ForemanInventoryUpload
|
|
5
|
+
module Async
|
|
6
|
+
class UploadReportDirectJob < ::Actions::EntryAction
|
|
7
|
+
include AsyncHelpers
|
|
8
|
+
include ::ForemanRhCloud::Async::ExponentialBackoff
|
|
9
|
+
include ::ForemanRhCloud::CloudRequest
|
|
10
|
+
|
|
11
|
+
# Wrapper class to avoid monkey-patching File for multipart uploads
|
|
12
|
+
class FileUpload
|
|
13
|
+
attr_reader :file, :content_type
|
|
14
|
+
|
|
15
|
+
def initialize(file, content_type:)
|
|
16
|
+
@file = file
|
|
17
|
+
@content_type = content_type
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
def read(*args)
|
|
21
|
+
@file.read(*args)
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
def path
|
|
25
|
+
@file.path
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
def respond_to_missing?(method_name, include_private = false)
|
|
29
|
+
@file.respond_to?(method_name, include_private) || super
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
def method_missing(method_name, *args, &block)
|
|
33
|
+
if @file.respond_to?(method_name)
|
|
34
|
+
@file.send(method_name, *args, &block)
|
|
35
|
+
else
|
|
36
|
+
super
|
|
37
|
+
end
|
|
38
|
+
end
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
def self.output_label(label)
|
|
42
|
+
"upload_for_#{label}"
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
def plan(filename, organization_id)
|
|
46
|
+
# NOTE: This implementation assumes a single organization will not trigger multiple
|
|
47
|
+
# concurrent uploads. The instance_label is derived from organization_id alone, which
|
|
48
|
+
# means concurrent uploads for the same org would share ProgressOutput storage.
|
|
49
|
+
# This matches the pattern in GenerateReportJob. A full fix for thread-safety
|
|
50
|
+
# requires UI changes to display multiple concurrent tasks per org (tracked for PR #2).
|
|
51
|
+
label = UploadReportDirectJob.output_label(organization_id)
|
|
52
|
+
clear_task_output(label)
|
|
53
|
+
plan_self(
|
|
54
|
+
instance_label: label,
|
|
55
|
+
filename: filename,
|
|
56
|
+
organization_id: organization_id
|
|
57
|
+
)
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
def try_execute
|
|
61
|
+
if content_disconnected?
|
|
62
|
+
progress_output do |progress_output|
|
|
63
|
+
progress_output.write_line("Report was not moved and upload was canceled because connection to Insights is not enabled. Report location: #{filename}.")
|
|
64
|
+
progress_output.status = "Task aborted, exit 1"
|
|
65
|
+
done!
|
|
66
|
+
end
|
|
67
|
+
return
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
unless organization.owner_details&.dig('upstreamConsumer', 'idCert')
|
|
71
|
+
logger.info("Skipping organization '#{organization}', no candlepin certificate defined.")
|
|
72
|
+
progress_output do |progress_output|
|
|
73
|
+
progress_output.write_line("Skipping organization #{organization}, no candlepin certificate defined.")
|
|
74
|
+
progress_output.status = "Task aborted, exit 1"
|
|
75
|
+
done!
|
|
76
|
+
end
|
|
77
|
+
return
|
|
78
|
+
end
|
|
79
|
+
|
|
80
|
+
Tempfile.create([organization.name, '.pem']) do |cer_file|
|
|
81
|
+
cer_file.write(certificate[:cert])
|
|
82
|
+
cer_file.write(certificate[:key])
|
|
83
|
+
cer_file.flush
|
|
84
|
+
upload_report(cer_file.path)
|
|
85
|
+
end
|
|
86
|
+
|
|
87
|
+
done!
|
|
88
|
+
end
|
|
89
|
+
|
|
90
|
+
def upload_report(cer_path)
|
|
91
|
+
progress_output do |progress_output|
|
|
92
|
+
progress_output.write_line("Uploading report for organization #{organization.label}...")
|
|
93
|
+
progress_output.status = "Running upload"
|
|
94
|
+
|
|
95
|
+
begin
|
|
96
|
+
upload_file(cer_path)
|
|
97
|
+
progress_output.write_line("Upload completed successfully")
|
|
98
|
+
move_to_done_folder
|
|
99
|
+
progress_output.write_line("Uploaded file moved to done/ folder")
|
|
100
|
+
progress_output.status = "pid #{Process.pid} exit 0"
|
|
101
|
+
rescue StandardError => e
|
|
102
|
+
progress_output.write_line("Upload failed: #{e.message}")
|
|
103
|
+
progress_output.status = "pid #{Process.pid} exit 1"
|
|
104
|
+
raise
|
|
105
|
+
end
|
|
106
|
+
end
|
|
107
|
+
end
|
|
108
|
+
|
|
109
|
+
def upload_file(cer_path)
|
|
110
|
+
cert_content = File.read(cer_path)
|
|
111
|
+
|
|
112
|
+
File.open(filename, 'rb') do |file|
|
|
113
|
+
# Wrap file with FileUpload class for RestClient multipart handling
|
|
114
|
+
# RestClient requires objects with :read, :path, and :content_type methods
|
|
115
|
+
wrapped_file = FileUpload.new(file, content_type: 'application/vnd.redhat.qpc.tar+tgz')
|
|
116
|
+
|
|
117
|
+
response = execute_cloud_request(
|
|
118
|
+
method: :post,
|
|
119
|
+
url: ForemanInventoryUpload.upload_url,
|
|
120
|
+
payload: {
|
|
121
|
+
multipart: true,
|
|
122
|
+
file: wrapped_file,
|
|
123
|
+
},
|
|
124
|
+
headers: {
|
|
125
|
+
'X-Org-Id' => organization.label,
|
|
126
|
+
},
|
|
127
|
+
ssl_client_cert: OpenSSL::X509::Certificate.new(cert_content),
|
|
128
|
+
ssl_client_key: OpenSSL::PKey::RSA.new(cert_content),
|
|
129
|
+
timeout: 600,
|
|
130
|
+
open_timeout: 60
|
|
131
|
+
)
|
|
132
|
+
|
|
133
|
+
logger.debug("Upload response code: #{response.code}")
|
|
134
|
+
end
|
|
135
|
+
end
|
|
136
|
+
|
|
137
|
+
def move_to_done_folder
|
|
138
|
+
FileUtils.mkdir_p(ForemanInventoryUpload.done_folder)
|
|
139
|
+
done_file = ForemanInventoryUpload.done_file_path(File.basename(filename))
|
|
140
|
+
FileUtils.mv(filename, done_file)
|
|
141
|
+
logger.debug("Moved #{filename} to #{done_file}")
|
|
142
|
+
end
|
|
143
|
+
|
|
144
|
+
def certificate
|
|
145
|
+
ForemanRhCloud.with_iop_smart_proxy? ? foreman_certificate : manifest_certificate
|
|
146
|
+
end
|
|
147
|
+
|
|
148
|
+
def manifest_certificate
|
|
149
|
+
candlepin_id_certificate = organization.owner_details['upstreamConsumer']['idCert']
|
|
150
|
+
{
|
|
151
|
+
cert: candlepin_id_certificate['cert'],
|
|
152
|
+
key: candlepin_id_certificate['key'],
|
|
153
|
+
}
|
|
154
|
+
end
|
|
155
|
+
|
|
156
|
+
def foreman_certificate
|
|
157
|
+
{
|
|
158
|
+
cert: File.read(Setting[:ssl_certificate]),
|
|
159
|
+
key: File.read(Setting[:ssl_priv_key]),
|
|
160
|
+
}
|
|
161
|
+
end
|
|
162
|
+
|
|
163
|
+
def filename
|
|
164
|
+
input[:filename]
|
|
165
|
+
end
|
|
166
|
+
|
|
167
|
+
def organization
|
|
168
|
+
Organization.find(input[:organization_id])
|
|
169
|
+
end
|
|
170
|
+
|
|
171
|
+
def content_disconnected?
|
|
172
|
+
!Setting[:subscription_connection_enabled]
|
|
173
|
+
end
|
|
174
|
+
|
|
175
|
+
def progress_output
|
|
176
|
+
progress_output = ProgressOutput.register(instance_label)
|
|
177
|
+
yield(progress_output)
|
|
178
|
+
ensure
|
|
179
|
+
progress_output.close
|
|
180
|
+
end
|
|
181
|
+
|
|
182
|
+
def instance_label
|
|
183
|
+
input[:instance_label]
|
|
184
|
+
end
|
|
185
|
+
|
|
186
|
+
def logger
|
|
187
|
+
Foreman::Logging.logger('background')
|
|
188
|
+
end
|
|
189
|
+
|
|
190
|
+
def rescue_strategy_for_self
|
|
191
|
+
Dynflow::Action::Rescue::Fail
|
|
192
|
+
end
|
|
193
|
+
|
|
194
|
+
def clear_task_output(label)
|
|
195
|
+
TaskOutputLine.where(label: label).delete_all
|
|
196
|
+
TaskOutputStatus.where(label: label).delete_all
|
|
197
|
+
end
|
|
198
|
+
end
|
|
199
|
+
end
|
|
200
|
+
end
|
|
@@ -48,10 +48,6 @@ module ForemanInventoryUpload
|
|
|
48
48
|
@outputs_folder ||= ensure_folder(File.join(ForemanInventoryUpload.base_folder, 'outputs/'))
|
|
49
49
|
end
|
|
50
50
|
|
|
51
|
-
def self.upload_script_file
|
|
52
|
-
'uploader.sh'
|
|
53
|
-
end
|
|
54
|
-
|
|
55
51
|
def self.facts_archive_name(organization, filter = nil)
|
|
56
52
|
"report_for_#{organization}#{filter.empty? ? nil : "[#{filter.to_s.parameterize}]"}.tar.xz"
|
|
57
53
|
end
|
|
@@ -88,8 +84,12 @@ module ForemanInventoryUpload
|
|
|
88
84
|
inventory_base_url + "?hostname_or_id=#{ForemanRhCloud.foreman_host.fqdn}"
|
|
89
85
|
end
|
|
90
86
|
|
|
91
|
-
def self.
|
|
92
|
-
|
|
87
|
+
def self.host_by_id_url(host_uuid)
|
|
88
|
+
"#{inventory_base_url}/#{host_uuid}"
|
|
89
|
+
end
|
|
90
|
+
|
|
91
|
+
def self.hosts_by_ids_url(host_uuids)
|
|
92
|
+
host_ids_string = host_uuids.join(',')
|
|
93
93
|
"#{inventory_base_url}/#{host_ids_string}"
|
|
94
94
|
end
|
|
95
95
|
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
|
|
@@ -8,8 +8,6 @@ module InventorySync
|
|
|
8
8
|
set_callback :step, :around, :create_missing_hosts
|
|
9
9
|
|
|
10
10
|
def plan(organizations)
|
|
11
|
-
# Do not run for local advisor, since we use sub-man id to identify hosts.
|
|
12
|
-
return if ForemanRhCloud.with_iop_smart_proxy?
|
|
13
11
|
# by default the tasks will be executed concurrently
|
|
14
12
|
super(organizations)
|
|
15
13
|
plan_self_host_sync
|
|
@@ -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
|
@@ -11,7 +11,7 @@ class AccountsControllerTest < ActionController::TestCase
|
|
|
11
11
|
generate_label = ForemanInventoryUpload::Async::GenerateReportJob.output_label(test_org.id)
|
|
12
12
|
generate_output = ForemanInventoryUpload::Async::ProgressOutput.register(generate_label)
|
|
13
13
|
generate_output.status = 'generate_status_test'
|
|
14
|
-
upload_label = ForemanInventoryUpload::Async::
|
|
14
|
+
upload_label = ForemanInventoryUpload::Async::UploadReportDirectJob.output_label(test_org.id)
|
|
15
15
|
upload_output = ForemanInventoryUpload::Async::ProgressOutput.register(upload_label)
|
|
16
16
|
upload_output.status = 'upload_status_test'
|
|
17
17
|
|
|
@@ -8,7 +8,7 @@ class UploadsControllerTest < ActionController::TestCase
|
|
|
8
8
|
test_org = FactoryBot.create(:organization)
|
|
9
9
|
ForemanInventoryUpload::Async::ProgressOutput
|
|
10
10
|
.expects(:get)
|
|
11
|
-
.with(ForemanInventoryUpload::Async::
|
|
11
|
+
.with(ForemanInventoryUpload::Async::UploadReportDirectJob.output_label(test_org.id))
|
|
12
12
|
.returns(progress_output)
|
|
13
13
|
progress_output.expects(:full_output).returns('test output')
|
|
14
14
|
|
|
@@ -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']
|