foreman_rh_cloud 11.0.3 → 11.1.0

Sign up to get free protection for your applications and to get access to all the features.
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