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.
- checksums.yaml +4 -4
- data/README.md +2 -2
- data/app/controllers/api/v2/advisor_engine/advisor_engine_controller.rb +98 -0
- data/app/controllers/api/v2/rh_cloud/advisor_engine_config_controller.rb +16 -0
- data/app/models/concerns/rh_cloud_host.rb +5 -0
- data/app/services/foreman_rh_cloud/cloud_connector.rb +1 -1
- data/app/services/foreman_rh_cloud/cloud_request.rb +1 -1
- data/app/services/foreman_rh_cloud/hits_uploader.rb +55 -0
- data/app/views/api/v2/advisor_engine/host_details.json.rabl +9 -0
- data/app/views/api/v2/hosts/insights/base.rabl +5 -0
- data/app/views/api/v2/hosts/insights/insights.rabl +3 -0
- data/config/routes.rb +6 -1
- data/db/migrate/20241217190624_add_unique_index_to_rule_id_and_host_id_in_insights_hits.rb +5 -0
- data/db/migrate/20241220184900_change_sync_insights_recommendations_to_true.rb +5 -0
- data/lib/foreman_inventory_upload/async/generate_all_reports_job.rb +21 -13
- data/lib/foreman_inventory_upload/async/upload_report_job.rb +1 -1
- data/lib/foreman_inventory_upload/generators/slice.rb +1 -1
- data/lib/foreman_rh_cloud/engine.rb +24 -5
- data/lib/foreman_rh_cloud/version.rb +1 -1
- data/lib/foreman_rh_cloud.rb +21 -31
- data/lib/insights_cloud/async/insights_scheduled_sync.rb +10 -2
- data/lib/inventory_sync/async/inventory_full_sync.rb +0 -10
- data/lib/inventory_sync/async/inventory_scheduled_sync.rb +15 -7
- data/package.json +1 -1
- data/test/controllers/insights_cloud/api/advisor_engine_controller_test.rb +48 -0
- data/test/controllers/insights_sync/settings_controller_test.rb +3 -0
- data/test/factories/insights_factories.rb +1 -1
- data/test/jobs/inventory_scheduled_sync_test.rb +10 -0
- data/test/unit/rh_cloud_http_proxy_test.rb +1 -26
- data/test/unit/services/foreman_rh_cloud/hits_uploader_test.rb +120 -0
- data/webpack/ForemanInventoryUpload/Components/PageHeader/__tests__/__snapshots__/PageTitle.test.js.snap +1 -1
- data/webpack/ForemanInventoryUpload/Components/PageHeader/components/CloudConnectorButton/CloudConnectorButton.js +2 -2
- data/webpack/ForemanInventoryUpload/Components/PageHeader/components/CloudConnectorButton/__tests__/__snapshots__/CloudConnectorButton.test.js.snap +2 -2
- data/webpack/ForemanInventoryUpload/Components/PageHeader/components/PageDescription/PageDescription.js +3 -1
- data/webpack/ForemanInventoryUpload/Components/PageHeader/components/PageDescription/__tests__/__snapshots__/PageDescription.test.js.snap +1 -1
- data/webpack/ForemanInventoryUpload/Components/PageHeader/components/SyncButton/__tests__/__snapshots__/SyncButton.test.js.snap +1 -1
- data/webpack/ForemanInventoryUpload/Components/TabHeader/TabHeader.js +1 -1
- data/webpack/ForemanInventoryUpload/ForemanInventoryConstants.js +1 -1
- data/webpack/ForemanInventoryUpload/ForemanInventoryHelpers.js +1 -1
- data/webpack/InsightsCloudSync/Components/InsightsSettings/InsightsSettings.js +26 -22
- data/webpack/InsightsCloudSync/Components/InsightsSettings/InsightsSettingsActions.js +2 -1
- data/webpack/InsightsCloudSync/Components/InsightsTable/InsightsTable.js +10 -1
- data/webpack/InsightsCloudSync/Components/InsightsTable/InsightsTableConstants.js +8 -1
- data/webpack/InsightsCloudSync/Components/InsightsTable/InsightsTableHelpers.js +3 -1
- data/webpack/InsightsCloudSync/Components/ToolbarDropdown.js +5 -0
- data/webpack/InsightsCloudSync/InsightsCloudSync.js +1 -2
- data/webpack/InsightsCloudSync/__snapshots__/InsightsCloudSync.test.js.snap +1 -1
- data/webpack/InsightsHostDetailsTab/NewHostDetailsTab.js +3 -1
- data/webpack/__mocks__/foremanReact/common/hooks/API/APIHooks.js +3 -0
- data/webpack/common/Hooks/ConfigHooks.js +19 -0
- metadata +17 -9
- data/webpack/InsightsCloudSync/Components/InsightsHeader/InsightsHeader.scss +0 -8
- data/webpack/InsightsCloudSync/Components/InsightsHeader/index.js +0 -16
- data/webpack/InsightsCloudSync/Components/InsightsSettings/__tests__/InsightsSettings.test.js +0 -18
- data/webpack/InsightsCloudSync/Components/InsightsSettings/__tests__/__snapshots__/InsightsSettings.test.js.snap +0 -15
- data/webpack/InsightsCloudSync/Components/__tests__/InsightsHeader.test.js +0 -10
- 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:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: a0510d9fc263ac8ff7313350cdcdf6fc82e0d13c35c5e8936463f1d5f7367d88
|
4
|
+
data.tar.gz: 14561397aed26a96af5a7105c24147c7cf31d9235ea987d065dcb451fb7b05a7
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
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 ->
|
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
|
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
|
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
|
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
|
@@ -13,22 +13,30 @@ module ForemanInventoryUpload
|
|
13
13
|
return
|
14
14
|
end
|
15
15
|
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
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
|
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')
|
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:
|
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
|
109
|
-
|
110
|
-
|
111
|
-
|
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
|
data/lib/foreman_rh_cloud.rb
CHANGED
@@ -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 ||=
|
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 ||=
|
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 ||=
|
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
|
28
|
-
ForemanRhCloud.proxy_setting
|
37
|
+
def self.http_proxy_string
|
38
|
+
ForemanRhCloud.proxy_setting
|
29
39
|
end
|
30
40
|
|
31
|
-
def self.transformed_http_proxy_string
|
32
|
-
ForemanRhCloud.transform_scheme(ForemanRhCloud.proxy_setting
|
41
|
+
def self.transformed_http_proxy_string
|
42
|
+
ForemanRhCloud.transform_scheme(ForemanRhCloud.proxy_setting)
|
33
43
|
end
|
34
44
|
|
35
|
-
def self.proxy_setting
|
36
|
-
fix_port(proxy_string
|
45
|
+
def self.proxy_setting
|
46
|
+
fix_port(proxy_string)
|
37
47
|
end
|
38
48
|
|
39
|
-
def self.proxy_string
|
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
|
-
|
17
|
-
|
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
|
-
|
17
|
-
#
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
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
@@ -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
|