foreman_rh_cloud 4.0.24 → 4.0.26

Sign up to get free protection for your applications and to get access to all the features.
Files changed (104) 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 +23 -7
  5. data/app/controllers/insights_cloud/hits_controller.rb +0 -1
  6. data/app/models/insights_client_report_status.rb +8 -23
  7. data/app/services/foreman_rh_cloud/cloud_auth.rb +4 -0
  8. data/app/services/foreman_rh_cloud/cloud_ping_service.rb +83 -0
  9. data/app/services/foreman_rh_cloud/cloud_request_forwarder.rb +15 -3
  10. data/app/services/foreman_rh_cloud/insights_status_cleaner.rb +17 -0
  11. data/app/services/foreman_rh_cloud/remediations_retriever.rb +5 -0
  12. data/config/Gemfile.lock.gh_test +74 -84
  13. data/config/rh_cert-api_chain.pem +74 -0
  14. data/config/routes.rb +3 -1
  15. data/db/migrate/20210720000001_remove_old_insights_statuses.foreman_rh_cloud.rb +6 -0
  16. data/lib/foreman_inventory_upload/generators/queries.rb +0 -16
  17. data/lib/foreman_inventory_upload/generators/tags.rb +3 -1
  18. data/lib/foreman_rh_cloud/engine.rb +2 -3
  19. data/lib/foreman_rh_cloud/version.rb +1 -1
  20. data/lib/foreman_rh_cloud.rb +4 -0
  21. data/lib/insights_cloud/async/insights_client_status_aging.rb +13 -3
  22. data/lib/insights_cloud/async/insights_full_sync.rb +9 -0
  23. data/lib/insights_cloud/async/insights_generate_notifications.rb +4 -0
  24. data/lib/insights_cloud/async/insights_resolutions_sync.rb +16 -2
  25. data/lib/insights_cloud/async/insights_rules_sync.rb +15 -2
  26. data/lib/insights_cloud.rb +4 -0
  27. data/lib/inventory_sync/async/inventory_full_sync.rb +9 -0
  28. data/lib/inventory_sync/async/inventory_hosts_sync.rb +9 -0
  29. data/lib/inventory_sync/async/inventory_scheduled_sync.rb +4 -0
  30. data/lib/inventory_sync/async/inventory_self_host_sync.rb +13 -0
  31. data/lib/inventory_sync/async/query_inventory_job.rb +4 -0
  32. data/lib/tasks/insights.rake +15 -0
  33. data/lib/tasks/rh_cloud_inventory.rake +2 -9
  34. data/package.json +1 -1
  35. data/test/controllers/insights_cloud/api/machine_telemetries_controller_test.rb +20 -39
  36. data/test/controllers/inventory_upload/cloud_status_controller_test.rb +44 -0
  37. data/test/jobs/insights_client_status_aging_test.rb +7 -7
  38. data/test/jobs/insights_full_sync_test.rb +1 -0
  39. data/test/jobs/insights_resolutions_sync_test.rb +11 -1
  40. data/test/jobs/insights_rules_sync_test.rb +1 -0
  41. data/test/jobs/inventory_full_sync_test.rb +10 -0
  42. data/test/jobs/inventory_hosts_sync_test.rb +1 -0
  43. data/test/jobs/inventory_self_host_sync_test.rb +1 -0
  44. data/test/models/insights_client_report_status_test.rb +70 -72
  45. data/test/test_plugin_helper.rb +53 -0
  46. data/test/unit/services/foreman_rh_cloud/cloud_request_forwarder_test.rb +29 -34
  47. data/test/unit/services/foreman_rh_cloud/cloud_status_service_test.rb +66 -0
  48. data/test/unit/services/foreman_rh_cloud/insights_status_cleaner_test.rb +31 -0
  49. data/test/unit/services/foreman_rh_cloud/template_renderer_helper_test.rb +1 -0
  50. data/test/unit/tags_generator_test.rb +41 -0
  51. data/webpack/ForemanInventoryUpload/Components/AccountList/Components/EmptyState/EmptyState.js +1 -1
  52. data/webpack/ForemanInventoryUpload/Components/AccountList/Components/EmptyState/__tests__/__snapshots__/EmptyState.test.js.snap +1 -2
  53. data/webpack/ForemanInventoryUpload/Components/FileDownload/FileDownload.js +3 -1
  54. data/webpack/ForemanInventoryUpload/Components/FileDownload/__tests__/__snapshots__/FileDownload.test.js.snap +2 -1
  55. data/webpack/ForemanInventoryUpload/Components/InventoryFilter/InventoryFilter.js +1 -2
  56. data/webpack/ForemanInventoryUpload/Components/InventoryFilter/InventoryFilterConstants.js +3 -1
  57. data/webpack/ForemanInventoryUpload/Components/InventorySettings/InventorySettings.scss +0 -4
  58. data/webpack/ForemanInventoryUpload/Components/PageHeader/PageTitle.js +12 -0
  59. data/webpack/ForemanInventoryUpload/Components/PageHeader/__tests__/__snapshots__/PageTitle.test.js.snap +10 -0
  60. data/webpack/ForemanInventoryUpload/Components/PageHeader/components/CloudPingModal/index.js +144 -0
  61. data/webpack/ForemanInventoryUpload/Components/PageHeader/components/CloudPingModal/index.scss +5 -0
  62. data/webpack/ForemanInventoryUpload/Components/PageHeader/components/PageDescription/PageDescription.js +2 -2
  63. data/webpack/ForemanInventoryUpload/Components/PageHeader/components/SyncButton/components/Modal.js +1 -1
  64. data/webpack/ForemanInventoryUpload/Components/PageHeader/components/SyncButton/components/Toast.js +2 -2
  65. data/webpack/ForemanInventoryUpload/Components/StatusChart/StatusChart.js +4 -3
  66. data/webpack/ForemanInventoryUpload/ForemanInventoryConstants.js +2 -0
  67. data/webpack/ForemanInventoryUpload/SubscriptionsPageExtension/InventoryAutoUpload/InventoryAutoUpload.js +3 -1
  68. data/webpack/InsightsCloudSync/Components/InsightsHeader/InsightsHeader.scss +5 -1
  69. data/webpack/InsightsCloudSync/Components/InsightsHeader/index.js +6 -6
  70. data/webpack/InsightsCloudSync/Components/InsightsSettings/InsightsSettings.js +9 -5
  71. data/webpack/InsightsCloudSync/Components/InsightsSettings/__tests__/__snapshots__/InsightsSettings.test.js.snap +6 -6
  72. data/webpack/InsightsCloudSync/Components/InsightsSettings/insightsSettings.scss +1 -14
  73. data/webpack/InsightsCloudSync/Components/InsightsTable/InsightsTable.js +4 -22
  74. data/webpack/InsightsCloudSync/Components/InsightsTable/InsightsTableConstants.js +25 -4
  75. data/webpack/InsightsCloudSync/Components/InsightsTable/InsightsTableSelectors.js +0 -3
  76. data/webpack/InsightsCloudSync/Components/InsightsTable/Pagination.js +51 -0
  77. data/webpack/InsightsCloudSync/Components/InsightsTable/SelectAllAlert.js +1 -1
  78. data/webpack/InsightsCloudSync/Components/InsightsTable/__tests__/__snapshots__/InsightsTable.test.js.snap +3 -68
  79. data/webpack/InsightsCloudSync/Components/InsightsTable/table.scss +10 -0
  80. data/webpack/InsightsCloudSync/Components/RemediationModal/RemediationModal.js +11 -10
  81. data/webpack/InsightsCloudSync/Components/RemediationModal/RemediationModal.scss +14 -0
  82. data/webpack/InsightsCloudSync/Components/RemediationModal/index.js +0 -2
  83. data/webpack/InsightsCloudSync/Components/ToolbarDropdown.js +32 -0
  84. data/webpack/InsightsCloudSync/Components/__tests__/__snapshots__/InsightsHeader.test.js.snap +5 -5
  85. data/webpack/InsightsCloudSync/InsightsCloudSync.js +19 -13
  86. data/webpack/InsightsCloudSync/InsightsCloudSync.scss +82 -2
  87. data/webpack/InsightsCloudSync/__snapshots__/InsightsCloudSync.test.js.snap +16 -6
  88. data/webpack/InsightsHostDetailsTab/InsightsTab.js +3 -2
  89. data/webpack/InsightsHostDetailsTab/InsightsTab.scss +4 -4
  90. data/webpack/InsightsHostDetailsTab/components/ListItem/ListItem.js +9 -7
  91. data/webpack/common/Switcher/HelpLabel.js +1 -1
  92. data/webpack/common/Switcher/SwitcherPF4.js +1 -1
  93. data/webpack/common/Switcher/SwitcherPF4.scss +6 -7
  94. data/webpack/common/Switcher/__tests__/__snapshots__/HelpLabel.test.js.snap +1 -1
  95. data/webpack/common/Switcher/__tests__/__snapshots__/SwitcherPF4.test.js.snap +1 -1
  96. metadata +18 -25
  97. data/app/subscribers/foreman_rh_cloud/insights_subscriber.rb +0 -9
  98. data/webpack/InsightsCloudSync/Components/InsightsSyncSwitcher/InsightsSyncSwitcher.fixtures.js +0 -1
  99. data/webpack/InsightsCloudSync/Components/InsightsSyncSwitcher/InsightsSyncSwitcher.js +0 -45
  100. data/webpack/InsightsCloudSync/Components/InsightsSyncSwitcher/__tests__/InsightsSyncSwitcher.test.js +0 -17
  101. data/webpack/InsightsCloudSync/Components/InsightsSyncSwitcher/__tests__/__snapshots__/InsightsSyncSwitcher.test.js.snap +0 -38
  102. data/webpack/InsightsCloudSync/Components/InsightsSyncSwitcher/index.js +0 -1
  103. data/webpack/InsightsCloudSync/Components/InsightsSyncSwitcher/insightsSyncSwitcher.scss +0 -3
  104. data/webpack/InsightsCloudSync/Components/RemediationModal/RemediateButton.js +0 -59
@@ -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
@@ -0,0 +1,31 @@
1
+ require 'test_plugin_helper'
2
+
3
+ class InsightsStatusCleanerTest < ActiveSupport::TestCase
4
+ setup do
5
+ @host1 = FactoryBot.create(:host)
6
+ @host2 = FactoryBot.create(:host)
7
+
8
+ InsightsClientReportStatus.find_or_initialize_by(host_id: @host1.id).update(status: InsightsClientReportStatus::NO_REPORT, reported_at: Time.now - InsightsClientReportStatus::REPORT_INTERVAL + 1.day)
9
+ InsightsClientReportStatus.find_or_initialize_by(host_id: @host2.id).update(status: InsightsClientReportStatus::NO_REPORT, reported_at: Time.now - InsightsClientReportStatus::REPORT_INTERVAL + 1.day)
10
+
11
+ @host1.refresh_global_status!
12
+ @host2.refresh_global_status!
13
+ end
14
+
15
+ test 'Cleans hosts by search condition' do
16
+ assert_equal HostStatus::Global::ERROR, @host1.global_status
17
+ assert_equal HostStatus::Global::ERROR, @host2.global_status
18
+
19
+ instance = ForemanRhCloud::InsightsStatusCleaner.new
20
+ actual_count = instance.clean("name = #{@host1.name}")
21
+
22
+ @host1.reload
23
+ @host2.refresh_global_status!
24
+
25
+ assert_equal 1, actual_count
26
+ assert_equal HostStatus::Global::OK, @host1.global_status
27
+ assert_equal HostStatus::Global::ERROR, @host2.global_status
28
+ assert InsightsClientReportStatus.where(host_id: @host1.id).empty?
29
+ refute InsightsClientReportStatus.where(host_id: @host2.id).empty?
30
+ end
31
+ end
@@ -8,6 +8,7 @@ class TemplateRendererHelperTest < ActiveSupport::TestCase
8
8
  response.stubs(:body).returns('TEST PLAYBOOK')
9
9
  ForemanRhCloud::RemediationsRetriever.any_instance.stubs(:query_playbook).returns(response)
10
10
  @host1 = FactoryBot.create(:host)
11
+ FactoryBot.create(:setting, name: 'rh_cloud_token', value: 'MOCK_TOKEN')
11
12
  end
12
13
 
13
14
  test 'Generates a playbook for hit and remediation' do
@@ -62,6 +62,47 @@ class TagsGeneratorTest < ActiveSupport::TestCase
62
62
  assert_equal false, actual.key?('content_view')
63
63
  end
64
64
 
65
+ test 'generates parameter tags' do
66
+ FactoryBot.create(:setting, :name => 'include_parameter_tags', :settings_type => "boolean", :category => "Setting::RhCloud", :default => false, :value => true)
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
+ ]
76
+ )
77
+
78
+ generator = create_generator
79
+ actual = Hash[generator.generate_parameters]
80
+
81
+ assert_equal 3, actual.count
82
+ assert_equal true, actual['bool_param']
83
+ assert_equal false, actual['false_param']
84
+ assert_equal 1, actual['int_param']
85
+ end
86
+
87
+ test 'skips parameter tags if include_parameter_tags setting is off' do
88
+ FactoryBot.create(:setting, :name => 'include_parameter_tags', :settings_type => "boolean", :category => "Setting::RhCloud", :default => false, :value => false)
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
+ ]
98
+ )
99
+
100
+ generator = create_generator
101
+ actual = generator.generate_parameters.group_by { |key, value| key }
102
+
103
+ assert_equal 0, actual.count
104
+ end
105
+
65
106
  private
66
107
 
67
108
  def create_generator
@@ -9,7 +9,7 @@ const inventoryEmptyState = () => (
9
9
  <EmptyState.Title>
10
10
  {__('Fetching data about your accounts')}
11
11
  </EmptyState.Title>
12
- <EmptyState.Info>{__('Loading')}...</EmptyState.Info>
12
+ <EmptyState.Info>{__('Loading...')}</EmptyState.Info>
13
13
  </EmptyState>
14
14
  );
15
15
 
@@ -19,8 +19,7 @@ exports[`EmptyState rendering render without Props 1`] = `
19
19
  <EmptyStateInfo
20
20
  className=""
21
21
  >
22
- Loading
23
- ...
22
+ Loading...
24
23
  </EmptyStateInfo>
25
24
  </EmptyState>
26
25
  `;
@@ -2,12 +2,14 @@ import React from 'react';
2
2
  import PropTypes from 'prop-types';
3
3
  import { Grid, Button, Icon } from 'patternfly-react';
4
4
  import { noop } from 'foremanReact/common/helpers';
5
+ import { translate as __ } from 'foremanReact/common/I18n';
6
+
5
7
  import './fileDownload.scss';
6
8
 
7
9
  const FileDownload = ({ onClick }) => (
8
10
  <Grid.Col sm={12}>
9
11
  <Button onClick={onClick} className="download-button">
10
- Download Report <Icon name="download" />
12
+ {__('Download Report')} <Icon name="download" />
11
13
  </Button>
12
14
  </Grid.Col>
13
15
  );
@@ -15,7 +15,8 @@ exports[`FileDownload rendering render without Props 1`] = `
15
15
  disabled={false}
16
16
  onClick={[Function]}
17
17
  >
18
- Download Report
18
+ Download Report
19
+
19
20
  <Icon
20
21
  name="download"
21
22
  type="fa"
@@ -15,8 +15,7 @@ const InventoryFilter = ({
15
15
  organization,
16
16
  }) => {
17
17
  useEffect(() => {
18
- const initialTerm =
19
- organization === __(ANY_ORGANIZATION) ? '' : organization;
18
+ const initialTerm = organization === ANY_ORGANIZATION ? '' : organization;
20
19
  handleFilterChange(initialTerm);
21
20
  }, []);
22
21
 
@@ -1,3 +1,5 @@
1
+ import { translate as __ } from 'foremanReact/common/I18n';
2
+
1
3
  export const INVENTORY_FILTER_UPDATE = 'INVENTORY_FILTER_UPDATE';
2
4
  export const INVENTORY_FILTER_CLEAR = 'INVENTORY_FILTER_CLEAR';
3
- export const ANY_ORGANIZATION = 'Any Organization';
5
+ export const ANY_ORGANIZATION = __('Any Organization');
@@ -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;