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
@@ -57,17 +57,39 @@ module ForemanInventoryUpload
57
57
  end
58
58
 
59
59
  def obfuscate_hostname?(host)
60
+ # Returns true if hostname obfuscation should be applied for a given host, based on hierarchy:
61
+ # 1. Global setting for hostname obfuscation.
62
+ return true if Setting[:obfuscate_inventory_hostnames]
63
+
60
64
  insights_client_setting = fact_value(host, 'insights_client::obfuscate_hostname_enabled')
61
65
  insights_client_setting = ActiveModel::Type::Boolean.new.cast(insights_client_setting)
62
- return insights_client_setting unless insights_client_setting.nil?
63
66
 
64
- Setting[:obfuscate_inventory_hostnames]
67
+ # 2. host fact reported by insights_client
68
+ # 3. if neither of the above, don't obfuscate.
69
+ insights_client_setting.nil? ? false : insights_client_setting
65
70
  end
66
71
 
67
72
  def fqdn(host)
68
- return host.fqdn unless obfuscate_hostname?(host)
69
-
70
- fact_value(host, 'insights_client::hostname') || obfuscate_fqdn(host.fqdn)
73
+ if obfuscate_hostname?(host)
74
+ # If obfuscation is enabled, attempt to retrieve an already obfuscated hostname
75
+ # from the 'insights_client::obfuscated_hostname' fact.
76
+ # Example format of `parsed_insights_array`:
77
+ # [{"original"=>"host.example.com", "obfuscated"=>"0dd449d0a027.example.com"},
78
+ # {"original"=>"satellite.example.com", "obfuscated"=>"host2.example.com"}]
79
+ begin
80
+ parsed_insights_array = JSON.parse(fact_value(host, 'insights_client::obfuscated_hostname') || '[]')
81
+ rescue JSON::ParserError
82
+ parsed_insights_array = []
83
+ end
84
+ # Obfuscate using the following hierarchy:
85
+ # 1. the obfuscated_hostname fact sent by insights_client
86
+ parsed_insights_item = parsed_insights_array.find { |item| item['original'] == host.fqdn }
87
+ # 2. our own helper method
88
+ parsed_insights_item&.[]('obfuscated') || obfuscate_fqdn(host.fqdn)
89
+ else
90
+ # If hostname obfuscation is not enabled for this host, return the host's original FQDN.
91
+ host.fqdn
92
+ end
71
93
  end
72
94
 
73
95
  def obfuscate_fqdn(fqdn)
@@ -75,35 +97,65 @@ module ForemanInventoryUpload
75
97
  end
76
98
 
77
99
  def obfuscate_ips?(host)
78
- insights_client_setting = fact_value(host, 'insights_client::obfuscate_ip_enabled')
79
- insights_client_setting = ActiveModel::Type::Boolean.new.cast(insights_client_setting)
80
- return insights_client_setting unless insights_client_setting.nil?
100
+ # Returns true if IP obfuscation should be applied for a given host, based on hierarchy:
101
+ # 1. Global setting for IP obfuscation.
102
+ return true if Setting[:obfuscate_inventory_ips]
81
103
 
82
- Setting[:obfuscate_inventory_ips]
104
+ insights_client_ipv4_setting = fact_value(host, 'insights_client::obfuscate_ipv4_enabled')
105
+ insights_client_ipv6_setting = fact_value(host, 'insights_client::obfuscate_ipv6_enabled')
106
+
107
+ cast_ipv4_setting = ActiveModel::Type::Boolean.new.cast(insights_client_ipv4_setting)
108
+ cast_ipv6_setting = ActiveModel::Type::Boolean.new.cast(insights_client_ipv6_setting)
109
+
110
+ # 2. The host's IPv4 or IPv6 obfuscation fact value is true
111
+ # 3. If neither of the above, don't obfuscate.
112
+ cast_ipv4_setting || cast_ipv6_setting || false
83
113
  end
84
114
 
85
115
  def host_ips(host)
116
+ # Determines and returns the IP addresses associated with a host, applying obfuscation if enabled.
117
+
118
+ # If IP obfuscation is enabled for the host return a representation of obfuscated IP addresses.
86
119
  return obfuscated_ips(host) if obfuscate_ips?(host)
87
120
 
88
- # return a pass through proxy hash in case no obfuscation needed
121
+ # If IP obfuscation is NOT needed, return a special kind of Hash.
122
+ # where when you try to access a key in it
123
+ # if the key doesn't exist, it simply returns the key itself.
124
+ # This is useful because it means if you try to get an IP from this hash,
125
+ # you'll just get the original IP back. It allows the calling code to
126
+ # use the same interface whether obfuscation is applied or not.
89
127
  Hash.new { |h, k| k }
90
128
  end
91
129
 
92
130
  def obfuscated_ips(host)
93
- insights_client_ips = JSON.parse(fact_value(host, 'insights_client::ips') || '[]')
131
+ # Example format of `parsed_insights_array`:
132
+ # [{"original": "192.168.1.10", "obfuscated": "10.230.230.1"},
133
+ # {"original": "192.168.1.11", "obfuscated": "10.230.230.2"}]
134
+ begin
135
+ parsed_insights_array = JSON.parse(fact_value(host, 'insights_client::obfuscated_ipv4') || '[]')
136
+ rescue JSON::ParserError
137
+ parsed_insights_array = []
138
+ end
94
139
 
140
+ # Create a new Hash to store the mapping from original IP addresses to their obfuscated versions.
141
+ # where the 'original' IP is the key and the 'obfuscated' IP is the value.
95
142
  obfuscated_ips = Hash[
96
- insights_client_ips.map { |ip_record| [ip_record['original'], ip_record['obfuscated']] }
143
+ parsed_insights_array.map { |ip_record| [ip_record['original'], ip_record['obfuscated']] }
97
144
  ]
98
145
 
146
+ # Sets a default proc for the obfuscated_ips hash.
147
+ # When a key is accessed that does not exist in the hash, this proc is called.
148
+ # It assigns the result of obfuscate_ip(key, hash) to the missing key in the hash.
149
+ # This ensures that any missing IP address key will be obfuscated and stored automatically.
99
150
  obfuscated_ips.default_proc = proc do |hash, key|
100
151
  hash[key] = obfuscate_ip(key, hash)
101
152
  end
102
-
103
153
  obfuscated_ips
104
154
  end
105
155
 
106
156
  def obfuscate_ip(ip, ips_dict)
157
+ # Produce a new, unique obfuscated IP that is
158
+ # numerically one greater than the highest existing obfuscated IP
107
159
  max_obfuscated = ips_dict.values.map { |v| IPAddr.new(v).to_i }.max || IPAddr.new('10.230.230.0').to_i
108
160
 
109
161
  IPAddr.new(max_obfuscated + 1, Socket::AF_INET).to_s
@@ -26,9 +26,11 @@ module ForemanInventoryUpload
26
26
  'dmi::system::product_name',
27
27
  'dmi::chassis::asset_tag',
28
28
  'insights_client::obfuscate_hostname_enabled',
29
- 'insights_client::obfuscate_ip_enabled',
30
- 'insights_client::hostname',
31
- 'insights_client::ips',
29
+ 'insights_client::obfuscate_ipv4_enabled',
30
+ 'insights_client::obfuscate_ipv6_enabled',
31
+ 'insights_client::obfuscated_ipv4',
32
+ 'insights_client::obfuscated_ipv6',
33
+ 'insights_client::obfuscated_hostname',
32
34
  'insights_id',
33
35
  'conversions::activity',
34
36
  'conversions::packages::0::nevra',
@@ -58,8 +60,8 @@ module ForemanInventoryUpload
58
60
  )
59
61
  end
60
62
 
61
- def self.for_org(organization_id, use_batches: true)
62
- base_query = for_slice(Host.unscoped.where(organization_id: organization_id))
63
+ def self.for_org(organization_id, use_batches: true, hosts_query: '')
64
+ base_query = for_slice(Host.unscoped.where(organization_id: organization_id).search_for(hosts_query))
63
65
  use_batches ? base_query.in_batches(of: ForemanInventoryUpload.slice_size) : base_query
64
66
  end
65
67
  end
@@ -190,7 +190,6 @@ module ForemanInventoryUpload
190
190
  ) { |v| os_release_value(*v) }
191
191
  @stream.simple_field('os_kernel_version', fact_value(host, 'uname::release'))
192
192
  @stream.simple_field('arch', host.architecture&.name)
193
- @stream.simple_field('katello_agent_running', false)
194
193
  @stream.simple_field(
195
194
  'infrastructure_type',
196
195
  ActiveModel::Type::Boolean.new.cast(fact_value(host, 'virt::is_guest')) ? 'virtual' : 'physical'
@@ -52,8 +52,8 @@ module ForemanInventoryUpload
52
52
  'uploader.sh'
53
53
  end
54
54
 
55
- def self.facts_archive_name(organization)
56
- "report_for_#{organization}.tar.xz"
55
+ def self.facts_archive_name(organization, filter = nil)
56
+ "report_for_#{organization}#{filter.empty? ? nil : "[#{filter.to_s.parameterize}]"}.tar.xz"
57
57
  end
58
58
 
59
59
  def self.upload_url
@@ -84,6 +84,7 @@ module ForemanRhCloud
84
84
  '/foreman_rh_cloud/insights_cloud': [:index], # for bookmarks and later for showing the page
85
85
  'insights_cloud/hits': [:index, :show, :auto_complete_search, :resolutions],
86
86
  'insights_cloud/settings': [:index, :show],
87
+ 'insights_cloud/ui_requests': [:forward_request],
87
88
  'react': [:index],
88
89
  },
89
90
  :resource_type => ::InsightsHit.name
@@ -114,8 +115,7 @@ module ForemanRhCloud
114
115
  caption: N_('Inventory Upload'),
115
116
  url: '/foreman_rh_cloud/inventory_upload',
116
117
  url_hash: { controller: :react, action: :index },
117
- parent: :insights_menu,
118
- if: -> { !ForemanRhCloud.with_local_advisor_engine? }
118
+ parent: :insights_menu
119
119
  menu :top_menu, :insights_hits, caption: N_('Recommendations'), url: '/foreman_rh_cloud/insights_cloud', url_hash: { controller: :react, action: :index }, parent: :insights_menu
120
120
  menu :top_menu,
121
121
  :insights_vulnerability,
@@ -165,6 +165,8 @@ module ForemanRhCloud
165
165
  ::Katello::UINotifications::Subscriptions::ManifestImportSuccess.include ForemanInventoryUpload::Notifications::ManifestImportSuccessNotificationOverride if defined?(Katello)
166
166
 
167
167
  ::Host::Managed.include RhCloudHost
168
+
169
+ ::Katello::Api::Rhsm::CandlepinDynflowProxyController.include InsightsCloud::PackageProfileUploadExtensions
168
170
  end
169
171
  end
170
172
 
@@ -198,7 +200,7 @@ module ForemanRhCloud
198
200
  RemoteExecutionFeature.register(
199
201
  :rh_cloud_connector_run_playbook,
200
202
  N_('Run RH Cloud playbook'),
201
- description: N_('Run playbook genrated by Red Hat remediations app'),
203
+ description: N_('Run playbook generated by Red Hat remediations app'),
202
204
  host_action_button: false,
203
205
  provided_inputs: ['playbook_url', 'report_url', 'correlation_id', 'report_interval']
204
206
  )
@@ -1,3 +1,3 @@
1
1
  module ForemanRhCloud
2
- VERSION = '12.1.3'.freeze
2
+ VERSION = '12.1.5'.freeze
3
3
  end
@@ -21,6 +21,14 @@ module InsightsCloud
21
21
  ForemanRhCloud.cert_base_url + '/api/remediations/v1/playbook'
22
22
  end
23
23
 
24
+ def self.gateway_url
25
+ ForemanRhCloud.cert_base_url
26
+ end
27
+
28
+ def self.ui_base_url
29
+ InsightsCloud.gateway_url
30
+ end
31
+
24
32
  def self.remediation_rule_id(rule_id)
25
33
  "advisor:#{rule_id}"
26
34
  end
@@ -8,6 +8,8 @@ module InventorySync
8
8
  set_callback :step, :around, :create_missing_hosts
9
9
 
10
10
  def plan(organizations)
11
+ # Do not run for local advisor, since we use sub-man id to identify hosts.
12
+ return if ForemanRhCloud.with_local_advisor_engine?
11
13
  # by default the tasks will be executed concurrently
12
14
  super(organizations)
13
15
  plan_self_host_sync
@@ -26,6 +26,7 @@ namespace :rh_cloud_inventory do
26
26
  task generate: :environment do
27
27
  organizations = [ENV['organization_id']]
28
28
  base_folder = ENV['target'] || Dir.pwd
29
+ filter = ENV['hosts_filter']
29
30
 
30
31
  unless File.writable?(base_folder)
31
32
  puts "#{base_folder} is not writable by the current process"
@@ -40,9 +41,9 @@ namespace :rh_cloud_inventory do
40
41
 
41
42
  User.as_anonymous_admin do
42
43
  organizations.each do |organization|
43
- target = File.join(base_folder, ForemanInventoryUpload.facts_archive_name(organization))
44
+ target = File.join(base_folder, ForemanInventoryUpload.facts_archive_name(organization, filter))
44
45
  archived_report_generator = ForemanInventoryUpload::Generators::ArchivedReport.new(target, Logger.new(STDOUT))
45
- archived_report_generator.render(organization: organization)
46
+ archived_report_generator.render(organization: organization, filter: filter)
46
47
  puts "Successfully generated #{target} for organization id #{organization}"
47
48
  end
48
49
  end
data/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "foreman_rh_cloud",
3
- "version": "12.1.3",
3
+ "version": "12.1.5",
4
4
  "description": "Inventory Upload =============",
5
5
  "main": "index.js",
6
6
  "scripts": {
@@ -21,6 +21,10 @@
21
21
  "peerDependencies": {
22
22
  "@theforeman/vendor": ">= 15.0.1"
23
23
  },
24
+ "dependencies": {
25
+ "@scalprum/react-core": "^0.9.3",
26
+ "@scalprum/core": "^0.8.1"
27
+ },
24
28
  "devDependencies": {
25
29
  "@babel/core": "^7.7.0",
26
30
  "@theforeman/builder": ">= 15.0.1",
@@ -0,0 +1,169 @@
1
+ require 'test_plugin_helper'
2
+ require 'rest-client'
3
+
4
+ module InsightsCloud
5
+ class UIRequestsControllerTest < ActionController::TestCase
6
+ include KatelloCVEHelper
7
+
8
+ setup do
9
+ FactoryBot.create(:common_parameter, name: InsightsCloud.enable_client_param, key_type: 'boolean', value: true)
10
+ end
11
+
12
+ context '#forward_request' do
13
+ include MockCerts
14
+
15
+ setup do
16
+ @body = 'Cloud response body'
17
+ @http_req = RestClient::Request.new(:method => 'GET', :url => 'http://test.theforeman.org')
18
+
19
+ @org = FactoryBot.create(:organization)
20
+ @loc = FactoryBot.create(:location)
21
+ host = FactoryBot.create(:host, :with_subscription, :organization => @org)
22
+ User.current = ::Katello::CpConsumerUser.new(:uuid => host.subscription_facet.uuid, :login => host.subscription_facet.uuid)
23
+ InsightsCloud::UIRequestsController.any_instance.stubs(:upstream_owner).returns({ 'uuid' => 'abcdefg' })
24
+ ForemanRhCloud::TagsAuth.any_instance.stubs(:execute_cloud_request)
25
+
26
+ setup_certs_expectation do
27
+ ForemanRhCloud::InsightsApiForwarder.any_instance.stubs(:foreman_certificates)
28
+ end
29
+ end
30
+
31
+ test "should respond with response from cloud" do
32
+ net_http_resp = Net::HTTPResponse.new(1.0, 200, "OK")
33
+ net_http_resp.add_field 'Set-Cookie', 'Monster'
34
+ res = RestClient::Response.create(@body, net_http_resp, @http_req)
35
+ ::ForemanRhCloud::InsightsApiForwarder.any_instance.stubs(:forward_request).returns(res)
36
+
37
+ get :forward_request, params: { "controller" => "vulnerabilities", "path" => "api/vulnerability/v1/cves" }, session: set_session
38
+ assert_equal @body, @response.body
39
+ end
40
+
41
+ test "should handle timeout from cloud" do
42
+ ::ForemanRhCloud::InsightsApiForwarder.any_instance.
43
+ stubs(:forward_request).
44
+ raises(RestClient::Exceptions::OpenTimeout.new("Timed out connecting to server"))
45
+
46
+ get :forward_request, params: { "controller" => "vulnerabilities", "path" => "api/vulnerability/v1/cves" }, session: set_session
47
+ request_response = JSON.parse(@response.body)
48
+ # I can't get @response.status to take a nil value so I'm not asserting for that
49
+
50
+ assert_equal 'Timed out connecting to server', request_response['error']
51
+ end
52
+
53
+ test "should add headers to response from cloud" do
54
+ x_resource_count = '101'
55
+ x_rh_insights_request_id = '202'
56
+ net_http_resp = Net::HTTPResponse.new(1.0, 200, "OK")
57
+ net_http_resp['x_resource_count'] = x_resource_count
58
+ net_http_resp['x_rh_insights_request_id'] = x_rh_insights_request_id
59
+ res = RestClient::Response.create(@body, net_http_resp, @http_req)
60
+ ::ForemanRhCloud::InsightsApiForwarder.any_instance.stubs(:forward_request).returns(res)
61
+
62
+ get :forward_request, params: { "controller" => "vulnerabilities", "path" => "api/vulnerability/v1/cves" }, session: set_session
63
+ assert_equal x_resource_count, @response.headers['x-resource-count']
64
+ assert_equal x_rh_insights_request_id, @response.headers['x_rh_insights_request_id']
65
+ end
66
+
67
+ test "should extract path from original_fullpath when URL starts with insights_cloud" do
68
+ net_http_resp = Net::HTTPResponse.new(1.0, 200, "OK")
69
+ # Simulate a request with insights_cloud in the path
70
+ @request.stubs(:original_fullpath).returns('/insights_cloud/api/vulnerability/v1/cves?search=test')
71
+
72
+ res = RestClient::Response.create(@body, net_http_resp, @http_req)
73
+ ::ForemanRhCloud::InsightsApiForwarder
74
+ .any_instance
75
+ .expects(:forward_request)
76
+ .returns(res)
77
+ .with { |_, path_to_forward| _(path_to_forward).must_equal('api/vulnerability/v1/cves') }
78
+
79
+ get :forward_request, params: { "controller" => "vulnerabilities", "path" => "api/vulnerability/v1/cves" }, session: set_session
80
+
81
+ assert_equal @body, @response.body
82
+ end
83
+
84
+ test "should set etag header to response from cloud" do
85
+ etag = '12345'
86
+ req = RestClient::Request.new(:method => 'GET', :url => 'http://test.theforeman.org', :headers => { "If-None-Match": etag })
87
+ net_http_resp = Net::HTTPResponse.new(1.0, 200, "OK")
88
+ net_http_resp[Rack::ETAG] = etag
89
+ res = RestClient::Response.create(@body, net_http_resp, req)
90
+ ::ForemanRhCloud::InsightsApiForwarder.any_instance.stubs(:forward_request).returns(res)
91
+
92
+ get :forward_request, params: { "controller" => "vulnerabilities", "path" => "api/vulnerability/v1/cves" }, session: set_session
93
+ assert_equal etag, @response.headers[Rack::ETAG]
94
+ end
95
+
96
+ test "should set content type header to response from cloud" do
97
+ req = RestClient::Request.new(:method => 'GET', :url => 'http://test.theforeman.org')
98
+ net_http_resp = Net::HTTPResponse.new(1.0, 200, "OK")
99
+ net_http_resp[:content_type] = 'application/zip'
100
+ res = RestClient::Response.create(@body, net_http_resp, req)
101
+ ::ForemanRhCloud::InsightsApiForwarder.any_instance.stubs(:forward_request).returns(res)
102
+
103
+ get :forward_request, params: { "controller" => "vulnerabilities", "path" => "api/vulnerability/v1/cves" }, session: set_session
104
+ assert_equal net_http_resp[:content_type], @response.headers['Content-Type']
105
+ end
106
+
107
+ test "should handle StandardError" do
108
+ error_message = "Connection refused"
109
+ ::ForemanRhCloud::InsightsApiForwarder.any_instance.stubs(:execute_cloud_request).raises(Errno::ECONNREFUSED.new)
110
+
111
+ get :forward_request, params: { "controller" => "vulnerabilities", "path" => "api/vulnerability/v1/cves" }, session: set_session
112
+ assert_equal 502, @response.status
113
+ body = JSON.parse(@response.body)
114
+ assert_equal error_message, body['error']
115
+ end
116
+
117
+ test "should handle 304 cloud" do
118
+ net_http_resp = Net::HTTPResponse.new(1.0, 304, "Not Modified")
119
+ res = RestClient::Response.create(@body, net_http_resp, @http_req)
120
+
121
+ ::ForemanRhCloud::InsightsApiForwarder.any_instance.stubs(:execute_cloud_request).raises(RestClient::NotModified.new(res))
122
+
123
+ get :forward_request, params: { "controller" => "vulnerabilities", "path" => "api/vulnerability/v1/cves" }, session: set_session
124
+ assert_equal 304, @response.status
125
+ assert_equal 'Cloud request not modified', JSON.parse(@response.body)['message']
126
+ end
127
+
128
+ test "should handle RestClient::Exceptions::Timeout" do
129
+ timeout_message = "execution expired"
130
+ ::ForemanRhCloud::InsightsApiForwarder.any_instance.stubs(:execute_cloud_request).raises(RestClient::Exceptions::Timeout.new(timeout_message))
131
+
132
+ get :forward_request, params: { "controller" => "vulnerabilities", "path" => "api/vulnerability/v1/cves" }, session: set_session
133
+ assert_equal 504, @response.status
134
+ body = JSON.parse(@response.body)
135
+ assert_equal timeout_message, body['message']
136
+ assert_equal timeout_message, body['error']
137
+ end
138
+
139
+ test "should handle failed authentication to cloud" do
140
+ net_http_resp = Net::HTTPResponse.new(1.0, 401, "Unauthorized")
141
+ res = RestClient::Response.create(@body, net_http_resp, @http_req)
142
+
143
+ ::ForemanRhCloud::InsightsApiForwarder.any_instance.stubs(:execute_cloud_request).raises(RestClient::Unauthorized.new(res))
144
+
145
+ get :forward_request, params: { "controller" => "vulnerabilities", "path" => "api/vulnerability/v1/cves" }, session: set_session
146
+ assert_equal 401, @response.status
147
+ assert_equal 'Authentication to the Insights Service failed.', JSON.parse(@response.body)['message']
148
+ end
149
+
150
+ test "should forward errors to the client" do
151
+ net_http_resp = Net::HTTPResponse.new(1.0, 500, "TEST_RESPONSE")
152
+ res = RestClient::Response.create(@body, net_http_resp, @http_req)
153
+ ::ForemanRhCloud::InsightsApiForwarder.any_instance.stubs(:execute_cloud_request).raises(RestClient::InternalServerError.new(res))
154
+
155
+ get :forward_request, params: { "controller" => "vulnerabilities", "path" => "api/vulnerability/v1/cves" }, session: set_session
156
+ assert_equal 500, @response.status
157
+ assert_equal 'Cloud request failed', JSON.parse(@response.body)['message']
158
+ assert_match(/#{@body}/, JSON.parse(@response.body)['response'])
159
+ end
160
+ end
161
+
162
+ def set_session
163
+ set_session_user.merge(
164
+ organization_id: @org.id,
165
+ location_id: @loc.id
166
+ )
167
+ end
168
+ end
169
+ end
@@ -50,7 +50,7 @@ class ArchivedReportGeneratorTest < ActiveSupport::TestCase
50
50
  batches = Host.where(id: @host.id).in_batches
51
51
  test_org = FactoryBot.create(:organization)
52
52
 
53
- ForemanInventoryUpload::Generators::Queries.expects(:for_org).with(test_org.id).returns(batches)
53
+ ForemanInventoryUpload::Generators::Queries.expects(:for_org).with(test_org.id, hosts_query: '').returns(batches)
54
54
  ForemanInventoryUpload::Generators::Slice.any_instance.stubs(:golden_ticket?).returns(false)
55
55
  Dir.mktmpdir do |tmpdir|
56
56
  target = File.join(tmpdir, 'test.tar.gz')