foreman_rh_cloud 11.0.3 → 11.1.0

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.
Files changed (57) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +2 -2
  3. data/app/controllers/api/v2/advisor_engine/advisor_engine_controller.rb +98 -0
  4. data/app/controllers/api/v2/rh_cloud/advisor_engine_config_controller.rb +16 -0
  5. data/app/models/concerns/rh_cloud_host.rb +5 -0
  6. data/app/services/foreman_rh_cloud/cloud_connector.rb +1 -1
  7. data/app/services/foreman_rh_cloud/cloud_request.rb +1 -1
  8. data/app/services/foreman_rh_cloud/hits_uploader.rb +55 -0
  9. data/app/views/api/v2/advisor_engine/host_details.json.rabl +9 -0
  10. data/app/views/api/v2/hosts/insights/base.rabl +5 -0
  11. data/app/views/api/v2/hosts/insights/insights.rabl +3 -0
  12. data/config/routes.rb +6 -1
  13. data/db/migrate/20241217190624_add_unique_index_to_rule_id_and_host_id_in_insights_hits.rb +5 -0
  14. data/db/migrate/20241220184900_change_sync_insights_recommendations_to_true.rb +5 -0
  15. data/lib/foreman_inventory_upload/async/generate_all_reports_job.rb +21 -13
  16. data/lib/foreman_inventory_upload/async/upload_report_job.rb +1 -1
  17. data/lib/foreman_inventory_upload/generators/slice.rb +1 -1
  18. data/lib/foreman_rh_cloud/engine.rb +24 -5
  19. data/lib/foreman_rh_cloud/version.rb +1 -1
  20. data/lib/foreman_rh_cloud.rb +21 -31
  21. data/lib/insights_cloud/async/insights_scheduled_sync.rb +10 -2
  22. data/lib/inventory_sync/async/inventory_full_sync.rb +0 -10
  23. data/lib/inventory_sync/async/inventory_scheduled_sync.rb +15 -7
  24. data/package.json +1 -1
  25. data/test/controllers/insights_cloud/api/advisor_engine_controller_test.rb +48 -0
  26. data/test/controllers/insights_sync/settings_controller_test.rb +3 -0
  27. data/test/factories/insights_factories.rb +1 -1
  28. data/test/jobs/inventory_scheduled_sync_test.rb +10 -0
  29. data/test/unit/rh_cloud_http_proxy_test.rb +1 -26
  30. data/test/unit/services/foreman_rh_cloud/hits_uploader_test.rb +120 -0
  31. data/webpack/ForemanInventoryUpload/Components/PageHeader/__tests__/__snapshots__/PageTitle.test.js.snap +1 -1
  32. data/webpack/ForemanInventoryUpload/Components/PageHeader/components/CloudConnectorButton/CloudConnectorButton.js +2 -2
  33. data/webpack/ForemanInventoryUpload/Components/PageHeader/components/CloudConnectorButton/__tests__/__snapshots__/CloudConnectorButton.test.js.snap +2 -2
  34. data/webpack/ForemanInventoryUpload/Components/PageHeader/components/PageDescription/PageDescription.js +3 -1
  35. data/webpack/ForemanInventoryUpload/Components/PageHeader/components/PageDescription/__tests__/__snapshots__/PageDescription.test.js.snap +1 -1
  36. data/webpack/ForemanInventoryUpload/Components/PageHeader/components/SyncButton/__tests__/__snapshots__/SyncButton.test.js.snap +1 -1
  37. data/webpack/ForemanInventoryUpload/Components/TabHeader/TabHeader.js +1 -1
  38. data/webpack/ForemanInventoryUpload/ForemanInventoryConstants.js +1 -1
  39. data/webpack/ForemanInventoryUpload/ForemanInventoryHelpers.js +1 -1
  40. data/webpack/InsightsCloudSync/Components/InsightsSettings/InsightsSettings.js +26 -22
  41. data/webpack/InsightsCloudSync/Components/InsightsSettings/InsightsSettingsActions.js +2 -1
  42. data/webpack/InsightsCloudSync/Components/InsightsTable/InsightsTable.js +10 -1
  43. data/webpack/InsightsCloudSync/Components/InsightsTable/InsightsTableConstants.js +8 -1
  44. data/webpack/InsightsCloudSync/Components/InsightsTable/InsightsTableHelpers.js +3 -1
  45. data/webpack/InsightsCloudSync/Components/ToolbarDropdown.js +5 -0
  46. data/webpack/InsightsCloudSync/InsightsCloudSync.js +1 -2
  47. data/webpack/InsightsCloudSync/__snapshots__/InsightsCloudSync.test.js.snap +1 -1
  48. data/webpack/InsightsHostDetailsTab/NewHostDetailsTab.js +3 -1
  49. data/webpack/__mocks__/foremanReact/common/hooks/API/APIHooks.js +3 -0
  50. data/webpack/common/Hooks/ConfigHooks.js +19 -0
  51. metadata +17 -9
  52. data/webpack/InsightsCloudSync/Components/InsightsHeader/InsightsHeader.scss +0 -8
  53. data/webpack/InsightsCloudSync/Components/InsightsHeader/index.js +0 -16
  54. data/webpack/InsightsCloudSync/Components/InsightsSettings/__tests__/InsightsSettings.test.js +0 -18
  55. data/webpack/InsightsCloudSync/Components/InsightsSettings/__tests__/__snapshots__/InsightsSettings.test.js.snap +0 -15
  56. data/webpack/InsightsCloudSync/Components/__tests__/InsightsHeader.test.js +0 -10
  57. data/webpack/InsightsCloudSync/Components/__tests__/__snapshots__/InsightsHeader.test.js.snap +0 -13
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 9feba25e71b2e6db50de3b2f32665a4889dce130fa44dcc7ef461116ba2abf62
4
- data.tar.gz: ec6ce86e970247fab7b565831b414b2a15cb3e2e7ac2f678ccbbd2a43b6692d9
3
+ metadata.gz: a0510d9fc263ac8ff7313350cdcdf6fc82e0d13c35c5e8936463f1d5f7367d88
4
+ data.tar.gz: 14561397aed26a96af5a7105c24147c7cf31d9235ea987d065dcb451fb7b05a7
5
5
  SHA512:
6
- metadata.gz: d98ca68b9fde700bbc66dd6bdfad34bbd50d8d9b6558e47f9f2c13a538330b53bea3b319e4e9861c41884f9c6397b21c882de7a255bffab45c3a157196fe60e4
7
- data.tar.gz: bbafd13720bb8e60ae2e9c2af9d8888cc231fcba509f046f76d5b3c560cb78642c7f8a12fbe6d9feb489fb6a11d955739568f9effb9447201e8411980f7a6989
6
+ metadata.gz: 7947b880d5a0e7544f1e668d59f67bf5ec8169a4a0d0fd5922160949cd60636e1f8294637f033df4d1df18a624deb207d16da95292511731735e530f1d959534
7
+ data.tar.gz: 58f596790b70a0daa7174ba6360094d2bbf024cacce3cda74e2dedb8319333395df96ce0590c4cf397f3bd6ca3f5c36c89e839fe6fa364beb62314d533050483
data/README.md CHANGED
@@ -15,7 +15,7 @@ for how to install Foreman plugins
15
15
 
16
16
  #### Inventory upload
17
17
 
18
- In UI: Configure -> Inventory Upload -> Restart
18
+ In UI: Configure -> Inventory Upload -> Generate and upload report
19
19
 
20
20
  From command-line:
21
21
 
@@ -46,7 +46,7 @@ From command-line:
46
46
 
47
47
  #### Synchronize inventory status
48
48
 
49
- In UI: Configure -> Inventory Upload -> Sync inventory status
49
+ In UI: Configure -> Inventory Upload -> Sync all inventory status
50
50
 
51
51
  From command-line:
52
52
 
@@ -0,0 +1,98 @@
1
+ module Api
2
+ module V2
3
+ module AdvisorEngine
4
+ class AdvisorEngineController < ::Api::V2::BaseController
5
+ include ::Api::Version2
6
+ include Foreman::Controller::SmartProxyAuth
7
+ include ::Foreman::Controller::FilterParameters
8
+
9
+ filter_parameters :payload
10
+ add_smart_proxy_filters [:host_details, :upload_hits]
11
+
12
+ api :GET, "/advisor_engine/host_details", N_('Fetch Insights-related host details')
13
+ param :host_uuids, Array, required: true, desc: N_('List of host UUIDs')
14
+ def host_details
15
+ uuids = params.require(:host_uuids)
16
+ @hosts = ::Host.joins(:insights).where(:insights => { :uuid => uuids })
17
+ if @hosts.empty?
18
+ render json: { error: 'No hosts found for the given UUIDs' }, status: :not_found
19
+ else
20
+ respond_to do |format|
21
+ format.json { render 'api/v2/advisor_engine/host_details' }
22
+ end
23
+ end
24
+ end
25
+
26
+ api :PATCH, "/advisor_engine/upload_hits", N_("Upload hits from iop-advisor-engine")
27
+ param :host_name, String, required: true
28
+ param :host_uuid, String
29
+
30
+ param :payload, Hash, :desc => N_("iop payload including resolutions, rules, hits") do
31
+ param :resolutions, Array, :desc => N_("upload resolutions related to the hits") do
32
+ param :rule_id, String, :desc => N_("rule id"), :required => true
33
+ param :description, String, :desc => N_("resolution description")
34
+ param :needs_reboot, :bool, :desc => N_("Whether the resolution requires reboot")
35
+ param :resolution_risk, String, :desc => N_("resolution risk")
36
+ param :resolution_type, String, :desc => N_("type")
37
+ end
38
+
39
+ param :rules, Array, :desc => N_("Upload rules related to the hits") do
40
+ param :rule_id, String, :desc => N_("rule id"), :required => true
41
+ param :description, String, :desc => N_("rule description")
42
+ param :category_name, String, :desc => N_("category name")
43
+ param :impact_name, String, :desc => N_("impact name")
44
+ param :summary, String, :desc => N_("summary")
45
+ param :generic, String, :desc => N_("generic")
46
+ param :reason, String, :desc => N_("reason")
47
+ param :total_risk, :number, :desc => N_("total risk")
48
+ param :reboot_required, :bool, :desc => N_("reboot required")
49
+ param :more_info, String, :desc => N_("more info")
50
+ param :rating, :number, :desc => N_("rating")
51
+ end
52
+
53
+ param :hits, Array, :desc => N_("Upload hits information") do
54
+ param :rule_id, String, :desc => N_("rule id"), :required => true
55
+ param :title, String, :desc => N_("rule title")
56
+ param :solution_url, String, :desc => N_("solution url")
57
+ param :total_risk, :number, :desc => N_("total risk")
58
+ param :likelihood, :number, :desc => N_("likelihood number")
59
+ param :publish_date, String, :desc => N_("publish date (YYYY-MM-DD)")
60
+ param :results_url, String, :desc => N_("result url")
61
+ end
62
+ param :details, String, :desc => N_("upload hits details json")
63
+ end
64
+
65
+ def upload_hits
66
+ host = Host.find_by(name: params.require(:host_name))
67
+ if host.blank?
68
+ render json: { error: 'No host found for the given host name' }, status: :not_found
69
+ else
70
+ hits_uploader = ForemanRhCloud::HitsUploader.new(host: host, payload: payload_params.to_h, uuid: params[:host_uuid])
71
+ hits_uploader.upload!
72
+ render json: {
73
+ action_status: 'success',
74
+ }, status: :ok
75
+ end
76
+ end
77
+
78
+ def payload_params
79
+ params.require(:payload).permit(
80
+ :details,
81
+ {
82
+ resolutions: [
83
+ :rule_id, :description, :needs_reboot, :resolution_risk, :resolution_type
84
+ ],
85
+ rules: [
86
+ :rule_id, :description, :category_name, :impact_name, :summary, :generic,
87
+ :reason, :total_risk, :reboot_required, :more_info, :rating
88
+ ],
89
+ hits: [
90
+ :rule_id, :title, :solution_url, :total_risk, :likelihood, :publish_date, :results_url
91
+ ],
92
+ }
93
+ )
94
+ end
95
+ end
96
+ end
97
+ end
98
+ end
@@ -0,0 +1,16 @@
1
+ module Api
2
+ module V2
3
+ module RhCloud
4
+ class AdvisorEngineConfigController < ::Api::V2::BaseController
5
+ include ::Api::Version2
6
+
7
+ api :GET, "/rh_cloud/advisor_engine_config", N_("Show if system is configured to use local iop-advisor-engine.")
8
+ def show
9
+ render json: {
10
+ use_local_advisor_engine: ForemanRhCloud.with_local_advisor_engine?,
11
+ }, status: :ok
12
+ end
13
+ end
14
+ end
15
+ end
16
+ end
@@ -21,5 +21,10 @@ module RhCloudHost
21
21
  scoped_search :relation => :inventory_sync_status_object, :on => :status, :rename => :insights_inventory_sync_status,
22
22
  :complete_value => { :disconnect => ::InventorySync::InventoryStatus::DISCONNECT,
23
23
  :sync => ::InventorySync::InventoryStatus::SYNC }
24
+ scoped_search :relation => :insights, :on => :uuid, :only_explicit => true, :rename => :insights_uuid
25
+
26
+ def insights_facet
27
+ insights
28
+ end
24
29
  end
25
30
  end
@@ -17,7 +17,7 @@ module ForemanRhCloud
17
17
  :satellite_cloud_connector_password => token_value,
18
18
  }
19
19
 
20
- if (http_proxy = ForemanRhCloud.proxy_setting(logger: Foreman::Logging.logger('app')))
20
+ if (http_proxy = ForemanRhCloud.proxy_setting)
21
21
  input[:satellite_cloud_connector_http_proxy] = http_proxy
22
22
  end
23
23
 
@@ -5,7 +5,7 @@ module ForemanRhCloud
5
5
  def execute_cloud_request(params)
6
6
  final_params = {
7
7
  verify_ssl: ForemanRhCloud.verify_ssl_method,
8
- proxy: ForemanRhCloud.transformed_http_proxy_string(logger: logger),
8
+ proxy: ForemanRhCloud.transformed_http_proxy_string,
9
9
  }.deep_merge(params)
10
10
 
11
11
  response = RestClient::Request.execute(final_params)
@@ -0,0 +1,55 @@
1
+ module ForemanRhCloud
2
+ class HitsUploader
3
+ def initialize(host:, payload:, uuid: nil)
4
+ @host = host
5
+ @uuid = uuid
6
+ @payload = payload
7
+ end
8
+
9
+ def upload!
10
+ ActiveRecord::Base.transaction do
11
+ update_facets
12
+ update_hits
13
+ update_rules_and_resolutions
14
+ update_details
15
+ end
16
+ end
17
+
18
+ private
19
+
20
+ def update_facets
21
+ facet = InsightsFacet.find_or_create_by(host_id: @host.id)
22
+ facet.update!(uuid: @uuid) if @uuid.present?
23
+ @host.reload
24
+ end
25
+
26
+ def update_hits
27
+ facet = @host.insights
28
+ facet.hits.delete_all
29
+ hits = @payload[:hits]
30
+ # rubocop:disable Rails/SkipsModelValidations
31
+ facet.hits.insert_all(hits) if hits.present?
32
+ # rubocop:enable Rails/SkipsModelValidations
33
+ InsightsFacet.reset_counters(facet.id, :hits_count)
34
+ end
35
+
36
+ def update_rules_and_resolutions
37
+ return if @payload[:rules].blank?
38
+ # rubocop:disable Rails/SkipsModelValidations
39
+ ::InsightsRule.upsert_all(@payload[:rules], unique_by: :rule_id)
40
+ rules = @payload[:rules].map { |rule| rule[:rule_id] }
41
+
42
+ return if @payload[:resolutions].blank?
43
+ ::InsightsResolution.where(rule_id: rules).delete_all
44
+ ::InsightsResolution.insert_all(@payload[:resolutions])
45
+ # rubocop:enable Rails/SkipsModelValidations
46
+ end
47
+
48
+ def update_details
49
+ return if @payload[:details].blank?
50
+ fact_name = FactName.where(name: "insights::hit_details", short_name: 'insights_details').first_or_create
51
+ fact_value = @host.fact_values.where(fact_name: fact_name).first_or_create
52
+ fact_value.update(value: @payload[:details])
53
+ end
54
+ end
55
+ end
@@ -0,0 +1,9 @@
1
+ collection @hosts
2
+
3
+ attributes :name
4
+ node :insights_uuid do |host|
5
+ host.insights_facet&.uuid
6
+ end
7
+ node :insights_hit_details do |host|
8
+ host&.facts('insights::hit_details')&.values&.first
9
+ end
@@ -0,0 +1,5 @@
1
+ attributes :uuid
2
+
3
+ node :insights_hit_details do |facet|
4
+ facet&.host&.facts('insights::hit_details')&.values&.first
5
+ end
@@ -0,0 +1,3 @@
1
+ node :insights_attributes do
2
+ partial 'api/v2/hosts/insights/base', object: @object&.insights_facet
3
+ end
data/config/routes.rb CHANGED
@@ -62,8 +62,13 @@ Rails.application.routes.draw do
62
62
 
63
63
  namespace 'rh_cloud' do
64
64
  post 'enable_connector', to: 'inventory#enable_cloud_connector'
65
-
66
65
  post 'cloud_request', to: 'cloud_request#update'
66
+ get 'advisor_engine_config', to: 'advisor_engine_config#show'
67
+ end
68
+
69
+ namespace 'advisor_engine' do
70
+ get 'host_details', to: 'advisor_engine#host_details'
71
+ patch 'upload_hits', to: 'advisor_engine#upload_hits'
67
72
  end
68
73
  end
69
74
  end
@@ -0,0 +1,5 @@
1
+ class AddUniqueIndexToRuleIdAndHostIdInInsightsHits < ActiveRecord::Migration[7.0]
2
+ def change
3
+ add_index :insights_hits, [:rule_id, :host_id], unique: true, name: 'index_insight_hits_on_rule_id_and_host_id'
4
+ end
5
+ end
@@ -0,0 +1,5 @@
1
+ class ChangeSyncInsightsRecommendationsToTrue < ActiveRecord::Migration[7.0]
2
+ def change
3
+ Setting.where(name: 'allow_auto_insights_sync')&.destroy_all
4
+ end
5
+ end
@@ -13,22 +13,30 @@ module ForemanInventoryUpload
13
13
  return
14
14
  end
15
15
 
16
- after_delay do
17
- organizations = Organization.unscoped.all
18
-
19
- organizations.map do |organization|
20
- total_hosts = ForemanInventoryUpload::Generators::Queries.for_org(organization.id, use_batches: false).count
21
-
22
- if total_hosts <= ForemanInventoryUpload.max_org_size
23
- disconnected = false
24
- plan_generate_report(ForemanInventoryUpload.generated_reports_folder, organization, disconnected)
25
- else
26
- logger.info("Skipping automatic uploads for organization #{organization.name}, too many hosts (#{total_hosts}/#{ForemanInventoryUpload.max_org_size})")
27
- end
28
- end.compact
16
+ if ForemanRhCloud.with_local_advisor_engine?
17
+ plan_self # so that 'run' runs
18
+ else
19
+ after_delay do
20
+ organizations = Organization.unscoped.all
21
+
22
+ organizations.map do |organization|
23
+ total_hosts = ForemanInventoryUpload::Generators::Queries.for_org(organization.id, use_batches: false).count
24
+
25
+ if total_hosts <= ForemanInventoryUpload.max_org_size
26
+ disconnected = false
27
+ plan_generate_report(ForemanInventoryUpload.generated_reports_folder, organization, disconnected)
28
+ else
29
+ logger.info("Skipping automatic uploads for organization #{organization.name}, too many hosts (#{total_hosts}/#{ForemanInventoryUpload.max_org_size})")
30
+ end
31
+ end.compact
32
+ end
29
33
  end
30
34
  end
31
35
 
36
+ def run
37
+ output[:status] = _('The scheduled process is disabled because this Foreman is configured with the use_local_advisor_engine option.') if ForemanRhCloud.with_local_advisor_engine?
38
+ end
39
+
32
40
  def rescue_strategy_for_self
33
41
  Dynflow::Action::Rescue::Fail
34
42
  end
@@ -51,7 +51,7 @@ module ForemanInventoryUpload
51
51
  'CER_PATH' => @cer_path
52
52
  )
53
53
 
54
- http_proxy_string = ForemanRhCloud.http_proxy_string(logger: logger)
54
+ http_proxy_string = ForemanRhCloud.http_proxy_string
55
55
  if http_proxy_string
56
56
  env_vars['http_proxy'] = http_proxy_string
57
57
  env_vars['https_proxy'] = http_proxy_string
@@ -47,7 +47,7 @@ module ForemanInventoryUpload
47
47
  @stream.simple_field('packages_0_signature', fact_value(host, 'conversions::packages::0::signature'))
48
48
  @stream.simple_field('activity_started', fact_value(host, 'conversions::activity_started'))
49
49
  @stream.simple_field('activity_ended', fact_value(host, 'conversions::activity_ended'))
50
- @stream.simple_field('success', fact_value(host, 'conversions::success') || false, :last)
50
+ @stream.simple_field('success', ActiveModel::Type::Boolean.new.cast(fact_value(host, 'conversions::success')), :last)
51
51
  end
52
52
 
53
53
  def report_host(host)
@@ -42,7 +42,7 @@ module ForemanRhCloud
42
42
  settings do
43
43
  category(:rh_cloud, N_('RHCloud')) do
44
44
  setting('allow_auto_inventory_upload', type: :boolean, description: N_('Enable automatic upload of your host inventory to the Red Hat cloud'), default: true, full_name: N_('Automatic inventory upload'))
45
- setting('allow_auto_insights_sync', type: :boolean, description: N_('Enable automatic synchronization of Insights recommendations from the Red Hat cloud'), default: false, full_name: N_('Synchronize recommendations Automatically'))
45
+ setting('allow_auto_insights_sync', type: :boolean, description: N_('Enable automatic synchronization of Insights recommendations from the Red Hat cloud'), default: true, full_name: N_('Synchronize recommendations Automatically'))
46
46
  setting('allow_auto_insights_mismatch_delete', type: :boolean, description: N_('Enable automatic deletion of mismatched host records from the Red Hat cloud'), default: false, full_name: N_('Automatic mismatch deletion'))
47
47
  setting('obfuscate_inventory_hostnames', type: :boolean, description: N_('Obfuscate host names sent to the Red Hat cloud'), default: false, full_name: N_('Obfuscate host names'))
48
48
  setting('obfuscate_inventory_ips', type: :boolean, description: N_('Obfuscate ipv4 addresses sent to the Red Hat cloud'), default: false, full_name: N_('Obfuscate host ipv4 addresses'))
@@ -74,6 +74,7 @@ module ForemanRhCloud
74
74
  'foreman_inventory_upload/cloud_status': [:index],
75
75
  'foreman_inventory_upload/uploads_settings': [:index],
76
76
  'foreman_inventory_upload/missing_hosts': [:index],
77
+ 'api/v2/rh_cloud/advisor_engine_config': [:show],
77
78
  'react': [:index]
78
79
  )
79
80
  permission(
@@ -105,13 +106,21 @@ module ForemanRhCloud
105
106
  Role::MANAGER => plugin_permissions,
106
107
  Role::SYSTEM_ADMIN => plugin_permissions
107
108
 
108
- # Adding a sub menu after hosts menu
109
- divider :top_menu, caption: N_('RH Cloud'), parent: :configure_menu
110
- menu :top_menu, :inventory_upload, caption: N_('Inventory Upload'), url: '/foreman_rh_cloud/inventory_upload', url_hash: { controller: :react, action: :index }, parent: :configure_menu
111
- menu :top_menu, :insights_hits, caption: N_('Insights'), url: '/foreman_rh_cloud/insights_cloud', url_hash: { controller: :react, action: :index }, parent: :configure_menu
109
+ # Adding a top-level menu item
110
+ sub_menu :top_menu, :insights_menu, caption: N_('Insights'), icon: 'fa fa-cloud', after: :hosts_menu do
111
+ menu :top_menu,
112
+ :inventory_upload,
113
+ caption: N_('Inventory Upload'),
114
+ url: '/foreman_rh_cloud/inventory_upload',
115
+ url_hash: { controller: :react, action: :index },
116
+ parent: :insights_menu,
117
+ if: -> { !ForemanRhCloud.with_local_advisor_engine? }
118
+ menu :top_menu, :insights_hits, caption: N_('Recommendations'), url: '/foreman_rh_cloud/insights_cloud', url_hash: { controller: :react, action: :index }, parent: :insights_menu
119
+ end
112
120
 
113
121
  register_facet InsightsFacet, :insights do
114
122
  configure_host do
123
+ api_view :list => 'api/v2/hosts/insights/insights'
115
124
  set_dependent_action :destroy
116
125
  end
117
126
  end
@@ -151,6 +160,12 @@ module ForemanRhCloud
151
160
  end
152
161
  end
153
162
 
163
+ initializer "foreman_rh_cloud.add_rabl_view_path" do
164
+ Rabl.configure do |config|
165
+ config.view_paths << ForemanRhCloud::Engine.root.join('app', 'views')
166
+ end
167
+ end
168
+
154
169
  initializer 'foreman_rh_cloud.register_scheduled_tasks', :before => :finisher_hook do |_app|
155
170
  # skip database manipulations while tables do not exist, like in migrations
156
171
  # skip object creation when admin user is not present, for example in test DB
@@ -193,4 +208,8 @@ module ForemanRhCloud
193
208
  end
194
209
  end
195
210
  end
211
+
212
+ def self.with_local_advisor_engine?
213
+ SETTINGS.dig(:foreman_rh_cloud, :use_local_advisor_engine) || false
214
+ end
196
215
  end
@@ -1,3 +1,3 @@
1
1
  module ForemanRhCloud
2
- VERSION = '11.0.3'.freeze
2
+ VERSION = '11.1.0'.freeze
3
3
  end
@@ -3,17 +3,27 @@ require 'cgi'
3
3
  require 'uri'
4
4
 
5
5
  module ForemanRhCloud
6
+ def self.on_premise_url
7
+ return unless ForemanRhCloud.with_local_advisor_engine?
8
+ port = ENV['ADVISOR_ENGINE_PORT'] || "24443"
9
+ ENV['ADVISOR_ENGINE_URL'] || "https://localhost:#{port}"
10
+ end
11
+
12
+ def self.env_or_on_premise_url(env_var_name)
13
+ ENV[env_var_name] || on_premise_url
14
+ end
15
+
6
16
  def self.base_url
7
17
  # for testing set ENV to 'https://ci.cloud.redhat.com'
8
- @base_url ||= ENV['SATELLITE_RH_CLOUD_URL'] || 'https://cloud.redhat.com'
18
+ @base_url ||= env_or_on_premise_url('SATELLITE_RH_CLOUD_URL') || 'https://cloud.redhat.com'
9
19
  end
10
20
 
11
21
  def self.cert_base_url
12
- @cert_base_url ||= ENV['SATELLITE_CERT_RH_CLOUD_URL'] || 'https://cert.cloud.redhat.com'
22
+ @cert_base_url ||= env_or_on_premise_url('SATELLITE_CERT_RH_CLOUD_URL') || 'https://cert.cloud.redhat.com'
13
23
  end
14
24
 
15
25
  def self.legacy_insights_url
16
- @legacy_insights_url ||= ENV['SATELLITE_LEGACY_INSIGHTS_URL'] || 'https://cert-api.access.redhat.com'
26
+ @legacy_insights_url ||= env_or_on_premise_url('SATELLITE_LEGACY_INSIGHTS_URL') || 'https://cert-api.access.redhat.com'
17
27
  end
18
28
 
19
29
  def self.verify_ssl_method
@@ -24,21 +34,20 @@ module ForemanRhCloud
24
34
  @query_limit ||= ENV['SATELLITE_RH_CLOUD_QUERY_LIMIT'] ? ENV['SATELLITE_RH_CLOUD_QUERY_LIMIT'].to_i : 100
25
35
  end
26
36
 
27
- def self.http_proxy_string(logger: Foreman::Logging.logger('background'))
28
- ForemanRhCloud.proxy_setting(logger: logger)
37
+ def self.http_proxy_string
38
+ ForemanRhCloud.proxy_setting
29
39
  end
30
40
 
31
- def self.transformed_http_proxy_string(logger: Foreman::Logging.logger('background'))
32
- ForemanRhCloud.transform_scheme(ForemanRhCloud.proxy_setting(logger: logger))
41
+ def self.transformed_http_proxy_string
42
+ ForemanRhCloud.transform_scheme(ForemanRhCloud.proxy_setting)
33
43
  end
34
44
 
35
- def self.proxy_setting(logger: Foreman::Logging.logger('background'))
36
- fix_port(proxy_string(logger: logger))
45
+ def self.proxy_setting
46
+ fix_port(proxy_string)
37
47
  end
38
48
 
39
- def self.proxy_string(logger: Foreman::Logging.logger('background'))
49
+ def self.proxy_string
40
50
  HttpProxy.default_global_content_proxy&.full_url ||
41
- ForemanRhCloud.cdn_proxy(logger: logger) ||
42
51
  ForemanRhCloud.global_foreman_proxy ||
43
52
  ''
44
53
  end
@@ -52,25 +61,6 @@ module ForemanRhCloud
52
61
  uri.to_s
53
62
  end
54
63
 
55
- def self.cdn_proxy(logger: Foreman::Logging.logger('app'))
56
- proxy_config = SETTINGS[:katello][:cdn_proxy]
57
- return nil unless proxy_config
58
-
59
- uri = URI('')
60
- uri.host = proxy_config[:host]
61
- uri.port = proxy_config[:port]
62
- uri.scheme = proxy_config[:scheme] || 'http'
63
-
64
- if proxy_config[:user]
65
- uri.user = CGI.escape(proxy_config[:user])
66
- uri.password = CGI.escape(proxy_config[:password])
67
- end
68
- uri.to_s
69
- rescue URI::Error => e
70
- logger.warn("cdn_proxy parsing failed: #{e}")
71
- nil
72
- end
73
-
74
64
  def self.global_foreman_proxy
75
65
  Setting[:http_proxy]
76
66
  end
@@ -114,7 +104,7 @@ module ForemanRhCloud
114
104
  end
115
105
 
116
106
  def self.legacy_insights_ca
117
- "#{ForemanRhCloud::Engine.root}/config/rh_cert-api_chain.pem"
107
+ "#{ForemanRhCloud::Engine.root}/config/rh_cert-api_chain.pem" unless ForemanRhCloud.with_local_advisor_engine?
118
108
  end
119
109
 
120
110
  def self.cloud_url_validator
@@ -13,11 +13,19 @@ module InsightsCloud
13
13
  return
14
14
  end
15
15
 
16
- after_delay do
17
- plan_full_sync
16
+ if ForemanRhCloud.with_local_advisor_engine?
17
+ plan_self
18
+ else
19
+ after_delay do
20
+ plan_full_sync # so that 'run' runs
21
+ end
18
22
  end
19
23
  end
20
24
 
25
+ def run
26
+ output[:status] = _('The scheduled process is disabled because this Foreman is configured with the use_local_advisor_engine option.') if ForemanRhCloud.with_local_advisor_engine?
27
+ end
28
+
21
29
  def plan_full_sync
22
30
  plan_action(InsightsFullSync, Organization.unscoped.all)
23
31
  end
@@ -28,16 +28,6 @@ module InventorySync
28
28
  output[:host_statuses] = host_statuses
29
29
  end
30
30
 
31
- def clear_inventory_statuses_for_hosts_with_insights_false
32
- host_ids_to_delete = Host.joins(:host_parameters).where(id: InventorySync::InventoryStatus.select(:host_id), host_parameters: { name: 'host_registration_insights', value: false })
33
- if host_ids_to_delete.present?
34
- InventorySync::InventoryStatus.where(host_id: host_ids_to_delete).delete_all
35
- Host.where(id: host_ids_to_delete).find_each(&:refresh_global_status!)
36
- else
37
- logger.debug('No hosts with host_registration_insights set to false found')
38
- end
39
- end
40
-
41
31
  def update_statuses_batch
42
32
  results = yield
43
33
 
@@ -13,13 +13,17 @@ module InventorySync
13
13
  return
14
14
  end
15
15
 
16
- after_delay do
17
- # perform a sequence of sync then delete in parallel for all organizations
18
- concurrence do
19
- Organization.unscoped.each do |org|
20
- sequence do
21
- plan_org_sync(org)
22
- plan_remove_insights_hosts(org.id) if Setting[:allow_auto_insights_mismatch_delete]
16
+ if ForemanRhCloud.with_local_advisor_engine?
17
+ plan_self # so that 'run' runs
18
+ else
19
+ after_delay do
20
+ # perform a sequence of sync then delete in parallel for all organizations
21
+ concurrence do
22
+ Organization.unscoped.each do |org|
23
+ sequence do
24
+ plan_org_sync(org)
25
+ plan_remove_insights_hosts(org.id) if Setting[:allow_auto_insights_mismatch_delete]
26
+ end
23
27
  end
24
28
  end
25
29
  end
@@ -30,6 +34,10 @@ module InventorySync
30
34
  plan_action InventoryFullSync, org
31
35
  end
32
36
 
37
+ def run
38
+ output[:status] = _('The scheduled process is disabled because this Foreman is configured with the use_local_advisor_engine option.') if ForemanRhCloud.with_local_advisor_engine?
39
+ end
40
+
33
41
  def plan_remove_insights_hosts(org_id)
34
42
  # plan a remove hosts action with search set to empty (all records)
35
43
  plan_action(ForemanInventoryUpload::Async::RemoveInsightsHostsJob, '', org_id)
data/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "foreman_rh_cloud",
3
- "version": "11.0.3",
3
+ "version": "11.1.0",
4
4
  "description": "Inventory Upload =============",
5
5
  "main": "index.js",
6
6
  "scripts": {
@@ -0,0 +1,48 @@
1
+ require 'test_plugin_helper'
2
+
3
+ module InsightsCloud
4
+ module Api
5
+ class AdvisorEngineControllerTest < ActionController::TestCase
6
+ tests ::Api::V2::AdvisorEngine::AdvisorEngineController
7
+
8
+ setup do
9
+ @test_org = FactoryBot.create(:organization)
10
+ @host1 = FactoryBot.create(:host, :with_insights_hits, organization: @test_org, hostname: 'insightshost1')
11
+ @host2 = FactoryBot.create(:host, :with_insights_hits, organization: @test_org, hostname: 'insightshost2')
12
+ @host3 = FactoryBot.create(:host, organization: @test_org)
13
+ end
14
+
15
+ test 'shows hosts with uuids' do
16
+ uuids = [@host1.insights.uuid, @host2.insights.uuid]
17
+ get :host_details, params: { organization_id: @test_org.id, host_uuids: uuids }
18
+ assert_response :success
19
+ assert_template 'api/v2/advisor_engine/host_details'
20
+ assert_equal @test_org.hosts.joins(:insights).where(:insights => { :uuid => uuids }).count, assigns(:hosts).count
21
+ refute_equal @test_org.hosts.count, assigns(:hosts).count
22
+ end
23
+
24
+ test 'shows error when no hosts found' do
25
+ get :host_details, params: { organization_id: @test_org.id, host_uuids: ['nonexistentuuid'] }
26
+ assert_response :not_found
27
+ assert_equal 'No hosts found for the given UUIDs', JSON.parse(response.body)['error']
28
+ end
29
+
30
+ test 'test upload hits with payload' do
31
+ uuid = SecureRandom.uuid
32
+ payload = { "data": "dummy data" }
33
+ ForemanRhCloud::HitsUploader.any_instance.expects(:upload!).returns
34
+ patch :upload_hits, params: { host_name: @host1.name, host_uuid: uuid, payload: payload }
35
+ assert_response :ok
36
+ assert_equal 'success', JSON.parse(response.body)['action_status']
37
+ end
38
+
39
+ test 'test upload hits with bad host' do
40
+ uuid = SecureRandom.uuid
41
+ payload = { "data": "dummy data" }
42
+ patch :upload_hits, params: { host_name: "NO SUCH HOST", host_uuid: uuid, payload: payload }
43
+ assert_response :not_found
44
+ assert_equal 'No host found for the given host name', JSON.parse(response.body)['error']
45
+ end
46
+ end
47
+ end
48
+ end