foreman_rh_cloud 5.0.32 → 5.0.35
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/app/controllers/api/v2/rh_cloud/cloud_request_controller.rb +83 -0
- data/app/controllers/foreman_inventory_upload/uploads_controller.rb +7 -0
- data/app/controllers/insights_cloud/api/machine_telemetries_controller.rb +13 -2
- data/app/controllers/insights_cloud/hits_controller.rb +8 -1
- data/app/models/setting/rh_cloud.rb +2 -1
- data/app/services/foreman_rh_cloud/cloud_connector.rb +1 -1
- data/app/services/foreman_rh_cloud/cloud_presence.rb +124 -0
- data/app/services/foreman_rh_cloud/cloud_request.rb +8 -1
- data/app/services/foreman_rh_cloud/cloud_request_forwarder.rb +16 -5
- data/app/services/foreman_rh_cloud/hit_remediations_retriever.rb +67 -0
- data/app/services/foreman_rh_cloud/remediations_retriever.rb +16 -45
- data/app/services/foreman_rh_cloud/template_renderer_helper.rb +13 -1
- data/app/services/foreman_rh_cloud/url_remediations_retriever.rb +37 -0
- data/app/views/job_templates/cloud_connector.erb +30 -0
- data/app/views/job_templates/rh_cloud_download_playbook.erb +26 -0
- data/config/routes.rb +2 -0
- data/lib/foreman_rh_cloud/engine.rb +33 -12
- data/lib/foreman_rh_cloud/version.rb +1 -1
- data/lib/foreman_rh_cloud.rb +4 -0
- data/lib/insights_cloud/async/connector_playbook_execution_reporter_task.rb +193 -0
- data/lib/insights_cloud/async/insights_scheduled_sync.rb +4 -0
- data/lib/insights_cloud/generators/playbook_progress_generator.rb +49 -0
- data/lib/tasks/insights.rake +13 -0
- data/package.json +1 -1
- data/test/controllers/insights_cloud/api/cloud_request_controller_test.rb +78 -0
- data/test/controllers/insights_cloud/api/machine_telemetries_controller_test.rb +16 -0
- data/test/jobs/connector_playbook_execution_reporter_task_test.rb +207 -0
- data/test/unit/playbook_progress_generator_test.rb +75 -0
- data/test/unit/services/foreman_rh_cloud/cloud_request_forwarder_test.rb +13 -8
- data/test/unit/services/foreman_rh_cloud/{remediations_retriever_test.rb → hit_remediations_retriever_test.rb} +3 -3
- data/test/unit/services/foreman_rh_cloud/url_remediations_retriever_test.rb +27 -0
- data/webpack/InsightsCloudSync/Components/InsightsTable/InsightsTableActions.js +6 -11
- data/webpack/InsightsCloudSync/Components/InsightsTable/InsightsTableHelpers.js +22 -0
- data/webpack/InsightsCloudSync/Components/RemediationModal/RemediationActions.js +6 -1
- data/webpack/InsightsHostDetailsTab/InsightsTotalRiskChart.js +3 -2
- metadata +20 -4
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 437d70d98a43e88f7835426bf1a8ae7995a2b759038e3a5908dc41e122544ed1
|
|
4
|
+
data.tar.gz: a655276cda12b06662db3670019747c518e9204c22ca8ad3591024945dd48fb8
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 3d59ebbe9a845efd88c9d70f1d44ff9ebae7e5faabd947c3ba3d48e5f22435c97052be363839805208b381fea29f643a35ef241f2ff0ae462d1720d6ff5fd538
|
|
7
|
+
data.tar.gz: f7d94f184cbeba9d50b6e8a83d71db08a3c6417972b6d51b6ca247558a4769a6f17fbfdae37f9e4f5efe2a73a8095885a44e109d2b736fbc1d824f9e68528fe1
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
module Api::V2::RhCloud
|
|
2
|
+
class CloudRequestController < ::Api::V2::BaseController
|
|
3
|
+
layout false
|
|
4
|
+
|
|
5
|
+
KNOWN_DIRECTIVES = {
|
|
6
|
+
'playbook-sat' => :handle_run_playbook_request,
|
|
7
|
+
'foreman_rh_cloud' => :handle_run_playbook_request,
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
def update
|
|
11
|
+
handler = KNOWN_DIRECTIVES[directive]
|
|
12
|
+
|
|
13
|
+
unless handler
|
|
14
|
+
render json: {
|
|
15
|
+
:message => "No valid handler is found for directive: #{directive}",
|
|
16
|
+
}, status: :bad_request
|
|
17
|
+
return
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
send(handler)
|
|
21
|
+
|
|
22
|
+
render json: {
|
|
23
|
+
:message => "Handled #{directive} by #{handler}",
|
|
24
|
+
}
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
private
|
|
28
|
+
|
|
29
|
+
def metadata
|
|
30
|
+
params['metadata']
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
def content
|
|
34
|
+
# the content received as base 64 of the string in double quotes
|
|
35
|
+
Base64.decode64(params['content']).tr('"', '')
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
def directive
|
|
39
|
+
params['directive']
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
def handle_run_playbook_request
|
|
43
|
+
logger.error("API token is not set, unable to fetch data from the cloud") && return if Setting[:rh_cloud_token].empty?
|
|
44
|
+
logger.error("Playbook URL is not valid: #{content}") && return unless valid_url?(content)
|
|
45
|
+
logger.error("Reporting URL is not valid: #{metadata['return_url']}") && return unless valid_url?(metadata['return_url'])
|
|
46
|
+
|
|
47
|
+
hosts = metadata['hosts'].split(',')
|
|
48
|
+
host_ids = host_ids(hosts)
|
|
49
|
+
|
|
50
|
+
logger.warn("Some hosts were not found. Looked for: #{hosts}, found ids: #{host_ids}") unless host_ids.length == hosts.length
|
|
51
|
+
|
|
52
|
+
logger.error("sat_org_id is not present in the metadata") && return unless metadata['sat_org_id']
|
|
53
|
+
org_id = metadata['sat_org_id'].to_i
|
|
54
|
+
organization = Organization.find(org_id)
|
|
55
|
+
|
|
56
|
+
composer = nil
|
|
57
|
+
Organization.as_org(organization) do
|
|
58
|
+
composer = ::JobInvocationComposer.for_feature(
|
|
59
|
+
:rh_cloud_connector_run_playbook,
|
|
60
|
+
host_ids,
|
|
61
|
+
{
|
|
62
|
+
playbook_url: content,
|
|
63
|
+
report_url: metadata['return_url'],
|
|
64
|
+
report_interval: metadata['response_interval'].to_i,
|
|
65
|
+
correlation_id: metadata['correlation_id'],
|
|
66
|
+
}
|
|
67
|
+
)
|
|
68
|
+
composer.trigger!
|
|
69
|
+
end
|
|
70
|
+
|
|
71
|
+
composer.job_invocation
|
|
72
|
+
end
|
|
73
|
+
|
|
74
|
+
def valid_url?(url)
|
|
75
|
+
parsed = URI(url)
|
|
76
|
+
ForemanRhCloud.cloud_url_validator.match(parsed.host)
|
|
77
|
+
end
|
|
78
|
+
|
|
79
|
+
def host_ids(hosts)
|
|
80
|
+
InsightsFacet.where(uuid: hosts).pluck(:host_id)
|
|
81
|
+
end
|
|
82
|
+
end
|
|
83
|
+
end
|
|
@@ -18,6 +18,13 @@ module ForemanInventoryUpload
|
|
|
18
18
|
end
|
|
19
19
|
|
|
20
20
|
def enable_cloud_connector
|
|
21
|
+
Organization.unscoped.each do |org|
|
|
22
|
+
presence = ForemanRhCloud::CloudPresence.new(org, logger)
|
|
23
|
+
presence.announce_to_sources
|
|
24
|
+
rescue StandardError => ex
|
|
25
|
+
logger.warn(ex)
|
|
26
|
+
end
|
|
27
|
+
|
|
21
28
|
cloud_connector = ForemanRhCloud::CloudConnector.new
|
|
22
29
|
render json: cloud_connector.install.to_json
|
|
23
30
|
end
|
|
@@ -37,14 +37,25 @@ module InsightsCloud::Api
|
|
|
37
37
|
return send_data @cloud_response, disposition: @cloud_response.headers[:content_disposition], type: @cloud_response.headers[:content_type]
|
|
38
38
|
end
|
|
39
39
|
|
|
40
|
+
# Append redhat-specific headers
|
|
41
|
+
@cloud_response.headers.each do |key, value|
|
|
42
|
+
assign_header(response, @cloud_response, key, false) if key.to_s.start_with?('x_rh_')
|
|
43
|
+
end
|
|
44
|
+
# Append general headers
|
|
40
45
|
assign_header(response, @cloud_response, :x_resource_count, true)
|
|
41
|
-
|
|
46
|
+
headers[Rack::ETAG] = @cloud_response.headers[:etag]
|
|
42
47
|
|
|
43
48
|
render json: @cloud_response, status: @cloud_response.code
|
|
44
49
|
end
|
|
45
50
|
|
|
46
51
|
def branch_info
|
|
47
|
-
|
|
52
|
+
payload = nil
|
|
53
|
+
|
|
54
|
+
User.as_anonymous_admin do
|
|
55
|
+
payload = ForemanRhCloud::BranchInfo.new.generate(@uuid, @host, @branch_id, request.host).to_json
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
render :json => payload
|
|
48
59
|
end
|
|
49
60
|
|
|
50
61
|
def assign_header(res, cloud_res, header, transform)
|
|
@@ -14,9 +14,16 @@ module InsightsCloud
|
|
|
14
14
|
|
|
15
15
|
def show
|
|
16
16
|
host = Host.where(id: host_id_param).first
|
|
17
|
+
hits = host.insights&.hits
|
|
18
|
+
|
|
19
|
+
unless hits
|
|
20
|
+
return render json: {
|
|
21
|
+
error: 'No recommendations were found for this host',
|
|
22
|
+
}, status: :not_found
|
|
23
|
+
end
|
|
17
24
|
|
|
18
25
|
render json: {
|
|
19
|
-
hits:
|
|
26
|
+
hits: hits,
|
|
20
27
|
}, status: :ok
|
|
21
28
|
end
|
|
22
29
|
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
class Setting::RhCloud < Setting
|
|
2
|
-
::Setting::BLANK_ATTRS.concat %w{rh_cloud_token}
|
|
2
|
+
::Setting::BLANK_ATTRS.concat %w{rh_cloud_token rhc_instance_id}
|
|
3
3
|
|
|
4
4
|
def self.load_defaults
|
|
5
5
|
return false unless table_exists?
|
|
@@ -20,6 +20,7 @@ class Setting::RhCloud < Setting
|
|
|
20
20
|
set('rh_cloud_token', N_('Authentication token to Red Hat cloud services. Used to authenticate requests to cloud APIs'), nil, N_('Red Hat Cloud token'), nil, encrypted: true),
|
|
21
21
|
set('exclude_installed_packages', N_('Exclude installed packages from being uploaded to the Red Hat cloud'), false, N_("Exclude installed Packages")),
|
|
22
22
|
set('include_parameter_tags', N_('Should import include parameter tags from Foreman?'), false, N_('Include parameters in insights-client reports')),
|
|
23
|
+
set('rhc_instance_id', N_('RHC daemon id'), nil, N_('ID of the RHC(Yggdrasil) daemon')),
|
|
23
24
|
]
|
|
24
25
|
end
|
|
25
26
|
|
|
@@ -16,7 +16,7 @@ module ForemanRhCloud
|
|
|
16
16
|
composer = ::JobInvocationComposer.for_feature(
|
|
17
17
|
CLOUD_CONNECTOR_FEATURE,
|
|
18
18
|
[target_host.id],
|
|
19
|
-
{:
|
|
19
|
+
{:satellite_cloud_connector_user => service_user.login, :satellite_cloud_connector_password => token_value}
|
|
20
20
|
)
|
|
21
21
|
composer.trigger!
|
|
22
22
|
end
|
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
module ForemanRhCloud
|
|
2
|
+
class CloudPresence
|
|
3
|
+
include InsightsCloud::CandlepinCache
|
|
4
|
+
include ForemanRhCloud::CloudRequest
|
|
5
|
+
|
|
6
|
+
attr_reader :organization, :logger
|
|
7
|
+
|
|
8
|
+
def initialize(organization, logger)
|
|
9
|
+
@organization = organization
|
|
10
|
+
@logger = logger
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
def announce_to_sources
|
|
14
|
+
register_rhc_instance
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
def satellite_source_type
|
|
18
|
+
@satellite_source_type ||= begin
|
|
19
|
+
source_type_response = JSON.parse(
|
|
20
|
+
execute_cloud_request(
|
|
21
|
+
method: :get,
|
|
22
|
+
url: source_type_url,
|
|
23
|
+
headers: {
|
|
24
|
+
content_type: :json,
|
|
25
|
+
},
|
|
26
|
+
ssl_client_cert: OpenSSL::X509::Certificate.new(certs[:cert]),
|
|
27
|
+
ssl_client_key: OpenSSL::PKey::RSA.new(certs[:key])
|
|
28
|
+
)
|
|
29
|
+
)
|
|
30
|
+
|
|
31
|
+
source_type_response['data'].first['id']
|
|
32
|
+
end
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
def satellite_instance_source
|
|
36
|
+
@satellite_instance_source ||= begin
|
|
37
|
+
source_response = JSON.parse(
|
|
38
|
+
execute_cloud_request(
|
|
39
|
+
method: :get,
|
|
40
|
+
url: satellite_instance_source_url,
|
|
41
|
+
headers: {
|
|
42
|
+
content_type: :json,
|
|
43
|
+
},
|
|
44
|
+
ssl_client_cert: OpenSSL::X509::Certificate.new(certs[:cert]),
|
|
45
|
+
ssl_client_key: OpenSSL::PKey::RSA.new(certs[:key])
|
|
46
|
+
)
|
|
47
|
+
)
|
|
48
|
+
|
|
49
|
+
result = source_response['data'].first
|
|
50
|
+
result&.dig('id')
|
|
51
|
+
end
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
def create_satellite_instance_source
|
|
55
|
+
create_response = JSON.parse(
|
|
56
|
+
execute_cloud_request(
|
|
57
|
+
method: :post,
|
|
58
|
+
url: create_satellite_instance_source_url,
|
|
59
|
+
headers: {
|
|
60
|
+
content_type: :json,
|
|
61
|
+
},
|
|
62
|
+
ssl_client_cert: OpenSSL::X509::Certificate.new(certs[:cert]),
|
|
63
|
+
ssl_client_key: OpenSSL::PKey::RSA.new(certs[:key]),
|
|
64
|
+
payload: {
|
|
65
|
+
name: "satellite: #{Foreman.instance_id} org: #{@organization.name}",
|
|
66
|
+
source_ref: Foreman.instance_id,
|
|
67
|
+
source_type_id: satellite_source_type,
|
|
68
|
+
}.to_json
|
|
69
|
+
)
|
|
70
|
+
)
|
|
71
|
+
|
|
72
|
+
@satellite_instance_source = create_response['id']
|
|
73
|
+
end
|
|
74
|
+
|
|
75
|
+
def register_rhc_instance
|
|
76
|
+
raise Foreman::Exception.new('rhc_instance_id is empty, cannot register RHC to the cloud') if Setting[:rhc_instance_id].empty?
|
|
77
|
+
source_id = satellite_instance_source || create_satellite_instance_source
|
|
78
|
+
|
|
79
|
+
create_response = JSON.parse(
|
|
80
|
+
execute_cloud_request(
|
|
81
|
+
method: :post,
|
|
82
|
+
url: create_rhc_connections_url,
|
|
83
|
+
headers: {
|
|
84
|
+
content_type: :json,
|
|
85
|
+
},
|
|
86
|
+
ssl_client_cert: OpenSSL::X509::Certificate.new(certs[:cert]),
|
|
87
|
+
ssl_client_key: OpenSSL::PKey::RSA.new(certs[:key]),
|
|
88
|
+
payload: {
|
|
89
|
+
source_id: source_id,
|
|
90
|
+
rhc_id: Setting[:rhc_instance_id],
|
|
91
|
+
}.to_json
|
|
92
|
+
)
|
|
93
|
+
)
|
|
94
|
+
|
|
95
|
+
@satellite_instance_source = create_response['id']
|
|
96
|
+
end
|
|
97
|
+
|
|
98
|
+
private
|
|
99
|
+
|
|
100
|
+
def sources_url(path)
|
|
101
|
+
"#{ForemanRhCloud.cert_base_url}/api/sources/v3.1#{path}"
|
|
102
|
+
end
|
|
103
|
+
|
|
104
|
+
def source_type_url
|
|
105
|
+
sources_url('/source_types?filter[name]=satellite')
|
|
106
|
+
end
|
|
107
|
+
|
|
108
|
+
def satellite_instance_source_url
|
|
109
|
+
sources_url("/sources?filter[source_ref]=#{Foreman.instance_id}")
|
|
110
|
+
end
|
|
111
|
+
|
|
112
|
+
def create_satellite_instance_source_url
|
|
113
|
+
sources_url('/sources')
|
|
114
|
+
end
|
|
115
|
+
|
|
116
|
+
def create_rhc_connections_url
|
|
117
|
+
sources_url('/rhc_connections')
|
|
118
|
+
end
|
|
119
|
+
|
|
120
|
+
def certs
|
|
121
|
+
@certs ||= candlepin_id_cert(@organization)
|
|
122
|
+
end
|
|
123
|
+
end
|
|
124
|
+
end
|
|
@@ -8,7 +8,14 @@ module ForemanRhCloud
|
|
|
8
8
|
proxy: ForemanRhCloud.transformed_http_proxy_string(logger: logger),
|
|
9
9
|
}.deep_merge(params)
|
|
10
10
|
|
|
11
|
-
RestClient::Request.execute(final_params)
|
|
11
|
+
response = RestClient::Request.execute(final_params)
|
|
12
|
+
|
|
13
|
+
logger.debug("Response headers for request url #{final_params[:url]} are: #{response.headers}")
|
|
14
|
+
|
|
15
|
+
response
|
|
16
|
+
rescue RestClient::Exception => ex
|
|
17
|
+
logger.debug("Failed response with code #{ex.http_code} headers for request url #{final_params[:url]} are: #{ex.http_headers} and body: #{ex.http_body}")
|
|
18
|
+
raise ex
|
|
12
19
|
end
|
|
13
20
|
end
|
|
14
21
|
end
|
|
@@ -25,11 +25,12 @@ module ForemanRhCloud
|
|
|
25
25
|
base_params = {
|
|
26
26
|
method: original_request.method,
|
|
27
27
|
payload: forward_payload,
|
|
28
|
-
headers:
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
28
|
+
headers: original_headers(original_request).merge(
|
|
29
|
+
{
|
|
30
|
+
params: forward_params,
|
|
31
|
+
user_agent: http_user_agent(original_request),
|
|
32
|
+
content_type: original_request.media_type.presence || original_request.format.to_s,
|
|
33
|
+
}),
|
|
33
34
|
}
|
|
34
35
|
base_params.merge(path_params(original_request.path, certs))
|
|
35
36
|
end
|
|
@@ -80,6 +81,16 @@ module ForemanRhCloud
|
|
|
80
81
|
end
|
|
81
82
|
end
|
|
82
83
|
|
|
84
|
+
def original_headers(original_request)
|
|
85
|
+
headers = {
|
|
86
|
+
if_none_match: original_request.if_none_match,
|
|
87
|
+
if_modified_since: original_request.if_modified_since,
|
|
88
|
+
}.compact
|
|
89
|
+
|
|
90
|
+
logger.debug("Sending headers: #{headers}")
|
|
91
|
+
headers
|
|
92
|
+
end
|
|
93
|
+
|
|
83
94
|
def platform_request?
|
|
84
95
|
->(request_path) { request_path.include? '/platform' }
|
|
85
96
|
end
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
module ForemanRhCloud
|
|
2
|
+
class HitRemediationsRetriever < RemediationsRetriever
|
|
3
|
+
def initialize(hit_remediation_pairs, logger: Logger.new(IO::NULL))
|
|
4
|
+
super(logger: logger)
|
|
5
|
+
@hit_remediation_pairs = hit_remediation_pairs
|
|
6
|
+
logger.debug("Querying playbook for #{hit_remediation_pairs}")
|
|
7
|
+
end
|
|
8
|
+
|
|
9
|
+
private
|
|
10
|
+
|
|
11
|
+
def hit_ids
|
|
12
|
+
@hit_remediation_pairs.map { |pair| pair["hit_id"] }
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
def remediation_ids
|
|
16
|
+
@hit_remediation_pairs.map { |pair| pair["resolution_id"] }
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
def hits
|
|
20
|
+
@hits ||= Hash[
|
|
21
|
+
InsightsHit.joins(:insights_facet).where(id: hit_ids).pluck(:id, 'insights_facets.uuid')
|
|
22
|
+
]
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
def pairs_by_remediation_id
|
|
26
|
+
@hit_remediation_pairs.group_by { |pair| pair["resolution_id"] }
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
def remediations
|
|
30
|
+
@remediations ||= Hash[
|
|
31
|
+
InsightsResolution.where(id: remediation_ids).pluck(:id, :resolution_type, :rule_id).map do |id, resolution_type, rule_id|
|
|
32
|
+
[id, {resolution_type: resolution_type, rule_id: rule_id}]
|
|
33
|
+
end
|
|
34
|
+
]
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
def playbook_request
|
|
38
|
+
{
|
|
39
|
+
issues: pairs_by_remediation_id.map do |remediation_id, pairs|
|
|
40
|
+
{
|
|
41
|
+
resolution: remediations[remediation_id][:resolution_type],
|
|
42
|
+
id: InsightsCloud.remediation_rule_id(remediations[remediation_id][:rule_id]),
|
|
43
|
+
systems: pairs.map do |pair|
|
|
44
|
+
hits[pair["hit_id"]]
|
|
45
|
+
end,
|
|
46
|
+
}
|
|
47
|
+
end,
|
|
48
|
+
}
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
def playbook_url
|
|
52
|
+
InsightsCloud.playbook_url
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
def headers
|
|
56
|
+
super
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
def payload
|
|
60
|
+
playbook_request.to_json
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
def method
|
|
64
|
+
:post
|
|
65
|
+
end
|
|
66
|
+
end
|
|
67
|
+
end
|
|
@@ -4,11 +4,8 @@ module ForemanRhCloud
|
|
|
4
4
|
|
|
5
5
|
attr_reader :logger
|
|
6
6
|
|
|
7
|
-
def initialize(
|
|
8
|
-
@hit_remediation_pairs = hit_remediation_pairs
|
|
7
|
+
def initialize(logger: Logger.new(IO::NULL))
|
|
9
8
|
@logger = logger
|
|
10
|
-
|
|
11
|
-
logger.debug("Querying playbook for #{hit_remediation_pairs}")
|
|
12
9
|
end
|
|
13
10
|
|
|
14
11
|
def create_playbook
|
|
@@ -26,55 +23,29 @@ module ForemanRhCloud
|
|
|
26
23
|
|
|
27
24
|
private
|
|
28
25
|
|
|
29
|
-
def
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
def hits
|
|
38
|
-
@hits ||= Hash[
|
|
39
|
-
InsightsHit.joins(:insights_facet).where(id: hit_ids).pluck(:id, 'insights_facets.uuid')
|
|
40
|
-
]
|
|
41
|
-
end
|
|
42
|
-
|
|
43
|
-
def pairs_by_remediation_id
|
|
44
|
-
@hit_remediation_pairs.group_by { |pair| pair["resolution_id"] }
|
|
26
|
+
def query_playbook
|
|
27
|
+
execute_cloud_request(
|
|
28
|
+
method: method,
|
|
29
|
+
url: playbook_url,
|
|
30
|
+
headers: headers,
|
|
31
|
+
payload: payload
|
|
32
|
+
)
|
|
45
33
|
end
|
|
46
34
|
|
|
47
|
-
def
|
|
48
|
-
@remediations ||= Hash[
|
|
49
|
-
InsightsResolution.where(id: remediation_ids).pluck(:id, :resolution_type, :rule_id).map do |id, resolution_type, rule_id|
|
|
50
|
-
[id, {resolution_type: resolution_type, rule_id: rule_id}]
|
|
51
|
-
end
|
|
52
|
-
]
|
|
35
|
+
def playbook_url
|
|
53
36
|
end
|
|
54
37
|
|
|
55
|
-
def
|
|
38
|
+
def headers
|
|
56
39
|
{
|
|
57
|
-
|
|
58
|
-
{
|
|
59
|
-
resolution: remediations[remediation_id][:resolution_type],
|
|
60
|
-
id: InsightsCloud.remediation_rule_id(remediations[remediation_id][:rule_id]),
|
|
61
|
-
systems: pairs.map do |pair|
|
|
62
|
-
hits[pair["hit_id"]]
|
|
63
|
-
end,
|
|
64
|
-
}
|
|
65
|
-
end,
|
|
40
|
+
content_type: :json,
|
|
66
41
|
}
|
|
67
42
|
end
|
|
68
43
|
|
|
69
|
-
def
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
content_type: :json,
|
|
75
|
-
},
|
|
76
|
-
payload: playbook_request.to_json
|
|
77
|
-
)
|
|
44
|
+
def payload
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
def method
|
|
48
|
+
:get
|
|
78
49
|
end
|
|
79
50
|
end
|
|
80
51
|
end
|
|
@@ -15,8 +15,20 @@ module ForemanRhCloud
|
|
|
15
15
|
end
|
|
16
16
|
def remediations_playbook(hit_remediation_pairs)
|
|
17
17
|
hit_remediation_pairs = JSON.parse(hit_remediation_pairs)
|
|
18
|
-
retriever = ForemanRhCloud::
|
|
18
|
+
retriever = ForemanRhCloud::HitRemediationsRetriever.new(hit_remediation_pairs, logger: template_logger)
|
|
19
19
|
retriever.create_playbook
|
|
20
20
|
end
|
|
21
|
+
|
|
22
|
+
apipie :method, 'Returns a Red Hat remediation playbook compiled on console.redhat.com' do
|
|
23
|
+
required :remediation_path, String, desc: ''
|
|
24
|
+
returns String, desc: 'Playbook downloaded from the cloud'
|
|
25
|
+
end
|
|
26
|
+
def download_rh_playbook(playbook_url)
|
|
27
|
+
retriever = ForemanRhCloud::UrlRemediationsRetriever.new(url: playbook_url, logger: template_logger)
|
|
28
|
+
|
|
29
|
+
cached("rh_playbook_#{playbook_url}") do
|
|
30
|
+
retriever.create_playbook
|
|
31
|
+
end
|
|
32
|
+
end
|
|
21
33
|
end
|
|
22
34
|
end
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
module ForemanRhCloud
|
|
2
|
+
class UrlRemediationsRetriever < RemediationsRetriever
|
|
3
|
+
attr_reader :url, :payload, :headers
|
|
4
|
+
|
|
5
|
+
def initialize(url:, payload: '', headers: {}, logger: Logger.new(IO::NULL))
|
|
6
|
+
super(logger: logger)
|
|
7
|
+
|
|
8
|
+
@url = url
|
|
9
|
+
@payload = payload
|
|
10
|
+
@headers = headers
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
private
|
|
14
|
+
|
|
15
|
+
def query_playbook
|
|
16
|
+
logger.debug("Querying playbook at: #{url} with payload: #{payload} and headers: #{headers}")
|
|
17
|
+
|
|
18
|
+
super
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
def playbook_url
|
|
22
|
+
@url
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
def headers
|
|
26
|
+
super.deep_merge(@headers)
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
def payload
|
|
30
|
+
@payload.to_json
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
def method
|
|
34
|
+
:get
|
|
35
|
+
end
|
|
36
|
+
end
|
|
37
|
+
end
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
<%#
|
|
2
|
+
name: Configure Cloud Connector
|
|
3
|
+
snippet: false
|
|
4
|
+
template_inputs:
|
|
5
|
+
- name: satellite_cloud_connector_user
|
|
6
|
+
required: true
|
|
7
|
+
input_type: user
|
|
8
|
+
advanced: false
|
|
9
|
+
value_type: plain
|
|
10
|
+
hidden_value: false
|
|
11
|
+
- name: satellite_cloud_connector_password
|
|
12
|
+
required: true
|
|
13
|
+
input_type: user
|
|
14
|
+
advanced: false
|
|
15
|
+
value_type: plain
|
|
16
|
+
hidden_value: true
|
|
17
|
+
model: JobTemplate
|
|
18
|
+
job_category: Maintenance Operations
|
|
19
|
+
description_format: "%{template_name}"
|
|
20
|
+
provider_type: Ansible
|
|
21
|
+
kind: job_template
|
|
22
|
+
feature: ansible_configure_cloud_connector
|
|
23
|
+
%>
|
|
24
|
+
|
|
25
|
+
---
|
|
26
|
+
- hosts: all
|
|
27
|
+
vars:
|
|
28
|
+
satellite_cloud_connector_url: "<%= foreman_server_url %>"
|
|
29
|
+
roles:
|
|
30
|
+
- redhat.satellite_operations.cloud_connector
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
<%#
|
|
2
|
+
kind: job_template
|
|
3
|
+
name: Run a playbook downloaded from RH cloud
|
|
4
|
+
job_category: Red Hat Insights
|
|
5
|
+
description_format: 'Playbook generated by RH Cloud'
|
|
6
|
+
feature: rh_cloud_connector_run_playbook
|
|
7
|
+
template_inputs:
|
|
8
|
+
- name: playbook_url
|
|
9
|
+
description: URL of the playbook to run
|
|
10
|
+
input_type: user
|
|
11
|
+
required: true
|
|
12
|
+
- name: report_url
|
|
13
|
+
description: URL for calling the report callback
|
|
14
|
+
input_type: user
|
|
15
|
+
required: true
|
|
16
|
+
- name: correlation_id
|
|
17
|
+
description: correlation ID used to identify the original calling message
|
|
18
|
+
input_type: user
|
|
19
|
+
required: true
|
|
20
|
+
- name: report_interval
|
|
21
|
+
description: Reporting interval for the task. A report will be generated every report_interval seconds.
|
|
22
|
+
input_type: user
|
|
23
|
+
required: true
|
|
24
|
+
provider_type: Ansible
|
|
25
|
+
%>
|
|
26
|
+
<%= download_rh_playbook(input('playbook_url')) %>
|