foreman_rh_cloud 5.0.37 → 5.0.41

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: 8b1fcbb6ac1367f8d83a29a6723c9244314b70cd3d8fb675747cdf44ae312a27
4
- data.tar.gz: c9adec3a0002212f49e8ab7a30e793431809076e9b204a43725001b0a9e391ee
3
+ metadata.gz: 4520a12619aad77a5d0ddeafd83203d8281e0ff7d3e9fcc2eef10a2a779bad27
4
+ data.tar.gz: 7e6d55970f4c0742328e5a5e9159b084a391cc98305cf67cff6555a1575b6fe1
5
5
  SHA512:
6
- metadata.gz: db98fee746e070be33b584993e56479290df9b462ab9277a66f43c3b5c0af37a9ba3a765f66c4d3fc03f114d300b4ce206db3a8228e0417544c9a092f0e25e23
7
- data.tar.gz: '09dd3108525df34ef72654cf8f9030af5fc2a6996b806d78b026e56d493b3d49cb5794852733b63dd500102878049e6e4e9f96d16428aa52f55ad8c1c727a610'
6
+ metadata.gz: f55b1b61ed73778bc62c7cf1819b1eac363417a6f929cbc1f6e9b8043f45904b2dec26f1c9294ab68e1b175a4cbda091ef7091d755180649d0f2e242784092c5
7
+ data.tar.gz: 5b7fe9198f6c0172f93638f8315274158471169033de6f6c9113aa94dd2de8ab5ac0a0c9b32b0c1bb374cfb3303ab9d7915519139919799d9a88531bb280f024
@@ -27,16 +27,18 @@ module Api::V2::RhCloud
27
27
  private
28
28
 
29
29
  def metadata
30
- params['metadata']
30
+ params['Metadata'] || params['metadata']
31
31
  end
32
32
 
33
33
  def content
34
+ content = params['Content'] || params['content']
35
+
34
36
  # the content received as base 64 of the string in double quotes
35
- Base64.decode64(params['content']).tr('"', '')
37
+ Base64.decode64(content).tr('"', '')
36
38
  end
37
39
 
38
40
  def directive
39
- params['directive']
41
+ params['Directive'] || params['directive']
40
42
  end
41
43
 
42
44
  def handle_run_playbook_request
@@ -44,9 +46,13 @@ module Api::V2::RhCloud
44
46
  logger.error("Reporting URL is not valid: #{metadata['return_url']}") && return unless valid_url?(metadata['return_url'])
45
47
 
46
48
  hosts = metadata['hosts'].split(',')
47
- host_ids = host_ids(hosts)
48
49
 
49
- logger.warn("Some hosts were not found. Looked for: #{hosts}, found ids: #{host_ids}") unless host_ids.length == hosts.length
50
+ # select hosts from the metadata list that are not disabled by the parameter.
51
+ host_ids = Host.search_for("not params.#{InsightsCloud.enable_cloud_remediations_param} = f")
52
+ .where(id: host_ids(hosts))
53
+ .pluck(:id)
54
+
55
+ logger.warn("Some hosts were not found/ignored. Looked for: #{hosts}, found ids: #{host_ids}") unless host_ids.length == hosts.length
50
56
 
51
57
  logger.error("sat_org_id is not present in the metadata") && return unless metadata['sat_org_id']
52
58
  org_id = metadata['sat_org_id'].to_i
@@ -18,13 +18,6 @@ module ForemanInventoryUpload
18
18
  end
19
19
 
20
20
  def enable_cloud_connector
21
- Organization.unscoped.each do |org|
22
- presence = ForemanRhCloud::CloudPresence.new(org, logger)
23
- presence.announce_to_sources
24
- rescue StandardError => ex
25
- logger.warn(ex)
26
- end
27
-
28
21
  cloud_connector = ForemanRhCloud::CloudConnector.new
29
22
  render json: cloud_connector.install.to_json
30
23
  end
@@ -9,6 +9,20 @@ module InsightsCloud
9
9
  render_setting(:insightsSyncEnabled, :allow_auto_insights_sync)
10
10
  end
11
11
 
12
+ def set_org_parameter
13
+ parameter = params.require(:parameter)
14
+ new_value = ActiveModel::Type::Boolean.new.cast(params.require(:value))
15
+ org_id = params.require(:organization_id)
16
+
17
+ organization = Organization.authorized.find(org_id)
18
+
19
+ org_param = organization.organization_parameters.find_or_create_by(name: parameter) do |org_param|
20
+ org_param.name = parameter
21
+ end
22
+ org_param.value = new_value
23
+ org_param.save!
24
+ end
25
+
12
26
  private
13
27
 
14
28
  def render_setting(node_name, setting)
data/config/routes.rb CHANGED
@@ -25,6 +25,8 @@ Rails.application.routes.draw do
25
25
  end
26
26
  end
27
27
  match 'hits/:host_id', to: 'hits#show', via: :get
28
+
29
+ post ':organization_id/parameter', to: 'settings#set_org_parameter', constraints: { organization_id: %r{[^\/]+} }
28
30
  end
29
31
 
30
32
  namespace :foreman_rh_cloud do
@@ -32,6 +32,10 @@ module ForemanInventoryUpload
32
32
  def plan_generate_report(folder, organization)
33
33
  plan_action(ForemanInventoryUpload::Async::GenerateReportJob, folder, organization.id)
34
34
  end
35
+
36
+ def logger
37
+ action_logger
38
+ end
35
39
  end
36
40
  end
37
41
  end
@@ -83,9 +83,13 @@ module ForemanRhCloud
83
83
  :dispatch_cloud_requests,
84
84
  'api/v2/rh_cloud/cloud_request': [:update]
85
85
  )
86
+ permission(
87
+ :control_organization_insights,
88
+ 'insights_cloud/settings': [:set_org_parameter]
89
+ )
86
90
  end
87
91
 
88
- plugin_permissions = [:view_foreman_rh_cloud, :generate_foreman_rh_cloud, :view_insights_hits, :dispatch_cloud_requests]
92
+ plugin_permissions = [:view_foreman_rh_cloud, :generate_foreman_rh_cloud, :view_insights_hits, :dispatch_cloud_requests, :control_organization_insights]
89
93
 
90
94
  role 'ForemanRhCloud', plugin_permissions, 'Role granting permissions to view the hosts inventory,
91
95
  generate a report, upload it to the cloud and download it locally'
@@ -1,3 +1,3 @@
1
1
  module ForemanRhCloud
2
- VERSION = '5.0.37'.freeze
2
+ VERSION = '5.0.41'.freeze
3
3
  end
@@ -0,0 +1,44 @@
1
+ module InsightsCloud
2
+ module Async
3
+ class CloudConnectorAnnounceTask < ::Actions::EntryAction
4
+ def self.subscribe
5
+ Actions::RemoteExecution::RunHostsJob
6
+ end
7
+
8
+ def self.connector_feature_id
9
+ @connector_feature_id ||= RemoteExecutionFeature.feature!(ForemanRhCloud::CloudConnector::CLOUD_CONNECTOR_FEATURE).id
10
+ end
11
+
12
+ def plan(job_invocation)
13
+ return unless connector_playbook_job?(job_invocation)
14
+
15
+ plan_self
16
+ end
17
+
18
+ def finalize
19
+ Organization.unscoped.each do |org|
20
+ presence = ForemanRhCloud::CloudPresence.new(org, logger)
21
+ presence.announce_to_sources
22
+ rescue StandardError => ex
23
+ logger.warn(ex)
24
+ end
25
+ end
26
+
27
+ def rescue_strategy_for_self
28
+ Dynflow::Action::Rescue::Skip
29
+ end
30
+
31
+ def connector_playbook_job?(job_invocation)
32
+ job_invocation&.remote_execution_feature_id == connector_feature_id
33
+ end
34
+
35
+ def connector_feature_id
36
+ self.class.connector_feature_id
37
+ end
38
+
39
+ def logger
40
+ action_logger
41
+ end
42
+ end
43
+ end
44
+ end
@@ -137,6 +137,7 @@ module InsightsCloud
137
137
 
138
138
  def report_job_progress(invocation_status)
139
139
  generator = InsightsCloud::Generators::PlaybookProgressGenerator.new(correlation_id)
140
+ all_hosts_success = true
140
141
 
141
142
  invocation_status.each do |host_name, status|
142
143
  # skip host if the host already reported that it's finished
@@ -151,9 +152,10 @@ module InsightsCloud
151
152
  if status['state'] == 'stopped'
152
153
  generator.host_finished_message(host_name, status['exit_status'])
153
154
  status['report_done'] = true
155
+ all_hosts_success &&= status['exit_status'] == 0
154
156
  end
155
157
  end
156
- generator.job_finished_message if done?(invocation_status)
158
+ generator.job_finished_message(all_hosts_success) if done?(invocation_status)
157
159
 
158
160
  send_report(generator.generate)
159
161
  end
@@ -30,12 +30,12 @@ module InsightsCloud
30
30
  }
31
31
  end
32
32
 
33
- def job_finished_message
33
+ def job_finished_message(success)
34
34
  @messages << {
35
35
  "type": "playbook_run_completed",
36
36
  "version": 3,
37
37
  "correlation_id": correlation_id,
38
- "status": "success",
38
+ "status": success ? 'success' : 'failure',
39
39
  }
40
40
  end
41
41
 
@@ -28,4 +28,8 @@ module InsightsCloud
28
28
  def self.enable_client_param
29
29
  'host_registration_insights'
30
30
  end
31
+
32
+ def self.enable_cloud_remediations_param
33
+ 'enable_cloud_remediations'
34
+ end
31
35
  end
data/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "foreman_rh_cloud",
3
- "version": "5.0.37",
3
+ "version": "5.0.41",
4
4
  "description": "Inventory Upload =============",
5
5
  "main": "index.js",
6
6
  "scripts": {
@@ -22,14 +22,14 @@
22
22
  "url": "http://projects.theforeman.org/projects/foreman_rh_cloud/issues"
23
23
  },
24
24
  "peerDependencies": {
25
- "@theforeman/vendor": "~8.16.0"
25
+ "@theforeman/vendor": ">= 8.16.0"
26
26
  },
27
27
  "devDependencies": {
28
28
  "@babel/core": "~7.7.0",
29
- "@theforeman/builder": "~8.16.0",
30
- "@theforeman/stories": "~8.16.0",
31
- "@theforeman/test": "~8.16.0",
32
- "@theforeman/eslint-plugin-foreman": "~8.16.0",
29
+ "@theforeman/builder": ">= 8.16.0",
30
+ "@theforeman/stories": ">= 8.16.0",
31
+ "@theforeman/test": ">= 8.16.0",
32
+ "@theforeman/eslint-plugin-foreman": ">= 8.16.0",
33
33
  "babel-eslint": "~10.0.0",
34
34
  "eslint": "~6.7.2",
35
35
  "eslint-plugin-spellcheck": "~0.0.17",
@@ -40,6 +40,33 @@ module InsightsCloud::Api
40
40
  assert_response :success
41
41
  end
42
42
 
43
+ test 'Starts playbook run for correct directive with capitalized keys' do
44
+ host1 = FactoryBot.create(:host, :with_insights_hits)
45
+ host1.insights.uuid = 'TEST_UUID1'
46
+ host1.insights.save!
47
+ host2 = FactoryBot.create(:host, :with_insights_hits)
48
+ host2.insights.uuid = 'TEST_UUID2'
49
+ host2.insights.save!
50
+
51
+ mock_composer = mock('composer')
52
+ ::JobInvocationComposer.expects(:for_feature).with do |feature, host_ids, params|
53
+ feature == :rh_cloud_connector_run_playbook &&
54
+ host_ids.first == host1.id &&
55
+ host_ids.last == host2.id
56
+ end.returns(mock_composer)
57
+ mock_composer.expects(:trigger!)
58
+ mock_composer.expects(:job_invocation)
59
+
60
+ params = run_playbook_request
61
+ params['Directive'] = params.delete('directive')
62
+ params['Metadata'] = params.delete('metadata')
63
+ params['Content'] = params.delete('content')
64
+
65
+ post :update, params: run_playbook_request
66
+
67
+ assert_response :success
68
+ end
69
+
43
70
  private
44
71
 
45
72
  def run_playbook_request
@@ -27,4 +27,21 @@ class SettingsControllerTest < ActionController::TestCase
27
27
  assert_equal true, actual['insightsSyncEnabled']
28
28
  assert_equal true, Setting[:allow_auto_insights_sync]
29
29
  end
30
+
31
+ test 'Should update an organization parameter' do
32
+ FactoryBot.create(:common_parameter, name: InsightsCloud.enable_cloud_remediations_param, value: false)
33
+ host = FactoryBot.create(:host)
34
+
35
+ # make sure the parameter is there
36
+ assert_equal false, host.host_params[InsightsCloud.enable_cloud_remediations_param]
37
+
38
+ post :set_org_parameter, params: { parameter: InsightsCloud.enable_cloud_remediations_param, value: true, organization_id: host.organization.id }, session: set_session_user
39
+
40
+ # needed for properly access host_params
41
+ User.as_anonymous_admin do
42
+ # refresh the host record
43
+ host = Host.find(host.id)
44
+ assert_equal true, host.host_params[InsightsCloud.enable_cloud_remediations_param]
45
+ end
46
+ end
30
47
  end
@@ -0,0 +1,125 @@
1
+ require 'json'
2
+ require 'test_plugin_helper'
3
+ require 'foreman_tasks/test_helpers'
4
+ require "#{ForemanTasks::Engine.root}/test/support/dummy_dynflow_action"
5
+
6
+ class CloudConnectorAnnounceTaskTest < ActiveSupport::TestCase
7
+ include ForemanTasks::TestHelpers::WithInThreadExecutor
8
+
9
+ setup do
10
+ RemoteExecutionFeature.register(
11
+ :ansible_configure_cloud_connector,
12
+ N_('Configure Cloud Connector on given hosts'),
13
+ :description => N_('Configure Cloud Connector on given hosts'),
14
+ :proxy_selector_override => ::RemoteExecutionProxySelector::INTERNAL_PROXY
15
+ )
16
+
17
+ @job_invocation = generate_job_invocation(:ansible_configure_cloud_connector)
18
+
19
+ # reset connector feature ID cache
20
+ InsightsCloud::Async::CloudConnectorAnnounceTask.instance_variable_set(:@connector_feature_id, nil)
21
+ end
22
+
23
+ test 'It executes cloud presence announcer' do
24
+ ForemanRhCloud::CloudPresence.any_instance.expects(:announce_to_sources).times(Organization.unscoped.count)
25
+
26
+ ForemanTasks.sync_task(InsightsCloud::Async::CloudConnectorAnnounceTask, @job_invocation)
27
+ end
28
+
29
+ private
30
+
31
+ def generate_job_invocation(feature_name)
32
+ job_template = FactoryBot.build(
33
+ :job_template,
34
+ :template => 'BLEH'
35
+ )
36
+ feature = RemoteExecutionFeature.feature!(feature_name).id
37
+
38
+ job_invocation = FactoryBot.create(
39
+ :job_invocation,
40
+ remote_execution_feature_id: feature,
41
+ task_id: FactoryBot.create(:dynflow_task).id
42
+ )
43
+
44
+ job_template.template_inputs << playbook_url_input = FactoryBot.build(:template_input,
45
+ :name => 'playbook_url',
46
+ :input_type => 'user',
47
+ :required => true)
48
+ job_template.template_inputs << report_url_input = FactoryBot.build(:template_input,
49
+ :name => 'report_url',
50
+ :input_type => 'user',
51
+ :required => true)
52
+ job_template.template_inputs << correlation_id_input = FactoryBot.build(:template_input,
53
+ :name => 'correlation_id',
54
+ :input_type => 'user',
55
+ :required => true)
56
+ job_template.template_inputs << report_interval_input = FactoryBot.build(:template_input,
57
+ :name => 'report_interval',
58
+ :input_type => 'user',
59
+ :required => true)
60
+
61
+ template_invocation = FactoryBot.build(:template_invocation,
62
+ :template => job_template,
63
+ :job_invocation => job_invocation
64
+ )
65
+
66
+ template_invocation.input_values << FactoryBot.create(
67
+ :template_invocation_input_value,
68
+ :template_invocation => template_invocation,
69
+ :template_input => playbook_url_input,
70
+ :value => 'http://example.com/TEST_PLAYBOOK'
71
+ )
72
+ template_invocation.input_values << FactoryBot.create(
73
+ :template_invocation_input_value,
74
+ :template_invocation => template_invocation,
75
+ :template_input => report_url_input,
76
+ :value => 'http://example.com/TEST_REPORT'
77
+ )
78
+ template_invocation.input_values << FactoryBot.create(
79
+ :template_invocation_input_value,
80
+ :template_invocation => template_invocation,
81
+ :template_input => correlation_id_input,
82
+ :value => 'TEST_CORRELATION'
83
+ )
84
+ template_invocation.input_values << FactoryBot.create(
85
+ :template_invocation_input_value,
86
+ :template_invocation => template_invocation,
87
+ :template_input => report_interval_input,
88
+ :value => '1'
89
+ )
90
+
91
+ @host1 = FactoryBot.create(:host, :with_insights_hits, name: 'host1')
92
+ @host1.insights.uuid = 'TEST_UUID1'
93
+ @host1.insights.save!
94
+ @host2 = FactoryBot.create(:host, :with_insights_hits, name: 'host2')
95
+ @host2.insights.uuid = 'TEST_UUID2'
96
+ @host2.insights.save!
97
+
98
+ targeting = FactoryBot.create(:targeting, hosts: [@host1, @host2])
99
+ job_invocation.targeting = targeting
100
+ job_invocation.save!
101
+
102
+ job_invocation.template_invocations << FactoryBot.create(
103
+ :template_invocation,
104
+ run_host_job_task: FactoryBot.create(:dynflow_task),
105
+ host_id: @host1.id
106
+ )
107
+ job_invocation.template_invocations << FactoryBot.create(
108
+ :template_invocation,
109
+ run_host_job_task: FactoryBot.create(:dynflow_task),
110
+ host_id: @host2.id
111
+ )
112
+
113
+ fake_output = (1..5).map do |i|
114
+ { 'timestamp' => (Time.now - (5 - i)).to_f, 'output' => "#{i}\n" }
115
+ end
116
+ Support::DummyDynflowAction.any_instance.stubs(:live_output).returns(fake_output)
117
+ Support::DummyDynflowAction.any_instance.stubs(:exit_status).returns(0)
118
+
119
+ job_invocation
120
+ end
121
+
122
+ def read_jsonl(jsonl)
123
+ jsonl.lines.map { |l| JSON.parse(l) }
124
+ end
125
+ end
@@ -51,7 +51,7 @@ class PlaybookProgressGeneratorTest < ActiveSupport::TestCase
51
51
  end
52
52
 
53
53
  test 'Outputs job finished message' do
54
- @generator.job_finished_message
54
+ @generator.job_finished_message(true)
55
55
 
56
56
  actual = @generator.generate
57
57
  actual_message = JSON.parse(actual)
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: foreman_rh_cloud
3
3
  version: !ruby/object:Gem::Version
4
- version: 5.0.37
4
+ version: 5.0.41
5
5
  platform: ruby
6
6
  authors:
7
7
  - Foreman Red Hat Cloud team
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2022-05-25 00:00:00.000000000 Z
11
+ date: 2022-08-02 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: katello
@@ -221,6 +221,7 @@ files:
221
221
  - lib/foreman_rh_cloud/engine.rb
222
222
  - lib/foreman_rh_cloud/version.rb
223
223
  - lib/insights_cloud.rb
224
+ - lib/insights_cloud/async/cloud_connector_announce_task.rb
224
225
  - lib/insights_cloud/async/connector_playbook_execution_reporter_task.rb
225
226
  - lib/insights_cloud/async/insights_client_status_aging.rb
226
227
  - lib/insights_cloud/async/insights_full_sync.rb
@@ -255,6 +256,7 @@ files:
255
256
  - test/controllers/uploads_settings_controller_test.rb
256
257
  - test/factories/insights_factories.rb
257
258
  - test/factories/inventory_upload_factories.rb
259
+ - test/jobs/cloud_connector_announce_task_test.rb
258
260
  - test/jobs/connector_playbook_execution_reporter_task_test.rb
259
261
  - test/jobs/insights_client_status_aging_test.rb
260
262
  - test/jobs/insights_full_sync_test.rb
@@ -672,7 +674,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
672
674
  - !ruby/object:Gem::Version
673
675
  version: '0'
674
676
  requirements: []
675
- rubygems_version: 3.1.4
677
+ rubygems_version: 3.3.7
676
678
  signing_key:
677
679
  specification_version: 4
678
680
  summary: Summary of ForemanRhCloud.
@@ -688,33 +690,34 @@ test_files:
688
690
  - test/controllers/uploads_settings_controller_test.rb
689
691
  - test/factories/insights_factories.rb
690
692
  - test/factories/inventory_upload_factories.rb
691
- - test/jobs/insights_client_status_aging_test.rb
692
- - test/jobs/inventory_scheduled_sync_test.rb
693
- - test/jobs/upload_report_job_test.rb
693
+ - test/jobs/cloud_connector_announce_task_test.rb
694
694
  - test/jobs/connector_playbook_execution_reporter_task_test.rb
695
+ - test/jobs/insights_client_status_aging_test.rb
695
696
  - test/jobs/insights_full_sync_test.rb
696
697
  - test/jobs/insights_resolutions_sync_test.rb
697
698
  - test/jobs/insights_rules_sync_test.rb
698
699
  - test/jobs/inventory_full_sync_test.rb
699
700
  - test/jobs/inventory_hosts_sync_test.rb
701
+ - test/jobs/inventory_scheduled_sync_test.rb
700
702
  - test/jobs/inventory_self_host_sync_test.rb
703
+ - test/jobs/upload_report_job_test.rb
701
704
  - test/models/insights_client_report_status_test.rb
702
705
  - test/test_plugin_helper.rb
703
706
  - test/unit/archived_report_generator_test.rb
704
707
  - test/unit/fact_helpers_test.rb
708
+ - test/unit/foreman_rh_cloud_self_host_test.rb
705
709
  - test/unit/insights_facet_test.rb
706
710
  - test/unit/metadata_generator_test.rb
711
+ - test/unit/playbook_progress_generator_test.rb
707
712
  - test/unit/rh_cloud_http_proxy_test.rb
708
713
  - test/unit/rh_cloud_permissions_test.rb
709
714
  - test/unit/services/foreman_rh_cloud/branch_info_test.rb
710
- - test/unit/services/foreman_rh_cloud/insights_status_cleaner_test.rb
711
715
  - test/unit/services/foreman_rh_cloud/cloud_request_forwarder_test.rb
712
716
  - test/unit/services/foreman_rh_cloud/cloud_status_service_test.rb
713
717
  - test/unit/services/foreman_rh_cloud/hit_remediations_retriever_test.rb
718
+ - test/unit/services/foreman_rh_cloud/insights_status_cleaner_test.rb
714
719
  - test/unit/services/foreman_rh_cloud/template_renderer_helper_test.rb
715
720
  - test/unit/services/foreman_rh_cloud/url_remediations_retriever_test.rb
716
721
  - test/unit/shell_process_job_test.rb
717
722
  - test/unit/slice_generator_test.rb
718
723
  - test/unit/tags_generator_test.rb
719
- - test/unit/foreman_rh_cloud_self_host_test.rb
720
- - test/unit/playbook_progress_generator_test.rb