foreman_rh_cloud 3.0.19 → 3.0.20

Sign up to get free protection for your applications and to get access to all the features.
Files changed (49) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +17 -2
  3. data/app/controllers/insights_cloud/hits_controller.rb +37 -0
  4. data/app/controllers/insights_cloud/settings_controller.rb +1 -1
  5. data/app/controllers/insights_cloud/tasks_controller.rb +1 -2
  6. data/app/models/inventory_sync/inventory_status.rb +6 -0
  7. data/app/models/setting/rh_cloud.rb +5 -5
  8. data/app/services/foreman_rh_cloud/remediations_retriever.rb +78 -0
  9. data/app/services/foreman_rh_cloud/template_renderer_helper.rb +22 -0
  10. data/app/views/job_templates/rh_cloud_remediations.erb +14 -0
  11. data/config/routes.rb +1 -0
  12. data/db/migrate/20210404000001_change_resolutions.foreman_rh_cloud.rb +10 -0
  13. data/db/seeds.d/50_job_templates.rb +14 -0
  14. data/lib/foreman_rh_cloud/engine.rb +13 -1
  15. data/lib/foreman_rh_cloud/version.rb +1 -1
  16. data/lib/insights_cloud.rb +12 -0
  17. data/lib/insights_cloud/async/insights_full_sync.rb +16 -6
  18. data/lib/insights_cloud/async/insights_resolutions_sync.rb +69 -0
  19. data/lib/insights_cloud/async/insights_rules_sync.rb +13 -17
  20. data/lib/insights_cloud/async/insights_scheduled_sync.rb +1 -1
  21. data/lib/tasks/rh_cloud_inventory.rake +1 -1
  22. data/package.json +1 -1
  23. data/test/factories/insights_factories.rb +22 -0
  24. data/test/jobs/insights_full_sync_test.rb +12 -8
  25. data/test/jobs/insights_resolutions_sync_test.rb +74 -0
  26. data/test/jobs/insights_rules_sync_test.rb +5 -3
  27. data/test/jobs/inventory_full_sync_test.rb +1 -1
  28. data/test/unit/services/foreman_rh_cloud/remediations_retriever_test.rb +49 -0
  29. data/test/unit/services/foreman_rh_cloud/template_renderer_helper_test.rb +28 -0
  30. data/webpack/ForemanInventoryUpload/Components/InventorySettings/AdvancedSetting/AdvancedSettingsConstants.js +5 -3
  31. data/webpack/ForemanInventoryUpload/Components/PageHeader/components/PageDescription/PageDescription.js +15 -2
  32. data/webpack/ForemanInventoryUpload/Components/PageHeader/components/PageDescription/__tests__/__snapshots__/PageDescription.test.js.snap +13 -2
  33. data/webpack/InsightsCloudSync/Components/InsightsTable/InsightsTable.js +1 -1
  34. data/webpack/InsightsCloudSync/Components/InsightsTable/InsightsTableSelectors.js +3 -0
  35. data/webpack/InsightsCloudSync/Components/RemediationModal/RemediateButton.js +59 -0
  36. data/webpack/InsightsCloudSync/Components/RemediationModal/RemediationActions.js +12 -0
  37. data/webpack/InsightsCloudSync/Components/RemediationModal/RemediationHelpers.js +43 -0
  38. data/webpack/InsightsCloudSync/Components/RemediationModal/RemediationModal.js +101 -0
  39. data/webpack/InsightsCloudSync/Components/RemediationModal/RemediationModal.scss +9 -0
  40. data/webpack/InsightsCloudSync/Components/RemediationModal/RemediationModalFooter.js +43 -0
  41. data/webpack/InsightsCloudSync/Components/RemediationModal/RemediationTableConstants.js +38 -0
  42. data/webpack/InsightsCloudSync/Components/RemediationModal/Resolutions.js +55 -0
  43. data/webpack/InsightsCloudSync/Components/RemediationModal/index.js +34 -0
  44. data/webpack/InsightsCloudSync/InsightsCloudSync.js +8 -3
  45. data/webpack/InsightsCloudSync/InsightsCloudSync.scss +5 -0
  46. data/webpack/InsightsCloudSync/__snapshots__/InsightsCloudSync.test.js.snap +9 -6
  47. data/webpack/{InsightsCloudSync/Components/InsightsTable/components → common/table}/EmptyState.js +0 -0
  48. data/webpack/common/table/helpers.js +7 -0
  49. metadata +33 -9
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 43110585639a77e33c9c4fb1fce44855b6fb4c9793db3fc624a01b567c09e400
4
- data.tar.gz: '00285b699105835e629127cc96801082ece7ff41c9a93d82fcb7e7a6b2662c65'
3
+ metadata.gz: 1a6bf66d7fd1c5302e88b9cd6f28f36c36d9ba8ecfcba3f32e4076c5ba856a05
4
+ data.tar.gz: d9d67e5ec55ac92e3101544c9e2d7f8f3d8e40112927c70efc23ddb117e8f96b
5
5
  SHA512:
6
- metadata.gz: aa89cca9fb72a26453a44cba2120c51ab3f47f67ec40ca8e539a1dfaeddae73687bd909e3f3880cd3eed94c7c5d4b509bb55e2450f5bf4e55a8db2f73ceaabe9
7
- data.tar.gz: 33d4200395db6f2f9a0e2dbd8b27d8c55ff66d7da87efa9c9c39663468f0dd9c43c8949b0ce09b2158875d053375e39d03e4550b821732df4d49fb52f5872cb3
6
+ metadata.gz: c241a52fe6d3f028777c0c70cea3cc68a2008cf2392d4dd9608b5332614638dce68baade016fddd46985ddcf6cddfa9638d28a86c6f645147ed52a304063a4a4
7
+ data.tar.gz: f32f203c82ddc7d4964155ac0afcfa18fc6cd6501df8a9bff9197e6fc03590cd5c71720fb8c512c64c920b503ed01d7a6118f2633e64f36f5a05ffd222af4197
data/README.md CHANGED
@@ -52,7 +52,7 @@ From command-line:
52
52
 
53
53
  # all organizations
54
54
  /usr/sbin/foreman-rake rh_cloud_insights:sync
55
-
55
+
56
56
  # specific organization with id 1
57
57
  export organization_id=1
58
58
  /usr/sbin/foreman-rake rh_cloud_insights:sync
@@ -61,6 +61,22 @@ From command-line:
61
61
 
62
62
  *Todo list here*
63
63
 
64
+ ## Design
65
+
66
+ ### Endpoints
67
+
68
+ | purpose | url | ENV setting for the **bold** part
69
+ | ------------------------------| -------| -----------
70
+ | Inventory uploads | **https://cert.cloud.redhat.com/api/ingress/v1/upload** | SATELLITE_INVENTORY_UPLOAD_URL
71
+ | Query inventory hosts list | **https://cloud.redhat.com** /api/inventory/v1/hosts?tags= | SATELLITE_RH_CLOUD_URL
72
+ | Query insights hits | **https://cloud.redhat.com** /api/insights/v1/export/hits/ | SATELLITE_RH_CLOUD_URL
73
+ | Query insights rules | **https://cloud.redhat.com** /api/insights/v1/rule/?impacting=true&rule_status=enabled&has_playbook=true&limit=&offset= | SATELLITE_RH_CLOUD_URL
74
+ | Query insights resolutions | **https://cloud.redhat.com** /api/remediations/v1/resolutions| SATELLITE_RH_CLOUD_URL
75
+ | Forward insights-client `/static` requests | **https://cloud.redhat.com** /api/static | SATELLITE_RH_CLOUD_URL
76
+ | Forward insights-client legacy `/platform` requests | **https://cert.cloud.redhat.com** /api | SATELLITE_CERT_RH_CLOUD_URL
77
+ | Forward insights-client legacy `/redhat_access/r/insights` requests | **https://cert-api.access.redhat.com** /r/insights | SATELLITE_LEGACY_INSIGHTS_URL
78
+
79
+
64
80
  ## Contributing
65
81
 
66
82
  Fork and send a Pull Request. Thanks!
@@ -81,4 +97,3 @@ GNU General Public License for more details.
81
97
 
82
98
  You should have received a copy of the GNU General Public License
83
99
  along with this program. If not, see <http://www.gnu.org/licenses/>.
84
-
@@ -9,6 +9,7 @@ module InsightsCloud
9
9
  hasToken: !Setting[:rh_cloud_token].empty?,
10
10
  hits: hits.map { |hit| hit.attributes.merge(hostname: hit.host&.name, has_playbook: hit.has_playbook?) },
11
11
  itemCount: hits.count,
12
+ isExperimentalMode: Setting[:lab_features],
12
13
  }, status: :ok
13
14
  end
14
15
 
@@ -20,6 +21,21 @@ module InsightsCloud
20
21
  }, status: :ok
21
22
  end
22
23
 
24
+ def resolutions
25
+ if remediation_all_selected_param
26
+ hits = InsightsHit.with_playbook.search_for(params[:query])
27
+ else
28
+ hits = resource_base_search_and_page.where(id: remediation_ids_param)
29
+ end
30
+
31
+ hits.preload(:host, rule: :resolutions)
32
+
33
+ render json: {
34
+ hits: hits.map { |hit| hit.attributes.merge(hostname: hit.host&.name, resolutions: hit.rule.resolutions.map(&:attributes), reboot: hit.rule.reboot_required) },
35
+ itemCount: hits.count,
36
+ }, status: :ok
37
+ end
38
+
23
39
  def model_of_controller
24
40
  ::InsightsHit
25
41
  end
@@ -32,10 +48,31 @@ module InsightsCloud
32
48
  :insights_hits
33
49
  end
34
50
 
51
+ def action_permission
52
+ case params[:action]
53
+ when 'resolutions'
54
+ 'view'
55
+ else
56
+ super
57
+ end
58
+ end
59
+
35
60
  private
36
61
 
37
62
  def host_id_param
38
63
  params.require(:host_id)
39
64
  end
65
+
66
+ def remediation_request_params
67
+ params.permit(remediations: [:hit_id, :remediation_id]).require(:remediations)
68
+ end
69
+
70
+ def remediation_ids_param
71
+ params.require(:ids).map(&:to_i)
72
+ end
73
+
74
+ def remediation_all_selected_param
75
+ ActiveModel::Type::Boolean.new.cast(params[:isAllSelected])
76
+ end
40
77
  end
41
78
  end
@@ -13,7 +13,7 @@ module InsightsCloud
13
13
  token = Setting::RhCloud.find_by_name("rh_cloud_token")
14
14
  token.value = params.require(:value)
15
15
  token.save!
16
- InsightsCloud::Async::InsightsFullSync.perform_now
16
+ ForemanTasks.sync_task(InsightsCloud::Async::InsightsFullSync)
17
17
  redirect_to(:controller => "hits", :action => 'index')
18
18
  end
19
19
 
@@ -1,8 +1,7 @@
1
1
  module InsightsCloud
2
2
  class TasksController < ::ApplicationController
3
3
  def create
4
- job = InsightsCloud::Async::InsightsFullSync.perform_later
5
- task = ForemanTasks::Task.find_by(external_id: job.provider_job_id)
4
+ task = ForemanTasks.async_task(InsightsCloud::Async::InsightsFullSync)
6
5
 
7
6
  render json: {
8
7
  task: task,
@@ -26,5 +26,11 @@ module InventorySync
26
26
  N_('Successfully uploaded to your RH cloud inventory')
27
27
  end
28
28
  end
29
+
30
+ def to_status(options = {})
31
+ # this method used to calculate status.
32
+ # Since the calculation is done externally we should return the previously calculated status
33
+ status
34
+ end
29
35
  end
30
36
  end
@@ -14,12 +14,12 @@ class Setting::RhCloud < Setting
14
14
  def self.default_settings
15
15
  return unless ActiveRecord::Base.connection.table_exists?('settings')
16
16
  [
17
- set('allow_auto_inventory_upload', N_('Allow automatic upload of the host inventory to the Red Hat cloud'), true, N_('Allow automatic inventory uploads')),
18
- set('allow_auto_insights_sync', N_('Allow recommendations synchronization from Red Hat cloud'), false, N_('Allow recommendations synchronization')),
19
- set('obfuscate_inventory_hostnames', N_('Obfuscate host names sent to Red Hat cloud'), false, N_('Obfuscate host names')),
20
- set('obfuscate_inventory_ips', N_('Obfuscate ip addresses sent to Red Hat cloud'), false, N_('Obfuscate IPs')),
17
+ set('allow_auto_inventory_upload', N_('Enable automatic upload of your host inventory to the Red Hat cloud'), true, N_('Automatic inventory upload')),
18
+ set('allow_auto_insights_sync', N_('Enable automatic synchronization of Insights recommendations from the Red Hat cloud'), false, N_('Synchronize recommendations Automatically')),
19
+ set('obfuscate_inventory_hostnames', N_('Obfuscate host names sent to the Red Hat cloud'), false, N_('Obfuscate host names')),
20
+ set('obfuscate_inventory_ips', N_('Obfuscate ipv4 addresses sent to the Red Hat cloud'), false, N_('Obfuscate host ipv4 addresses')),
21
21
  set('rh_cloud_token', N_('Authentication token to Red Hat cloud services. Used to authenticate requests to cloud APIs'), nil, N_('Red Hat Cloud token'), nil, encrypted: true),
22
- set('exclude_installed_packages', N_('Exclude installed packages from Red Hat cloud inventory report'), false, N_("Don't upload installed packages")),
22
+ set('exclude_installed_packages', N_('Exclude installed packages from being uploaded to the Red Hat cloud'), false, N_("Exclude installed Packages")),
23
23
  set('include_parameter_tags', N_('Should import include parameter tags from Foreman?'), false, N_('Include parameters in insights-client reports')),
24
24
  ]
25
25
  end
@@ -0,0 +1,78 @@
1
+ module ForemanRhCloud
2
+ class RemediationsRetriever
3
+ include CloudAuth
4
+
5
+ attr_reader :logger
6
+
7
+ def initialize(hit_remediation_pairs, logger: Logger.new(IO::NULL))
8
+ @hit_remediation_pairs = hit_remediation_pairs
9
+ @logger = logger
10
+
11
+ logger.debug("Querying playbook for #{hit_remediation_pairs}")
12
+ end
13
+
14
+ def create_playbook
15
+ response = query_playbook
16
+
17
+ logger.debug("Got playbook response: #{response.body}")
18
+
19
+ response.body
20
+ end
21
+
22
+ private
23
+
24
+ def hit_ids
25
+ @hit_remediation_pairs.map { |pair| pair["hit_id"] }
26
+ end
27
+
28
+ def remediation_ids
29
+ @hit_remediation_pairs.map { |pair| pair["resolution_id"] }
30
+ end
31
+
32
+ def hits
33
+ @hits ||= Hash[
34
+ InsightsHit.joins(:insights_facet).where(id: hit_ids).pluck(:id, 'insights_facets.uuid')
35
+ ]
36
+ end
37
+
38
+ def pairs_by_remediation_id
39
+ @hit_remediation_pairs.group_by { |pair| pair["resolution_id"] }
40
+ end
41
+
42
+ def remediations
43
+ @remediations ||= Hash[
44
+ InsightsResolution.where(id: remediation_ids).pluck(:id, :resolution_type, :rule_id).map do |id, resolution_type, rule_id|
45
+ [id, {resolution_type: resolution_type, rule_id: rule_id}]
46
+ end
47
+ ]
48
+ end
49
+
50
+ def playbook_request
51
+ {
52
+ issues: pairs_by_remediation_id.map do |remediation_id, pairs|
53
+ {
54
+ resolution: remediations[remediation_id][:resolution_type],
55
+ id: InsightsCloud.remediation_rule_id(remediations[remediation_id][:rule_id]),
56
+ systems: pairs.map do |pair|
57
+ hits[pair["hit_id"]]
58
+ end,
59
+ }
60
+ end,
61
+ }
62
+ end
63
+
64
+ def query_playbook
65
+ RestClient::Request.execute(
66
+ method: :post,
67
+ url: InsightsCloud.playbook_url,
68
+ verify_ssl: ForemanRhCloud.verify_ssl_method,
69
+ proxy: ForemanRhCloud.transformed_http_proxy_string(logger: logger),
70
+ headers: {
71
+ content_type: :json,
72
+ Authorization: "Bearer #{rh_credentials}",
73
+ },
74
+ payload: playbook_request.to_json
75
+ )
76
+ end
77
+ end
78
+ end
@@ -0,0 +1,22 @@
1
+ module ForemanRhCloud
2
+ # Macro to fetch remediation playbook from cloud.redhat.com
3
+ module TemplateRendererHelper
4
+ extend ActiveSupport::Concern
5
+ extend ApipieDSL::Module
6
+
7
+ apipie :class, 'Macros related to Red Hat cloud interface' do
8
+ name 'RHCloud'
9
+ sections only: %w[all jobs]
10
+ end
11
+
12
+ apipie :method, 'Returns a playbook generated from Red Hat cloud recommendations' do
13
+ required :hit_remediation_pairs, String, desc: 'JSON-encoded array of hashes in the form of [{hit_id: 1, remediation_id: 2}, ...]'
14
+ returns String, desc: 'Playbook generated for the specific recommendations and hosts'
15
+ end
16
+ def remediations_playbook(hit_remediation_pairs)
17
+ hit_remediation_pairs = JSON.parse(hit_remediation_pairs)
18
+ retriever = ForemanRhCloud::RemediationsRetriever.new(hit_remediation_pairs, logger: template_logger)
19
+ retriever.create_playbook
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,14 @@
1
+ <%#
2
+ kind: job_template
3
+ name: Run remediations based on Insights recommendations
4
+ job_category: Red Hat Insights
5
+ description_format: 'Insights remediations for selected issues'
6
+ feature: rh_cloud_remediate_hosts
7
+ template_inputs:
8
+ - name: hit_remediation_pairs
9
+ description: Pairs of issues and selected remediation
10
+ input_type: user
11
+ required: true
12
+ provider_type: Ansible
13
+ %>
14
+ <%= remediations_playbook(input('hit_remediation_pairs')) %>
data/config/routes.rb CHANGED
@@ -19,6 +19,7 @@ Rails.application.routes.draw do
19
19
  resources :hits, except: %i[show] do
20
20
  collection do
21
21
  get 'auto_complete_search'
22
+ get 'resolutions', to: 'hits#resolutions'
22
23
  end
23
24
  end
24
25
  match 'hits/:host_id', to: 'hits#show', via: :get
@@ -0,0 +1,10 @@
1
+ class ChangeResolutions < ActiveRecord::Migration[5.2]
2
+ def change
3
+ remove_column :insights_resolutions, :system_type, :integer
4
+ remove_column :insights_resolutions, :has_playbook, :boolean
5
+ rename_column :insights_resolutions, :resolution, :description
6
+ add_column :insights_resolutions, :needs_reboot, :boolean
7
+ add_column :insights_resolutions, :resolution_risk, :integer
8
+ add_column :insights_resolutions, :resolution_type, :string
9
+ end
10
+ end
@@ -0,0 +1,14 @@
1
+ organizations = Organization.unscoped.all
2
+ locations = Location.unscoped.all
3
+ User.as_anonymous_admin do
4
+ JobTemplate.without_auditing do
5
+ Dir[File.join("#{ForemanRhCloud::Engine.root}/app/views/job_templates/**/*.erb")].each do |template|
6
+ template = JobTemplate.import_raw!(File.read(template),
7
+ :default => true,
8
+ :lock => true,
9
+ :update => true)
10
+ template.organizations = organizations if template.present?
11
+ template.locations = locations if template.present?
12
+ end
13
+ end
14
+ end
@@ -48,7 +48,7 @@ module ForemanRhCloud
48
48
  :view_insights_hits,
49
49
  {
50
50
  '/foreman_rh_cloud/insights_cloud': [:index], # for bookmarks and later for showing the page
51
- 'insights_cloud/hits': [:index, :show, :auto_complete_search],
51
+ 'insights_cloud/hits': [:index, :show, :auto_complete_search, :resolutions],
52
52
  'insights_cloud/settings': [:index, :show],
53
53
  'react': [:index],
54
54
  },
@@ -87,6 +87,9 @@ module ForemanRhCloud
87
87
  id: 'insights',
88
88
  onlyif: proc { |host| host.insights }
89
89
  end
90
+
91
+ extend_template_helpers ForemanRhCloud::TemplateRendererHelper
92
+ allowed_template_helpers :remediations_playbook
90
93
  end
91
94
 
92
95
  ::Katello::UINotifications::Subscriptions::ManifestImportSuccess.include ForemanInventoryUpload::Notifications::ManifestImportSuccessNotificationOverride if defined?(Katello)
@@ -114,5 +117,14 @@ module ForemanRhCloud
114
117
  locale_domain = 'foreman_rh_cloud'
115
118
  Foreman::Gettext::Support.add_text_domain locale_domain, locale_dir
116
119
  end
120
+
121
+ config.to_prepare do
122
+ RemoteExecutionFeature.register(
123
+ :rh_cloud_remediate_hosts,
124
+ N_('Apply Insights recommendations'),
125
+ description: N_('Run remediation playbook generated by Insights'),
126
+ host_action_button: false
127
+ )
128
+ end
117
129
  end
118
130
  end
@@ -1,3 +1,3 @@
1
1
  module ForemanRhCloud
2
- VERSION = '3.0.19'.freeze
2
+ VERSION = '3.0.20'.freeze
3
3
  end
@@ -16,4 +16,16 @@ module InsightsCloud
16
16
  def self.rules_url(limit: ForemanRhCloud.query_limit, offset: 0)
17
17
  ForemanRhCloud.base_url + "/api/insights/v1/rule/?impacting=true&rule_status=enabled&has_playbook=true&limit=#{limit}&offset=#{offset}"
18
18
  end
19
+
20
+ def self.resolutions_url
21
+ ForemanRhCloud.base_url + '/api/remediations/v1/resolutions'
22
+ end
23
+
24
+ def self.playbook_url
25
+ ForemanRhCloud.base_url + '/api/remediations/v1/playbook'
26
+ end
27
+
28
+ def self.remediation_rule_id(rule_id)
29
+ "advisor:#{rule_id}"
30
+ end
19
31
  end
@@ -2,17 +2,19 @@ require 'rest-client'
2
2
 
3
3
  module InsightsCloud
4
4
  module Async
5
- class InsightsFullSync < ::ApplicationJob
5
+ class InsightsFullSync < ::Actions::EntryAction
6
6
  include ::ForemanRhCloud::CloudAuth
7
7
 
8
- def perform
8
+ def plan
9
9
  # This can be turned off when we enable automatic status syncs
10
10
  # This step will query cloud inventory to retrieve inventory uuids for each host
11
- ForemanTasks.sync_task(InventorySync::Async::InventoryHostsSync)
11
+ plan_hosts_sync
12
+ plan_self
13
+ plan_rules_sync
14
+ end
12
15
 
16
+ def run
13
17
  perform_hits_sync
14
-
15
- InsightsRulesSync.perform_later
16
18
  end
17
19
 
18
20
  def perform_hits_sync
@@ -25,11 +27,19 @@ module InsightsCloud
25
27
  end
26
28
 
27
29
  def logger
28
- Foreman::Logging.logger('background')
30
+ action_logger
29
31
  end
30
32
 
31
33
  private
32
34
 
35
+ def plan_hosts_sync
36
+ plan_action InventorySync::Async::InventoryHostsSync
37
+ end
38
+
39
+ def plan_rules_sync
40
+ plan_action InsightsRulesSync
41
+ end
42
+
33
43
  def query_insights_hits
34
44
  hits_response = RestClient::Request.execute(
35
45
  method: :get,
@@ -0,0 +1,69 @@
1
+ require 'rest-client'
2
+
3
+ module InsightsCloud
4
+ module Async
5
+ class InsightsResolutionsSync < ::Actions::EntryAction
6
+ include ::ForemanRhCloud::CloudAuth
7
+
8
+ RULE_ID_REGEX = /[^:]*:(?<id>.*)/
9
+
10
+ def run
11
+ InsightsResolution.transaction do
12
+ InsightsResolution.delete_all
13
+ api_response = query_insights_resolutions(relevant_rules)
14
+ write_resolutions(api_response)
15
+ end
16
+ end
17
+
18
+ def logger
19
+ action_logger
20
+ end
21
+
22
+ private
23
+
24
+ def query_insights_resolutions(rule_ids)
25
+ resolutions_response = RestClient::Request.execute(
26
+ method: :post,
27
+ url: InsightsCloud.resolutions_url,
28
+ verify_ssl: ForemanRhCloud.verify_ssl_method,
29
+ proxy: ForemanRhCloud.transformed_http_proxy_string(logger: logger),
30
+ headers: {
31
+ content_type: :json,
32
+ Authorization: "Bearer #{rh_credentials}",
33
+ },
34
+ payload: {
35
+ issues: rule_ids,
36
+ }.to_json
37
+ )
38
+
39
+ JSON.parse(resolutions_response)
40
+ end
41
+
42
+ def relevant_rules
43
+ InsightsRule.all.pluck(:rule_id).map { |id| InsightsCloud.remediation_rule_id(id) }
44
+ end
45
+
46
+ def to_resolution_hash(rule_id, resolution_hash)
47
+ {
48
+ rule_id: rule_id,
49
+ description: resolution_hash['description'],
50
+ resolution_type: resolution_hash['id'],
51
+ needs_reboot: resolution_hash['needs_reboot'],
52
+ resolution_risk: resolution_hash['resolution_risk'],
53
+ }
54
+ end
55
+
56
+ def write_resolutions(response)
57
+ all_resolutions = response.map do |rule_id, rule_details|
58
+ rule_details['resolutions'].map { |resolution| to_resolution_hash(to_rule_id(rule_id), resolution) }
59
+ end.flatten
60
+
61
+ InsightsResolution.create(all_resolutions)
62
+ end
63
+
64
+ def to_rule_id(resolution_rule_id)
65
+ RULE_ID_REGEX.match(resolution_rule_id).named_captures.fetch('id', resolution_rule_id)
66
+ end
67
+ end
68
+ end
69
+ end