foreman_rh_cloud 12.2.4 → 12.2.6

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: f0c1c612bfa55b7b792c80577d33718502ad3ecc35273f6c9ae5fef2d055e872
4
- data.tar.gz: 16f86dba2beea9aa6930b1a60579b6f29097bc1e06c8fa4c1eadeb7ebb4cfd46
3
+ metadata.gz: 72c0454c0e34313e47f06f3da48616dc6030ad4e253ee09b7180ad57fb40c658
4
+ data.tar.gz: 2ba96de28fb86c571fc49bab18d0fd7449539bf0292d4d16fdf3840a91845575
5
5
  SHA512:
6
- metadata.gz: b5f2081a2f011ad358a56a13c51f7098e762faa98bba4556b60a24fa7dd3f05151a919eb61d40fb10e8125c083fb553a0fc5bc39c89a9b8ce6ca6a2dea12491c
7
- data.tar.gz: a1a6496c40f2716c7b05606047f5daab3b0578f699bbc604d2082db36b8595514c2b6c681e487150eda127311e2142227b75fe23ce86f3a5fcaa7c4ad4a6510c
6
+ metadata.gz: 98f812e64bf664dba79c550efac4b378a079c199591d8ddf1e4dbba19315db93421c7266ee3e4c9d0c7de4e89c1622bda2de32cb987b6837822362192cf4eff6
7
+ data.tar.gz: b1894fac6ea9fee921425195313532923389b4948d90887caac55564ed71109dc21b0eafca14fbe32961bb72ee6798aa911ad48687f6321d871fb1c199b51fc5
@@ -14,13 +14,14 @@ module ForemanInventoryUpload
14
14
  hosts_filter: hosts_filter
15
15
  )
16
16
 
17
- plan_action(
18
- QueueForUploadJob,
19
- base_folder,
20
- ForemanInventoryUpload.facts_archive_name(organization_id, hosts_filter),
21
- organization_id,
22
- disconnected
23
- )
17
+ unless content_disconnected?(disconnected)
18
+ plan_action(
19
+ QueueForUploadJob,
20
+ base_folder,
21
+ ForemanInventoryUpload.facts_archive_name(organization_id, hosts_filter),
22
+ organization_id
23
+ )
24
+ end
24
25
  end
25
26
  end
26
27
 
@@ -40,6 +41,10 @@ module ForemanInventoryUpload
40
41
  )
41
42
  end
42
43
 
44
+ def content_disconnected?(disconnected)
45
+ disconnected || !Setting[:subscription_connection_enabled]
46
+ end
47
+
43
48
  def base_folder
44
49
  input[:base_folder]
45
50
  end
@@ -1,9 +1,9 @@
1
1
  module ForemanInventoryUpload
2
2
  module Async
3
3
  class QueueForUploadJob < ::Actions::EntryAction
4
- def plan(base_folder, report_file, organization_id, disconnected)
4
+ def plan(base_folder, report_file, organization_id)
5
5
  enqueue_task = plan_self(base_folder: base_folder, report_file: report_file)
6
- plan_upload_report(enqueue_task.output[:enqueued_file_name], organization_id, disconnected)
6
+ plan_upload_report(enqueue_task.output[:enqueued_file_name], organization_id)
7
7
  end
8
8
 
9
9
  def run
@@ -59,8 +59,8 @@ module ForemanInventoryUpload
59
59
  input[:report_file]
60
60
  end
61
61
 
62
- def plan_upload_report(enqueued_file_name, organization_id, disconnected)
63
- plan_action(UploadReportJob, enqueued_file_name, organization_id, disconnected)
62
+ def plan_upload_report(enqueued_file_name, organization_id)
63
+ plan_action(UploadReportJob, enqueued_file_name, organization_id)
64
64
  end
65
65
  end
66
66
  end
@@ -7,15 +7,15 @@ module ForemanInventoryUpload
7
7
  "upload_for_#{label}"
8
8
  end
9
9
 
10
- def plan(filename, organization_id, disconnected = false)
10
+ def plan(filename, organization_id)
11
11
  label = UploadReportJob.output_label(organization_id)
12
- super(label, filename: filename, organization_id: organization_id, disconnected: disconnected)
12
+ super(label, filename: filename, organization_id: organization_id)
13
13
  end
14
14
 
15
15
  def try_execute
16
16
  if content_disconnected?
17
17
  progress_output do |progress_output|
18
- progress_output.write_line('Upload canceled because connection to Insights is not enabled or the --no-upload option was passed.')
18
+ progress_output.write_line("Report was not moved and upload was canceled because connection to Insights is not enabled. Report location: #{filename}.")
19
19
  progress_output.status = "Task aborted, exit 1"
20
20
  done!
21
21
  end
@@ -89,7 +89,7 @@ module ForemanInventoryUpload
89
89
  end
90
90
 
91
91
  def content_disconnected?
92
- input[:disconnected] || !Setting[:subscription_connection_enabled]
92
+ !Setting[:subscription_connection_enabled]
93
93
  end
94
94
  end
95
95
  end
@@ -1,3 +1,3 @@
1
1
  module ForemanRhCloud
2
- VERSION = '12.2.4'.freeze
2
+ VERSION = '12.2.6'.freeze
3
3
  end
@@ -0,0 +1,71 @@
1
+ require 'rest-client'
2
+
3
+ module InsightsCloud
4
+ module Async
5
+ # Triggers VMaaS reposcan sync via IoP gateway when repositories are synced
6
+ class VmaasReposcanSync < ::Actions::EntryAction
7
+ include ::ForemanRhCloud::CertAuth
8
+
9
+ # Subscribe to Katello repository sync hook action, if available
10
+ def self.subscribe
11
+ 'Actions::Katello::Repository::SyncHook'.constantize
12
+ rescue NameError
13
+ Rails.logger.debug('VMaaS reposcan sync: Repository::SyncHook action not found')
14
+ nil
15
+ end
16
+
17
+ def plan(repo, *_args)
18
+ return unless ::ForemanRhCloud.with_iop_smart_proxy?
19
+
20
+ repo_id = repo.is_a?(Hash) ? (repo[:id] || repo['id']) : nil
21
+ unless repo_id
22
+ logger.error("VMaaS reposcan sync: missing repository id in SyncHook plan parameters: #{repo.inspect}")
23
+ return
24
+ end
25
+
26
+ plan_self
27
+ end
28
+
29
+ def run
30
+ url = ::InsightsCloud.vmaas_reposcan_sync_url
31
+
32
+ response = execute_cloud_request(
33
+ method: :put,
34
+ url: url,
35
+ headers: { 'Content-Type' => 'application/json' }
36
+ )
37
+
38
+ if response.code >= 200 && response.code < 300
39
+ message = "VMaaS reposcan sync triggered successfully: #{response.code}"
40
+ logger.info(message)
41
+ else
42
+ message = "VMaaS reposcan sync failed with status: #{response.code}, body: #{response.body}"
43
+ logger.error(message)
44
+ end
45
+ output[:message] = message
46
+
47
+ response
48
+ rescue RestClient::ExceptionWithResponse => e
49
+ message = "VMaaS reposcan sync failed: #{e.response&.code} - #{e.response&.body}"
50
+ logger.error(message)
51
+ output[:message] = message
52
+ raise
53
+ rescue StandardError => e
54
+ message = "Error triggering VMaaS reposcan sync: #{e.message}, response: #{e.respond_to?(:response) ? e.response : nil}"
55
+ logger.error(message)
56
+ output[:message] = message
57
+ raise
58
+ end
59
+
60
+ def rescue_strategy_for_self
61
+ Dynflow::Action::Rescue::Skip
62
+ end
63
+
64
+ private
65
+
66
+ def logger
67
+ action_logger
68
+ end
69
+ end
70
+ end
71
+ end
@@ -44,4 +44,8 @@ module InsightsCloud
44
44
  def self.enable_cloud_remediations_param
45
45
  'enable_cloud_remediations'
46
46
  end
47
+
48
+ def self.vmaas_reposcan_sync_url
49
+ ForemanRhCloud.iop_smart_proxy.url + '/api/vmaas-reposcan/sync'
50
+ end
47
51
  end
data/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "foreman_rh_cloud",
3
- "version": "12.2.4",
3
+ "version": "12.2.6",
4
4
  "description": "Inventory Upload =============",
5
5
  "main": "index.js",
6
6
  "scripts": {
@@ -0,0 +1,63 @@
1
+ require 'test_plugin_helper'
2
+ require 'foreman_tasks/test_helpers'
3
+
4
+ class QueueForUploadJobTest < ActiveSupport::TestCase
5
+ include ForemanTasks::TestHelpers::WithInThreadExecutor
6
+ include FolderIsolation
7
+
8
+ let(:organization) { FactoryBot.create(:organization) }
9
+ let(:base_folder) { @tmpdir }
10
+ let(:report_file) { 'test_report.tar.xz' }
11
+ let(:report_path) { File.join(base_folder, report_file) }
12
+ let(:uploads_folder) { ForemanInventoryUpload.uploads_folder }
13
+ subject { ForemanTasks.sync_task(ForemanInventoryUpload::Async::QueueForUploadJob, base_folder, report_file, organization.id) }
14
+
15
+ setup do
16
+ # Stub the script template source
17
+ script_source = File.join(ForemanRhCloud::Engine.root, 'lib/foreman_inventory_upload/scripts/uploader.sh.erb')
18
+ File.stubs(:read).with(script_source).returns('#!/bin/bash\necho "Test script"')
19
+
20
+ # Stub template rendering
21
+ Foreman::Renderer.stubs(:render).returns('#!/bin/bash\necho "Rendered script"')
22
+
23
+ # Stub additional settings that are accessed
24
+ Setting.stubs(:[]).with(:content_default_http_proxy).returns(nil)
25
+ Setting.stubs(:[]).with(:http_proxy).returns(nil)
26
+ Setting.stubs(:[]).with("foreman_tasks_sync_task_timeout").returns(120)
27
+ FileUtils.touch(report_path)
28
+ end
29
+
30
+ teardown do
31
+ FileUtils.rm_rf(uploads_folder) if Dir.exist?(uploads_folder)
32
+ end
33
+
34
+ test 'plan method sets up the job correctly and calls plan_upload_report' do
35
+ # Mock plan_upload_report to verify it's called
36
+ ForemanInventoryUpload::Async::QueueForUploadJob.any_instance.expects(:plan_upload_report).once
37
+
38
+ assert_equal 'success', subject.result
39
+ end
40
+
41
+ test 'run method processes file and moves it to uploads folder' do
42
+ ForemanInventoryUpload::Async::QueueForUploadJob.any_instance.stubs(:plan_upload_report)
43
+
44
+ assert_equal 'success', subject.result
45
+
46
+ # Verify the file was moved
47
+ refute File.exist?(report_path), "Original file should be moved"
48
+ assert File.exist?(File.join(uploads_folder, report_file)), "File should exist in uploads folder"
49
+ end
50
+
51
+ test 'creates necessary folders and scripts' do
52
+ ForemanInventoryUpload::Async::QueueForUploadJob.any_instance.stubs(:plan_upload_report)
53
+
54
+ assert_equal 'success', subject.result
55
+
56
+ # Verify the uploads folder was created
57
+ assert Dir.exist?(uploads_folder), "Uploads folder should be created"
58
+
59
+ # Verify the script file was created
60
+ script_path = File.join(uploads_folder, ForemanInventoryUpload.upload_script_file)
61
+ assert File.exist?(script_path), "Upload script should be created"
62
+ end
63
+ end
@@ -18,7 +18,8 @@ class UploadReportJobTest < ActiveSupport::TestCase
18
18
 
19
19
  label = ForemanInventoryUpload::Async::UploadReportJob.output_label(organization.id)
20
20
  progress_output = ForemanInventoryUpload::Async::ProgressOutput.get(label)
21
- assert_match(/Upload canceled/, progress_output.full_output)
21
+ assert_match(/upload was canceled because connection to Insights is not enabled/, progress_output.full_output)
22
+ assert_match(/Report location:/, progress_output.full_output)
22
23
  assert_match(/exit 1/, progress_output.status)
23
24
  end
24
25
 
@@ -0,0 +1,137 @@
1
+ require 'test_plugin_helper'
2
+ require 'foreman_tasks/test_helpers'
3
+
4
+ class VmaasReposcanSyncTest < ActiveSupport::TestCase
5
+ include ForemanTasks::TestHelpers::WithInThreadExecutor
6
+
7
+ setup do
8
+ @repo_payload = { id: 123 }
9
+ @expected_url = 'https://example.com/api/v1/vmaas/reposcan/sync'
10
+ InsightsCloud.stubs(:vmaas_reposcan_sync_url).returns(@expected_url)
11
+ ForemanRhCloud.stubs(:with_iop_smart_proxy?).returns(true)
12
+ end
13
+
14
+ # Planning behavior
15
+ test 'plan plans_self when repo payload has id and IoP is available' do
16
+ InsightsCloud::Async::VmaasReposcanSync.any_instance.expects(:plan_self).once
17
+
18
+ ForemanTasks.sync_task(InsightsCloud::Async::VmaasReposcanSync, @repo_payload)
19
+ end
20
+
21
+ test 'plan does not plan_self when repo payload is missing id' do
22
+ payload_without_id = {}
23
+
24
+ mock_logger = mock('logger')
25
+ mock_logger.expects(:error).with { |msg| msg =~ /missing repository id/i }
26
+ InsightsCloud::Async::VmaasReposcanSync.any_instance.stubs(:logger).returns(mock_logger)
27
+ InsightsCloud::Async::VmaasReposcanSync.any_instance.expects(:plan_self).never
28
+
29
+ ForemanTasks.sync_task(InsightsCloud::Async::VmaasReposcanSync, payload_without_id)
30
+ end
31
+
32
+ test 'plan does not plan_self when IoP smart proxy is not available' do
33
+ ForemanRhCloud.stubs(:with_iop_smart_proxy?).returns(false)
34
+
35
+ InsightsCloud::Async::VmaasReposcanSync.any_instance.expects(:plan_self).never
36
+
37
+ ForemanTasks.sync_task(InsightsCloud::Async::VmaasReposcanSync, @repo_payload)
38
+ end
39
+
40
+ test 'plan skips repo_id validation when IoP smart proxy is not available' do
41
+ ForemanRhCloud.stubs(:with_iop_smart_proxy?).returns(false)
42
+ payload_without_id = {}
43
+
44
+ # Logger should not be called since IoP check returns early
45
+ InsightsCloud::Async::VmaasReposcanSync.any_instance.expects(:logger).never
46
+ InsightsCloud::Async::VmaasReposcanSync.any_instance.expects(:plan_self).never
47
+
48
+ ForemanTasks.sync_task(InsightsCloud::Async::VmaasReposcanSync, payload_without_id)
49
+ end
50
+
51
+ test 'plan does not plan_self when repository is nil' do
52
+ mock_logger = mock('logger')
53
+ mock_logger.expects(:error).with { |msg| msg =~ /missing repository id/i }
54
+ InsightsCloud::Async::VmaasReposcanSync.any_instance.stubs(:logger).returns(mock_logger)
55
+ InsightsCloud::Async::VmaasReposcanSync.any_instance.expects(:plan_self).never
56
+
57
+ ForemanTasks.sync_task(InsightsCloud::Async::VmaasReposcanSync, nil)
58
+ end
59
+
60
+ # Run behavior
61
+ test 'run triggers VMaaS reposcan sync successfully' do
62
+ mock_response = mock('response')
63
+ mock_response.stubs(:code).returns(200)
64
+
65
+ InsightsCloud::Async::VmaasReposcanSync.any_instance
66
+ .expects(:execute_cloud_request)
67
+ .with do |params|
68
+ params[:method] == :put &&
69
+ params[:url] == @expected_url &&
70
+ params[:headers].is_a?(Hash) &&
71
+ params[:headers]['Content-Type'] == 'application/json'
72
+ end
73
+ .returns(mock_response)
74
+
75
+ task = ForemanTasks.sync_task(InsightsCloud::Async::VmaasReposcanSync, @repo_payload)
76
+
77
+ assert_equal 'VMaaS reposcan sync triggered successfully: 200', task.output[:message]
78
+ end
79
+
80
+ test 'run sets error message in task output for failed response' do
81
+ mock_response = mock('response')
82
+ mock_response.stubs(:code).returns(500)
83
+ mock_response.stubs(:body).returns('Internal Server Error')
84
+
85
+ InsightsCloud::Async::VmaasReposcanSync.any_instance
86
+ .stubs(:execute_cloud_request)
87
+ .returns(mock_response)
88
+
89
+ task = ForemanTasks.sync_task(InsightsCloud::Async::VmaasReposcanSync, @repo_payload)
90
+
91
+ assert_equal 'VMaaS reposcan sync failed with status: 500, body: Internal Server Error', task.output[:message]
92
+ end
93
+
94
+ test 'run sets error message in task output for RestClient exception' do
95
+ error_response = mock('error_response')
96
+ error_response.stubs(:code).returns(500)
97
+ error_response.stubs(:body).returns('Server Error')
98
+ exception = RestClient::ExceptionWithResponse.new(error_response)
99
+
100
+ InsightsCloud::Async::VmaasReposcanSync.any_instance
101
+ .stubs(:execute_cloud_request)
102
+ .raises(exception)
103
+
104
+ error = assert_raises(ForemanTasks::TaskError) do
105
+ ForemanTasks.sync_task(InsightsCloud::Async::VmaasReposcanSync, @repo_payload)
106
+ end
107
+
108
+ assert_equal 'VMaaS reposcan sync failed: 500 - Server Error', error.task.output[:message]
109
+ end
110
+
111
+ test 'run sets error message in task output for StandardError exception' do
112
+ InsightsCloud::Async::VmaasReposcanSync.any_instance
113
+ .stubs(:execute_cloud_request)
114
+ .raises(StandardError.new('Network timeout'))
115
+
116
+ error = assert_raises(ForemanTasks::TaskError) do
117
+ ForemanTasks.sync_task(InsightsCloud::Async::VmaasReposcanSync, @repo_payload)
118
+ end
119
+
120
+ # The task is available via main_action
121
+ assert_match(/Error triggering VMaaS reposcan sync: Network timeout, response: /,
122
+ error.task.main_action.output[:message])
123
+ end
124
+
125
+ test 'run logs and re-raises when cloud request returns error response' do
126
+ error_response = mock('error_response', code: 500, body: 'error')
127
+ exception = RestClient::ExceptionWithResponse.new(error_response)
128
+
129
+ InsightsCloud::Async::VmaasReposcanSync.any_instance
130
+ .stubs(:execute_cloud_request)
131
+ .raises(exception)
132
+
133
+ assert_raises(ForemanTasks::TaskError) do
134
+ ForemanTasks.sync_task(InsightsCloud::Async::VmaasReposcanSync, @repo_payload)
135
+ end
136
+ end
137
+ end
@@ -6,7 +6,7 @@ import { translate as __ } from 'foremanReact/common/I18n';
6
6
  import { propsToCamelCase } from 'foremanReact/common/helpers';
7
7
  import { CVECountCell } from '../InsightsVulnerabilityHostIndexExtensions/CVECountCell';
8
8
 
9
- const HostedRecommendationsCell = hostDetails => {
9
+ const HostedRecommendationsCell = ({ hostDetails }) => {
10
10
  const insightsAttributes = propsToCamelCase(
11
11
  // eslint-disable-next-line camelcase
12
12
  hostDetails?.insights_attributes ?? {}
@@ -19,6 +19,10 @@ const HostedRecommendationsCell = hostDetails => {
19
19
  return <a href={hitsUrl}>{hitsCount}</a>;
20
20
  };
21
21
 
22
+ HostedRecommendationsCell.propTypes = {
23
+ hostDetails: PropTypes.object.isRequired,
24
+ };
25
+
22
26
  const IopRecommendationsCell = ({ hostDetails }) => {
23
27
  // eslint-disable-next-line camelcase
24
28
  const uuid = hostDetails?.insights_attributes?.uuid;
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: foreman_rh_cloud
3
3
  version: !ruby/object:Gem::Version
4
- version: 12.2.4
4
+ version: 12.2.6
5
5
  platform: ruby
6
6
  authors:
7
7
  - Foreman Red Hat Cloud team
@@ -217,6 +217,7 @@ files:
217
217
  - lib/insights_cloud/async/insights_rules_sync.rb
218
218
  - lib/insights_cloud/async/insights_scheduled_sync.rb
219
219
  - lib/insights_cloud/async/rules_result.rb
220
+ - lib/insights_cloud/async/vmaas_reposcan_sync.rb
220
221
  - lib/insights_cloud/generators/playbook_progress_generator.rb
221
222
  - lib/insights_vulnerability.rb
222
223
  - lib/inventory_sync/async/host_result.rb
@@ -267,6 +268,7 @@ files:
267
268
  - test/jobs/inventory_hosts_sync_test.rb
268
269
  - test/jobs/inventory_scheduled_sync_test.rb
269
270
  - test/jobs/inventory_self_host_sync_test.rb
271
+ - test/jobs/queue_for_upload_job_test.rb
270
272
  - test/jobs/remove_insights_hosts_job_test.rb
271
273
  - test/jobs/upload_report_job_test.rb
272
274
  - test/models/insights_client_report_status_test.rb
@@ -275,6 +277,7 @@ files:
275
277
  - test/unit/fact_helpers_test.rb
276
278
  - test/unit/foreman_rh_cloud_self_host_test.rb
277
279
  - test/unit/insights_facet_test.rb
280
+ - test/unit/lib/insights_cloud/async/vmaas_reposcan_sync_test.rb
278
281
  - test/unit/metadata_generator_test.rb
279
282
  - test/unit/playbook_progress_generator_test.rb
280
283
  - test/unit/rh_cloud_http_proxy_test.rb
@@ -719,6 +722,7 @@ test_files:
719
722
  - test/jobs/inventory_hosts_sync_test.rb
720
723
  - test/jobs/inventory_scheduled_sync_test.rb
721
724
  - test/jobs/inventory_self_host_sync_test.rb
725
+ - test/jobs/queue_for_upload_job_test.rb
722
726
  - test/jobs/remove_insights_hosts_job_test.rb
723
727
  - test/jobs/upload_report_job_test.rb
724
728
  - test/models/insights_client_report_status_test.rb
@@ -727,6 +731,7 @@ test_files:
727
731
  - test/unit/fact_helpers_test.rb
728
732
  - test/unit/foreman_rh_cloud_self_host_test.rb
729
733
  - test/unit/insights_facet_test.rb
734
+ - test/unit/lib/insights_cloud/async/vmaas_reposcan_sync_test.rb
730
735
  - test/unit/metadata_generator_test.rb
731
736
  - test/unit/playbook_progress_generator_test.rb
732
737
  - test/unit/rh_cloud_http_proxy_test.rb