foreman_rh_cloud 12.1.3 → 12.1.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (73) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +3 -5
  3. data/app/controllers/concerns/insights_cloud/package_profile_upload_extensions.rb +33 -0
  4. data/app/controllers/insights_cloud/api/machine_telemetries_controller.rb +1 -2
  5. data/app/controllers/insights_cloud/ui_requests_controller.rb +99 -0
  6. data/app/services/foreman_rh_cloud/cert_auth.rb +9 -1
  7. data/app/services/foreman_rh_cloud/cloud_request_forwarder.rb +12 -13
  8. data/app/services/foreman_rh_cloud/gateway_request.rb +26 -0
  9. data/app/services/foreman_rh_cloud/insights_api_forwarder.rb +116 -0
  10. data/app/services/foreman_rh_cloud/tags_auth.rb +55 -0
  11. data/app/views/api/v2/hosts/insights/base.rabl +6 -0
  12. data/config/routes.rb +2 -0
  13. data/lib/foreman_inventory_upload/async/generate_report_job.rb +11 -5
  14. data/lib/foreman_inventory_upload/async/upload_report_job.rb +15 -4
  15. data/lib/foreman_inventory_upload/generators/archived_report.rb +2 -2
  16. data/lib/foreman_inventory_upload/generators/fact_helpers.rb +65 -13
  17. data/lib/foreman_inventory_upload/generators/queries.rb +7 -5
  18. data/lib/foreman_inventory_upload/generators/slice.rb +0 -1
  19. data/lib/foreman_inventory_upload.rb +2 -2
  20. data/lib/foreman_rh_cloud/engine.rb +5 -3
  21. data/lib/foreman_rh_cloud/version.rb +1 -1
  22. data/lib/insights_cloud.rb +8 -0
  23. data/lib/inventory_sync/async/inventory_hosts_sync.rb +2 -0
  24. data/lib/tasks/rh_cloud_inventory.rake +3 -2
  25. data/package.json +5 -1
  26. data/test/controllers/insights_cloud/ui_requests_controller_test.rb +169 -0
  27. data/test/unit/archived_report_generator_test.rb +1 -1
  28. data/test/unit/fact_helpers_test.rb +267 -2
  29. data/test/unit/services/foreman_rh_cloud/cloud_request_forwarder_test.rb +20 -3
  30. data/test/unit/services/foreman_rh_cloud/insights_api_forwarder_test.rb +176 -0
  31. data/test/unit/services/foreman_rh_cloud/tags_auth_test.rb +29 -0
  32. data/test/unit/slice_generator_test.rb +69 -10
  33. data/webpack/CVEsHostDetailsTab/CVEsHostDetailsTab.js +30 -10
  34. data/webpack/CVEsHostDetailsTab/__tests__/CVEsHostDetailsTab.test.js +18 -11
  35. data/webpack/CVEsHostDetailsTab/index.js +2 -2
  36. data/webpack/ForemanColumnExtensions/index.js +51 -0
  37. data/webpack/ForemanInventoryUpload/Components/InventoryFilter/InventoryFilter.js +1 -0
  38. data/webpack/ForemanInventoryUpload/Components/InventoryFilter/__tests__/__snapshots__/InventoryFilter.test.js.snap +1 -0
  39. data/webpack/ForemanInventoryUpload/Components/InventorySettings/MinimalInventoryDropdown.js +2 -0
  40. data/webpack/ForemanInventoryUpload/Components/PageHeader/PageTitle.js +8 -1
  41. data/webpack/ForemanInventoryUpload/Components/PageHeader/__tests__/__snapshots__/PageTitle.test.js.snap +4 -0
  42. data/webpack/ForemanInventoryUpload/Components/PageHeader/components/CloudConnectorButton/CloudConnectorButton.js +3 -3
  43. data/webpack/ForemanInventoryUpload/Components/PageHeader/components/CloudConnectorButton/__tests__/__snapshots__/CloudConnectorButton.test.js.snap +3 -0
  44. data/webpack/ForemanInventoryUpload/Components/PageHeader/components/CloudPingModal/index.js +10 -4
  45. data/webpack/ForemanInventoryUpload/Components/PageHeader/components/PageDescription/PageDescription.js +6 -6
  46. data/webpack/ForemanInventoryUpload/Components/PageHeader/components/SettingsWarning/SettingsWarning.js +2 -0
  47. data/webpack/ForemanInventoryUpload/Components/PageHeader/components/SettingsWarning/__snapshots__/SettingsWarning.test.js.snap +2 -0
  48. data/webpack/ForemanInventoryUpload/Components/PageHeader/components/SyncButton/SyncButton.js +1 -0
  49. data/webpack/ForemanInventoryUpload/Components/PageHeader/components/SyncButton/__tests__/__snapshots__/SyncButton.test.js.snap +1 -0
  50. data/webpack/ForemanInventoryUpload/SubscriptionsPageExtension/InventoryAutoUpload/InventoryAutoUpload.js +3 -1
  51. data/webpack/ForemanInventoryUpload/SubscriptionsPageExtension/InventoryAutoUpload/__tests__/__snapshots__/InventoryAutoUpload.test.js.snap +3 -0
  52. data/webpack/ForemanRhCloudFills.js +6 -3
  53. data/webpack/ForemanRhCloudPages.js +6 -3
  54. data/webpack/InsightsCloudSync/Components/InsightsTable/InsightsTable.js +1 -0
  55. data/webpack/InsightsCloudSync/Components/InsightsTable/SelectAllAlert.js +2 -0
  56. data/webpack/InsightsCloudSync/Components/InsightsTable/__tests__/__snapshots__/InsightsTable.test.js.snap +1 -0
  57. data/webpack/InsightsCloudSync/Components/RemediationModal/RemediationModal.js +3 -0
  58. data/webpack/InsightsCloudSync/Components/RemediationModal/RemediationModalFooter.js +12 -2
  59. data/webpack/InsightsCloudSync/Components/RemediationModal/Resolutions.js +1 -0
  60. data/webpack/InsightsCloudSync/Components/ToolbarDropdown.js +6 -1
  61. data/webpack/InsightsVulnerability/InsightsVulnerabilityListPage.js +21 -0
  62. data/webpack/InsightsVulnerability/InsightsVulnerabilityListPage.test.js +20 -0
  63. data/webpack/InsightsVulnerabilityHostIndexExtensions/CVECountCell.js +45 -0
  64. data/webpack/InsightsVulnerabilityHostIndexExtensions/__tests__/CVECountCell.test.js +28 -0
  65. data/webpack/common/DropdownToggle.js +1 -0
  66. data/webpack/common/ScalprumModule/ScalprumContext.js +63 -0
  67. data/webpack/common/Switcher/SwitcherPF4.js +1 -0
  68. data/webpack/common/Switcher/__tests__/__snapshots__/SwitcherPF4.test.js.snap +1 -0
  69. data/webpack/common/Switcher/index.js +1 -0
  70. data/webpack/global_index.js +3 -0
  71. metadata +19 -4
  72. data/webpack/InsightsVulnerability/InsightsVulnerability.js +0 -13
  73. data/webpack/InsightsVulnerability/InsightsVulnerability.test.js +0 -18
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 6bc60ead37485cf4bb034dd6ccbd416ca9ad957c37123553c1cf529a2a948d48
4
- data.tar.gz: 7490a0bf69893145965f99d692735dca1ad3786439efb306e99423f555c83ad0
3
+ metadata.gz: abf912ff1170fb60a3b10a6d1178f71ad7a92662c2272a883179eb30a62e2c2e
4
+ data.tar.gz: 3ff64877a61a50890423e1d25980ea37e9fc3ae949f875be344b299f5580ab24
5
5
  SHA512:
6
- metadata.gz: 68a8fcbff3c147991ee6c05699a9a0be941552dd97bcd94fb8230635120c40302a06b1ed4d2428a16ad71b353da2a56696e045eca29a3beda0b3df2877bd2206
7
- data.tar.gz: 00ae0a4cafbad304e4da6ff962c8214c67aecc0e7af37a8c2dbd1be1f889dbca095cf93f4c6222441cef08298d333758ff8c2f942358736aca8473cc813fee34
6
+ metadata.gz: 5792bc34bf4e7a254cacc14cd014b9e008378d695ddc5ae00afcbd5f10371840a53ecdd106f2a845531a2c174fab3c7d1b931ba0a6f766c749124adcbcff742f
7
+ data.tar.gz: dffa948ae7cca41a839be2c07f26193ccc11c9af71d84c07d4b0f256a0ad0e5763ce107cf69a22ecb6436212a5e68d09512a4043eb8eb5b01a2268c88d0d44fd
data/README.md CHANGED
@@ -1,18 +1,16 @@
1
1
  [![Ruby tests](https://github.com/theforeman/foreman_rh_cloud/actions/workflows/ruby_tests.yml/badge.svg)](https://github.com/theforeman/foreman_rh_cloud/actions/workflows/ruby_tests.yml)
2
2
  [![JS](https://github.com/theforeman/foreman_rh_cloud/actions/workflows/js_tests.yml/badge.svg)](https://github.com/theforeman/foreman_rh_cloud/actions/workflows/js_tests.yml)
3
+ [![Ask DeepWiki](https://deepwiki.com/badge.svg)](https://deepwiki.com/theforeman/foreman_rh_cloud)
3
4
 
4
5
  # ForemanRhCloud
5
6
 
6
- *Introduction here*
7
-
8
7
  ## Installation
9
8
 
10
9
  See [How_to_Install_a_Plugin](http://projects.theforeman.org/projects/foreman/wiki/How_to_Install_a_Plugin)
11
10
  for how to install Foreman plugins
12
11
 
13
- ## Usage
14
-
15
- *Usage here*
12
+ ## Project overview
13
+ See our [wiki](https://deepwiki.com/theforeman/foreman_rh_cloud)
16
14
 
17
15
  ### In Satellite
18
16
 
@@ -0,0 +1,33 @@
1
+ module InsightsCloud
2
+ module PackageProfileUploadExtensions
3
+ extend ActiveSupport::Concern
4
+
5
+ included do
6
+ # This method explicitly listens on Katello actions
7
+ # rubocop:disable Rails/LexicallyScopedActionFilter
8
+ after_action :generate_host_report, only: [:upload_package_profile, :upload_profiles]
9
+ # rubocop:enable Rails/LexicallyScopedActionFilter
10
+ end
11
+
12
+ def generate_host_report
13
+ return unless ForemanRhCloud.with_local_advisor_engine?
14
+
15
+ logger.debug("Generating host-specific report for host #{@host.name}")
16
+
17
+ ForemanTasks.async_task(
18
+ ForemanInventoryUpload::Async::GenerateReportJob,
19
+ ForemanInventoryUpload.generated_reports_folder,
20
+ @host.organization_id,
21
+ false,
22
+ "id=#{@host.id}"
23
+ )
24
+
25
+ # in IoP case, the hosts are identified by the sub-man ID, and we can assume they already
26
+ # exist in the local inventory. This will also handle facet creation for new hosts.
27
+ return if @host.insights
28
+
29
+ insights_facet = @host.build_insights(uuid: @host.subscription_facet.uuid)
30
+ insights_facet.save
31
+ end
32
+ end
33
+ end
@@ -15,9 +15,8 @@ module InsightsCloud::Api
15
15
 
16
16
  # The method that "proxies" requests over to Cloud
17
17
  def forward_request
18
- certs = candlepin_id_cert @organization
19
18
  begin
20
- @cloud_response = ::ForemanRhCloud::CloudRequestForwarder.new.forward_request(request, controller_name, @branch_id, certs)
19
+ @cloud_response = ::ForemanRhCloud::CloudRequestForwarder.new.forward_request(request, controller_name, @branch_id, @host)
21
20
  rescue RestClient::Exceptions::Timeout => e
22
21
  response_obj = e.response.presence || e.exception
23
22
  return render json: { message: response_obj.to_s, error: response_obj.to_s }, status: :gateway_timeout
@@ -0,0 +1,99 @@
1
+ module InsightsCloud
2
+ class UIRequestsController < ::ApplicationController
3
+ layout false
4
+
5
+ before_action :ensure_org, :ensure_loc, :only => [:forward_request]
6
+
7
+ # The method that "proxies" requests over to Cloud
8
+ def forward_request
9
+ begin
10
+ path_match = request.original_fullpath.match(%r{^/insights_cloud/(?<path>[^?]*)})&.[](:path)
11
+ path_to_forward = path_match || params.require(:path)
12
+
13
+ @cloud_response = ::ForemanRhCloud::InsightsApiForwarder.new.forward_request(
14
+ request,
15
+ path_to_forward,
16
+ controller_name,
17
+ User.current,
18
+ @organization,
19
+ @location
20
+ )
21
+ rescue RestClient::Exceptions::Timeout => e
22
+ response_obj = e.response.presence || e.exception
23
+ return render json: { message: response_obj.to_s, error: response_obj.to_s }, status: :gateway_timeout
24
+ rescue RestClient::Unauthorized => e
25
+ logger.warn("Forwarding request auth error: #{e}")
26
+ message = 'Authentication to the Insights Service failed.'
27
+ return render json: { message: message, error: message }, status: :unauthorized
28
+ rescue RestClient::NotModified => e
29
+ logger.info("Forwarding request not modified: #{e}")
30
+ message = 'Cloud request not modified'
31
+ return render json: { message: message, error: message }, status: :not_modified
32
+ rescue RestClient::ExceptionWithResponse => e
33
+ response_obj = e.response.presence || e.exception
34
+ code = response_obj.try(:code) || response_obj.try(:http_code) || 500
35
+ message = 'Cloud request failed'
36
+
37
+ return render json: {
38
+ :message => message,
39
+ :error => response_obj.to_s,
40
+ :headers => {},
41
+ :response => response_obj,
42
+ }, status: code
43
+ rescue StandardError => e
44
+ # Catch any other exceptions here, such as Errno::ECONNREFUSED
45
+ logger.warn("Cloud request failed with exception: #{e}")
46
+ return render json: { error: e.to_s }, status: :bad_gateway
47
+ end
48
+
49
+ # Append redhat-specific headers
50
+ @cloud_response.headers.each do |key, _value|
51
+ assign_header(response, @cloud_response, key, false) if key.to_s.start_with?('x_rh_')
52
+ end
53
+
54
+ # Append general headers
55
+ assign_header(response, @cloud_response, :x_resource_count, true)
56
+ headers[Rack::ETAG] = @cloud_response.headers[:etag]
57
+
58
+ if @cloud_response.headers[:content_disposition]
59
+ # If there is a Content-Disposition header, it means we are forwarding binary data, send the raw data with proper
60
+ # content type
61
+ send_data @cloud_response, disposition: @cloud_response.headers[:content_disposition], type: @cloud_response.headers[:content_type]
62
+ elsif @cloud_response.headers[:content_type] =~ /zip/
63
+ # If there is no Content-Disposition, but the content type is binary according to Content-Type, send the raw data
64
+ # with proper content type
65
+ send_data @cloud_response, type: @cloud_response.headers[:content_type]
66
+ else
67
+ render json: @cloud_response, status: @cloud_response.code
68
+ end
69
+ end
70
+
71
+ def assign_header(res, cloud_res, header, transform)
72
+ header_content = cloud_res.headers[header]
73
+ return unless header_content
74
+ new_header = transform ? header.to_s.tr('_', '-') : header.to_s
75
+ res.headers[new_header] = header_content
76
+ end
77
+
78
+ private
79
+
80
+ def ensure_org
81
+ @organization = Organization.current
82
+ return render_message 'Organization not found or invalid', :status => 400 unless @organization
83
+ end
84
+
85
+ def ensure_loc
86
+ @location = Location.current
87
+ return render_message 'Location not found or invalid', :status => 400 unless @location
88
+ end
89
+
90
+ def base_url
91
+ InsightsCloud.ui_base_url
92
+ end
93
+
94
+ def render_message(msg, render_options = {})
95
+ render_options[:json] = { :message => msg }
96
+ render render_options
97
+ end
98
+ end
99
+ end
@@ -10,7 +10,8 @@ module ForemanRhCloud
10
10
  end
11
11
 
12
12
  def execute_cloud_request(params)
13
- certs = candlepin_id_cert(params.delete(:organization))
13
+ organization = params.delete(:organization)
14
+ certs = ForemanRhCloud.with_local_advisor_engine? ? foreman_certificate : candlepin_id_cert(organization)
14
15
  final_params = {
15
16
  ssl_client_cert: OpenSSL::X509::Certificate.new(certs[:cert]),
16
17
  ssl_client_key: OpenSSL::PKey.read(certs[:key]),
@@ -18,5 +19,12 @@ module ForemanRhCloud
18
19
 
19
20
  super(final_params)
20
21
  end
22
+
23
+ def foreman_certificate
24
+ @foreman_certificate ||= {
25
+ cert: File.read(Setting[:ssl_certificate]),
26
+ key: File.read(Setting[:ssl_priv_key]),
27
+ }
28
+ end
21
29
  end
22
30
  end
@@ -3,8 +3,9 @@ require 'rest-client'
3
3
  module ForemanRhCloud
4
4
  class CloudRequestForwarder
5
5
  include ForemanRhCloud::CloudRequest
6
+ include ForemanRhCloud::CertAuth
6
7
 
7
- def forward_request(original_request, controller_name, branch_id, certs)
8
+ def forward_request(original_request, controller_name, branch_id, host)
8
9
  forward_params = prepare_forward_params(original_request, branch_id)
9
10
  logger.debug("Request parameters for telemetry request: #{forward_params}")
10
11
 
@@ -12,14 +13,15 @@ module ForemanRhCloud
12
13
 
13
14
  logger.debug("User agent for telemetry is: #{http_user_agent original_request}")
14
15
 
15
- request_opts = prepare_request_opts(original_request, forward_payload, forward_params, certs)
16
+ request_opts = prepare_request_opts(original_request, forward_payload, forward_params, host)
17
+ request_opts[:organization] = host.organization
16
18
 
17
19
  logger.debug("Sending request to: #{request_opts[:url]}")
18
20
 
19
21
  execute_cloud_request(request_opts)
20
22
  end
21
23
 
22
- def prepare_request_opts(original_request, forward_payload, forward_params, certs)
24
+ def prepare_request_opts(original_request, forward_payload, forward_params, host)
23
25
  base_params = {
24
26
  method: original_request.method,
25
27
  payload: forward_payload,
@@ -28,11 +30,12 @@ module ForemanRhCloud
28
30
  params: forward_params,
29
31
  user_agent: http_user_agent(original_request),
30
32
  content_type: original_request.media_type.presence || original_request.format.to_s,
33
+ Forwarded: prepare_forwarded_header(host),
31
34
  }
32
35
  ),
33
36
  }
34
37
  requested_url = original_request.original_fullpath.end_with?('/') ? original_request.path + '/' : original_request.path
35
- params = path_params(requested_url, certs)
38
+ params = path_params(requested_url)
36
39
 
37
40
  if ForemanRhCloud.with_local_advisor_engine?
38
41
  params[:ssl_ca_file] = ForemanRhCloud.ca_cert
@@ -65,31 +68,23 @@ module ForemanRhCloud
65
68
  forward_params
66
69
  end
67
70
 
68
- def path_params(request_path, certs)
71
+ def path_params(request_path)
69
72
  case request_path
70
73
  when lightspeed?
71
74
  {
72
75
  url: ForemanRhCloud.cert_base_url + request_path,
73
- ssl_client_cert: OpenSSL::X509::Certificate.new(certs[:cert]),
74
- ssl_client_key: OpenSSL::PKey.read(certs[:key]),
75
76
  }
76
77
  when platform_request?
77
78
  {
78
79
  url: ForemanRhCloud.cert_base_url + request_path.sub('/redhat_access/r/insights/platform', '/api'),
79
- ssl_client_cert: OpenSSL::X509::Certificate.new(certs[:cert]),
80
- ssl_client_key: OpenSSL::PKey.read(certs[:key]),
81
80
  }
82
81
  when connection_test_request?
83
82
  {
84
83
  url: ForemanRhCloud.cert_base_url + '/api/apicast-tests/ping',
85
- ssl_client_cert: OpenSSL::X509::Certificate.new(certs[:cert]),
86
- ssl_client_key: OpenSSL::PKey.read(certs[:key]),
87
84
  }
88
85
  else # Legacy insights API
89
86
  {
90
87
  url: ForemanRhCloud.legacy_insights_url + request_path.sub('/redhat_access/r/insights', '/r/insights'),
91
- ssl_client_cert: OpenSSL::X509::Certificate.new(certs[:cert]),
92
- ssl_client_key: OpenSSL::PKey.read(certs[:key]),
93
88
  ssl_ca_file: ForemanRhCloud.legacy_insights_ca,
94
89
  }
95
90
  end
@@ -105,6 +100,10 @@ module ForemanRhCloud
105
100
  headers
106
101
  end
107
102
 
103
+ def prepare_forwarded_header(host)
104
+ "for=\"_#{host.subscription_facet.uuid}\""
105
+ end
106
+
108
107
  def lightspeed?
109
108
  ->(request_path) { request_path.include? '/lightspeed' }
110
109
  end
@@ -0,0 +1,26 @@
1
+ module ForemanRhCloud
2
+ module GatewayRequest
3
+ extend ActiveSupport::Concern
4
+
5
+ include CloudRequest
6
+
7
+ def execute_cloud_request(params)
8
+ certs = params.delete(:certs) || foreman_certificates
9
+ final_params = {
10
+ ssl_client_cert: OpenSSL::X509::Certificate.new(certs[:cert]),
11
+ ssl_client_key: OpenSSL::PKey.read(certs[:key]),
12
+ ssl_ca_file: Setting[:ssl_ca_file],
13
+ verify_ssl: OpenSSL::SSL::VERIFY_PEER,
14
+ }.deep_merge(params)
15
+
16
+ super(final_params)
17
+ end
18
+
19
+ def foreman_certificates
20
+ {
21
+ cert: File.read(Setting[:ssl_certificate]),
22
+ key: File.read(Setting[:ssl_priv_key]),
23
+ }
24
+ end
25
+ end
26
+ end
@@ -0,0 +1,116 @@
1
+ require 'rest-client'
2
+
3
+ module ForemanRhCloud
4
+ class InsightsApiForwarder
5
+ include ForemanRhCloud::GatewayRequest
6
+
7
+ SCOPED_REQUESTS = [
8
+ %r{/api/vulnerability/v1/vulnerabilities/cves},
9
+ %r{/api/vulnerability/v1/dashbar},
10
+ %r{/api/vulnerability/v1/cves/[^/]+/affected_systems},
11
+ %r{/api/vulnerability/v1/systems/[^/]+/cves},
12
+ %r{/api/insights/.*},
13
+ %r{/api/inventory/.*},
14
+ %r{/api/tasks/.*},
15
+ ].freeze
16
+
17
+ def forward_request(original_request, path, controller_name, user, organization, location)
18
+ TagsAuth.new(user, organization, location, logger).update_tag if scope_request?(original_request, path)
19
+
20
+ forward_params = prepare_forward_params(original_request, path, user: user, organization: organization, location: location).to_a
21
+ logger.debug("Request parameters for UI request: #{forward_params}")
22
+
23
+ forward_payload = prepare_forward_payload(original_request, controller_name)
24
+
25
+ logger.debug("User agent for UI is: #{http_user_agent(original_request)}")
26
+
27
+ request_opts = prepare_request_opts(original_request, path, forward_payload, forward_params)
28
+
29
+ logger.debug("Sending request to: #{request_opts[:url]}")
30
+
31
+ execute_cloud_request(request_opts)
32
+ end
33
+
34
+ def prepare_tags(user, organization, location)
35
+ [
36
+ TagsAuth.auth_tag_for(user, organization, location),
37
+ ].map { |tag_value| [:tag, tag_value] }
38
+ end
39
+
40
+ def prepare_request_opts(original_request, path, forward_payload, forward_params)
41
+ base_params = {
42
+ method: original_request.method,
43
+ payload: forward_payload,
44
+ headers: original_headers(original_request).merge(
45
+ {
46
+ params: RestClient::ParamsArray.new(forward_params),
47
+ user_agent: http_user_agent(original_request),
48
+ content_type: original_request.media_type.presence || original_request.format.to_s,
49
+ }
50
+ ),
51
+ }
52
+ params = path_params(path)
53
+
54
+ base_params.merge(params)
55
+ end
56
+
57
+ def prepare_forward_payload(original_request, controller_name)
58
+ forward_payload = original_request.request_parameters[controller_name]
59
+
60
+ forward_payload = original_request.raw_post.clone if (original_request.post? || original_request.patch?) && original_request.raw_post
61
+ forward_payload = original_request.body.read if original_request.put?
62
+
63
+ forward_payload = original_request.params.slice(:file, :metadata) if original_request.params[:file]
64
+
65
+ # fix rails behaviour for http PATCH:
66
+ forward_payload = forward_payload.to_json if original_request.format.json? && original_request.patch? && forward_payload && !forward_payload.is_a?(String)
67
+ forward_payload
68
+ end
69
+
70
+ def prepare_forward_params(original_request, path, user:, organization:, location:)
71
+ forward_params = original_request.query_parameters.to_a
72
+
73
+ forward_params += prepare_tags(user, organization, location) if scope_request?(original_request, path)
74
+
75
+ forward_params
76
+ end
77
+
78
+ def path_params(path)
79
+ {
80
+ url: "#{InsightsCloud.ui_base_url}/#{path}",
81
+ }
82
+ end
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
+
94
+ def scope_request?(original_request, path)
95
+ return false unless original_request.get?
96
+
97
+ SCOPED_REQUESTS.any? { |request_pattern| request_pattern.match?(path) }
98
+ end
99
+
100
+ def core_app_name
101
+ BranchInfo.new.core_app_name
102
+ end
103
+
104
+ def core_app_version
105
+ BranchInfo.new.core_app_version
106
+ end
107
+
108
+ def http_user_agent(original_request)
109
+ "#{core_app_name}/#{core_app_version};#{ForemanRhCloud::Engine.engine_name}/#{ForemanRhCloud::VERSION};#{original_request.env['HTTP_USER_AGENT']}"
110
+ end
111
+
112
+ def logger
113
+ Foreman::Logging.logger('app')
114
+ end
115
+ end
116
+ end
@@ -0,0 +1,55 @@
1
+ module ForemanRhCloud
2
+ class TagsAuth
3
+ include GatewayRequest
4
+
5
+ TAG_NAMESPACE = 'sat_iam'.freeze
6
+ TAG_SHORT_NAME = 'scope'.freeze
7
+ TAG_NAME = "#{TAG_NAMESPACE}/#{TAG_SHORT_NAME}".freeze
8
+
9
+ def self.auth_tag_for(user, org, loc)
10
+ new(user, org, loc, nil).auth_tag
11
+ end
12
+
13
+ attr_reader :logger
14
+
15
+ def initialize(user, org, loc, logger)
16
+ @user = user
17
+ @org = org
18
+ @loc = loc
19
+ @logger = logger
20
+ end
21
+
22
+ def update_tag
23
+ logger.debug("Updating tags for user: #{@user}, org: #{@org.name}, loc: #{@loc.name}")
24
+
25
+ params = {
26
+ method: :post,
27
+ url: "#{InsightsCloud.gateway_url}/tags",
28
+ headers: {
29
+ content_type: :json,
30
+ },
31
+ payload: tags_query_payload.to_json,
32
+ }
33
+ execute_cloud_request(params)
34
+ end
35
+
36
+ def allowed_hosts
37
+ Host.authorized_as(@user, nil, nil).where(organization: @org, location: @loc).joins(:subscription_facet).pluck('katello_subscription_facets.uuid')
38
+ end
39
+
40
+ def tags_query_payload
41
+ {
42
+ tags: [{ "namespace": TAG_NAMESPACE, "key": TAG_SHORT_NAME, "value": tag_value }],
43
+ host_id_list: allowed_hosts,
44
+ }
45
+ end
46
+
47
+ def tag_value
48
+ "U:\"#{@user.login}\"O:\"#{@org.name}\"L:\"#{@loc.name}\""
49
+ end
50
+
51
+ def auth_tag
52
+ "#{TAG_NAME}=#{tag_value}"
53
+ end
54
+ end
55
+ end
@@ -3,3 +3,9 @@ attributes :uuid
3
3
  node :insights_hit_details do |facet|
4
4
  facet&.host&.facts('insights::hit_details')&.values&.first
5
5
  end
6
+ node :insights_hits_count do |facet|
7
+ facet.hits&.count
8
+ end
9
+ node :use_local_advisor_engine do |_facet|
10
+ ForemanRhCloud.with_local_advisor_engine?
11
+ end
data/config/routes.rb CHANGED
@@ -30,6 +30,8 @@ Rails.application.routes.draw do
30
30
  match 'hits/:host_id', to: 'hits#show', via: :get
31
31
 
32
32
  post ':organization_id/parameter', to: 'settings#set_org_parameter', constraints: { organization_id: %r{[^\/]+} }
33
+
34
+ match '/*path', constraints: { path: %r{api/[^\?]+} }, to: 'ui_requests#forward_request', via: :all
33
35
  end
34
36
 
35
37
  namespace :foreman_rh_cloud do
@@ -5,18 +5,19 @@ module ForemanInventoryUpload
5
5
  "report_for_#{label}"
6
6
  end
7
7
 
8
- def plan(base_folder, organization_id, disconnected)
8
+ def plan(base_folder, organization_id, disconnected, hosts_filter = nil)
9
9
  sequence do
10
10
  super(
11
- GenerateReportJob.output_label(organization_id),
11
+ GenerateReportJob.output_label("#{organization_id}#{hosts_filter.empty? ? nil : "[#{hosts_filter.to_s.parameterize}]"}"),
12
12
  organization_id: organization_id,
13
- base_folder: base_folder
13
+ base_folder: base_folder,
14
+ hosts_filter: hosts_filter
14
15
  )
15
16
 
16
17
  plan_action(
17
18
  QueueForUploadJob,
18
19
  base_folder,
19
- ForemanInventoryUpload.facts_archive_name(organization_id),
20
+ ForemanInventoryUpload.facts_archive_name(organization_id, hosts_filter),
20
21
  organization_id,
21
22
  disconnected
22
23
  )
@@ -34,7 +35,8 @@ module ForemanInventoryUpload
34
35
  def env
35
36
  super.merge(
36
37
  'target' => base_folder,
37
- 'organization_id' => organization_id
38
+ 'organization_id' => organization_id,
39
+ 'hosts_filter' => hosts_filter
38
40
  )
39
41
  end
40
42
 
@@ -45,6 +47,10 @@ module ForemanInventoryUpload
45
47
  def organization_id
46
48
  input[:organization_id]
47
49
  end
50
+
51
+ def hosts_filter
52
+ input[:hosts_filter]
53
+ end
48
54
  end
49
55
  end
50
56
  end
@@ -33,8 +33,8 @@ module ForemanInventoryUpload
33
33
  end
34
34
 
35
35
  Tempfile.create([organization.name, '.pem']) do |cer_file|
36
- cer_file.write(rh_credentials[:cert])
37
- cer_file.write(rh_credentials[:key])
36
+ cer_file.write(certificate[:cert])
37
+ cer_file.write(certificate[:key])
38
38
  cer_file.flush
39
39
  @cer_path = cer_file.path
40
40
  super
@@ -59,8 +59,12 @@ module ForemanInventoryUpload
59
59
  env_vars
60
60
  end
61
61
 
62
- def rh_credentials
63
- @rh_credentials ||= begin
62
+ def certificate
63
+ ForemanRhCloud.with_local_advisor_engine? ? foreman_certificate : manifest_certificate
64
+ end
65
+
66
+ def manifest_certificate
67
+ @manifest_certificate ||= begin
64
68
  candlepin_id_certificate = organization.owner_details['upstreamConsumer']['idCert']
65
69
  {
66
70
  cert: candlepin_id_certificate['cert'],
@@ -69,6 +73,13 @@ module ForemanInventoryUpload
69
73
  end
70
74
  end
71
75
 
76
+ def foreman_certificate
77
+ @foreman_certificate ||= {
78
+ cert: File.read(Setting[:ssl_certificate]),
79
+ key: File.read(Setting[:ssl_priv_key]),
80
+ }
81
+ end
82
+
72
83
  def filename
73
84
  input[:filename]
74
85
  end
@@ -6,10 +6,10 @@ module ForemanInventoryUpload
6
6
  @logger = logger
7
7
  end
8
8
 
9
- def render(organization:)
9
+ def render(organization:, filter: nil)
10
10
  Dir.mktmpdir do |tmpdir|
11
11
  @logger.info "Started generating hosts report in #{tmpdir}"
12
- host_batches = ForemanInventoryUpload::Generators::Queries.for_org(organization)
12
+ host_batches = ForemanInventoryUpload::Generators::Queries.for_org(organization, hosts_query: filter || '')
13
13
  File.open(File.join(tmpdir, 'metadata.json'), 'w') do |metadata_out|
14
14
  metadata_generator = ForemanInventoryUpload::Generators::Metadata.new(metadata_out)
15
15
  metadata_generator.render do |inner_generator|