foreman_rh_cloud 1.0.8 → 1.0.9
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/app/models/setting/rh_cloud.rb +1 -1
- data/app/views/foreman_rh_cloud/react/insights_cloud.html.erb +6 -1
- data/lib/foreman_inventory_upload/generators/json_stream.rb +10 -0
- data/lib/foreman_inventory_upload/generators/slice.rb +14 -10
- data/lib/foreman_rh_cloud/version.rb +1 -1
- data/lib/insights_cloud/async/insights_full_sync.rb +6 -2
- data/test/jobs/insights_full_sync_test.rb +30 -0
- data/test/unit/slice_generator_test.rb +29 -3
- data/webpack/ForemanInventoryUpload/Components/PageHeader/components/PageDescription/PageDescription.js +2 -2
- data/webpack/ForemanInventoryUpload/Components/PageHeader/components/PageDescription/__tests__/__snapshots__/PageDescription.test.js.snap +2 -2
- data/webpack/InsightsCloudSync/InsightsCloudSync.js +34 -5
- data/webpack/InsightsCloudSync/InsightsCloudSync.test.js +3 -0
- data/webpack/InsightsCloudSync/__snapshots__/InsightsCloudSync.test.js.snap +47 -10
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 8e4b8f3297e5f7e0279d18de6ee94ae4607eb94e9df9fd3976881af75314c93a
|
4
|
+
data.tar.gz: 5673e003e78a64e4127ceb313899792161392387b0398a6b966e5da98821f036
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: d42c544257f0db44fa5d0d9dc7dc778f5a630cad2ba88667660aa1a9bf257192ab7df8645611cedd1aa988b64f84449adcd4337376e22ac0ab4ea6fd21c4cac0
|
7
|
+
data.tar.gz: 82968701d406c36012ab10043c95448f86d6723808b99009861a54132e8e372b78978b86a5477eeeb5b4c2c6176fd72bef204dd77680432174daa9ab07af35fc
|
@@ -3,7 +3,7 @@ class Setting::RhCloud < Setting
|
|
3
3
|
return unless ActiveRecord::Base.connection.table_exists?('settings')
|
4
4
|
return unless super
|
5
5
|
[
|
6
|
-
set('allow_auto_inventory_upload', N_('Allow automatic upload of the host inventory to the Red Hat cloud'),
|
6
|
+
set('allow_auto_inventory_upload', N_('Allow automatic upload of the host inventory to the Red Hat cloud'), false),
|
7
7
|
set('obfuscate_inventory_hostnames', N_('Obfuscate host names sent to Red Hat cloud'), false),
|
8
8
|
set('rh_cloud_token', N_('Authentication token to Red Hat cloud services. Used to authenticate requests to cloud APIs'), 'DEFAULT', N_('Red Hat Cloud token'), nil, encrypted: true),
|
9
9
|
]
|
@@ -36,6 +36,16 @@ module ForemanInventoryUpload
|
|
36
36
|
@out << ',' unless last
|
37
37
|
end
|
38
38
|
|
39
|
+
def string_array_value(name, value, last = false)
|
40
|
+
return if value.empty?
|
41
|
+
|
42
|
+
string_value = value.map { |v| stringify_value(v) }
|
43
|
+
|
44
|
+
array_field(name, last) do
|
45
|
+
raw(string_value.join(', '))
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
39
49
|
def object_field(name, last = false, &block)
|
40
50
|
@out << "\"#{name}\": "
|
41
51
|
object(&block)
|
@@ -45,16 +45,8 @@ module ForemanInventoryUpload
|
|
45
45
|
@stream.simple_field('satellite_id', host.subscription_facet&.uuid)
|
46
46
|
@stream.simple_field('bios_uuid', fact_value(host, 'dmi::system::uuid'))
|
47
47
|
@stream.simple_field('vm_uuid', fact_value(host, 'virt::uuid'))
|
48
|
-
|
49
|
-
|
50
|
-
@stream.stringify_value(nic.ip) if nic.ip
|
51
|
-
end.compact.join(', '))
|
52
|
-
end
|
53
|
-
@stream.array_field('mac_addresses') do
|
54
|
-
@stream.raw(host.interfaces.map do |nic|
|
55
|
-
@stream.stringify_value(nic.mac) if nic.mac
|
56
|
-
end.compact.join(', '))
|
57
|
-
end
|
48
|
+
report_ip_addresses(host)
|
49
|
+
report_mac_addresses(host)
|
58
50
|
@stream.object_field('system_profile') do
|
59
51
|
report_system_profile(host)
|
60
52
|
end
|
@@ -161,6 +153,18 @@ module ForemanInventoryUpload
|
|
161
153
|
@stream.simple_field('organization_id', host.organization_id, :last)
|
162
154
|
end
|
163
155
|
|
156
|
+
def report_ip_addresses(host)
|
157
|
+
ip_addresses = host.interfaces.map { |nic| nic.ip }.compact
|
158
|
+
|
159
|
+
@stream.string_array_value('ip_addresses', ip_addresses)
|
160
|
+
end
|
161
|
+
|
162
|
+
def report_mac_addresses(host)
|
163
|
+
macs = host.interfaces.map { |nic| nic.mac }.compact
|
164
|
+
|
165
|
+
@stream.string_array_value('mac_addresses', macs)
|
166
|
+
end
|
167
|
+
|
164
168
|
def os_release_value(name:, version:, codename:)
|
165
169
|
"#{name} #{version} (#{codename})"
|
166
170
|
end
|
@@ -68,7 +68,7 @@ module InsightsCloud
|
|
68
68
|
def replace_hits_data(hits)
|
69
69
|
InsightsHit.transaction do
|
70
70
|
InsightsHit.delete_all
|
71
|
-
InsightsHit.create(hits.map { |hits_hash| to_model_hash(hits_hash) })
|
71
|
+
InsightsHit.create(hits.map { |hits_hash| to_model_hash(hits_hash) }.compact)
|
72
72
|
# create new facets for hosts that are missing one
|
73
73
|
hosts_with_existing_facets = InsightsFacet.where(host_id: @host_ids.values).pluck(:host_id)
|
74
74
|
InsightsFacet.create((@host_ids.values - hosts_with_existing_facets).map { |id| {host_id: id} })
|
@@ -76,8 +76,12 @@ module InsightsCloud
|
|
76
76
|
end
|
77
77
|
|
78
78
|
def to_model_hash(hit_hash)
|
79
|
+
hit_host_id = host_id(hit_hash['hostname'])
|
80
|
+
|
81
|
+
return unless hit_host_id
|
82
|
+
|
79
83
|
{
|
80
|
-
host_id:
|
84
|
+
host_id: hit_host_id,
|
81
85
|
last_seen: DateTime.parse(hit_hash['last_seen']),
|
82
86
|
publish_date: DateTime.parse(hit_hash['publish_date']),
|
83
87
|
title: hit_hash['title'],
|
@@ -59,4 +59,34 @@ class InsightsFullSyncTest < ActiveJob::TestCase
|
|
59
59
|
assert_equal 2, @host1.insights.hits.count
|
60
60
|
assert_equal 1, @host2.insights.hits.count
|
61
61
|
end
|
62
|
+
|
63
|
+
test 'Hits ignoring non-existent hosts' do
|
64
|
+
hits_json = <<-HITS_JSON
|
65
|
+
[
|
66
|
+
{
|
67
|
+
"hostname": "#{@host1.name}_non_existent",
|
68
|
+
"rhel_version": "7.5",
|
69
|
+
"uuid": "accdf444-5628-451d-bf3e-cf909ad72756",
|
70
|
+
"last_seen": "2019-11-22T08:41:42.447244Z",
|
71
|
+
"title": "New Ansible Engine packages are inaccessible when dedicated Ansible repo is not enabled",
|
72
|
+
"solution_url": "",
|
73
|
+
"total_risk": 2,
|
74
|
+
"likelihood": 2,
|
75
|
+
"publish_date": "2018-04-16T10:03:16Z",
|
76
|
+
"results_url": "https://cloud.redhat.com/insights/overview/stability/ansible_deprecated_repo%7CANSIBLE_DEPRECATED_REPO/accdf444-5628-451d-bf3e-cf909ad72756/"
|
77
|
+
}
|
78
|
+
]
|
79
|
+
HITS_JSON
|
80
|
+
hits = JSON.parse(hits_json)
|
81
|
+
|
82
|
+
InsightsCloud::Async::InsightsFullSync.any_instance.expects(:query_insights_hits).returns(hits)
|
83
|
+
|
84
|
+
InsightsCloud::Async::InsightsFullSync.perform_now(@host1.organization)
|
85
|
+
|
86
|
+
@host1.reload
|
87
|
+
@host2.reload
|
88
|
+
|
89
|
+
assert_nil @host1.insights
|
90
|
+
assert_nil @host2.insights
|
91
|
+
end
|
62
92
|
end
|
@@ -63,6 +63,25 @@ class ReportGeneratorTest < ActiveSupport::TestCase
|
|
63
63
|
|
64
64
|
assert_equal 'slice_123', actual['report_slice_id']
|
65
65
|
assert_not_nil(actual_host = actual['hosts'].first)
|
66
|
+
assert_nil actual_host['ip_addresses']
|
67
|
+
assert_nil actual_host['mac_addresses']
|
68
|
+
assert_equal @host.fqdn, actual_host['fqdn']
|
69
|
+
assert_equal '1234', actual_host['account']
|
70
|
+
assert_equal 1, generator.hosts_count
|
71
|
+
end
|
72
|
+
|
73
|
+
test 'generates ip_address and mac_address fields' do
|
74
|
+
@host.interfaces << FactoryBot.build(:nic_managed)
|
75
|
+
batch = Host.where(id: @host.id).in_batches.first
|
76
|
+
generator = create_generator(batch)
|
77
|
+
|
78
|
+
json_str = generator.render
|
79
|
+
actual = JSON.parse(json_str.join("\n"))
|
80
|
+
|
81
|
+
assert_equal 'slice_123', actual['report_slice_id']
|
82
|
+
assert_not_nil(actual_host = actual['hosts'].first)
|
83
|
+
assert_equal @host.interfaces.where.not(ip: nil).first.ip, actual_host['ip_addresses'].first
|
84
|
+
assert_equal @host.interfaces.where.not(mac: nil).first.mac, actual_host['mac_addresses'].first
|
66
85
|
assert_equal @host.fqdn, actual_host['fqdn']
|
67
86
|
assert_equal '1234', actual_host['account']
|
68
87
|
assert_equal 1, generator.hosts_count
|
@@ -262,10 +281,17 @@ class ReportGeneratorTest < ActiveSupport::TestCase
|
|
262
281
|
first_pool = @host.organization.pools.first
|
263
282
|
second_pool = FactoryBot.create(:katello_pool, account_number: nil, cp_id: 2)
|
264
283
|
new_org = FactoryBot.create(:organization, pools: [first_pool, second_pool])
|
265
|
-
@host.organization = new_org
|
266
|
-
@host.save!
|
267
284
|
|
268
|
-
|
285
|
+
another_host = FactoryBot.create(
|
286
|
+
:host,
|
287
|
+
:with_subscription,
|
288
|
+
:with_content,
|
289
|
+
content_view: @host.content_view,
|
290
|
+
lifecycle_environment: @host.lifecycle_environment,
|
291
|
+
organization: new_org
|
292
|
+
)
|
293
|
+
|
294
|
+
batch = Host.where(id: another_host.id).in_batches.first
|
269
295
|
generator = create_generator(batch)
|
270
296
|
|
271
297
|
json_str = generator.render
|
@@ -10,12 +10,12 @@ export const PageDescription = () => (
|
|
10
10
|
</p>
|
11
11
|
<p>
|
12
12
|
{__(
|
13
|
-
'In order to utilize these
|
13
|
+
'In order to utilize these services, you can set the auto upload in the settings to "ON".'
|
14
14
|
)}
|
15
15
|
</p>
|
16
16
|
<p>
|
17
17
|
{__(
|
18
|
-
'You can also trigger the upload manually by
|
18
|
+
'You can also trigger the upload manually by opening the relevant organization card, and clicking on the "Restart" button'
|
19
19
|
)}
|
20
20
|
</p>
|
21
21
|
</div>
|
@@ -8,10 +8,10 @@ exports[`PageDescription rendering render without Props 1`] = `
|
|
8
8
|
Red Hat Insights is a set of cloud services which provide unified subscription reporting, predictive analysis and remediation of issues through this Satellite instance.
|
9
9
|
</p>
|
10
10
|
<p>
|
11
|
-
In order to utilize these
|
11
|
+
In order to utilize these services, you can set the auto upload in the settings to "ON".
|
12
12
|
</p>
|
13
13
|
<p>
|
14
|
-
You can also trigger the upload manually by
|
14
|
+
You can also trigger the upload manually by opening the relevant organization card, and clicking on the "Restart" button
|
15
15
|
</p>
|
16
16
|
</div>
|
17
17
|
`;
|
@@ -2,18 +2,44 @@ import React from 'react';
|
|
2
2
|
import { IntlProvider } from 'react-intl';
|
3
3
|
import PropTypes from 'prop-types';
|
4
4
|
import { translate as __ } from 'foremanReact/common/I18n';
|
5
|
-
import { Button } from 'patternfly-react';
|
5
|
+
import { Button, Icon } from 'patternfly-react';
|
6
6
|
import { INSIGHTS_SYNC_PAGE_TITLE } from './InsightsCloudSyncConstants';
|
7
7
|
|
8
|
-
const InsightsCloudSync = ({ syncInsights }) => {
|
8
|
+
const InsightsCloudSync = ({ data: { settingsUrl }, syncInsights }) => {
|
9
9
|
document.title = INSIGHTS_SYNC_PAGE_TITLE;
|
10
10
|
return (
|
11
11
|
<IntlProvider locale={navigator.language}>
|
12
12
|
<div className="insights-cloud-sync">
|
13
13
|
<h1>{__('Red Hat Insights Sync')}</h1>
|
14
|
-
<
|
15
|
-
{__(
|
16
|
-
|
14
|
+
<p>
|
15
|
+
{__(`Insights synchronization process is used to provide Insights
|
16
|
+
recommendations output for hosts managed here`)}
|
17
|
+
</p>
|
18
|
+
<p>
|
19
|
+
{__(`1. Obtain an RHSM API token: `)}
|
20
|
+
<a
|
21
|
+
href="https://access.redhat.com/management/api"
|
22
|
+
target="_blank"
|
23
|
+
rel="noopener noreferrer"
|
24
|
+
>
|
25
|
+
access.redhat.com <Icon name="external-link" size="xs" />
|
26
|
+
</a>
|
27
|
+
<br />
|
28
|
+
{__("2. Copy the token to 'Red Hat Cloud token' setting: ")}
|
29
|
+
<a href={settingsUrl} target="_blank" rel="noopener noreferrer">
|
30
|
+
{__('Red Hat Cloud token ')}
|
31
|
+
<Icon name="external-link" size="xs" />
|
32
|
+
</a>
|
33
|
+
<br />
|
34
|
+
{__(
|
35
|
+
'3. Now you can syncronize recommendations manually using the "Sync now" button.'
|
36
|
+
)}
|
37
|
+
</p>
|
38
|
+
<div>
|
39
|
+
<Button bsStyle="primary" onClick={syncInsights}>
|
40
|
+
{__('Sync now')}
|
41
|
+
</Button>
|
42
|
+
</div>
|
17
43
|
</div>
|
18
44
|
</IntlProvider>
|
19
45
|
);
|
@@ -21,6 +47,9 @@ const InsightsCloudSync = ({ syncInsights }) => {
|
|
21
47
|
|
22
48
|
InsightsCloudSync.propTypes = {
|
23
49
|
syncInsights: PropTypes.func.isRequired,
|
50
|
+
data: PropTypes.shape({
|
51
|
+
settingsUrl: PropTypes.string.isRequired,
|
52
|
+
}).isRequired,
|
24
53
|
};
|
25
54
|
|
26
55
|
export default InsightsCloudSync;
|
@@ -10,16 +10,53 @@ exports[`InsightsCloudSync render 1`] = `
|
|
10
10
|
<h1>
|
11
11
|
Red Hat Insights Sync
|
12
12
|
</h1>
|
13
|
-
<
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
13
|
+
<p>
|
14
|
+
Insights synchronization process is used to provide Insights
|
15
|
+
recommendations output for hosts managed here
|
16
|
+
</p>
|
17
|
+
<p>
|
18
|
+
1. Obtain an RHSM API token:
|
19
|
+
<a
|
20
|
+
href="https://access.redhat.com/management/api"
|
21
|
+
rel="noopener noreferrer"
|
22
|
+
target="_blank"
|
23
|
+
>
|
24
|
+
access.redhat.com
|
25
|
+
<Icon
|
26
|
+
name="external-link"
|
27
|
+
size="xs"
|
28
|
+
type="fa"
|
29
|
+
/>
|
30
|
+
</a>
|
31
|
+
<br />
|
32
|
+
2. Copy the token to 'Red Hat Cloud token' setting:
|
33
|
+
<a
|
34
|
+
href="www.example.com/settings"
|
35
|
+
rel="noopener noreferrer"
|
36
|
+
target="_blank"
|
37
|
+
>
|
38
|
+
Red Hat Cloud token
|
39
|
+
<Icon
|
40
|
+
name="external-link"
|
41
|
+
size="xs"
|
42
|
+
type="fa"
|
43
|
+
/>
|
44
|
+
</a>
|
45
|
+
<br />
|
46
|
+
3. Now you can syncronize recommendations manually using the "Sync now" button.
|
47
|
+
</p>
|
48
|
+
<div>
|
49
|
+
<Button
|
50
|
+
active={false}
|
51
|
+
block={false}
|
52
|
+
bsClass="btn"
|
53
|
+
bsStyle="primary"
|
54
|
+
disabled={false}
|
55
|
+
onClick={[Function]}
|
56
|
+
>
|
57
|
+
Sync now
|
58
|
+
</Button>
|
59
|
+
</div>
|
23
60
|
</div>
|
24
61
|
</IntlProvider>
|
25
62
|
`;
|
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: 1.0.
|
4
|
+
version: 1.0.9
|
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-07-13 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: katello
|