foreman_rh_cloud 0.9.10 → 0.9.11
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +33 -0
- data/app/controllers/insights_cloud/hits_controller.rb +17 -0
- data/app/models/concerns/rh_cloud_host.rb +12 -0
- data/app/views/hosts/_insights_tab.html.erb +15 -0
- data/config/routes.rb +1 -0
- data/lib/foreman_inventory_upload/async/generate_report_job.rb +1 -1
- data/lib/foreman_inventory_upload/async/shell_process.rb +15 -9
- data/lib/foreman_inventory_upload/async/upload_report_job.rb +19 -1
- data/lib/foreman_inventory_upload/generators/metadata.rb +3 -0
- data/lib/foreman_inventory_upload/generators/queries.rb +2 -4
- data/lib/foreman_rh_cloud/engine.rb +10 -0
- data/lib/foreman_rh_cloud/version.rb +1 -1
- data/lib/tasks/insights.rake +15 -0
- data/lib/tasks/{generator.rake → rh_cloud_inventory.rake} +7 -1
- data/package.json +3 -1
- data/test/jobs/upload_report_job_test.rb +34 -0
- data/test/unit/metadata_generator_test.rb +2 -0
- data/test/unit/slice_generator_test.rb +17 -0
- data/webpack/ForemanInventoryUpload/Components/InventoryFilter/__tests__/__snapshots__/integration.test.js.snap +3 -0
- data/webpack/ForemanInventoryUpload/Components/PageHeader/components/SyncButton/components/Toast.js +1 -1
- data/webpack/ForemanInventoryUpload/Components/StatusChart/StatusChart.js +1 -1
- data/webpack/ForemanInventoryUpload/Components/StatusChart/__tests__/__snapshots__/StatusChart.test.js.snap +1 -1
- data/webpack/ForemanInventoryUpload/Components/TabContainer/tabContainer.scss +1 -1
- data/webpack/ForemanRhCloudPages.js +2 -0
- data/webpack/ForemanRhCloudReducers.js +2 -0
- data/webpack/ForemanRhCloudSelectors.js +5 -0
- data/webpack/ForemanRhCloudTestHelpers.js +6 -1
- data/webpack/InsightsHostDetailsTab/InsightsTab.js +64 -0
- data/webpack/InsightsHostDetailsTab/InsightsTab.scss +86 -0
- data/webpack/InsightsHostDetailsTab/InsightsTabActions.js +30 -0
- data/webpack/InsightsHostDetailsTab/InsightsTabConstants.js +3 -0
- data/webpack/InsightsHostDetailsTab/InsightsTabReducer.js +26 -0
- data/webpack/InsightsHostDetailsTab/InsightsTabSelectors.js +3 -0
- data/webpack/InsightsHostDetailsTab/__tests__/InsightsTab.fixtures.js +25 -0
- data/webpack/InsightsHostDetailsTab/__tests__/InsightsTab.test.js +13 -0
- data/webpack/InsightsHostDetailsTab/__tests__/InsightsTabActions.test.js +13 -0
- data/webpack/InsightsHostDetailsTab/__tests__/InsightsTabIntegration.test.js +17 -0
- data/webpack/InsightsHostDetailsTab/__tests__/InsightsTabReducer.test.js +35 -0
- data/webpack/InsightsHostDetailsTab/__tests__/InsightsTabSelectors.test.js +13 -0
- data/webpack/InsightsHostDetailsTab/__tests__/__snapshots__/InsightsTab.test.js.snap +30 -0
- data/webpack/InsightsHostDetailsTab/__tests__/__snapshots__/InsightsTabActions.test.js.snap +20 -0
- data/webpack/InsightsHostDetailsTab/__tests__/__snapshots__/InsightsTabReducer.test.js.snap +41 -0
- data/webpack/InsightsHostDetailsTab/__tests__/__snapshots__/InsightsTabSelectors.test.js.snap +20 -0
- data/webpack/InsightsHostDetailsTab/components/ListItem/ListItem.js +69 -0
- data/webpack/InsightsHostDetailsTab/components/ListItem/index.js +1 -0
- data/webpack/InsightsHostDetailsTab/index.js +20 -0
- data/webpack/__tests__/__snapshots__/ForemanRhCloudSelectors.test.js.snap +1 -0
- data/webpack/__tests__/__snapshots__/ForemanRhCloudTestHelpers.test.js.snap +3 -0
- data/webpack/stories/decorators/withCardsDecorator.js +1 -1
- metadata +38 -13
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 9a1ce84facb4e9281463d4f91b5a6082f87e1ef122bcde049b37427a21905dcc
|
4
|
+
data.tar.gz: 402653f54c9b5ac26c79ab326c8f0aad91645a0f91869be550f2056847bdde37
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: f36d854c682c3158599d5e18648ba365654deffa1ea35acd1601dda6801ebc28b57185c564766f31bde813c1f4f7c37644387c8a8f4f4d8685198a2e18c5b605
|
7
|
+
data.tar.gz: a0825d23ebff413d07a72c850728b5d22f030e3fc4323440d97b87e64f6d2a568dd1f9b4ded362cae56a4888e9fe375dbf81ba294aae6374126bc3bd82ca1731
|
data/README.md
CHANGED
@@ -11,6 +11,39 @@ for how to install Foreman plugins
|
|
11
11
|
|
12
12
|
*Usage here*
|
13
13
|
|
14
|
+
### In Satellite
|
15
|
+
|
16
|
+
#### Inventory upload
|
17
|
+
|
18
|
+
In UI: Configure -> Inventory Upload -> Restart
|
19
|
+
|
20
|
+
From command-line:
|
21
|
+
|
22
|
+
export organization_id=1
|
23
|
+
export target=/var/lib/foreman/red_hat_inventory/generated_reports/
|
24
|
+
/usr/sbin/foreman-rake rh_cloud_inventory:report:generate
|
25
|
+
|
26
|
+
#### Fetch hosts remediation data
|
27
|
+
|
28
|
+
In UI: Configure -> Insights -> Sync now
|
29
|
+
|
30
|
+
From command-line:
|
31
|
+
|
32
|
+
/usr/sbin/foreman-rake rh_cloud_inventory:sync
|
33
|
+
|
34
|
+
#### Synchronize inventory status
|
35
|
+
|
36
|
+
In UI: Configure -> Inventory Upload -> Sync inventory status
|
37
|
+
|
38
|
+
From command-line:
|
39
|
+
|
40
|
+
# all organizations
|
41
|
+
/usr/sbin/foreman-rake rh_cloud_insights:sync
|
42
|
+
|
43
|
+
# specific organization with id 1
|
44
|
+
export organization_id=1
|
45
|
+
/usr/sbin/foreman-rake rh_cloud_insights:sync
|
46
|
+
|
14
47
|
## TODO
|
15
48
|
|
16
49
|
*Todo list here*
|
@@ -0,0 +1,17 @@
|
|
1
|
+
module InsightsCloud
|
2
|
+
class HitsController < ::ApplicationController
|
3
|
+
def index
|
4
|
+
host = Host.where(id: host_id_param).first
|
5
|
+
|
6
|
+
render json: {
|
7
|
+
hits: host.insights.hits,
|
8
|
+
}, status: :ok
|
9
|
+
end
|
10
|
+
|
11
|
+
private
|
12
|
+
|
13
|
+
def host_id_param
|
14
|
+
params.require(:host_id)
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
@@ -0,0 +1,12 @@
|
|
1
|
+
module RhCloudHost
|
2
|
+
extend ActiveSupport::Concern
|
3
|
+
|
4
|
+
included do
|
5
|
+
has_many(
|
6
|
+
:inventory_upload_facts,
|
7
|
+
-> { where(fact_name_id: ForemanInventoryUpload::Generators::Queries.fact_names.values) },
|
8
|
+
class_name: 'FactValue',
|
9
|
+
:foreign_key => :host_id
|
10
|
+
)
|
11
|
+
end
|
12
|
+
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
<% content_for(:javascripts) do %>
|
2
|
+
<%= webpacked_plugins_js_for :'foreman_rh_cloud' %>
|
3
|
+
<% end %>
|
4
|
+
|
5
|
+
<% content_for(:stylesheets) do %>
|
6
|
+
<%= webpacked_plugins_css_for :'foreman_rh_cloud' %>
|
7
|
+
<% end %>
|
8
|
+
|
9
|
+
<div id="host_details_insights_react_container"></div>
|
10
|
+
<%= mount_react_component(
|
11
|
+
'InsightsHostDetailsTab',
|
12
|
+
'#host_details_insights_react_container',
|
13
|
+
{ hostID: host.id }.to_json,
|
14
|
+
flatten_data: true
|
15
|
+
) %>
|
data/config/routes.rb
CHANGED
@@ -8,24 +8,30 @@ module ForemanInventoryUpload
|
|
8
8
|
def perform(instance_label)
|
9
9
|
klass_name = self.class.name
|
10
10
|
logger.debug("Starting #{klass_name} with label #{instance_label}")
|
11
|
-
|
12
|
-
|
13
|
-
|
11
|
+
progress_output_for(instance_label) do |progress_output|
|
12
|
+
Open3.popen2e(hash_to_s(env), command) do |_stdin, stdout_stderr, wait_thread|
|
13
|
+
progress_output.status = "Running in pid #{wait_thread.pid}"
|
14
14
|
|
15
|
-
|
16
|
-
|
17
|
-
|
15
|
+
stdout_stderr.each do |out_line|
|
16
|
+
progress_output.write_line(out_line)
|
17
|
+
end
|
18
18
|
|
19
|
-
|
19
|
+
progress_output.status = wait_thread.value.to_s
|
20
|
+
end
|
20
21
|
end
|
21
22
|
logger.debug("Finished job #{klass_name} with label #{instance_label}")
|
22
|
-
ensure
|
23
|
-
progress_output.close
|
24
23
|
end
|
25
24
|
|
26
25
|
def command
|
27
26
|
end
|
28
27
|
|
28
|
+
def progress_output_for(instance_label)
|
29
|
+
progress_output = ProgressOutput.register(instance_label)
|
30
|
+
yield(progress_output)
|
31
|
+
ensure
|
32
|
+
progress_output.close
|
33
|
+
end
|
34
|
+
|
29
35
|
def env
|
30
36
|
{}
|
31
37
|
end
|
@@ -8,15 +8,33 @@ module ForemanInventoryUpload
|
|
8
8
|
end
|
9
9
|
|
10
10
|
def perform(filename, organization_id)
|
11
|
+
label = UploadReportJob.output_label(organization_id)
|
11
12
|
@filename = filename
|
12
13
|
@organization = Organization.find(organization_id)
|
13
14
|
|
15
|
+
if Setting[:content_disconnected]
|
16
|
+
progress_output_for(label) do |progress_output|
|
17
|
+
progress_output.write_line('Upload was stopped since disconnected mode setting is enabled for content on this instance.')
|
18
|
+
progress_output.status = "Task aborted, exit 1"
|
19
|
+
end
|
20
|
+
return
|
21
|
+
end
|
22
|
+
|
23
|
+
unless @organization.owner_details&.fetch('upstreamConsumer')&.fetch('idCert')
|
24
|
+
logger.info("Skipping organization '#{@organization}', no candlepin certificate defined.")
|
25
|
+
progress_output_for(label) do |progress_output|
|
26
|
+
progress_output.write_line("Skipping organization #{@organization}, no candlepin certificate defined.")
|
27
|
+
progress_output.status = "Task aborted, exit 1"
|
28
|
+
end
|
29
|
+
return
|
30
|
+
end
|
31
|
+
|
14
32
|
Tempfile.create([@organization.name, '.pem']) do |cer_file|
|
15
33
|
cer_file.write(rh_credentials[:cert])
|
16
34
|
cer_file.write(rh_credentials[:key])
|
17
35
|
cer_file.flush
|
18
36
|
@cer_path = cer_file.path
|
19
|
-
super(
|
37
|
+
super(label)
|
20
38
|
end
|
21
39
|
end
|
22
40
|
|
@@ -21,6 +21,9 @@ module ForemanInventoryUpload
|
|
21
21
|
private
|
22
22
|
|
23
23
|
def render_report(metadata)
|
24
|
+
metadata ||= {}
|
25
|
+
metadata['foreman_rh_cloud_version'] = ForemanRhCloud::VERSION
|
26
|
+
|
24
27
|
@stream.object do
|
25
28
|
@stream.simple_field('report_id', Foreman.uuid)
|
26
29
|
@stream.simple_field('host_inventory_api_version', '1.0')
|
@@ -30,23 +30,21 @@ module ForemanInventoryUpload
|
|
30
30
|
end
|
31
31
|
|
32
32
|
def self.for_slice(base)
|
33
|
-
fact_values = FactValue.where(fact_name_id: fact_names.values)
|
34
33
|
base
|
35
34
|
.joins(:subscription_facet)
|
36
|
-
.eager_load(:fact_values)
|
37
35
|
.preload(
|
38
36
|
:interfaces,
|
39
37
|
:installed_packages,
|
40
38
|
:content_facet,
|
41
39
|
:host_statuses,
|
40
|
+
:inventory_upload_facts,
|
42
41
|
subscription_facet: [:pools, :installed_products, :hypervisor_host]
|
43
42
|
)
|
44
|
-
.merge(fact_values)
|
45
43
|
end
|
46
44
|
|
47
45
|
def self.for_report(portal_user)
|
48
46
|
org_ids = organizations_for_user(portal_user).pluck(:id)
|
49
|
-
|
47
|
+
for_org(org_ids)
|
50
48
|
end
|
51
49
|
|
52
50
|
def self.for_org(organization_id)
|
@@ -64,9 +64,19 @@ module ForemanRhCloud
|
|
64
64
|
register_global_js_file 'subscriptions_extension'
|
65
65
|
|
66
66
|
register_custom_status(InventorySync::InventoryStatus)
|
67
|
+
|
68
|
+
extend_page 'hosts/show' do |context|
|
69
|
+
context.add_pagelet :main_tabs,
|
70
|
+
partial: 'hosts/insights_tab',
|
71
|
+
name: _('Insights'),
|
72
|
+
onlyif: proc { |host| host.insights }
|
73
|
+
end
|
67
74
|
end
|
68
75
|
|
69
76
|
::Katello::UINotifications::Subscriptions::ManifestImportSuccess.include ForemanInventoryUpload::Notifications::ManifestImportSuccessNotificationOverride if defined?(Katello)
|
77
|
+
|
78
|
+
::Host::Managed.include RhCloudHost
|
79
|
+
::Host::Base.include RhCloudHost
|
70
80
|
end
|
71
81
|
|
72
82
|
initializer "foreman_rh_cloud.set_dynflow.config.on_init", :before => :finisher_hook do |_app|
|
@@ -0,0 +1,15 @@
|
|
1
|
+
namespace :rh_cloud_insights do
|
2
|
+
desc "Synchronize Insights inventory"
|
3
|
+
task sync: :environment do
|
4
|
+
if !ENV['organization_id'].nil?
|
5
|
+
organizations = [ Organization.where(:id => ENV['organization_id']).first ]
|
6
|
+
else
|
7
|
+
organizations = Organization.all
|
8
|
+
end
|
9
|
+
|
10
|
+
organizations.each do |organization|
|
11
|
+
InventorySync::Async::InventoryFullSync.perform_now(organization)
|
12
|
+
puts "Synchronized inventory for organization '#{organization.name}'"
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
@@ -1,6 +1,6 @@
|
|
1
1
|
require 'tempfile'
|
2
2
|
|
3
|
-
namespace :
|
3
|
+
namespace :rh_cloud_inventory do
|
4
4
|
namespace :report do
|
5
5
|
desc 'Generate inventory report to be sent to Red Hat cloud'
|
6
6
|
task generate: :environment do
|
@@ -26,4 +26,10 @@ namespace :foreman_inventory_upload do
|
|
26
26
|
end
|
27
27
|
end
|
28
28
|
end
|
29
|
+
|
30
|
+
desc "Synchronize Insights hosts hits"
|
31
|
+
task sync: :environment do
|
32
|
+
InsightsCloud::Async::InsightsFullSync.perform_now()
|
33
|
+
puts "Synchronized Insights hosts hits data"
|
34
|
+
end
|
29
35
|
end
|
data/package.json
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
{
|
2
2
|
"name": "foreman_rh_cloud",
|
3
|
-
"version": "0.
|
3
|
+
"version": "0.9.11",
|
4
4
|
"description": "Inventory Upload =============",
|
5
5
|
"main": "index.js",
|
6
6
|
"scripts": {
|
@@ -47,6 +47,8 @@
|
|
47
47
|
"eslint": "^4.10.0",
|
48
48
|
"eslint-import-resolver-babel-module": "^4.0.0",
|
49
49
|
"eslint-plugin-patternfly-react": "0.2.0",
|
50
|
+
"eslint-plugin-promise": "^4.2.1",
|
51
|
+
"eslint-plugin-spellcheck": "^0.0.17",
|
50
52
|
"identity-obj-proxy": "^3.0.0",
|
51
53
|
"jed": "^1.1.1",
|
52
54
|
"jest-cli": "^23.6.0",
|
@@ -0,0 +1,34 @@
|
|
1
|
+
require 'test_plugin_helper'
|
2
|
+
|
3
|
+
class UploadReportJobTest < ActiveJob::TestCase
|
4
|
+
include FolderIsolation
|
5
|
+
|
6
|
+
test 'returns aborted state when disconnected' do
|
7
|
+
organization = FactoryBot.create(:organization)
|
8
|
+
Organization.any_instance.stubs(:owner_details).returns(
|
9
|
+
'upstreamConsumer' => {
|
10
|
+
'idCert' => 'TEST_CERT',
|
11
|
+
}
|
12
|
+
)
|
13
|
+
FactoryBot.create(:setting, :name => 'content_disconnected', :value => true)
|
14
|
+
|
15
|
+
ForemanInventoryUpload::Async::UploadReportJob.perform_now('', organization.id)
|
16
|
+
|
17
|
+
label = ForemanInventoryUpload::Async::UploadReportJob.output_label(organization.id)
|
18
|
+
progress_output = ForemanInventoryUpload::Async::ProgressOutput.get(label)
|
19
|
+
assert_match(/Upload was stopped/, progress_output.full_output)
|
20
|
+
assert_match(/exit 1/, progress_output.status)
|
21
|
+
end
|
22
|
+
|
23
|
+
test 'returns aborted state when no certificate defined on organization' do
|
24
|
+
organization = FactoryBot.create(:organization)
|
25
|
+
Organization.any_instance.expects(:owner_details).returns(nil)
|
26
|
+
|
27
|
+
ForemanInventoryUpload::Async::UploadReportJob.perform_now('', organization.id)
|
28
|
+
|
29
|
+
label = ForemanInventoryUpload::Async::UploadReportJob.output_label(organization.id)
|
30
|
+
progress_output = ForemanInventoryUpload::Async::ProgressOutput.get(label)
|
31
|
+
assert_match(/Skipping organization/, progress_output.full_output)
|
32
|
+
assert_match(/exit 1/, progress_output.status)
|
33
|
+
end
|
34
|
+
end
|
@@ -13,6 +13,8 @@ class MetadataGeneratorTest < ActiveSupport::TestCase
|
|
13
13
|
|
14
14
|
assert_not_nil actual['report_id']
|
15
15
|
assert_equal 'Satellite', actual['source']
|
16
|
+
assert_not_nil (actual_metadata = actual['source_metadata'])
|
17
|
+
assert_equal ForemanRhCloud::VERSION, actual_metadata['foreman_rh_cloud_version']
|
16
18
|
assert_equal({}, actual['report_slices'])
|
17
19
|
end
|
18
20
|
|
@@ -9,6 +9,7 @@ class ReportGeneratorTest < ActiveSupport::TestCase
|
|
9
9
|
|
10
10
|
@host = FactoryBot.create(
|
11
11
|
:host,
|
12
|
+
:redhat,
|
12
13
|
:with_subscription,
|
13
14
|
:with_content,
|
14
15
|
content_view: cv.first,
|
@@ -264,6 +265,22 @@ class ReportGeneratorTest < ActiveSupport::TestCase
|
|
264
265
|
assert_equal 1, generator.hosts_count
|
265
266
|
end
|
266
267
|
|
268
|
+
test 'include also hosts with non-redhat OS' do
|
269
|
+
os = @host.operatingsystem
|
270
|
+
os.name = 'Centos'
|
271
|
+
os.save!
|
272
|
+
|
273
|
+
# make a_host last
|
274
|
+
batch = ForemanInventoryUpload::Generators::Queries.for_org(@host.organization_id).first
|
275
|
+
generator = create_generator(batch)
|
276
|
+
|
277
|
+
json_str = generator.render
|
278
|
+
actual = JSON.parse(json_str.join("\n"))
|
279
|
+
|
280
|
+
assert_equal 'slice_123', actual['report_slice_id']
|
281
|
+
assert_equal 1, generator.hosts_count
|
282
|
+
end
|
283
|
+
|
267
284
|
test 'shows system_memory_bytes in bytes' do
|
268
285
|
FactoryBot.create(:fact_value, fact_name: fact_names['memory::memtotal'], value: '1', host: @host)
|
269
286
|
|
@@ -1,7 +1,9 @@
|
|
1
1
|
import ForemanInventoryUpload from './ForemanInventoryUpload';
|
2
2
|
import InsightsCloudSync from './InsightsCloudSync';
|
3
|
+
import InsightsHostDetailsTab from './InsightsHostDetailsTab';
|
3
4
|
|
4
5
|
export default [
|
5
6
|
{ name: 'ForemanInventoryUpload', type: ForemanInventoryUpload },
|
6
7
|
{ name: 'InsightsCloudSync', type: InsightsCloudSync },
|
8
|
+
{ name: 'InsightsHostDetailsTab', type: InsightsHostDetailsTab },
|
7
9
|
];
|
@@ -1,10 +1,12 @@
|
|
1
1
|
import { combineReducers } from 'redux';
|
2
2
|
import inventoryUploadReducers from './ForemanInventoryUpload/ForemanInventoryUploadReducers';
|
3
3
|
import insightsReducers from './InsightsCloudSync/InsightsCloudSyncReducers';
|
4
|
+
import { hostInsightsReducers } from './InsightsHostDetailsTab';
|
4
5
|
|
5
6
|
export default {
|
6
7
|
ForemanRhCloud: combineReducers({
|
7
8
|
...inventoryUploadReducers,
|
8
9
|
...insightsReducers,
|
10
|
+
...hostInsightsReducers,
|
9
11
|
}),
|
10
12
|
};
|
@@ -1,5 +1,10 @@
|
|
1
1
|
export const selectForemanRhCloud = state => state.ForemanRhCloud;
|
2
|
+
|
2
3
|
export const selectForemanInventoryUpload = state =>
|
3
4
|
selectForemanRhCloud(state).inventoryUpload;
|
5
|
+
|
4
6
|
export const selectInsightsCloudSync = state =>
|
5
7
|
selectForemanRhCloud(state).InsightsCloudSync;
|
8
|
+
|
9
|
+
export const selectHostInsights = state =>
|
10
|
+
selectForemanRhCloud(state).hostInsights;
|
@@ -1,10 +1,12 @@
|
|
1
1
|
export const rhCloudStateWrapper = (
|
2
2
|
inventoryState = {},
|
3
|
-
insightsState = {}
|
3
|
+
insightsState = {},
|
4
|
+
hostInsightsState = {}
|
4
5
|
) => ({
|
5
6
|
ForemanRhCloud: {
|
6
7
|
inventoryUpload: { ...inventoryState },
|
7
8
|
InsightsCloudSync: { ...insightsState },
|
9
|
+
hostInsights: { ...hostInsightsState },
|
8
10
|
},
|
9
11
|
});
|
10
12
|
|
@@ -13,3 +15,6 @@ export const inventoryStateWrapper = innerState =>
|
|
13
15
|
|
14
16
|
export const insightsStateWrapper = innerState =>
|
15
17
|
rhCloudStateWrapper({}, innerState);
|
18
|
+
|
19
|
+
export const hostInsightsStateWrapper = innerState =>
|
20
|
+
rhCloudStateWrapper({}, {}, innerState);
|
@@ -0,0 +1,64 @@
|
|
1
|
+
import React from 'react';
|
2
|
+
import PropTypes from 'prop-types';
|
3
|
+
import { orderBy } from 'lodash';
|
4
|
+
import { Grid, ListView, noop } from 'patternfly-react';
|
5
|
+
import ListItem from './components/ListItem';
|
6
|
+
import './InsightsTab.scss';
|
7
|
+
|
8
|
+
class InsightsHostDetailsTab extends React.Component {
|
9
|
+
componentDidMount() {
|
10
|
+
const { fetchHits, hostID } = this.props;
|
11
|
+
fetchHits(hostID);
|
12
|
+
}
|
13
|
+
|
14
|
+
render() {
|
15
|
+
const { hits } = this.props;
|
16
|
+
|
17
|
+
if (!hits.length) {
|
18
|
+
return <h2>No recommendations were found for this host!</h2>;
|
19
|
+
}
|
20
|
+
const hitsSorted = orderBy(hits, ['insights_hit.total_risk'], ['desc']);
|
21
|
+
const items = hitsSorted.map(
|
22
|
+
(
|
23
|
+
{
|
24
|
+
insights_hit: {
|
25
|
+
title,
|
26
|
+
total_risk: totalRisk,
|
27
|
+
results_url: resultsUrl,
|
28
|
+
solution_url: solutionUrl,
|
29
|
+
},
|
30
|
+
},
|
31
|
+
index
|
32
|
+
) => (
|
33
|
+
<ListItem
|
34
|
+
key={index}
|
35
|
+
title={title}
|
36
|
+
totalRisk={totalRisk}
|
37
|
+
resultsUrl={resultsUrl}
|
38
|
+
solutionUrl={solutionUrl}
|
39
|
+
/>
|
40
|
+
)
|
41
|
+
);
|
42
|
+
return (
|
43
|
+
<Grid.Row>
|
44
|
+
<Grid.Col xs={12}>
|
45
|
+
<h2>Recommendations</h2>
|
46
|
+
<ListView id="hits_list">{items}</ListView>
|
47
|
+
</Grid.Col>
|
48
|
+
</Grid.Row>
|
49
|
+
);
|
50
|
+
}
|
51
|
+
}
|
52
|
+
|
53
|
+
InsightsHostDetailsTab.propTypes = {
|
54
|
+
hostID: PropTypes.number.isRequired,
|
55
|
+
fetchHits: PropTypes.func,
|
56
|
+
hits: PropTypes.array,
|
57
|
+
};
|
58
|
+
|
59
|
+
InsightsHostDetailsTab.defaultProps = {
|
60
|
+
fetchHits: noop,
|
61
|
+
hits: [],
|
62
|
+
};
|
63
|
+
|
64
|
+
export default InsightsHostDetailsTab;
|
@@ -0,0 +1,86 @@
|
|
1
|
+
#host_details_insights_react_container {
|
2
|
+
#btn_toolbar {
|
3
|
+
float: right;
|
4
|
+
}
|
5
|
+
|
6
|
+
#btn_fullscreen {
|
7
|
+
margin-left: 5px;
|
8
|
+
|
9
|
+
.fa-arrows-alt {
|
10
|
+
margin-left: 5px;
|
11
|
+
}
|
12
|
+
}
|
13
|
+
|
14
|
+
h2 {
|
15
|
+
margin-top: 5px;
|
16
|
+
}
|
17
|
+
|
18
|
+
#hits_list {
|
19
|
+
max-height: 650px;
|
20
|
+
overflow-y: scroll;
|
21
|
+
overflow-x: hidden;
|
22
|
+
margin-top: 15px;
|
23
|
+
|
24
|
+
.list-view-pf-expand {
|
25
|
+
padding: 0;
|
26
|
+
}
|
27
|
+
|
28
|
+
.list-group-item-header {
|
29
|
+
.list-view-pf-expand .fa-angle-right {
|
30
|
+
margin-top: 6px;
|
31
|
+
}
|
32
|
+
|
33
|
+
.list-view-pf-main-info .list-view-pf-description {
|
34
|
+
width: 83%;
|
35
|
+
|
36
|
+
.list-group-item-heading {
|
37
|
+
width: 375px;
|
38
|
+
}
|
39
|
+
|
40
|
+
p {
|
41
|
+
margin: 0;
|
42
|
+
font-size: 14px;
|
43
|
+
}
|
44
|
+
}
|
45
|
+
|
46
|
+
.list-view-pf-additional-info {
|
47
|
+
.risk-label {
|
48
|
+
padding: 5px 8px;
|
49
|
+
border-radius: 12px;
|
50
|
+
|
51
|
+
&.Low {
|
52
|
+
background-color: #e7f1fa;
|
53
|
+
}
|
54
|
+
|
55
|
+
&.Moderate {
|
56
|
+
background-color: #fdf7e7;
|
57
|
+
}
|
58
|
+
|
59
|
+
&.Important {
|
60
|
+
background-color: #f9dddd;
|
61
|
+
}
|
62
|
+
|
63
|
+
&.Critical {
|
64
|
+
background-color: #ffecec;
|
65
|
+
}
|
66
|
+
|
67
|
+
p {
|
68
|
+
margin: 0;
|
69
|
+
}
|
70
|
+
}
|
71
|
+
}
|
72
|
+
}
|
73
|
+
|
74
|
+
&::-webkit-scrollbar {
|
75
|
+
width: 12px;
|
76
|
+
height: 12px;
|
77
|
+
}
|
78
|
+
|
79
|
+
&::-webkit-scrollbar-thumb {
|
80
|
+
background: #0e0e0e6e;
|
81
|
+
border-radius: 6px;
|
82
|
+
border: 3px solid transparent;
|
83
|
+
background-clip: content-box;
|
84
|
+
}
|
85
|
+
}
|
86
|
+
}
|
@@ -0,0 +1,30 @@
|
|
1
|
+
import API from 'foremanReact/API';
|
2
|
+
import { insightsCloudUrl } from '../InsightsCloudSync/InsightsCloudSyncHelpers';
|
3
|
+
import {
|
4
|
+
INSIGHTS_HITS_REQUEST,
|
5
|
+
INSIGHTS_HITS_SUCCESS,
|
6
|
+
INSIGHTS_HITS_FAILURE,
|
7
|
+
} from './InsightsTabConstants';
|
8
|
+
|
9
|
+
export const fetchHits = hostID => async dispatch => {
|
10
|
+
try {
|
11
|
+
dispatch({
|
12
|
+
type: INSIGHTS_HITS_REQUEST,
|
13
|
+
payload: {},
|
14
|
+
});
|
15
|
+
const {
|
16
|
+
data: { hits },
|
17
|
+
} = await API.get(insightsCloudUrl(`hits/${hostID}`));
|
18
|
+
dispatch({
|
19
|
+
type: INSIGHTS_HITS_SUCCESS,
|
20
|
+
payload: { hits },
|
21
|
+
});
|
22
|
+
} catch (error) {
|
23
|
+
dispatch({
|
24
|
+
type: INSIGHTS_HITS_FAILURE,
|
25
|
+
payload: {
|
26
|
+
error: error.message,
|
27
|
+
},
|
28
|
+
});
|
29
|
+
}
|
30
|
+
};
|
@@ -0,0 +1,26 @@
|
|
1
|
+
import Immutable from 'seamless-immutable';
|
2
|
+
import {
|
3
|
+
INSIGHTS_HITS_SUCCESS,
|
4
|
+
INSIGHTS_HITS_FAILURE,
|
5
|
+
} from './InsightsTabConstants';
|
6
|
+
|
7
|
+
const initialState = Immutable({
|
8
|
+
hits: [],
|
9
|
+
});
|
10
|
+
|
11
|
+
export default (state = initialState, action) => {
|
12
|
+
const { payload: { hits, error } = {} } = action;
|
13
|
+
|
14
|
+
switch (action.type) {
|
15
|
+
case INSIGHTS_HITS_SUCCESS:
|
16
|
+
return state.merge({
|
17
|
+
hits,
|
18
|
+
});
|
19
|
+
case INSIGHTS_HITS_FAILURE:
|
20
|
+
return state.merge({
|
21
|
+
error,
|
22
|
+
});
|
23
|
+
default:
|
24
|
+
return state;
|
25
|
+
}
|
26
|
+
};
|
@@ -0,0 +1,25 @@
|
|
1
|
+
export const hostID = 1234;
|
2
|
+
|
3
|
+
export const hits = [
|
4
|
+
{
|
5
|
+
insights_hit: {
|
6
|
+
hostname: 'my-host.example.com',
|
7
|
+
rhel_version: '7.8',
|
8
|
+
uuid: '4739b323-a343-4e89-b71b-81991b8dc656',
|
9
|
+
last_seen: '2020-08-19T04:43:09.068706Z',
|
10
|
+
title:
|
11
|
+
'New Ansible Engine packages are inaccessible when dedicated Ansible repo is not enabled',
|
12
|
+
solution_url: 'https://access.redhat.com/node/3359651',
|
13
|
+
total_risk: 2,
|
14
|
+
likelihood: 2,
|
15
|
+
publish_date: '2018-04-16T10:03:16Z',
|
16
|
+
results_url:
|
17
|
+
'https://cloud.redhat.com/insights/advisor/recommendations/ansible_deprecated_repo%7CANSIBLE_DEPRECATED_REPO/4739b323-a343-4e89-b71b-81991b8dc656/',
|
18
|
+
},
|
19
|
+
},
|
20
|
+
];
|
21
|
+
|
22
|
+
export const props = {
|
23
|
+
hostID,
|
24
|
+
hits,
|
25
|
+
};
|
@@ -0,0 +1,13 @@
|
|
1
|
+
import { testComponentSnapshotsWithFixtures } from 'react-redux-test-utils';
|
2
|
+
|
3
|
+
import InsightsTab from '../InsightsTab';
|
4
|
+
import { props } from './InsightsTab.fixtures';
|
5
|
+
|
6
|
+
const fixtures = {
|
7
|
+
'render with props': props,
|
8
|
+
};
|
9
|
+
|
10
|
+
describe('InsightsTab', () => {
|
11
|
+
describe('rendering', () =>
|
12
|
+
testComponentSnapshotsWithFixtures(InsightsTab, fixtures));
|
13
|
+
});
|
@@ -0,0 +1,13 @@
|
|
1
|
+
import { testActionSnapshotWithFixtures } from 'react-redux-test-utils';
|
2
|
+
import API from 'foremanReact/API';
|
3
|
+
import { fetchHits } from '../InsightsTabActions';
|
4
|
+
import { hostID, hits } from './InsightsTab.fixtures';
|
5
|
+
|
6
|
+
jest.mock('foremanReact/API');
|
7
|
+
API.get.mockImplementation(async () => hits);
|
8
|
+
|
9
|
+
const fixtures = {
|
10
|
+
'should fetchHits': () => fetchHits(hostID),
|
11
|
+
};
|
12
|
+
|
13
|
+
describe('InsightsTab actions', () => testActionSnapshotWithFixtures(fixtures));
|
@@ -0,0 +1,17 @@
|
|
1
|
+
import React from 'react';
|
2
|
+
import { IntegrationTestHelper } from 'react-redux-test-utils';
|
3
|
+
|
4
|
+
import InsightsTab from '../index';
|
5
|
+
import reducers from '../../ForemanRhCloudReducers';
|
6
|
+
import { hostID } from './InsightsTab.fixtures';
|
7
|
+
|
8
|
+
describe('InsightsTab integration test', () => {
|
9
|
+
it('should flow', async () => {
|
10
|
+
const integrationTestHelper = new IntegrationTestHelper(reducers);
|
11
|
+
const component = integrationTestHelper.mount(
|
12
|
+
<InsightsTab hostID={hostID} />
|
13
|
+
);
|
14
|
+
component.update();
|
15
|
+
/** Create a Flow test */
|
16
|
+
});
|
17
|
+
});
|
@@ -0,0 +1,35 @@
|
|
1
|
+
import { testReducerSnapshotWithFixtures } from 'react-redux-test-utils';
|
2
|
+
import reducer from '../InsightsTabReducer';
|
3
|
+
import { hits } from './InsightsTab.fixtures';
|
4
|
+
import {
|
5
|
+
INSIGHTS_HITS_REQUEST,
|
6
|
+
INSIGHTS_HITS_SUCCESS,
|
7
|
+
INSIGHTS_HITS_FAILURE,
|
8
|
+
} from '../InsightsTabConstants';
|
9
|
+
|
10
|
+
const fixtures = {
|
11
|
+
'should return the initial state': {},
|
12
|
+
'should handle INSIGHTS_HITS_REQUEST': {
|
13
|
+
action: {
|
14
|
+
type: INSIGHTS_HITS_REQUEST,
|
15
|
+
payload: {},
|
16
|
+
},
|
17
|
+
},
|
18
|
+
'should handle INSIGHTS_HITS_SUCCESS': {
|
19
|
+
action: {
|
20
|
+
type: INSIGHTS_HITS_SUCCESS,
|
21
|
+
payload: { hits },
|
22
|
+
},
|
23
|
+
},
|
24
|
+
'should handle INSIGHTS_HITS_FAILURE': {
|
25
|
+
action: {
|
26
|
+
type: INSIGHTS_HITS_FAILURE,
|
27
|
+
payload: {
|
28
|
+
error: 'some-error',
|
29
|
+
},
|
30
|
+
},
|
31
|
+
},
|
32
|
+
};
|
33
|
+
|
34
|
+
describe('AccountList reducer', () =>
|
35
|
+
testReducerSnapshotWithFixtures(reducer, fixtures));
|
@@ -0,0 +1,13 @@
|
|
1
|
+
import { testSelectorsSnapshotWithFixtures } from 'react-redux-test-utils';
|
2
|
+
import { hostInsightsStateWrapper } from '../../ForemanRhCloudTestHelpers';
|
3
|
+
import { hits } from './InsightsTab.fixtures';
|
4
|
+
import { selectHits } from '../InsightsTabSelectors';
|
5
|
+
|
6
|
+
const state = hostInsightsStateWrapper({ hits });
|
7
|
+
|
8
|
+
const fixtures = {
|
9
|
+
'should return hits': () => selectHits(state),
|
10
|
+
};
|
11
|
+
|
12
|
+
describe('InsightsTab selectors', () =>
|
13
|
+
testSelectorsSnapshotWithFixtures(fixtures));
|
@@ -0,0 +1,30 @@
|
|
1
|
+
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
2
|
+
|
3
|
+
exports[`InsightsTab rendering render with props 1`] = `
|
4
|
+
<Row
|
5
|
+
bsClass="row"
|
6
|
+
componentClass="div"
|
7
|
+
>
|
8
|
+
<Col
|
9
|
+
bsClass="col"
|
10
|
+
componentClass="div"
|
11
|
+
xs={12}
|
12
|
+
>
|
13
|
+
<h2>
|
14
|
+
Recommendations
|
15
|
+
</h2>
|
16
|
+
<ListView
|
17
|
+
className=""
|
18
|
+
id="hits_list"
|
19
|
+
>
|
20
|
+
<ListItem
|
21
|
+
key="0"
|
22
|
+
resultsUrl="https://cloud.redhat.com/insights/advisor/recommendations/ansible_deprecated_repo%7CANSIBLE_DEPRECATED_REPO/4739b323-a343-4e89-b71b-81991b8dc656/"
|
23
|
+
solutionUrl="https://access.redhat.com/node/3359651"
|
24
|
+
title="New Ansible Engine packages are inaccessible when dedicated Ansible repo is not enabled"
|
25
|
+
totalRisk={2}
|
26
|
+
/>
|
27
|
+
</ListView>
|
28
|
+
</Col>
|
29
|
+
</Row>
|
30
|
+
`;
|
@@ -0,0 +1,20 @@
|
|
1
|
+
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
2
|
+
|
3
|
+
exports[`InsightsTab actions should fetchHits 1`] = `
|
4
|
+
Array [
|
5
|
+
Array [
|
6
|
+
Object {
|
7
|
+
"payload": Object {},
|
8
|
+
"type": "INSIGHTS_HITS_REQUEST",
|
9
|
+
},
|
10
|
+
],
|
11
|
+
Array [
|
12
|
+
Object {
|
13
|
+
"payload": Object {
|
14
|
+
"error": "Cannot read property 'hits' of undefined",
|
15
|
+
},
|
16
|
+
"type": "INSIGHTS_HITS_FAILURE",
|
17
|
+
},
|
18
|
+
],
|
19
|
+
]
|
20
|
+
`;
|
@@ -0,0 +1,41 @@
|
|
1
|
+
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
2
|
+
|
3
|
+
exports[`AccountList reducer should handle INSIGHTS_HITS_FAILURE 1`] = `
|
4
|
+
Object {
|
5
|
+
"error": "some-error",
|
6
|
+
"hits": Array [],
|
7
|
+
}
|
8
|
+
`;
|
9
|
+
|
10
|
+
exports[`AccountList reducer should handle INSIGHTS_HITS_REQUEST 1`] = `
|
11
|
+
Object {
|
12
|
+
"hits": Array [],
|
13
|
+
}
|
14
|
+
`;
|
15
|
+
|
16
|
+
exports[`AccountList reducer should handle INSIGHTS_HITS_SUCCESS 1`] = `
|
17
|
+
Object {
|
18
|
+
"hits": Array [
|
19
|
+
Object {
|
20
|
+
"insights_hit": Object {
|
21
|
+
"hostname": "my-host.example.com",
|
22
|
+
"last_seen": "2020-08-19T04:43:09.068706Z",
|
23
|
+
"likelihood": 2,
|
24
|
+
"publish_date": "2018-04-16T10:03:16Z",
|
25
|
+
"results_url": "https://cloud.redhat.com/insights/advisor/recommendations/ansible_deprecated_repo%7CANSIBLE_DEPRECATED_REPO/4739b323-a343-4e89-b71b-81991b8dc656/",
|
26
|
+
"rhel_version": "7.8",
|
27
|
+
"solution_url": "https://access.redhat.com/node/3359651",
|
28
|
+
"title": "New Ansible Engine packages are inaccessible when dedicated Ansible repo is not enabled",
|
29
|
+
"total_risk": 2,
|
30
|
+
"uuid": "4739b323-a343-4e89-b71b-81991b8dc656",
|
31
|
+
},
|
32
|
+
},
|
33
|
+
],
|
34
|
+
}
|
35
|
+
`;
|
36
|
+
|
37
|
+
exports[`AccountList reducer should return the initial state 1`] = `
|
38
|
+
Object {
|
39
|
+
"hits": Array [],
|
40
|
+
}
|
41
|
+
`;
|
@@ -0,0 +1,20 @@
|
|
1
|
+
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
2
|
+
|
3
|
+
exports[`InsightsTab selectors should return hits 1`] = `
|
4
|
+
Array [
|
5
|
+
Object {
|
6
|
+
"insights_hit": Object {
|
7
|
+
"hostname": "my-host.example.com",
|
8
|
+
"last_seen": "2020-08-19T04:43:09.068706Z",
|
9
|
+
"likelihood": 2,
|
10
|
+
"publish_date": "2018-04-16T10:03:16Z",
|
11
|
+
"results_url": "https://cloud.redhat.com/insights/advisor/recommendations/ansible_deprecated_repo%7CANSIBLE_DEPRECATED_REPO/4739b323-a343-4e89-b71b-81991b8dc656/",
|
12
|
+
"rhel_version": "7.8",
|
13
|
+
"solution_url": "https://access.redhat.com/node/3359651",
|
14
|
+
"title": "New Ansible Engine packages are inaccessible when dedicated Ansible repo is not enabled",
|
15
|
+
"total_risk": 2,
|
16
|
+
"uuid": "4739b323-a343-4e89-b71b-81991b8dc656",
|
17
|
+
},
|
18
|
+
},
|
19
|
+
]
|
20
|
+
`;
|
@@ -0,0 +1,69 @@
|
|
1
|
+
import React, { Fragment } from 'react';
|
2
|
+
import { ListView, Icon } from 'patternfly-react';
|
3
|
+
import PropTypes from 'prop-types';
|
4
|
+
|
5
|
+
const labelMapper = {
|
6
|
+
1: 'Low',
|
7
|
+
2: 'Moderate',
|
8
|
+
3: 'Important',
|
9
|
+
4: 'Critical',
|
10
|
+
};
|
11
|
+
|
12
|
+
const ListItem = ({ title, totalRisk, resultsUrl, solutionUrl }) => {
|
13
|
+
const heading = (
|
14
|
+
<p className="ellipsis list-item-heading" title={title}>
|
15
|
+
{title}
|
16
|
+
</p>
|
17
|
+
);
|
18
|
+
|
19
|
+
const riskLabel = labelMapper[totalRisk];
|
20
|
+
const additionalInfo = [
|
21
|
+
<span key={`risk-info-${title}`} className={`risk-label ${riskLabel}`}>
|
22
|
+
<p>{riskLabel}</p>
|
23
|
+
</span>,
|
24
|
+
];
|
25
|
+
|
26
|
+
const knowledgebaseLink = solutionUrl && (
|
27
|
+
<p>
|
28
|
+
<a href={solutionUrl} target="_blank" rel="noopener noreferrer">
|
29
|
+
Knowledgebase article <Icon name="external-link" />
|
30
|
+
</a>
|
31
|
+
</p>
|
32
|
+
);
|
33
|
+
|
34
|
+
const insightsCloudLink = resultsUrl && (
|
35
|
+
<p>
|
36
|
+
<a href={resultsUrl} target="_blank" rel="noopener noreferrer">
|
37
|
+
Read more about it in RH cloud insights <Icon name="external-link" />
|
38
|
+
</a>
|
39
|
+
</p>
|
40
|
+
);
|
41
|
+
|
42
|
+
return (
|
43
|
+
<ListView.Item
|
44
|
+
heading={heading}
|
45
|
+
additionalInfo={additionalInfo}
|
46
|
+
hideCloseIcon
|
47
|
+
>
|
48
|
+
<Fragment>
|
49
|
+
<p>{title}</p>
|
50
|
+
{knowledgebaseLink}
|
51
|
+
{insightsCloudLink}
|
52
|
+
</Fragment>
|
53
|
+
</ListView.Item>
|
54
|
+
);
|
55
|
+
};
|
56
|
+
|
57
|
+
ListItem.propTypes = {
|
58
|
+
title: PropTypes.string.isRequired,
|
59
|
+
totalRisk: PropTypes.number.isRequired,
|
60
|
+
resultsUrl: PropTypes.string,
|
61
|
+
solutionUrl: PropTypes.string,
|
62
|
+
};
|
63
|
+
|
64
|
+
ListItem.defaultProps = {
|
65
|
+
resultsUrl: '',
|
66
|
+
solutionUrl: '',
|
67
|
+
};
|
68
|
+
|
69
|
+
export default ListItem;
|
@@ -0,0 +1 @@
|
|
1
|
+
export { default } from './ListItem';
|
@@ -0,0 +1,20 @@
|
|
1
|
+
import { bindActionCreators } from 'redux';
|
2
|
+
import { connect } from 'react-redux';
|
3
|
+
import InsightsTab from './InsightsTab';
|
4
|
+
import * as actions from './InsightsTabActions';
|
5
|
+
import reducer from './InsightsTabReducer';
|
6
|
+
import { selectHits } from './InsightsTabSelectors';
|
7
|
+
|
8
|
+
// map state to props
|
9
|
+
const mapStateToProps = state => ({
|
10
|
+
hits: selectHits(state),
|
11
|
+
});
|
12
|
+
|
13
|
+
// map action dispatchers to props
|
14
|
+
const mapDispatchToProps = dispatch => bindActionCreators(actions, dispatch);
|
15
|
+
|
16
|
+
// export reducers
|
17
|
+
export const hostInsightsReducers = { hostInsights: reducer };
|
18
|
+
|
19
|
+
// export connected component
|
20
|
+
export default connect(mapStateToProps, mapDispatchToProps)(InsightsTab);
|
@@ -6,6 +6,7 @@ Object {
|
|
6
6
|
"InsightsCloudSync": Object {
|
7
7
|
"insightsChild": Object {},
|
8
8
|
},
|
9
|
+
"hostInsights": Object {},
|
9
10
|
"inventoryUpload": Object {},
|
10
11
|
},
|
11
12
|
}
|
@@ -15,6 +16,7 @@ exports[`ForemanRhCloud helpers should return inventory wrapper 1`] = `
|
|
15
16
|
Object {
|
16
17
|
"ForemanRhCloud": Object {
|
17
18
|
"InsightsCloudSync": Object {},
|
19
|
+
"hostInsights": Object {},
|
18
20
|
"inventoryUpload": Object {
|
19
21
|
"inventoryChild": Object {},
|
20
22
|
},
|
@@ -28,6 +30,7 @@ Object {
|
|
28
30
|
"InsightsCloudSync": Object {
|
29
31
|
"insightsChild": Object {},
|
30
32
|
},
|
33
|
+
"hostInsights": Object {},
|
31
34
|
"inventoryUpload": Object {
|
32
35
|
"inventoryChild": Object {},
|
33
36
|
},
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: foreman_rh_cloud
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.9.
|
4
|
+
version: 0.9.11
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Foreman Red Hat Cloud team
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2020-
|
11
|
+
date: 2020-09-16 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: katello
|
@@ -81,10 +81,12 @@ files:
|
|
81
81
|
- app/controllers/foreman_inventory_upload/tasks_controller.rb
|
82
82
|
- app/controllers/foreman_inventory_upload/uploads_controller.rb
|
83
83
|
- app/controllers/foreman_rh_cloud/react_controller.rb
|
84
|
+
- app/controllers/insights_cloud/hits_controller.rb
|
84
85
|
- app/controllers/insights_cloud/settings_controller.rb
|
85
86
|
- app/controllers/insights_cloud/tasks_controller.rb
|
86
87
|
- app/helpers/foreman_inventory_upload_helper.rb
|
87
88
|
- app/helpers/foreman_inventory_upload_host_helper.rb
|
89
|
+
- app/models/concerns/rh_cloud_host.rb
|
88
90
|
- app/models/insights_facet.rb
|
89
91
|
- app/models/insights_hit.rb
|
90
92
|
- app/models/inventory_sync/inventory_status.rb
|
@@ -92,6 +94,7 @@ files:
|
|
92
94
|
- app/overrides/hosts_list.rb
|
93
95
|
- app/views/foreman_rh_cloud/react/insights_cloud.html.erb
|
94
96
|
- app/views/foreman_rh_cloud/react/inventory_upload.html.erb
|
97
|
+
- app/views/hosts/_insights_tab.html.erb
|
95
98
|
- app/views/layouts/foreman_rh_cloud/application.html.erb
|
96
99
|
- config/routes.rb
|
97
100
|
- db/migrate/20191215104806_create_insights_hits.foreman_inventory_upload.rb
|
@@ -122,7 +125,8 @@ files:
|
|
122
125
|
- lib/inventory_sync/async/host_result.rb
|
123
126
|
- lib/inventory_sync/async/inventory_full_sync.rb
|
124
127
|
- lib/tasks/foreman_rh_cloud_tasks.rake
|
125
|
-
- lib/tasks/
|
128
|
+
- lib/tasks/insights.rake
|
129
|
+
- lib/tasks/rh_cloud_inventory.rake
|
126
130
|
- locale/Makefile
|
127
131
|
- locale/en/foreman_rh_cloud.po
|
128
132
|
- locale/foreman_rh_cloud.pot
|
@@ -136,6 +140,7 @@ files:
|
|
136
140
|
- test/factories/inventory_upload_factories.rb
|
137
141
|
- test/jobs/insights_full_sync_test.rb
|
138
142
|
- test/jobs/inventory_full_sync_test.rb
|
143
|
+
- test/jobs/upload_report_job_test.rb
|
139
144
|
- test/test_plugin_helper.rb
|
140
145
|
- test/unit/archived_report_generator_test.rb
|
141
146
|
- test/unit/fact_helpers_test.rb
|
@@ -430,6 +435,25 @@ files:
|
|
430
435
|
- webpack/InsightsCloudSync/__tests__/InsightsCloudSyncHelpers.test.js
|
431
436
|
- webpack/InsightsCloudSync/__tests__/__snapshots__/InsightsCloudSyncHelpers.test.js.snap
|
432
437
|
- webpack/InsightsCloudSync/index.js
|
438
|
+
- webpack/InsightsHostDetailsTab/InsightsTab.js
|
439
|
+
- webpack/InsightsHostDetailsTab/InsightsTab.scss
|
440
|
+
- webpack/InsightsHostDetailsTab/InsightsTabActions.js
|
441
|
+
- webpack/InsightsHostDetailsTab/InsightsTabConstants.js
|
442
|
+
- webpack/InsightsHostDetailsTab/InsightsTabReducer.js
|
443
|
+
- webpack/InsightsHostDetailsTab/InsightsTabSelectors.js
|
444
|
+
- webpack/InsightsHostDetailsTab/__tests__/InsightsTab.fixtures.js
|
445
|
+
- webpack/InsightsHostDetailsTab/__tests__/InsightsTab.test.js
|
446
|
+
- webpack/InsightsHostDetailsTab/__tests__/InsightsTabActions.test.js
|
447
|
+
- webpack/InsightsHostDetailsTab/__tests__/InsightsTabIntegration.test.js
|
448
|
+
- webpack/InsightsHostDetailsTab/__tests__/InsightsTabReducer.test.js
|
449
|
+
- webpack/InsightsHostDetailsTab/__tests__/InsightsTabSelectors.test.js
|
450
|
+
- webpack/InsightsHostDetailsTab/__tests__/__snapshots__/InsightsTab.test.js.snap
|
451
|
+
- webpack/InsightsHostDetailsTab/__tests__/__snapshots__/InsightsTabActions.test.js.snap
|
452
|
+
- webpack/InsightsHostDetailsTab/__tests__/__snapshots__/InsightsTabReducer.test.js.snap
|
453
|
+
- webpack/InsightsHostDetailsTab/__tests__/__snapshots__/InsightsTabSelectors.test.js.snap
|
454
|
+
- webpack/InsightsHostDetailsTab/components/ListItem/ListItem.js
|
455
|
+
- webpack/InsightsHostDetailsTab/components/ListItem/index.js
|
456
|
+
- webpack/InsightsHostDetailsTab/index.js
|
433
457
|
- webpack/__mocks__/foremanReact/API.js
|
434
458
|
- webpack/__mocks__/foremanReact/common/I18n.js
|
435
459
|
- webpack/__mocks__/foremanReact/common/helpers.js
|
@@ -470,23 +494,24 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
470
494
|
- !ruby/object:Gem::Version
|
471
495
|
version: '0'
|
472
496
|
requirements: []
|
473
|
-
rubygems_version: 3.0.
|
497
|
+
rubygems_version: 3.0.8
|
474
498
|
signing_key:
|
475
499
|
specification_version: 4
|
476
500
|
summary: Summary of ForemanRhCloud.
|
477
501
|
test_files:
|
478
|
-
- test/controllers/uploads_controller_test.rb
|
479
|
-
- test/controllers/insights_sync/settings_controller_test.rb
|
480
|
-
- test/controllers/accounts_controller_test.rb
|
481
|
-
- test/controllers/reports_controller_test.rb
|
482
502
|
- test/test_plugin_helper.rb
|
483
|
-
- test/jobs/insights_full_sync_test.rb
|
484
|
-
- test/jobs/inventory_full_sync_test.rb
|
485
503
|
- test/factories/inventory_upload_factories.rb
|
486
504
|
- test/factories/insights_factories.rb
|
487
|
-
- test/
|
505
|
+
- test/controllers/reports_controller_test.rb
|
506
|
+
- test/controllers/uploads_controller_test.rb
|
507
|
+
- test/controllers/accounts_controller_test.rb
|
508
|
+
- test/controllers/insights_sync/settings_controller_test.rb
|
509
|
+
- test/unit/slice_generator_test.rb
|
488
510
|
- test/unit/metadata_generator_test.rb
|
511
|
+
- test/unit/shell_process_job_test.rb
|
489
512
|
- test/unit/insights_facet_test.rb
|
490
|
-
- test/unit/fact_helpers_test.rb
|
491
513
|
- test/unit/archived_report_generator_test.rb
|
492
|
-
- test/unit/
|
514
|
+
- test/unit/fact_helpers_test.rb
|
515
|
+
- test/jobs/inventory_full_sync_test.rb
|
516
|
+
- test/jobs/insights_full_sync_test.rb
|
517
|
+
- test/jobs/upload_report_job_test.rb
|