foreman_inventory_upload 1.0.0.beta7 → 1.0.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/app/controllers/foreman_inventory_upload/accounts_controller.rb +39 -0
- data/app/controllers/foreman_inventory_upload/reports_controller.rb +3 -4
- data/app/controllers/foreman_inventory_upload/uploads_controller.rb +3 -3
- data/app/views/scripts/uploader.sh.erb +21 -9
- data/config/routes.rb +5 -5
- data/lib/foreman_inventory_upload.rb +14 -10
- data/lib/foreman_inventory_upload/async/generate_all_reports_job.rb +4 -7
- data/lib/foreman_inventory_upload/async/generate_report_job.rb +13 -9
- data/lib/foreman_inventory_upload/async/queue_for_upload_job.rb +7 -7
- data/lib/foreman_inventory_upload/async/upload_report_job.rb +22 -17
- data/lib/foreman_inventory_upload/generators/archived_report.rb +2 -2
- data/lib/foreman_inventory_upload/generators/queries.rb +18 -9
- data/lib/foreman_inventory_upload/generators/slice.rb +16 -9
- data/lib/foreman_inventory_upload/version.rb +1 -1
- data/lib/tasks/generator.rake +19 -5
- data/test/controllers/{statuses_controller_test.rb → accounts_controller_test.rb} +6 -7
- data/test/controllers/reports_controller_test.rb +3 -3
- data/test/controllers/uploads_controller_test.rb +3 -3
- data/test/unit/archived_report_generator_test.rb +3 -3
- data/test/unit/slice_generator_test.rb +22 -0
- data/webpack/ForemanInventoryUpload/Components/AccountList/AccountList.fixtures.js +5 -2
- data/webpack/ForemanInventoryUpload/Components/AccountList/AccountList.js +11 -9
- data/webpack/ForemanInventoryUpload/Components/AccountList/AccountListActions.js +3 -3
- data/webpack/ForemanInventoryUpload/Components/AccountList/AccountListReducer.js +7 -7
- data/webpack/ForemanInventoryUpload/Components/AccountList/AccountListSelectors.js +1 -1
- data/webpack/ForemanInventoryUpload/Components/AccountList/Components/ListItem/ListItem.fixtures.js +1 -1
- data/webpack/ForemanInventoryUpload/Components/AccountList/Components/ListItem/ListItem.js +9 -7
- data/webpack/ForemanInventoryUpload/Components/AccountList/Components/ListItem/__tests__/__snapshots__/ListItem.test.js.snap +6 -4
- data/webpack/ForemanInventoryUpload/Components/AccountList/Components/ListItemStatus/ListItemStatus.fixtures.js +2 -1
- data/webpack/ForemanInventoryUpload/Components/AccountList/Components/ListItemStatus/ListItemStatus.js +5 -5
- data/webpack/ForemanInventoryUpload/Components/AccountList/__tests__/AccountListReducer.test.js +2 -2
- data/webpack/ForemanInventoryUpload/Components/AccountList/__tests__/AccountListSelectors.test.js +4 -4
- data/webpack/ForemanInventoryUpload/Components/AccountList/__tests__/__snapshots__/AccountList.test.js.snap +15 -12
- data/webpack/ForemanInventoryUpload/Components/AccountList/__tests__/__snapshots__/AccountListReducer.test.js.snap +13 -10
- data/webpack/ForemanInventoryUpload/Components/AccountList/__tests__/__snapshots__/AccountListSelectors.test.js.snap +9 -3
- data/webpack/ForemanInventoryUpload/Components/AccountList/index.js +3 -6
- data/webpack/ForemanInventoryUpload/Components/Dashboard/Dashboard.js +5 -5
- data/webpack/ForemanInventoryUpload/Components/Dashboard/index.js +1 -4
- data/webpack/ForemanInventoryUpload/Components/NavContainer/__tests__/__snapshots__/NavContainer.test.js.snap +4 -4
- data/webpack/ForemanInventoryUpload/Components/StatusChart/StatusChart.js +4 -1
- metadata +7 -7
- data/app/controllers/foreman_inventory_upload/statuses_controller.rb +0 -41
data/lib/tasks/generator.rake
CHANGED
@@ -4,12 +4,26 @@ namespace :foreman_inventory_upload 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
|
7
|
-
|
8
|
-
|
7
|
+
portal_user = ENV['portal_user']
|
8
|
+
organizations = [ENV['organization_id']]
|
9
|
+
base_folder = ENV['target'] || Dir.pwd
|
9
10
|
|
10
|
-
|
11
|
-
|
12
|
-
|
11
|
+
unless portal_user || organizations.empty?
|
12
|
+
puts "Must specify either portal_user or organization_id"
|
13
|
+
end
|
14
|
+
|
15
|
+
if portal_user
|
16
|
+
puts "Generating report for all organizations associated with #{portal_user}"
|
17
|
+
base_folder = File.join(base_folder, portal_user)
|
18
|
+
organizations = ForemanInventoryUpload::Generators::Queries.organizations_for_user(portal_user).pluck(:id)
|
19
|
+
end
|
20
|
+
|
21
|
+
organizations.each do |organization|
|
22
|
+
target = File.join(base_folder, ForemanInventoryUpload.facts_archive_name(organization))
|
23
|
+
archived_report_generator = ForemanInventoryUpload::Generators::ArchivedReport.new(target, Logger.new(STDOUT))
|
24
|
+
archived_report_generator.render(organization: organization)
|
25
|
+
puts "Successfully generated #{target} for organization id #{organization}"
|
26
|
+
end
|
13
27
|
end
|
14
28
|
end
|
15
29
|
end
|
@@ -1,25 +1,24 @@
|
|
1
1
|
require 'test_plugin_helper'
|
2
2
|
|
3
|
-
class
|
4
|
-
tests ForemanInventoryUpload::
|
3
|
+
class AccountsControllerTest < ActionController::TestCase
|
4
|
+
tests ForemanInventoryUpload::AccountsController
|
5
5
|
|
6
6
|
include FolderIsolation
|
7
7
|
|
8
8
|
test 'Returns statuses for each process type' do
|
9
|
-
|
10
|
-
configuration.save!
|
9
|
+
test_org = FactoryBot.create(:organization)
|
11
10
|
|
12
|
-
generate_label = ForemanInventoryUpload::Async::GenerateReportJob.output_label(
|
11
|
+
generate_label = ForemanInventoryUpload::Async::GenerateReportJob.output_label(test_org.id)
|
13
12
|
generate_output = ForemanInventoryUpload::Async::ProgressOutput.register(generate_label)
|
14
13
|
generate_output.status = 'generate_status_test'
|
15
|
-
upload_label = ForemanInventoryUpload::Async::UploadReportJob.output_label(
|
14
|
+
upload_label = ForemanInventoryUpload::Async::UploadReportJob.output_label(test_org.id)
|
16
15
|
upload_output = ForemanInventoryUpload::Async::ProgressOutput.register(upload_label)
|
17
16
|
upload_output.status = 'upload_status_test'
|
18
17
|
|
19
18
|
get :index, session: set_session_user
|
20
19
|
|
21
20
|
assert_response :success
|
22
|
-
actual = JSON.parse(response.body)['
|
21
|
+
actual = JSON.parse(response.body)['accounts'][test_org.id.to_s]
|
23
22
|
assert_equal 'generate_status_test', actual['generate_report_status']
|
24
23
|
assert_equal 'upload_status_test', actual['upload_report_status']
|
25
24
|
end
|
@@ -5,14 +5,14 @@ class ReportsControllerTest < ActionController::TestCase
|
|
5
5
|
|
6
6
|
test 'Returns latest report generation status' do
|
7
7
|
progress_output = mock('progress_output')
|
8
|
-
|
8
|
+
test_org = FactoryBot.create(:organization)
|
9
9
|
ForemanInventoryUpload::Async::ProgressOutput
|
10
10
|
.expects(:get)
|
11
|
-
.with(ForemanInventoryUpload::Async::GenerateReportJob.output_label(
|
11
|
+
.with(ForemanInventoryUpload::Async::GenerateReportJob.output_label(test_org.id))
|
12
12
|
.returns(progress_output)
|
13
13
|
progress_output.expects(:full_output).returns('test output')
|
14
14
|
|
15
|
-
get :last, params: {
|
15
|
+
get :last, params: { organization_id: test_org.id }, session: set_session_user
|
16
16
|
|
17
17
|
assert_response :success
|
18
18
|
actual = JSON.parse(response.body)
|
@@ -5,14 +5,14 @@ class UploadsControllerTest < ActionController::TestCase
|
|
5
5
|
|
6
6
|
test 'Returns latest upload status' do
|
7
7
|
progress_output = mock('progress_output')
|
8
|
-
|
8
|
+
test_org = FactoryBot.create(:organization)
|
9
9
|
ForemanInventoryUpload::Async::ProgressOutput
|
10
10
|
.expects(:get)
|
11
|
-
.with(ForemanInventoryUpload::Async::UploadReportJob.output_label(
|
11
|
+
.with(ForemanInventoryUpload::Async::UploadReportJob.output_label(test_org.id))
|
12
12
|
.returns(progress_output)
|
13
13
|
progress_output.expects(:full_output).returns('test output')
|
14
14
|
|
15
|
-
get :last, params: {
|
15
|
+
get :last, params: { organization_id: test_org.id }, session: set_session_user
|
16
16
|
|
17
17
|
assert_response :success
|
18
18
|
actual = JSON.parse(response.body)
|
@@ -46,13 +46,13 @@ class ArchivedReportGeneratorTest < ActiveSupport::TestCase
|
|
46
46
|
|
47
47
|
test 'generates a report for a single host' do
|
48
48
|
batches = Host.where(id: @host.id).in_batches
|
49
|
-
|
49
|
+
test_org = FactoryBot.create(:organization)
|
50
50
|
|
51
|
-
ForemanInventoryUpload::Generators::Queries.expects(:
|
51
|
+
ForemanInventoryUpload::Generators::Queries.expects(:for_org).with(test_org.id).returns(batches)
|
52
52
|
Dir.mktmpdir do |tmpdir|
|
53
53
|
target = File.join(tmpdir, 'test.tar.gz')
|
54
54
|
generator = ForemanInventoryUpload::Generators::ArchivedReport.new(target, Logger.new(STDOUT))
|
55
|
-
generator.render(
|
55
|
+
generator.render(organization: test_org.id)
|
56
56
|
|
57
57
|
files = Dir["#{tmpdir}/*"]
|
58
58
|
assert_equal "#{tmpdir}/test.tar.gz", files.first
|
@@ -109,4 +109,26 @@ class ReportGeneratorTest < ActiveSupport::TestCase
|
|
109
109
|
assert_equal hypervisor_host.name, fact_values['virtual_host_name']
|
110
110
|
assert_equal hypervisor_host.subscription_facet.uuid, fact_values['virtual_host_uuid']
|
111
111
|
end
|
112
|
+
|
113
|
+
test 'generates a report with system purpose' do
|
114
|
+
@host.subscription_facet.purpose_usage = 'test_usage'
|
115
|
+
@host.subscription_facet.purpose_role = 'test_role'
|
116
|
+
@host.subscription_facet.save!
|
117
|
+
|
118
|
+
batch = Host.where(id: @host.id).in_batches.first
|
119
|
+
generator = ForemanInventoryUpload::Generators::Slice.new(batch, [], 'slice_123')
|
120
|
+
|
121
|
+
json_str = generator.render
|
122
|
+
actual = JSON.parse(json_str.join("\n"))
|
123
|
+
|
124
|
+
assert_equal 'slice_123', actual['report_slice_id']
|
125
|
+
assert_not_nil(actual_host = actual['hosts'].first)
|
126
|
+
assert_equal @host.name, actual_host['display_name']
|
127
|
+
assert_equal @host.fqdn, actual_host['fqdn']
|
128
|
+
assert_not_nil(host_facts = actual_host['facts']&.first)
|
129
|
+
assert_equal 'satellite', host_facts['namespace']
|
130
|
+
assert_not_nil(fact_values = host_facts['facts'])
|
131
|
+
assert_equal 'test_usage', fact_values['system_purpose_usage']
|
132
|
+
assert_equal 'test_role', fact_values['system_purpose_role']
|
133
|
+
end
|
112
134
|
end
|
@@ -2,20 +2,23 @@ import { noop } from 'patternfly-react';
|
|
2
2
|
|
3
3
|
export const API_SUCCESS_RESPONSE = {
|
4
4
|
Account1: {
|
5
|
+
label: 'test_org1',
|
5
6
|
upload_report_status: 'running',
|
6
7
|
generate_report_status: 'running',
|
7
8
|
},
|
8
9
|
Account2: {
|
10
|
+
label: 'test_org2',
|
9
11
|
upload_report_status: 'unknown',
|
10
12
|
generate_report_status: 'failure',
|
11
13
|
},
|
12
14
|
Account3: {
|
15
|
+
label: 'test_org3',
|
13
16
|
upload_report_status: 'success',
|
14
17
|
generate_report_status: 'running',
|
15
18
|
},
|
16
19
|
};
|
17
20
|
|
18
|
-
export const
|
21
|
+
export const accounts = API_SUCCESS_RESPONSE;
|
19
22
|
|
20
23
|
export const pollingProcessID = 0;
|
21
24
|
|
@@ -26,7 +29,7 @@ export const accountID = 'user@redhat.com';
|
|
26
29
|
export const processStatusName = 'upload_report_status';
|
27
30
|
|
28
31
|
export const props = {
|
29
|
-
|
32
|
+
accounts,
|
30
33
|
fetchAccountsStatus: noop,
|
31
34
|
startAccountStatusPolling: noop,
|
32
35
|
stopAccountStatusPolling: noop,
|
@@ -20,23 +20,23 @@ class AccountList extends Component {
|
|
20
20
|
}
|
21
21
|
|
22
22
|
render() {
|
23
|
-
const {
|
24
|
-
const
|
23
|
+
const { accounts, error } = this.props;
|
24
|
+
const accountIds = Object.keys(accounts);
|
25
25
|
|
26
26
|
if (error) {
|
27
27
|
return <ErrorState error={error} />;
|
28
28
|
}
|
29
29
|
|
30
|
-
if (
|
30
|
+
if (accountIds.length === 0) {
|
31
31
|
return <EmptyState />;
|
32
32
|
}
|
33
|
-
const items =
|
34
|
-
const
|
33
|
+
const items = accountIds.map((accountID, index) => {
|
34
|
+
const account = accounts[accountID];
|
35
35
|
return (
|
36
36
|
<ListItem
|
37
37
|
key={index}
|
38
|
-
|
39
|
-
|
38
|
+
accountID={accountID}
|
39
|
+
account={account}
|
40
40
|
initExpanded={index === 0}
|
41
41
|
/>
|
42
42
|
);
|
@@ -50,10 +50,11 @@ AccountList.propTypes = {
|
|
50
50
|
startAccountStatusPolling: PropTypes.func,
|
51
51
|
stopAccountStatusPolling: PropTypes.func,
|
52
52
|
pollingProcessID: PropTypes.number,
|
53
|
-
|
53
|
+
account: PropTypes.shape({
|
54
54
|
generate_report_status: PropTypes.string,
|
55
55
|
upload_report_status: PropTypes.string,
|
56
56
|
}),
|
57
|
+
accounts: PropTypes.object,
|
57
58
|
error: PropTypes.string,
|
58
59
|
};
|
59
60
|
|
@@ -62,10 +63,11 @@ AccountList.defaultProps = {
|
|
62
63
|
startAccountStatusPolling: noop,
|
63
64
|
stopAccountStatusPolling: noop,
|
64
65
|
pollingProcessID: 0,
|
65
|
-
|
66
|
+
account: {
|
66
67
|
generate_report_status: 'unknown',
|
67
68
|
upload_report_status: 'unknown',
|
68
69
|
},
|
70
|
+
accounts: {},
|
69
71
|
error: '',
|
70
72
|
};
|
71
73
|
|
@@ -10,12 +10,12 @@ import {
|
|
10
10
|
export const fetchAccountsStatus = () => async dispatch => {
|
11
11
|
try {
|
12
12
|
const {
|
13
|
-
data: {
|
14
|
-
} = await API.get('
|
13
|
+
data: { accounts },
|
14
|
+
} = await API.get('accounts');
|
15
15
|
dispatch({
|
16
16
|
type: INVENTORY_ACCOUNT_STATUS_POLLING,
|
17
17
|
payload: {
|
18
|
-
|
18
|
+
accounts,
|
19
19
|
},
|
20
20
|
});
|
21
21
|
} catch (error) {
|
@@ -7,7 +7,7 @@ import {
|
|
7
7
|
} from './AccountListConstants';
|
8
8
|
|
9
9
|
const initialState = Immutable({
|
10
|
-
|
10
|
+
accounts: {},
|
11
11
|
pollingProcessID: 0,
|
12
12
|
error: null,
|
13
13
|
});
|
@@ -17,7 +17,7 @@ export default (state = initialState, action) => {
|
|
17
17
|
payload: {
|
18
18
|
pollingProcessID,
|
19
19
|
error,
|
20
|
-
|
20
|
+
accounts,
|
21
21
|
accountID,
|
22
22
|
processStatusName,
|
23
23
|
} = {},
|
@@ -27,13 +27,13 @@ export default (state = initialState, action) => {
|
|
27
27
|
case INVENTORY_ACCOUNT_STATUS_POLLING:
|
28
28
|
return state.merge({
|
29
29
|
...state,
|
30
|
-
|
30
|
+
accounts,
|
31
31
|
error: null,
|
32
32
|
});
|
33
33
|
case INVENTORY_ACCOUNT_STATUS_POLLING_ERROR:
|
34
34
|
return state.merge({
|
35
35
|
...state,
|
36
|
-
|
36
|
+
accounts: {},
|
37
37
|
error,
|
38
38
|
});
|
39
39
|
case INVENTORY_ACCOUNT_STATUS_POLLING_START:
|
@@ -42,10 +42,10 @@ export default (state = initialState, action) => {
|
|
42
42
|
pollingProcessID,
|
43
43
|
});
|
44
44
|
case INVENTORY_PROCESS_RESTART:
|
45
|
-
return state.setIn(['
|
46
|
-
...state.
|
45
|
+
return state.setIn(['accounts'], {
|
46
|
+
...state.accounts,
|
47
47
|
[accountID]: {
|
48
|
-
...state.
|
48
|
+
...state.accounts[accountID],
|
49
49
|
[processStatusName]: 'Restarting...',
|
50
50
|
},
|
51
51
|
});
|
@@ -2,7 +2,7 @@ import { selectForemanInventoryUpload } from '../../ForemanInventoryUploadSelect
|
|
2
2
|
|
3
3
|
export const selectAccountsList = state =>
|
4
4
|
selectForemanInventoryUpload(state).accountsList;
|
5
|
-
export const
|
5
|
+
export const selectAccounts = state => selectAccountsList(state).accounts;
|
6
6
|
export const selectPollingProcessID = state =>
|
7
7
|
selectAccountsList(state).pollingProcessID;
|
8
8
|
export const selectError = state => selectAccountsList(state).error;
|
data/webpack/ForemanInventoryUpload/Components/AccountList/Components/ListItem/ListItem.fixtures.js
CHANGED
@@ -1 +1 @@
|
|
1
|
-
export const props = {
|
1
|
+
export const props = { accountID: '1' };
|
@@ -4,34 +4,36 @@ import PropTypes from 'prop-types';
|
|
4
4
|
import ListItemStatus from '../ListItemStatus';
|
5
5
|
import Dashboard from '../../../Dashboard';
|
6
6
|
|
7
|
-
const ListItem = ({
|
7
|
+
const ListItem = ({ accountID, account, initExpanded }) => (
|
8
8
|
<ListView.Item
|
9
9
|
leftContent={<ListView.Icon name="user" />}
|
10
|
-
heading={
|
10
|
+
heading={account.label}
|
11
11
|
additionalInfo={[
|
12
|
-
<ListItemStatus key={`${
|
12
|
+
<ListItemStatus key={`${accountID}_status`} account={account} />,
|
13
13
|
]}
|
14
14
|
stacked
|
15
15
|
hideCloseIcon
|
16
16
|
initExpanded={initExpanded}
|
17
17
|
>
|
18
|
-
<Dashboard accountID={
|
18
|
+
<Dashboard accountID={accountID} account={account} />
|
19
19
|
</ListView.Item>
|
20
20
|
);
|
21
21
|
|
22
22
|
ListItem.propTypes = {
|
23
|
-
|
24
|
-
|
23
|
+
accountID: PropTypes.string.isRequired,
|
24
|
+
account: PropTypes.shape({
|
25
25
|
generate_report_status: PropTypes.string,
|
26
26
|
upload_report_status: PropTypes.string,
|
27
|
+
label: PropTypes.string,
|
27
28
|
}),
|
28
29
|
initExpanded: PropTypes.bool,
|
29
30
|
};
|
30
31
|
|
31
32
|
ListItem.defaultProps = {
|
32
|
-
|
33
|
+
account: {
|
33
34
|
generate_report_status: 'unknown',
|
34
35
|
upload_report_status: 'unknown',
|
36
|
+
label: 'default_org_name',
|
35
37
|
},
|
36
38
|
initExpanded: false,
|
37
39
|
};
|
@@ -6,9 +6,10 @@ exports[`ListItem rendering render with Props 1`] = `
|
|
6
6
|
additionalInfo={
|
7
7
|
Array [
|
8
8
|
<ListItemStatus
|
9
|
-
|
9
|
+
account={
|
10
10
|
Object {
|
11
11
|
"generate_report_status": "unknown",
|
12
|
+
"label": "default_org_name",
|
12
13
|
"upload_report_status": "unknown",
|
13
14
|
}
|
14
15
|
}
|
@@ -19,7 +20,7 @@ exports[`ListItem rendering render with Props 1`] = `
|
|
19
20
|
compoundExpand={false}
|
20
21
|
compoundExpanded={false}
|
21
22
|
description={null}
|
22
|
-
heading="
|
23
|
+
heading="default_org_name"
|
23
24
|
hideCloseIcon={true}
|
24
25
|
initExpanded={false}
|
25
26
|
leftContent={
|
@@ -36,13 +37,14 @@ exports[`ListItem rendering render with Props 1`] = `
|
|
36
37
|
stacked={true}
|
37
38
|
>
|
38
39
|
<Connect(Dashboard)
|
39
|
-
|
40
|
-
statuses={
|
40
|
+
account={
|
41
41
|
Object {
|
42
42
|
"generate_report_status": "unknown",
|
43
|
+
"label": "default_org_name",
|
43
44
|
"upload_report_status": "unknown",
|
44
45
|
}
|
45
46
|
}
|
47
|
+
accountID="1"
|
46
48
|
/>
|
47
49
|
</ListViewItem>
|
48
50
|
`;
|
@@ -5,12 +5,12 @@ import { translate as __ } from 'foremanReact/common/I18n';
|
|
5
5
|
import './listItemStatus.scss';
|
6
6
|
import { getStatusIconByRegex } from './ListItemStatusHelper';
|
7
7
|
|
8
|
-
const ListItemStatus = ({
|
8
|
+
const ListItemStatus = ({ account }) => {
|
9
9
|
const generatingStatusIcon = getStatusIconByRegex(
|
10
|
-
|
10
|
+
account.generate_report_status
|
11
11
|
);
|
12
12
|
const uploadingStatusIcon = getStatusIconByRegex(
|
13
|
-
|
13
|
+
account.upload_report_status
|
14
14
|
);
|
15
15
|
return (
|
16
16
|
<Grid className="status">
|
@@ -27,14 +27,14 @@ const ListItemStatus = ({ statuses }) => {
|
|
27
27
|
};
|
28
28
|
|
29
29
|
ListItemStatus.propTypes = {
|
30
|
-
|
30
|
+
account: PropTypes.shape({
|
31
31
|
generate_report_status: PropTypes.string,
|
32
32
|
upload_report_status: PropTypes.string,
|
33
33
|
}),
|
34
34
|
};
|
35
35
|
|
36
36
|
ListItemStatus.defaultProps = {
|
37
|
-
|
37
|
+
account: {
|
38
38
|
generate_report_status: 'unknown',
|
39
39
|
uploupload_report_statusading: 'unknown',
|
40
40
|
},
|