foreman_rh_cloud 5.0.36 → 5.0.39

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 229da2311b8f5aece8a84c51159cc218e0b40f6ed7e537c95741e86c4376be15
4
- data.tar.gz: 4f5f98dfa6c9e16b51f4a06709dbdbe39db56ffcd216468ce99d8a9823303053
3
+ metadata.gz: ee0416cdf8e5d2ed1315759fe70b9d5328754afbf676cecff442f20f835cde2c
4
+ data.tar.gz: c32a6486106d8dd395860f2ba956ef06980e8e8115a55b1f8731e3d7db440ffb
5
5
  SHA512:
6
- metadata.gz: b0da1a9cee46f80aeb164909f26b73302d7eb5552612361eb37281ff88996de448f3df5227955ad388ee63f88380578eabf8023a54433829d9e3dc47032b5638
7
- data.tar.gz: 8a9866f4c442d0d42f8d0673d41c0889522b45a0bd5940c05bab92cf21cf2df28eb1d41a65a2a70be25c5e2156cc0a8e65e252f2027267fbb9fa5f7710abbaba
6
+ metadata.gz: 1afe5ccd1f0704428ac26ff319491e737e04acd28cc8bfc2e2e77acba7195657ecd89a078aadc3e892f5953680d2da9113f52562847cf9839b28c2d9e4507f9c
7
+ data.tar.gz: 6e78ebbbd8a9e833aadb15b95673fe57f99a60daab0ca3c48d1829dfd055e7f7744c0189e63b51077d03c2dd5d0084d95ecf87a745796afc2965dc016bef2132
@@ -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)
@@ -9,7 +9,7 @@ module ForemanRhCloud
9
9
  end
10
10
 
11
11
  def create_playbook
12
- unless cert_auth_available?(@organization)
12
+ unless cert_auth_available?(organization)
13
13
  logger.debug('Manifest is not available, cannot continue')
14
14
  return
15
15
  end
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
@@ -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.36'.freeze
2
+ VERSION = '5.0.39'.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.36",
3
+ "version": "5.0.39",
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.36
4
+ version: 5.0.39
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-19 00:00:00.000000000 Z
11
+ date: 2022-06-13 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: katello
@@ -222,6 +222,7 @@ files:
222
222
  - lib/foreman_rh_cloud/engine.rb
223
223
  - lib/foreman_rh_cloud/version.rb
224
224
  - lib/insights_cloud.rb
225
+ - lib/insights_cloud/async/cloud_connector_announce_task.rb
225
226
  - lib/insights_cloud/async/connector_playbook_execution_reporter_task.rb
226
227
  - lib/insights_cloud/async/insights_client_status_aging.rb
227
228
  - lib/insights_cloud/async/insights_full_sync.rb
@@ -256,6 +257,7 @@ files:
256
257
  - test/controllers/uploads_settings_controller_test.rb
257
258
  - test/factories/insights_factories.rb
258
259
  - test/factories/inventory_upload_factories.rb
260
+ - test/jobs/cloud_connector_announce_task_test.rb
259
261
  - test/jobs/connector_playbook_execution_reporter_task_test.rb
260
262
  - test/jobs/insights_client_status_aging_test.rb
261
263
  - test/jobs/insights_full_sync_test.rb
@@ -689,6 +691,7 @@ test_files:
689
691
  - test/controllers/uploads_settings_controller_test.rb
690
692
  - test/factories/insights_factories.rb
691
693
  - test/factories/inventory_upload_factories.rb
694
+ - test/jobs/cloud_connector_announce_task_test.rb
692
695
  - test/jobs/connector_playbook_execution_reporter_task_test.rb
693
696
  - test/jobs/insights_client_status_aging_test.rb
694
697
  - test/jobs/insights_full_sync_test.rb