foreman_inventory_upload 1.0.0.beta7 → 1.0.0

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.
Files changed (43) hide show
  1. checksums.yaml +4 -4
  2. data/app/controllers/foreman_inventory_upload/accounts_controller.rb +39 -0
  3. data/app/controllers/foreman_inventory_upload/reports_controller.rb +3 -4
  4. data/app/controllers/foreman_inventory_upload/uploads_controller.rb +3 -3
  5. data/app/views/scripts/uploader.sh.erb +21 -9
  6. data/config/routes.rb +5 -5
  7. data/lib/foreman_inventory_upload.rb +14 -10
  8. data/lib/foreman_inventory_upload/async/generate_all_reports_job.rb +4 -7
  9. data/lib/foreman_inventory_upload/async/generate_report_job.rb +13 -9
  10. data/lib/foreman_inventory_upload/async/queue_for_upload_job.rb +7 -7
  11. data/lib/foreman_inventory_upload/async/upload_report_job.rb +22 -17
  12. data/lib/foreman_inventory_upload/generators/archived_report.rb +2 -2
  13. data/lib/foreman_inventory_upload/generators/queries.rb +18 -9
  14. data/lib/foreman_inventory_upload/generators/slice.rb +16 -9
  15. data/lib/foreman_inventory_upload/version.rb +1 -1
  16. data/lib/tasks/generator.rake +19 -5
  17. data/test/controllers/{statuses_controller_test.rb → accounts_controller_test.rb} +6 -7
  18. data/test/controllers/reports_controller_test.rb +3 -3
  19. data/test/controllers/uploads_controller_test.rb +3 -3
  20. data/test/unit/archived_report_generator_test.rb +3 -3
  21. data/test/unit/slice_generator_test.rb +22 -0
  22. data/webpack/ForemanInventoryUpload/Components/AccountList/AccountList.fixtures.js +5 -2
  23. data/webpack/ForemanInventoryUpload/Components/AccountList/AccountList.js +11 -9
  24. data/webpack/ForemanInventoryUpload/Components/AccountList/AccountListActions.js +3 -3
  25. data/webpack/ForemanInventoryUpload/Components/AccountList/AccountListReducer.js +7 -7
  26. data/webpack/ForemanInventoryUpload/Components/AccountList/AccountListSelectors.js +1 -1
  27. data/webpack/ForemanInventoryUpload/Components/AccountList/Components/ListItem/ListItem.fixtures.js +1 -1
  28. data/webpack/ForemanInventoryUpload/Components/AccountList/Components/ListItem/ListItem.js +9 -7
  29. data/webpack/ForemanInventoryUpload/Components/AccountList/Components/ListItem/__tests__/__snapshots__/ListItem.test.js.snap +6 -4
  30. data/webpack/ForemanInventoryUpload/Components/AccountList/Components/ListItemStatus/ListItemStatus.fixtures.js +2 -1
  31. data/webpack/ForemanInventoryUpload/Components/AccountList/Components/ListItemStatus/ListItemStatus.js +5 -5
  32. data/webpack/ForemanInventoryUpload/Components/AccountList/__tests__/AccountListReducer.test.js +2 -2
  33. data/webpack/ForemanInventoryUpload/Components/AccountList/__tests__/AccountListSelectors.test.js +4 -4
  34. data/webpack/ForemanInventoryUpload/Components/AccountList/__tests__/__snapshots__/AccountList.test.js.snap +15 -12
  35. data/webpack/ForemanInventoryUpload/Components/AccountList/__tests__/__snapshots__/AccountListReducer.test.js.snap +13 -10
  36. data/webpack/ForemanInventoryUpload/Components/AccountList/__tests__/__snapshots__/AccountListSelectors.test.js.snap +9 -3
  37. data/webpack/ForemanInventoryUpload/Components/AccountList/index.js +3 -6
  38. data/webpack/ForemanInventoryUpload/Components/Dashboard/Dashboard.js +5 -5
  39. data/webpack/ForemanInventoryUpload/Components/Dashboard/index.js +1 -4
  40. data/webpack/ForemanInventoryUpload/Components/NavContainer/__tests__/__snapshots__/NavContainer.test.js.snap +4 -4
  41. data/webpack/ForemanInventoryUpload/Components/StatusChart/StatusChart.js +4 -1
  42. metadata +7 -7
  43. data/app/controllers/foreman_inventory_upload/statuses_controller.rb +0 -41
@@ -1,3 +1,3 @@
1
1
  module ForemanInventoryUpload
2
- VERSION = '1.0.0.beta7'.freeze
2
+ VERSION = '1.0.0'.freeze
3
3
  end
@@ -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
- target = ENV['target'] || ForemanInventoryUpload.facts_archive_name
8
- portal_user = ENV['portal_user'] || 'anonymous'
7
+ portal_user = ENV['portal_user']
8
+ organizations = [ENV['organization_id']]
9
+ base_folder = ENV['target'] || Dir.pwd
9
10
 
10
- archived_report_generator = ForemanInventoryUpload::Generators::ArchivedReport.new(target, Logger.new(STDOUT))
11
- archived_report_generator.render(portal_user)
12
- puts "Successfully generated #{target} for #{portal_user}"
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 StatusesControllerTest < ActionController::TestCase
4
- tests ForemanInventoryUpload::StatusesController
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
- configuration = RedhatAccess::TelemetryConfiguration.new(enable_telemetry: true, portal_user: 'test')
10
- configuration.save!
9
+ test_org = FactoryBot.create(:organization)
11
10
 
12
- generate_label = ForemanInventoryUpload::Async::GenerateReportJob.output_label('test')
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('test')
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)['statuses']['test']
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
- test_portal_user = 'test_portal_user'
8
+ test_org = FactoryBot.create(:organization)
9
9
  ForemanInventoryUpload::Async::ProgressOutput
10
10
  .expects(:get)
11
- .with(ForemanInventoryUpload::Async::GenerateReportJob.output_label(test_portal_user))
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: { portal_user: test_portal_user }, session: set_session_user
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
- test_portal_user = 'test_portal_user'
8
+ test_org = FactoryBot.create(:organization)
9
9
  ForemanInventoryUpload::Async::ProgressOutput
10
10
  .expects(:get)
11
- .with(ForemanInventoryUpload::Async::UploadReportJob.output_label(test_portal_user))
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: { portal_user: test_portal_user }, session: set_session_user
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
- portal_user = 'test_portal_user'
49
+ test_org = FactoryBot.create(:organization)
50
50
 
51
- ForemanInventoryUpload::Generators::Queries.expects(:for_report).with(portal_user).returns(batches)
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(portal_user)
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 statuses = API_SUCCESS_RESPONSE;
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
- statuses,
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 { statuses, error } = this.props;
24
- const accountNames = Object.keys(statuses);
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 (accountNames.length === 0) {
30
+ if (accountIds.length === 0) {
31
31
  return <EmptyState />;
32
32
  }
33
- const items = accountNames.map((name, index) => {
34
- const status = statuses[name];
33
+ const items = accountIds.map((accountID, index) => {
34
+ const account = accounts[accountID];
35
35
  return (
36
36
  <ListItem
37
37
  key={index}
38
- name={name}
39
- statuses={status}
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
- statuses: PropTypes.shape({
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
- statuses: {
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: { statuses },
14
- } = await API.get('statuses');
13
+ data: { accounts },
14
+ } = await API.get('accounts');
15
15
  dispatch({
16
16
  type: INVENTORY_ACCOUNT_STATUS_POLLING,
17
17
  payload: {
18
- statuses,
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
- statuses: {},
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
- statuses,
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
- statuses,
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
- statuses: {},
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(['statuses'], {
46
- ...state.statuses,
45
+ return state.setIn(['accounts'], {
46
+ ...state.accounts,
47
47
  [accountID]: {
48
- ...state.statuses[accountID],
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 selectStatuses = state => selectAccountsList(state).statuses;
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;
@@ -1 +1 @@
1
- export const props = { name: 'some-name' };
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 = ({ name, statuses, initExpanded }) => (
7
+ const ListItem = ({ accountID, account, initExpanded }) => (
8
8
  <ListView.Item
9
9
  leftContent={<ListView.Icon name="user" />}
10
- heading={name}
10
+ heading={account.label}
11
11
  additionalInfo={[
12
- <ListItemStatus key={`${name}_status`} statuses={statuses} />,
12
+ <ListItemStatus key={`${accountID}_status`} account={account} />,
13
13
  ]}
14
14
  stacked
15
15
  hideCloseIcon
16
16
  initExpanded={initExpanded}
17
17
  >
18
- <Dashboard accountID={name} statuses={statuses} />
18
+ <Dashboard accountID={accountID} account={account} />
19
19
  </ListView.Item>
20
20
  );
21
21
 
22
22
  ListItem.propTypes = {
23
- name: PropTypes.string.isRequired,
24
- statuses: PropTypes.shape({
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
- statuses: {
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
- statuses={
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="some-name"
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
- accountID="some-name"
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
  `;
@@ -1,6 +1,7 @@
1
1
  export const props = {
2
- statuses: {
2
+ account: {
3
3
  generate_report_status: 'Exit Code: pid 22191 exit 0',
4
4
  upload_report_status: 'Exit Code: Running in pid 22376',
5
+ label: 'Default Org',
5
6
  },
6
7
  };
@@ -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 = ({ statuses }) => {
8
+ const ListItemStatus = ({ account }) => {
9
9
  const generatingStatusIcon = getStatusIconByRegex(
10
- statuses.generate_report_status
10
+ account.generate_report_status
11
11
  );
12
12
  const uploadingStatusIcon = getStatusIconByRegex(
13
- statuses.upload_report_status
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
- statuses: PropTypes.shape({
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
- statuses: {
37
+ account: {
38
38
  generate_report_status: 'unknown',
39
39
  uploupload_report_statusading: 'unknown',
40
40
  },