foreman_rh_cloud 2.0.8 → 2.0.9
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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/async/shell_process.rb +7 -1
- data/lib/foreman_inventory_upload/async/upload_report_job.rb +1 -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_inventory_upload/scripts/uploader.sh.erb +1 -1
- 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: c164b990c325cd1f5e90004585c0074c558ee29ece8b687d37115d88f278274d
|
4
|
+
data.tar.gz: 01f04d99170a49224c7687949acff8d7171ce73d0d620343ce348c324b2b6040
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: dc211d399ff2f518b47ccfe76e8a569cac8b3356bab5dc6f2dabfc8c0a3de2926dd8fe99f2a84ea8dba9e4dea3b871cdd3380dfebb48e51cdcb1198dbac16bc8
|
7
|
+
data.tar.gz: 622e9894c0bef62e38f25b687d2acb0c5db74cf8e299e5a327f102052704324e2aafaee71fa30b595de66a29124789a815899e3f324000c559e3c75ce2ce401c
|
@@ -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
|
]
|
@@ -9,7 +9,7 @@ module ForemanInventoryUpload
|
|
9
9
|
klass_name = self.class.name
|
10
10
|
logger.debug("Starting #{klass_name} with label #{instance_label}")
|
11
11
|
progress_output = ProgressOutput.register(instance_label)
|
12
|
-
Open3.popen2e(hash_to_s(env), command) do |_stdin, stdout_stderr, wait_thread|
|
12
|
+
Open3.popen2e(hash_to_s(env), *preprocess_command(command)) do |_stdin, stdout_stderr, wait_thread|
|
13
13
|
progress_output.status = "Running in pid #{wait_thread.pid}"
|
14
14
|
|
15
15
|
stdout_stderr.each do |out_line|
|
@@ -33,6 +33,12 @@ module ForemanInventoryUpload
|
|
33
33
|
def logger
|
34
34
|
Foreman::Logging.logger('background')
|
35
35
|
end
|
36
|
+
|
37
|
+
private
|
38
|
+
|
39
|
+
def preprocess_command(command)
|
40
|
+
command.kind_of?(Array) ? command : [command]
|
41
|
+
end
|
36
42
|
end
|
37
43
|
end
|
38
44
|
end
|
@@ -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: 2.0.
|
4
|
+
version: 2.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-14 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: katello
|