foreman_rh_cloud 4.0.25 → 4.0.29

Sign up to get free protection for your applications and to get access to all the features.
Files changed (79) hide show
  1. checksums.yaml +4 -4
  2. data/app/controllers/api/v2/rh_cloud/inventory_controller.rb +4 -1
  3. data/app/controllers/foreman_inventory_upload/cloud_status_controller.rb +26 -0
  4. data/app/controllers/insights_cloud/api/machine_telemetries_controller.rb +18 -4
  5. data/app/controllers/insights_cloud/hits_controller.rb +0 -1
  6. data/app/services/foreman_rh_cloud/cloud_ping_service.rb +83 -0
  7. data/app/services/foreman_rh_cloud/cloud_request_forwarder.rb +15 -3
  8. data/config/Gemfile.lock.gh_test +169 -160
  9. data/config/database.yml.example +2 -2
  10. data/config/rh_cert-api_chain.pem +74 -0
  11. data/config/routes.rb +3 -1
  12. data/lib/foreman_inventory_upload/generators/queries.rb +1 -16
  13. data/lib/foreman_inventory_upload/generators/tags.rb +1 -2
  14. data/lib/foreman_rh_cloud/engine.rb +2 -1
  15. data/lib/foreman_rh_cloud/version.rb +1 -1
  16. data/lib/foreman_rh_cloud.rb +16 -1
  17. data/lib/insights_cloud/async/insights_client_status_aging.rb +4 -0
  18. data/lib/insights_cloud/async/insights_full_sync.rb +4 -0
  19. data/lib/insights_cloud/async/insights_generate_notifications.rb +4 -0
  20. data/lib/insights_cloud/async/insights_resolutions_sync.rb +7 -2
  21. data/lib/insights_cloud/async/insights_rules_sync.rb +10 -2
  22. data/lib/insights_cloud.rb +4 -0
  23. data/lib/inventory_sync/async/host_result.rb +0 -5
  24. data/lib/inventory_sync/async/inventory_full_sync.rb +18 -9
  25. data/lib/inventory_sync/async/inventory_hosts_sync.rb +6 -6
  26. data/lib/inventory_sync/async/inventory_scheduled_sync.rb +4 -0
  27. data/lib/inventory_sync/async/inventory_self_host_sync.rb +4 -0
  28. data/lib/inventory_sync/async/query_inventory_job.rb +4 -0
  29. data/lib/tasks/rh_cloud_inventory.rake +2 -9
  30. data/package.json +1 -1
  31. data/test/controllers/insights_cloud/api/machine_telemetries_controller_test.rb +20 -39
  32. data/test/controllers/inventory_upload/cloud_status_controller_test.rb +44 -0
  33. data/test/factories/inventory_upload_factories.rb +14 -0
  34. data/test/jobs/insights_resolutions_sync_test.rb +10 -1
  35. data/test/jobs/inventory_full_sync_test.rb +28 -2
  36. data/test/jobs/inventory_hosts_sync_test.rb +15 -0
  37. data/test/test_plugin_helper.rb +53 -0
  38. data/test/unit/foreman_rh_cloud_self_host_test.rb +28 -0
  39. data/test/unit/services/foreman_rh_cloud/cloud_request_forwarder_test.rb +29 -34
  40. data/test/unit/services/foreman_rh_cloud/cloud_status_service_test.rb +66 -0
  41. data/test/unit/slice_generator_test.rb +36 -4
  42. data/test/unit/tags_generator_test.rb +16 -16
  43. data/webpack/ForemanInventoryUpload/Components/InventorySettings/InventorySettings.scss +0 -4
  44. data/webpack/ForemanInventoryUpload/Components/PageHeader/PageTitle.js +12 -0
  45. data/webpack/ForemanInventoryUpload/Components/PageHeader/__tests__/__snapshots__/PageTitle.test.js.snap +10 -0
  46. data/webpack/ForemanInventoryUpload/Components/PageHeader/components/CloudPingModal/index.js +144 -0
  47. data/webpack/ForemanInventoryUpload/Components/PageHeader/components/CloudPingModal/index.scss +5 -0
  48. data/webpack/ForemanInventoryUpload/ForemanInventoryConstants.js +2 -0
  49. data/webpack/InsightsCloudSync/Components/InsightsHeader/InsightsHeader.scss +5 -1
  50. data/webpack/InsightsCloudSync/Components/InsightsHeader/index.js +6 -6
  51. data/webpack/InsightsCloudSync/Components/InsightsSettings/InsightsSettings.js +9 -5
  52. data/webpack/InsightsCloudSync/Components/InsightsSettings/__tests__/__snapshots__/InsightsSettings.test.js.snap +6 -6
  53. data/webpack/InsightsCloudSync/Components/InsightsSettings/insightsSettings.scss +1 -14
  54. data/webpack/InsightsCloudSync/Components/InsightsTable/InsightsTable.js +5 -24
  55. data/webpack/InsightsCloudSync/Components/InsightsTable/InsightsTableConstants.js +11 -4
  56. data/webpack/InsightsCloudSync/Components/InsightsTable/InsightsTableSelectors.js +0 -3
  57. data/webpack/InsightsCloudSync/Components/InsightsTable/Pagination.js +51 -0
  58. data/webpack/InsightsCloudSync/Components/InsightsTable/__tests__/__snapshots__/InsightsTable.test.js.snap +3 -68
  59. data/webpack/InsightsCloudSync/Components/InsightsTable/table.scss +10 -0
  60. data/webpack/InsightsCloudSync/Components/RemediationModal/RemediationModal.js +11 -10
  61. data/webpack/InsightsCloudSync/Components/RemediationModal/index.js +0 -2
  62. data/webpack/InsightsCloudSync/Components/ToolbarDropdown.js +32 -0
  63. data/webpack/InsightsCloudSync/Components/__tests__/__snapshots__/InsightsHeader.test.js.snap +5 -5
  64. data/webpack/InsightsCloudSync/InsightsCloudSync.js +19 -13
  65. data/webpack/InsightsCloudSync/InsightsCloudSync.scss +82 -2
  66. data/webpack/InsightsCloudSync/__snapshots__/InsightsCloudSync.test.js.snap +16 -6
  67. data/webpack/common/Switcher/HelpLabel.js +1 -1
  68. data/webpack/common/Switcher/SwitcherPF4.js +1 -1
  69. data/webpack/common/Switcher/SwitcherPF4.scss +6 -7
  70. data/webpack/common/Switcher/__tests__/__snapshots__/HelpLabel.test.js.snap +1 -1
  71. data/webpack/common/Switcher/__tests__/__snapshots__/SwitcherPF4.test.js.snap +1 -1
  72. metadata +16 -24
  73. data/webpack/InsightsCloudSync/Components/InsightsSyncSwitcher/InsightsSyncSwitcher.fixtures.js +0 -1
  74. data/webpack/InsightsCloudSync/Components/InsightsSyncSwitcher/InsightsSyncSwitcher.js +0 -45
  75. data/webpack/InsightsCloudSync/Components/InsightsSyncSwitcher/__tests__/InsightsSyncSwitcher.test.js +0 -17
  76. data/webpack/InsightsCloudSync/Components/InsightsSyncSwitcher/__tests__/__snapshots__/InsightsSyncSwitcher.test.js.snap +0 -38
  77. data/webpack/InsightsCloudSync/Components/InsightsSyncSwitcher/index.js +0 -1
  78. data/webpack/InsightsCloudSync/Components/InsightsSyncSwitcher/insightsSyncSwitcher.scss +0 -3
  79. data/webpack/InsightsCloudSync/Components/RemediationModal/RemediateButton.js +0 -59
@@ -37,6 +37,18 @@ class InventoryFullSyncTest < ActiveSupport::TestCase
37
37
  @host2.subscription_facet.pools << pool
38
38
  @host2_inventory_id = '4536bf5c-ff03-4154-a8c9-32ff4b40e40c'
39
39
 
40
+ # this host would pass our plugin queries, so it could be uploaded to the cloud.
41
+ @host3 = FactoryBot.create(
42
+ :host,
43
+ :with_subscription,
44
+ :with_content,
45
+ content_view: cv.first,
46
+ lifecycle_environment: env,
47
+ organization: env.organization
48
+ )
49
+
50
+ @host3.subscription_facet.pools << pool
51
+
40
52
  ForemanInventoryUpload::Generators::Queries.instance_variable_set(:@fact_names, nil)
41
53
 
42
54
  inventory_json = <<-INVENTORY_JSON
@@ -151,7 +163,7 @@ class InventoryFullSyncTest < ActiveSupport::TestCase
151
163
  {
152
164
  "insights_id": "b533848e-465f-4f1a-9b2b-b71cb2d5239d",
153
165
  "rhel_machine_id": null,
154
- "subscription_manager_id": "d29bde40-348e-437c-8acf-8fa98320fc1b",
166
+ "subscription_manager_id": "#{@host3.subscription_facet.uuid}",
155
167
  "satellite_id": "d29bde40-348e-437c-8acf-8fa98320fc1b",
156
168
  "bios_uuid": "3cd5d972-cfb5-451a-8314-fd2f56629d7c",
157
169
  "ip_addresses": [
@@ -159,7 +171,7 @@ class InventoryFullSyncTest < ActiveSupport::TestCase
159
171
  "fd6e:2298:736e::857",
160
172
  "fd6e:2298:736e:0:2c66:6101:9cc6:2b23"
161
173
  ],
162
- "fqdn": "rhel8-demo.oss-lab.net",
174
+ "fqdn": "#{@host3.fqdn}",
163
175
  "mac_addresses": [
164
176
  "6e:66:a6:fe:fc:07",
165
177
  "00:00:00:00:00:00"
@@ -271,4 +283,18 @@ class InventoryFullSyncTest < ActiveSupport::TestCase
271
283
 
272
284
  ForemanTasks.sync_task(InventorySync::Async::InventoryFullSync, @host1.organization)
273
285
  end
286
+
287
+ test 'Should skip hosts that are not returned in query' do
288
+ assert_nil InventorySync::InventoryStatus.where(host_id: @host3.id).first
289
+
290
+ Setting[:rh_cloud_token] = 'TEST TOKEN'
291
+ InventorySync::Async::InventoryFullSync.any_instance.expects(:query_inventory).returns(@inventory)
292
+ InventorySync::Async::InventoryFullSync.any_instance.expects(:affected_host_ids).returns([@host1.id, @host2.id])
293
+ FactoryBot.create(:fact_value, fact_name: fact_names['virt::uuid'], value: '1234', host: @host2)
294
+
295
+ ForemanTasks.sync_task(InventorySync::Async::InventoryFullSync, @host1.organization)
296
+ @host2.reload
297
+
298
+ assert_nil InventorySync::InventoryStatus.where(host_id: @host3.id).first
299
+ end
274
300
  end
@@ -265,4 +265,19 @@ class InventoryHostsSyncTest < ActiveSupport::TestCase
265
265
 
266
266
  assert_equal @host2_inventory_id, @host2.insights.uuid
267
267
  end
268
+
269
+ test 'Inventory should sync empty facets list' do
270
+ empty_inventory = @inventory.deep_clone
271
+ empty_inventory['results'] = []
272
+ InventorySync::Async::InventoryHostsSync.any_instance.expects(:query_inventory).returns(empty_inventory)
273
+ InventorySync::Async::InventoryHostsSync.any_instance.expects(:plan_self_host_sync)
274
+
275
+ assert_nil @host2.insights
276
+
277
+ ForemanTasks.sync_task(InventorySync::Async::InventoryHostsSync)
278
+
279
+ @host2.reload
280
+
281
+ assert_nil @host2.insights
282
+ end
268
283
  end
@@ -38,3 +38,56 @@ module KatelloLocationFix
38
38
  end
39
39
  end
40
40
  end
41
+
42
+ module MockCerts
43
+ extend ActiveSupport::Concern
44
+
45
+ def test_certificate
46
+ @test_certificate ||= "-----BEGIN CERTIFICATE-----\r\n" +
47
+ "MIIFdDCCA1ygAwIBAgIJAM5Uqykb3EAtMA0GCSqGSIb3DQEBCwUAME8xCzAJBgNV\r\n" +
48
+ "BAYTAklMMREwDwYDVQQIDAhUZWwgQXZpdjEUMBIGA1UECgwLVGhlIEZvcmVtYW4x\r\n" +
49
+ "FzAVBgNVBAMMDnRoZWZvcmVtYW4ub3JnMB4XDTE4MDMyNDEyMzYyOFoXDTI4MDMy\r\n" +
50
+ "MTEyMzYyOFowTzELMAkGA1UEBhMCSUwxETAPBgNVBAgMCFRlbCBBdml2MRQwEgYD\r\n" +
51
+ "VQQKDAtUaGUgRm9yZW1hbjEXMBUGA1UEAwwOdGhlZm9yZW1hbi5vcmcwggIiMA0G\r\n" +
52
+ "CSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQDF04/s4h+BgHPG1HDZ/sDlYq925pkc\r\n" +
53
+ "RTVAfnE2EXDAmZ6W4Q9ueDY65MHe3ZWO5Dg72kNSP2sK9kRI7Dk5CAFOgyw1rH8t\r\n" +
54
+ "Hd1+0xp/lv6e4SvSYghxIL68vFe0ftKkm1usqejBM5ZTgKr7JCI+XSIN36F65Kde\r\n" +
55
+ "c+vxwBnayuhP04r9/aaE/709SXML4eRVYW8I3qFy9FPtUOm+bY8U2PIv5fHayqbG\r\n" +
56
+ "cL/4t3+MCtMhHJsLzdBXya+1P5t+HcKjUNlmwoUF961YAktVuEFloGd0RMRlqF3/\r\n" +
57
+ "itU3QNlXgA5QBIciE5VPr/PiqgMC3zgd5avjF4OribZ+N9AATLiQMW78il5wSfcc\r\n" +
58
+ "kQjU9ChOLrzku455vQ8KE4bc0qvpCWGfUah6MvL9JB+TQkRl/8kxl0b9ZinIvJDH\r\n" +
59
+ "ynVMb4cB/TDEjrjOfzn9mWLH0ZJqjmc2bER/G12WQxOaYLxdVwRStD3Yh6PtiFWu\r\n" +
60
+ "sXOk19UOTVkeuvGFVtvzLfEwQ1lDEo7+VBQz8FG/HBu2Hpq3IwCFrHuicikwjQJk\r\n" +
61
+ "nfturgD0rBOKEc1qWNZRCvovYOLL6ihvv5Orujsx5ZCHOAtnVNxkvIlFt2RS45LF\r\n" +
62
+ "MtPJyhAc6SjitllfUEirxprsbmeSZqrIfzcGaEhgOSnyik1WMv6bYiqPfBg8Fzjh\r\n" +
63
+ "vOCbtiDNPmvgOwIDAQABo1MwUTAdBgNVHQ4EFgQUtkAgQopsTtG9zSG3MgW2IxHD\r\n" +
64
+ "MDwwHwYDVR0jBBgwFoAUtkAgQopsTtG9zSG3MgW2IxHDMDwwDwYDVR0TAQH/BAUw\r\n" +
65
+ "AwEB/zANBgkqhkiG9w0BAQsFAAOCAgEAJq7iN+ZroRBweNhvUobxs75bLIV6tNn1\r\n" +
66
+ "MdNHDRA+hezwf+gxHZhFyaAHfTpst2/9leK5Qe5Zd6gZLr3E5/8ppQuRod72H39B\r\n" +
67
+ "vxMlG5zxDss0WMo3vZeKZbTY6QhXi/lY2IZ6OGV4feSvCsYxn27GTjjrRUSLFeHH\r\n" +
68
+ "JVemCwCDMavaE3+OIY4v2P4FcG+MjUvfOB9ahI24TWL7YgrsNVmJjCILq+EeUj0t\r\n" +
69
+ "Gde1SXVyLkqt7PoxHRJAE0BCEMJSnjxaVB329acJgeehBUxjj4CCPqtDxtbz9HEH\r\n" +
70
+ "mOKfNdaKpFor+DUeEKUWVGnr9U9xOaC+Ws+oX7MIEUCDM7p2ob4JwcjnFs1jZgHh\r\n" +
71
+ "Hwig+i7doTlc701PvKWO96fuNHK3B3/jTb1fVvSZ49O/RvY1VWODdUdxWmXGHNh3\r\n" +
72
+ "LoR8tSPEb46lC2DXGaIQumqQt8PnBG+vL1qkQa1SGTV7dJ8TTbxbv0S+sS+igkk9\r\n" +
73
+ "zsIEK8Ea3Ep935cXximz0faAAKHSA+It+xHLAyDtqy2KaAEBgGsBuuWlUfK6TaP3\r\n" +
74
+ "Gwdjct3y4yYUO45lUsUfHqX8vk/4ttW5zYeDiW+HArJz+9VUXNbEdury4kGuHgBj\r\n" +
75
+ "xHD4Bsul65+hHZ9QywKU26F1A6TLkYpQ2rk/Dx9LGICM4m4IlHjWJPFsQdtkyOor\r\n" +
76
+ "osxMtcaZZ1E=\r\n" +
77
+ "-----END CERTIFICATE-----"
78
+ end
79
+
80
+ def generate_certs_hash
81
+ {
82
+ cert: test_certificate,
83
+ key: OpenSSL::PKey::RSA.new(1024).to_pem,
84
+ }
85
+ end
86
+
87
+ def setup_certs_expectation
88
+ expectation = yield
89
+ expectation.returns(
90
+ generate_certs_hash
91
+ )
92
+ end
93
+ end
@@ -0,0 +1,28 @@
1
+ require 'test_plugin_helper'
2
+
3
+ class ForemanRhCloudSelfHostTest < ActiveSupport::TestCase
4
+ setup do
5
+ # reset cached value
6
+ ForemanRhCloud.instance_variable_set(:@foreman_host, nil)
7
+ end
8
+
9
+ test 'finds host by fullname' do
10
+ @domain
11
+ @host = FactoryBot.create(:host, :managed)
12
+ ForemanRhCloud.expects(:foreman_host_name).returns(@host.name)
13
+
14
+ actual = ForemanRhCloud.foreman_host
15
+
16
+ assert_not_nil actual
17
+ end
18
+
19
+ test 'finds host by shortname' do
20
+ @host = FactoryBot.create(:host, :managed)
21
+ Host.where(name: @host.name).update_all(name: @host.shortname)
22
+ ForemanRhCloud.expects(:foreman_host_name).returns(@host.name)
23
+
24
+ actual = ForemanRhCloud.foreman_host
25
+
26
+ assert_not_nil actual
27
+ end
28
+ end
@@ -2,41 +2,10 @@ require 'test_plugin_helper'
2
2
  require 'puma/null_io'
3
3
 
4
4
  class CloudRequestForwarderTest < ActiveSupport::TestCase
5
+ include MockCerts
6
+
5
7
  setup do
6
8
  @forwarder = ::ForemanRhCloud::CloudRequestForwarder.new
7
-
8
- @cert1 = "-----BEGIN CERTIFICATE-----\r\n" +
9
- "MIIFdDCCA1ygAwIBAgIJAM5Uqykb3EAtMA0GCSqGSIb3DQEBCwUAME8xCzAJBgNV\r\n" +
10
- "BAYTAklMMREwDwYDVQQIDAhUZWwgQXZpdjEUMBIGA1UECgwLVGhlIEZvcmVtYW4x\r\n" +
11
- "FzAVBgNVBAMMDnRoZWZvcmVtYW4ub3JnMB4XDTE4MDMyNDEyMzYyOFoXDTI4MDMy\r\n" +
12
- "MTEyMzYyOFowTzELMAkGA1UEBhMCSUwxETAPBgNVBAgMCFRlbCBBdml2MRQwEgYD\r\n" +
13
- "VQQKDAtUaGUgRm9yZW1hbjEXMBUGA1UEAwwOdGhlZm9yZW1hbi5vcmcwggIiMA0G\r\n" +
14
- "CSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQDF04/s4h+BgHPG1HDZ/sDlYq925pkc\r\n" +
15
- "RTVAfnE2EXDAmZ6W4Q9ueDY65MHe3ZWO5Dg72kNSP2sK9kRI7Dk5CAFOgyw1rH8t\r\n" +
16
- "Hd1+0xp/lv6e4SvSYghxIL68vFe0ftKkm1usqejBM5ZTgKr7JCI+XSIN36F65Kde\r\n" +
17
- "c+vxwBnayuhP04r9/aaE/709SXML4eRVYW8I3qFy9FPtUOm+bY8U2PIv5fHayqbG\r\n" +
18
- "cL/4t3+MCtMhHJsLzdBXya+1P5t+HcKjUNlmwoUF961YAktVuEFloGd0RMRlqF3/\r\n" +
19
- "itU3QNlXgA5QBIciE5VPr/PiqgMC3zgd5avjF4OribZ+N9AATLiQMW78il5wSfcc\r\n" +
20
- "kQjU9ChOLrzku455vQ8KE4bc0qvpCWGfUah6MvL9JB+TQkRl/8kxl0b9ZinIvJDH\r\n" +
21
- "ynVMb4cB/TDEjrjOfzn9mWLH0ZJqjmc2bER/G12WQxOaYLxdVwRStD3Yh6PtiFWu\r\n" +
22
- "sXOk19UOTVkeuvGFVtvzLfEwQ1lDEo7+VBQz8FG/HBu2Hpq3IwCFrHuicikwjQJk\r\n" +
23
- "nfturgD0rBOKEc1qWNZRCvovYOLL6ihvv5Orujsx5ZCHOAtnVNxkvIlFt2RS45LF\r\n" +
24
- "MtPJyhAc6SjitllfUEirxprsbmeSZqrIfzcGaEhgOSnyik1WMv6bYiqPfBg8Fzjh\r\n" +
25
- "vOCbtiDNPmvgOwIDAQABo1MwUTAdBgNVHQ4EFgQUtkAgQopsTtG9zSG3MgW2IxHD\r\n" +
26
- "MDwwHwYDVR0jBBgwFoAUtkAgQopsTtG9zSG3MgW2IxHDMDwwDwYDVR0TAQH/BAUw\r\n" +
27
- "AwEB/zANBgkqhkiG9w0BAQsFAAOCAgEAJq7iN+ZroRBweNhvUobxs75bLIV6tNn1\r\n" +
28
- "MdNHDRA+hezwf+gxHZhFyaAHfTpst2/9leK5Qe5Zd6gZLr3E5/8ppQuRod72H39B\r\n" +
29
- "vxMlG5zxDss0WMo3vZeKZbTY6QhXi/lY2IZ6OGV4feSvCsYxn27GTjjrRUSLFeHH\r\n" +
30
- "JVemCwCDMavaE3+OIY4v2P4FcG+MjUvfOB9ahI24TWL7YgrsNVmJjCILq+EeUj0t\r\n" +
31
- "Gde1SXVyLkqt7PoxHRJAE0BCEMJSnjxaVB329acJgeehBUxjj4CCPqtDxtbz9HEH\r\n" +
32
- "mOKfNdaKpFor+DUeEKUWVGnr9U9xOaC+Ws+oX7MIEUCDM7p2ob4JwcjnFs1jZgHh\r\n" +
33
- "Hwig+i7doTlc701PvKWO96fuNHK3B3/jTb1fVvSZ49O/RvY1VWODdUdxWmXGHNh3\r\n" +
34
- "LoR8tSPEb46lC2DXGaIQumqQt8PnBG+vL1qkQa1SGTV7dJ8TTbxbv0S+sS+igkk9\r\n" +
35
- "zsIEK8Ea3Ep935cXximz0faAAKHSA+It+xHLAyDtqy2KaAEBgGsBuuWlUfK6TaP3\r\n" +
36
- "Gwdjct3y4yYUO45lUsUfHqX8vk/4ttW5zYeDiW+HArJz+9VUXNbEdury4kGuHgBj\r\n" +
37
- "xHD4Bsul65+hHZ9QywKU26F1A6TLkYpQ2rk/Dx9LGICM4m4IlHjWJPFsQdtkyOor\r\n" +
38
- "osxMtcaZZ1E=\r\n" +
39
- "-----END CERTIFICATE-----"
40
9
  end
41
10
 
42
11
  test 'should prepare correct cloud url' do
@@ -48,10 +17,11 @@ class CloudRequestForwarderTest < ActiveSupport::TestCase
48
17
  "/redhat_access/r/insights/platform/inventory/v1/hosts" => "https://cert.cloud.redhat.com/api/inventory/v1/hosts",
49
18
  "/redhat_access/r/insights/platform/ingress/v1/upload" => "https://cert.cloud.redhat.com/api/ingress/v1/upload",
50
19
  "/redhat_access/r/insights/uploads/67200803-132b-474b-a6f9-37be74185df4" => "https://cert-api.access.redhat.com/r/insights/uploads/67200803-132b-474b-a6f9-37be74185df4",
20
+ "/redhat_access/r/insights/" => "https://cert.cloud.redhat.com/api/apicast-tests/ping",
51
21
  }
52
22
 
53
23
  paths.each do |key, value|
54
- actual_params = @forwarder.path_params(key, { cert: @cert1, key: OpenSSL::PKey::RSA.new(1024).to_pem })
24
+ actual_params = @forwarder.path_params(key, generate_certs_hash)
55
25
  assert_equal value, actual_params[:url]
56
26
  end
57
27
  end
@@ -138,4 +108,29 @@ class CloudRequestForwarderTest < ActiveSupport::TestCase
138
108
  )
139
109
  assert_equal params.merge(:branch_id => 74), @forwarder.prepare_forward_params(req, 74)
140
110
  end
111
+
112
+ test 'should reuse BranchInfo identifiers for user_agent' do
113
+ user_agent = { :foo => :bar }
114
+ params = { :page => 5, :per_page => 42 }
115
+ ForemanRhCloud::BranchInfo.any_instance.expects(:core_app_name).returns('test_app')
116
+ ForemanRhCloud::BranchInfo.any_instance.expects(:core_app_version).returns('test_ver')
117
+
118
+ req = ActionDispatch::Request.new(
119
+ 'REQUEST_URI' => '/foo/bar',
120
+ 'REQUEST_METHOD' => 'GET',
121
+ 'HTTP_USER_AGENT' => user_agent,
122
+ 'rack.input' => ::Puma::NullIO.new,
123
+ 'action_dispatch.request.query_parameters' => params
124
+ )
125
+
126
+ actual = @forwarder.prepare_request_opts(req, 'TEST PAYLOAD', params, generate_certs_hash)
127
+
128
+ assert_match /foo/, actual[:headers][:user_agent]
129
+ assert_match /bar/, actual[:headers][:user_agent]
130
+ assert_match /test_app/, actual[:headers][:user_agent]
131
+ assert_match /test_ver/, actual[:headers][:user_agent]
132
+ assert_equal 'TEST PAYLOAD', actual[:payload]
133
+ assert_equal 'GET', actual[:method]
134
+ assert_equal params, actual[:headers][:params]
135
+ end
141
136
  end
@@ -0,0 +1,66 @@
1
+ require 'test_plugin_helper'
2
+
3
+ class CloudStatusServiceTest < ActiveSupport::TestCase
4
+ include MockCerts
5
+
6
+ setup do
7
+ end
8
+
9
+ test 'generates ping response for each org' do
10
+ organizations = FactoryBot.create_list(:organization, 2)
11
+
12
+ ForemanRhCloud::CloudPingService::TokenPing.any_instance.expects(:execute_cloud_request).returns(
13
+ RestClient::Response.new('TEST RESPONSE')
14
+ )
15
+
16
+ setup_certs_expectation do
17
+ ForemanRhCloud::CloudPingService::CertPing.any_instance.expects(:candlepin_id_cert).with(organizations[0])
18
+ end
19
+ ForemanRhCloud::CloudPingService::CertPing.any_instance.expects(:execute_cloud_request).returns(
20
+ RestClient::Response.new('TEST RESPONSE ORG 0')
21
+ )
22
+
23
+ setup_certs_expectation do
24
+ ForemanRhCloud::CloudPingService::CertPing.any_instance.expects(:candlepin_id_cert).with(organizations[1])
25
+ end
26
+
27
+ ForemanRhCloud::CloudPingService::CertPing.any_instance.expects(:execute_cloud_request).returns(
28
+ RestClient::Response.new('TEST RESPONSE ORG 1')
29
+ )
30
+
31
+ service = ForemanRhCloud::CloudPingService.new(organizations, nil)
32
+ actual = service.ping
33
+
34
+ assert actual[:token_auth][:success]
35
+ assert_nil actual[:token_auth][:error]
36
+ assert actual[:cert_auth][organizations[0]][:success]
37
+ assert_nil actual[:cert_auth][organizations[0]][:error]
38
+ assert actual[:cert_auth][organizations[1]][:success]
39
+ assert_nil actual[:cert_auth][organizations[1]][:error]
40
+ end
41
+
42
+ test 'generates ping error response for org and token' do
43
+ organizations = FactoryBot.create_list(:organization, 1)
44
+
45
+ ForemanRhCloud::CloudPingService::TokenPing.any_instance.expects(:execute_cloud_request).raises(
46
+ RuntimeError,
47
+ 'TEST RESPONSE TOKEN'
48
+ )
49
+
50
+ setup_certs_expectation do
51
+ ForemanRhCloud::CloudPingService::CertPing.any_instance.expects(:candlepin_id_cert).with(organizations[0])
52
+ end
53
+ ForemanRhCloud::CloudPingService::CertPing.any_instance.expects(:execute_cloud_request).raises(
54
+ RuntimeError,
55
+ 'TEST RESPONSE ORG 0'
56
+ )
57
+
58
+ service = ForemanRhCloud::CloudPingService.new(organizations, nil)
59
+ actual = service.ping
60
+
61
+ refute actual[:token_auth][:success]
62
+ assert_match /TEST RESPONSE TOKEN/, actual[:token_auth][:error]
63
+ refute actual[:cert_auth][organizations[0]][:success]
64
+ assert_match /TEST RESPONSE ORG 0/, actual[:cert_auth][organizations[0]][:error]
65
+ end
66
+ end
@@ -22,7 +22,13 @@ class SliceGeneratorTest < ActiveSupport::TestCase
22
22
  location: location
23
23
  )
24
24
 
25
- @host.organization.pools << FactoryBot.create(:katello_pool, account_number: '1234', cp_id: 1)
25
+ @host.organization.pools << FactoryBot.create(
26
+ :katello_pool,
27
+ account_number: '1234',
28
+ cp_id: 1,
29
+ organization: env.organization,
30
+ subscription: FactoryBot.create(:katello_subscription, organization_id: env.organization.id)
31
+ )
26
32
  @host.interfaces.first.identifier = 'test_nic1'
27
33
  @host.save!
28
34
 
@@ -441,6 +447,18 @@ class SliceGeneratorTest < ActiveSupport::TestCase
441
447
  assert_equal 1, generator.hosts_count
442
448
  end
443
449
 
450
+ test 'excludes hosts with host_registration_insights set to false' do
451
+ @host.host_parameters << HostParameter.create(
452
+ name: 'host_registration_insights',
453
+ value: "false",
454
+ parameter_type: 'boolean'
455
+ )
456
+
457
+ count = ForemanInventoryUpload::Generators::Queries.for_org(@host.organization_id).count
458
+
459
+ assert_equal 0, count
460
+ end
461
+
444
462
  test 'shows system_memory_bytes in bytes' do
445
463
  FactoryBot.create(:fact_value, fact_name: fact_names['memory::memtotal'], value: '1', host: @host)
446
464
 
@@ -457,9 +475,23 @@ class SliceGeneratorTest < ActiveSupport::TestCase
457
475
  end
458
476
 
459
477
  test 'reports an account for hosts with multiple pools' do
460
- first_pool = @host.organization.pools.first
461
- second_pool = FactoryBot.create(:katello_pool, account_number: nil, cp_id: 2)
462
- new_org = FactoryBot.create(:organization, pools: [first_pool, second_pool])
478
+ new_org = FactoryBot.create(:organization)
479
+ first_pool = FactoryBot.create(
480
+ :katello_pool,
481
+ account_number: '5678',
482
+ cp_id: 2,
483
+ organization: new_org,
484
+ subscription: FactoryBot.create(:katello_subscription, organization_id: new_org.id)
485
+ )
486
+ second_pool = FactoryBot.create(
487
+ :katello_pool,
488
+ account_number: '9012',
489
+ cp_id: 3,
490
+ organization: new_org,
491
+ subscription: FactoryBot.create(:katello_subscription, organization_id: new_org.id)
492
+ )
493
+ new_org.pools << first_pool
494
+ new_org.pools << second_pool
463
495
 
464
496
  another_host = FactoryBot.create(
465
497
  :host,
@@ -65,14 +65,14 @@ class TagsGeneratorTest < ActiveSupport::TestCase
65
65
  test 'generates parameter tags' do
66
66
  FactoryBot.create(:setting, :name => 'include_parameter_tags', :settings_type => "boolean", :category => "Setting::RhCloud", :default => false, :value => true)
67
67
 
68
- @host.stubs(:host_inherited_params_objects).returns(
69
- [
70
- OpenStruct.new(name: 'bool_param', value: true),
71
- OpenStruct.new(name: 'false_param', value: false),
72
- OpenStruct.new(name: 'int_param', value: 1),
73
- OpenStruct.new(name: 'empty_param', value: nil),
74
- OpenStruct.new(name: 'empty_str_param', value: ''),
75
- ]
68
+ @host.stubs(:host_params).returns(
69
+ {
70
+ 'bool_param' => true,
71
+ 'false_param' => false,
72
+ 'int_param' => 1,
73
+ 'empty_param' => nil,
74
+ 'empty_str_param' => '',
75
+ }
76
76
  )
77
77
 
78
78
  generator = create_generator
@@ -87,14 +87,14 @@ class TagsGeneratorTest < ActiveSupport::TestCase
87
87
  test 'skips parameter tags if include_parameter_tags setting is off' do
88
88
  FactoryBot.create(:setting, :name => 'include_parameter_tags', :settings_type => "boolean", :category => "Setting::RhCloud", :default => false, :value => false)
89
89
 
90
- @host.stubs(:host_inherited_params_objects).returns(
91
- [
92
- OpenStruct.new(name: 'bool_param', value: true),
93
- OpenStruct.new(name: 'false_param', value: false),
94
- OpenStruct.new(name: 'int_param', value: 1),
95
- OpenStruct.new(name: 'empty_param', value: nil),
96
- OpenStruct.new(name: 'empty_str_param', value: ''),
97
- ]
90
+ @host.stubs(:host_params).returns(
91
+ {
92
+ 'bool_param' => true,
93
+ 'false_param' => false,
94
+ 'int_param' => 1,
95
+ 'empty_param' => nil,
96
+ 'empty_str_param' => '',
97
+ }
98
98
  )
99
99
 
100
100
  generator = create_generator
@@ -10,9 +10,5 @@
10
10
  margin-top: 0;
11
11
  font-weight: 600;
12
12
  }
13
-
14
- .foreman-switcher {
15
- display: block;
16
- }
17
13
  }
18
14
  }
@@ -9,14 +9,18 @@ import {
9
9
  INVENTORY_PAGE_TITLE,
10
10
  ACTIONS_HISTORY_BUTTON_TEXT,
11
11
  DOCS_BUTTON_TEXT,
12
+ CLOUD_PING_TITLE,
12
13
  } from '../../ForemanInventoryConstants';
13
14
  import {
14
15
  getActionsHistoryUrl,
15
16
  getInventoryDocsUrl,
16
17
  } from '../../ForemanInventoryHelpers';
18
+ import CloudPingModal from './components/CloudPingModal';
17
19
 
18
20
  const PageTitle = () => {
19
21
  const [isDropdownOpen, setIsDropdownOpen] = useState(false);
22
+ const [showPingModal, setPingModal] = useState(false);
23
+ const togglePingModal = () => setPingModal(v => !v);
20
24
  const dropdownItems = [
21
25
  <DropdownItem
22
26
  key="tasks-history-button"
@@ -34,6 +38,9 @@ const PageTitle = () => {
34
38
  >
35
39
  {DOCS_BUTTON_TEXT}
36
40
  </DropdownItem>,
41
+ <DropdownItem key="cloud-ping" onClick={togglePingModal}>
42
+ {CLOUD_PING_TITLE}
43
+ </DropdownItem>,
37
44
  ];
38
45
  return (
39
46
  <div className="row form-group inventory-upload-header-title">
@@ -47,6 +54,11 @@ const PageTitle = () => {
47
54
  dropdownItems={dropdownItems}
48
55
  position={DropdownPosition.right}
49
56
  />
57
+ <CloudPingModal
58
+ isOpen={showPingModal}
59
+ toggle={togglePingModal}
60
+ title={CLOUD_PING_TITLE}
61
+ />
50
62
  </div>
51
63
  );
52
64
  };
@@ -27,6 +27,11 @@ exports[`PageTitle rendering render without Props 1`] = `
27
27
  >
28
28
  Documentation
29
29
  </DropdownItem>,
30
+ <DropdownItem
31
+ onClick={[Function]}
32
+ >
33
+ Connectivity test
34
+ </DropdownItem>,
30
35
  ]
31
36
  }
32
37
  isOpen={false}
@@ -39,5 +44,10 @@ exports[`PageTitle rendering render without Props 1`] = `
39
44
  />
40
45
  }
41
46
  />
47
+ <CloudPingModal
48
+ isOpen={false}
49
+ title="Connectivity test"
50
+ toggle={[Function]}
51
+ />
42
52
  </div>
43
53
  `;
@@ -0,0 +1,144 @@
1
+ /* eslint-disable camelcase */
2
+ import React, { useCallback, useEffect, useState } from 'react';
3
+ import PropTypes from 'prop-types';
4
+ import { useDispatch, useSelector } from 'react-redux';
5
+ import { Table, TableBody, TableHeader } from '@patternfly/react-table';
6
+ import {
7
+ Card,
8
+ CardTitle,
9
+ CardBody,
10
+ Modal,
11
+ ModalVariant,
12
+ Spinner,
13
+ Text,
14
+ } from '@patternfly/react-core';
15
+ import {
16
+ CheckCircleIcon,
17
+ ExclamationCircleIcon,
18
+ } from '@patternfly/react-icons';
19
+ import { get } from 'foremanReact/redux/API';
20
+ import { translate as __, sprintf } from 'foremanReact/common/I18n';
21
+ import { STATUS } from 'foremanReact/constants';
22
+ import { selectAPIStatus } from 'foremanReact/redux/API/APISelectors';
23
+ import { inventoryUrl } from '../../../../ForemanInventoryHelpers';
24
+ import './index.scss';
25
+
26
+ export const API_KEY = 'CLOUD_PING';
27
+
28
+ const CloudPingModal = ({ title, isOpen, toggle }) => {
29
+ const [rows, setRows] = useState([]);
30
+ const [tokenStatus, setTokenStatus] = useState({});
31
+ const dispatch = useDispatch();
32
+ const handleSuccess = useCallback(
33
+ ({
34
+ data: {
35
+ ping: { cert_auth = [], token_auth = {} },
36
+ },
37
+ }) => {
38
+ cert_auth.length &&
39
+ setRows(
40
+ cert_auth.map(cert => ({
41
+ cells: [
42
+ {
43
+ title: (
44
+ <>
45
+ <StatusIcon
46
+ isPending={status === STATUS.PENDING}
47
+ authStatus={cert}
48
+ />{' '}
49
+ {cert.org_name}
50
+ </>
51
+ ),
52
+ },
53
+ ],
54
+ }))
55
+ );
56
+ setTokenStatus(token_auth);
57
+ },
58
+ [status]
59
+ );
60
+
61
+ useEffect(() => {
62
+ isOpen &&
63
+ dispatch(
64
+ get({
65
+ key: API_KEY,
66
+ url: inventoryUrl('status'),
67
+ handleSuccess,
68
+ })
69
+ );
70
+ }, [isOpen, dispatch, handleSuccess]);
71
+
72
+ const status = useSelector(state => selectAPIStatus(state, API_KEY));
73
+ const isPending = status === STATUS.PENDING;
74
+ // const error = useSelector(state => selectAPIErrorMessage(state, API_KEY));
75
+
76
+ return (
77
+ <>
78
+ <Modal
79
+ id="cloud-ping-modal"
80
+ appendTo={document.getElementsByClassName('react-container')[0]}
81
+ variant={ModalVariant.large}
82
+ title={title}
83
+ isOpen={isOpen}
84
+ onClose={toggle}
85
+ >
86
+ <Card className="token-status">
87
+ <CardTitle>
88
+ <StatusIcon isPending={isPending} authStatus={tokenStatus} />{' '}
89
+ {__('API token status')}
90
+ </CardTitle>
91
+ </Card>
92
+ <Card className="certs-status">
93
+ <CardTitle>{__('Organization status')}</CardTitle>
94
+ <CardBody>
95
+ <Text>
96
+ {__('Displays manifest statuses per accessible organizations.')}
97
+ </Text>
98
+ {isPending ? (
99
+ <Spinner size="xl" />
100
+ ) : (
101
+ <>
102
+ <Text className="pull-right">
103
+ {sprintf(__('%s organizations'), rows.length)}
104
+ </Text>
105
+ <Table aria-label="Simple Table" cells={['']} rows={rows}>
106
+ <TableHeader />
107
+ <TableBody />
108
+ </Table>{' '}
109
+ </>
110
+ )}
111
+ </CardBody>
112
+ </Card>
113
+ </Modal>
114
+ </>
115
+ );
116
+ };
117
+
118
+ const StatusIcon = ({ isPending, authStatus }) => {
119
+ if (isPending) return <Spinner size="sm" />;
120
+ if (authStatus.success) return <CheckCircleIcon color="green" />;
121
+ if (authStatus.error) return <ExclamationCircleIcon color="red" />;
122
+ return <Spinner size="sm" />;
123
+ };
124
+
125
+ StatusIcon.propTypes = {
126
+ isPending: PropTypes.bool,
127
+ authStatus: PropTypes.shape({
128
+ success: PropTypes.oneOfType([PropTypes.string, PropTypes.bool]),
129
+ error: PropTypes.oneOfType([PropTypes.string, PropTypes.bool]),
130
+ }),
131
+ };
132
+
133
+ StatusIcon.defaultProps = {
134
+ isPending: true,
135
+ authStatus: {},
136
+ };
137
+
138
+ CloudPingModal.propTypes = {
139
+ title: PropTypes.string.isRequired,
140
+ isOpen: PropTypes.bool.isRequired,
141
+ toggle: PropTypes.func.isRequired,
142
+ };
143
+
144
+ export default CloudPingModal;
@@ -0,0 +1,5 @@
1
+ #cloud-ping-modal {
2
+ .token-status {
3
+ margin-bottom: 24px;
4
+ }
5
+ }
@@ -7,3 +7,5 @@ export const DOCS_BUTTON_TEXT = __('Documentation');
7
7
  export const ACTIONS_HISTORY_BUTTON_TEXT = __('Actions history');
8
8
 
9
9
  export const SYNC_BUTTON_TEXT = __(' Sync inventory status');
10
+
11
+ export const CLOUD_PING_TITLE = __('Connectivity test');
@@ -1,4 +1,8 @@
1
1
  .insights-header {
2
- margin-bottom: '15px';
3
2
  overflow: auto;
3
+ margin-bottom: 30px;
4
+
5
+ p {
6
+ font-size: 16px;
7
+ }
4
8
  }