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.
- 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
|