foreman_leapp 0.0.5 → 0.1.3

Sign up to get free protection for your applications and to get access to all the features.
Files changed (89) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +11 -20
  3. data/app/controllers/api/v2/concerns/api_authorizer.rb +27 -0
  4. data/app/controllers/api/v2/preupgrade_reports_controller.rb +21 -2
  5. data/app/controllers/preupgrade_reports_controller.rb +11 -1
  6. data/app/lib/actions/preupgrade_job.rb +2 -1
  7. data/app/lib/helpers/job_helper.rb +3 -4
  8. data/app/models/preupgrade_report.rb +1 -0
  9. data/app/models/preupgrade_report_entry.rb +1 -0
  10. data/app/views/api/v2/preupgrade_report_entries/base.json.rabl +1 -1
  11. data/app/views/api/v2/preupgrade_reports/job_invocation.json.rabl +3 -0
  12. data/app/views/foreman_leapp/job_templates/leapp_check.erb +15 -0
  13. data/app/views/foreman_leapp/job_templates/{preupgrade.erb → leapp_preupgrade.erb} +5 -2
  14. data/app/views/foreman_leapp/job_templates/leapp_remediation.erb +29 -0
  15. data/app/views/foreman_leapp/job_templates/leapp_upgrade.erb +26 -0
  16. data/app/views/job_invocations/_leapp_preupgrade_report.html.erb +2 -1
  17. data/config/routes.rb +2 -1
  18. data/db/migrate/20200429080939_report_entries_flags.rb +5 -0
  19. data/db/seeds.d/10_leapp_preupgrade.rb +1 -1
  20. data/lib/foreman_leapp/engine.rb +7 -6
  21. data/lib/foreman_leapp/version.rb +1 -1
  22. data/package.json +3 -2
  23. data/test/functional/api/v2/preupgrade_reports_controller_test.rb +89 -6
  24. data/test/functional/preupgrade_reports_controller_test.rb +27 -4
  25. data/test/unit/actions/preupgrade_job_test.rb +1 -1
  26. data/test/unit/helpers/job_helper_test.rb +3 -10
  27. data/webpack/__mocks__/foremanReact/Root/Context/ForemanContext.js +4 -0
  28. data/webpack/__mocks__/foremanReact/common/I18n.js +1 -1
  29. data/webpack/__mocks__/foremanReact/components/Pagination/PaginationWrapper.js +2 -0
  30. data/webpack/__mocks__/foremanReact/components/common/EmptyState.js +1 -0
  31. data/webpack/components/PreupgradeReports/PreupgradeReports.js +119 -8
  32. data/webpack/components/PreupgradeReports/PreupgradeReportsActions.js +1 -1
  33. data/webpack/components/PreupgradeReports/PreupgradeReportsHelpers.js +152 -0
  34. data/webpack/components/PreupgradeReports/PreupgradeReportsReducer.js +2 -0
  35. data/webpack/components/PreupgradeReports/PreupgradeReportsSelectors.js +11 -0
  36. data/webpack/components/PreupgradeReports/__tests__/PreupgradeReports.fixtures.js +72 -2
  37. data/webpack/components/PreupgradeReports/__tests__/PreupgradeReports.test.js +26 -1
  38. data/webpack/components/PreupgradeReports/__tests__/PreupgradeReportsHelpers.test.js +78 -0
  39. data/webpack/components/PreupgradeReports/__tests__/__snapshots__/PreupgradeReports.test.js.snap +60 -5
  40. data/webpack/components/PreupgradeReports/__tests__/__snapshots__/PreupgradeReportsHelpers.test.js.snap +489 -0
  41. data/webpack/components/PreupgradeReports/__tests__/__snapshots__/PreupgradeReportsReducer.test.js.snap +40 -1
  42. data/webpack/components/PreupgradeReports/__tests__/__snapshots__/PreupgradeReportsSelectors.test.js.snap +36 -1
  43. data/webpack/components/PreupgradeReports/components/EntriesFilter.js +121 -0
  44. data/webpack/components/PreupgradeReports/components/EntriesFilter.scss +3 -0
  45. data/webpack/components/PreupgradeReports/components/EntriesFilter.test.js +30 -0
  46. data/webpack/components/PreupgradeReports/components/FixSelectedButton.js +35 -0
  47. data/webpack/components/PreupgradeReports/components/FixSelectedButton.test.js +15 -0
  48. data/webpack/components/PreupgradeReports/components/NoReports.js +35 -0
  49. data/webpack/components/PreupgradeReports/components/NoReports.test.js +15 -0
  50. data/webpack/components/PreupgradeReports/components/UpgradeAllButton.js +29 -0
  51. data/webpack/components/PreupgradeReports/components/UpgradeAllButton.test.js +17 -0
  52. data/webpack/components/PreupgradeReports/components/__snapshots__/EntriesFilter.test.js.snap +330 -0
  53. data/webpack/components/PreupgradeReports/components/__snapshots__/FixSelectedButton.test.js.snap +40 -0
  54. data/webpack/components/PreupgradeReports/components/__snapshots__/NoReports.test.js.snap +19 -0
  55. data/webpack/components/PreupgradeReports/components/__snapshots__/UpgradeAllButton.test.js.snap +29 -0
  56. data/webpack/components/PreupgradeReports/index.js +28 -5
  57. data/webpack/components/PreupgradeReportsList/PreupgradeReportList.scss +37 -0
  58. data/webpack/components/PreupgradeReportsList/__tests__/PreupgradeReportsList.test.js +28 -2
  59. data/webpack/components/PreupgradeReportsList/__tests__/__snapshots__/PreupgradeReportsList.test.js.snap +119 -0
  60. data/webpack/components/PreupgradeReportsList/components/InfoItem.js +1 -1
  61. data/webpack/components/PreupgradeReportsList/components/InhibitorInfoItem.js +33 -0
  62. data/webpack/components/PreupgradeReportsList/components/PreupgradeReportEntry.js +50 -6
  63. data/webpack/components/PreupgradeReportsList/components/PreupgradeReportsListHeader.js +56 -0
  64. data/webpack/components/PreupgradeReportsList/components/SortableHeaderItem.js +50 -0
  65. data/webpack/components/PreupgradeReportsList/components/__tests__/InhibitorInfoItem.test.js +27 -0
  66. data/webpack/components/PreupgradeReportsList/components/__tests__/PreupgradeReportEntry.fixtures.js +38 -0
  67. data/webpack/components/PreupgradeReportsList/components/__tests__/PreupgradeReportEntry.test.js +2 -0
  68. data/webpack/components/PreupgradeReportsList/components/__tests__/PreupgradeReportsListHeader.test.js +14 -0
  69. data/webpack/components/PreupgradeReportsList/components/__tests__/SortableHeaderItem.test.js +29 -0
  70. data/webpack/components/PreupgradeReportsList/components/__tests__/__snapshots__/InhibitorInfoItem.test.js.snap +32 -0
  71. data/webpack/components/PreupgradeReportsList/components/__tests__/__snapshots__/PreupgradeReportEntry.test.js.snap +95 -14
  72. data/webpack/components/PreupgradeReportsList/components/__tests__/__snapshots__/PreupgradeReportsListHeader.test.js.snap +113 -0
  73. data/webpack/components/PreupgradeReportsList/components/__tests__/__snapshots__/SortableHeaderItem.test.js.snap +36 -0
  74. data/webpack/components/PreupgradeReportsList/components/__tests__/__snapshots__/helpers.test.js.snap +191 -29
  75. data/webpack/components/PreupgradeReportsList/components/__tests__/helpers.test.js +19 -8
  76. data/webpack/components/PreupgradeReportsList/components/foreman_leapp.scss +15 -0
  77. data/webpack/components/PreupgradeReportsList/components/helpers.js +177 -21
  78. data/webpack/components/PreupgradeReportsList/components/images/i_severity-critical.svg +61 -0
  79. data/webpack/components/PreupgradeReportsList/components/images/i_severity-high.svg +61 -0
  80. data/webpack/components/PreupgradeReportsList/components/images/i_severity-low.svg +62 -0
  81. data/webpack/components/PreupgradeReportsList/components/images/i_severity-med.svg +62 -0
  82. data/webpack/components/PreupgradeReportsList/index.js +48 -10
  83. data/webpack/csrf.js +4 -0
  84. metadata +61 -10
  85. data/app/views/foreman_leapp/job_templates/remediation.erb +0 -17
  86. data/app/views/foreman_leapp/job_templates/upgrade.erb +0 -16
  87. data/webpack/components/PreupgradeReportsList/components/StringInfoItem.js +0 -49
  88. data/webpack/components/PreupgradeReportsList/components/__tests__/StringInfoItem.test.js +0 -13
  89. data/webpack/components/PreupgradeReportsList/components/__tests__/__snapshots__/StringInfoItem.test.js.snap +0 -12
@@ -5,6 +5,7 @@ Object {
5
5
  "error": Object {},
6
6
  "loadingPreupgradeReports": false,
7
7
  "preupgradeReports": Array [],
8
+ "reportsExpected": false,
8
9
  }
9
10
  `;
10
11
 
@@ -16,6 +17,7 @@ Object {
16
17
  },
17
18
  "loadingPreupgradeReports": false,
18
19
  "preupgradeReports": Array [],
20
+ "reportsExpected": false,
19
21
  }
20
22
  `;
21
23
 
@@ -24,6 +26,7 @@ Object {
24
26
  "error": Object {},
25
27
  "loadingPreupgradeReports": true,
26
28
  "preupgradeReports": Array [],
29
+ "reportsExpected": false,
27
30
  }
28
31
  `;
29
32
 
@@ -35,10 +38,16 @@ Object {
35
38
  Object {
36
39
  "entries": Array [
37
40
  Object {
38
- "severity": "Too severe to talk about",
41
+ "flags": Array [],
42
+ "hostname": "host.example.com",
43
+ "id": 42,
44
+ "severity": "info",
39
45
  "title": "Fix me!",
40
46
  },
41
47
  Object {
48
+ "flags": Array [],
49
+ "hostname": "host.example.com",
50
+ "id": 43,
42
51
  "severity": "medium",
43
52
  "title": "I am broken too",
44
53
  },
@@ -48,16 +57,46 @@ Object {
48
57
  Object {
49
58
  "entries": Array [
50
59
  Object {
60
+ "flags": Array [
61
+ "inhibitor",
62
+ ],
63
+ "hostname": "foo.example.com",
64
+ "id": 44,
51
65
  "severity": "high",
52
66
  "title": "Octocat is not happy",
53
67
  },
54
68
  Object {
69
+ "flags": Array [],
70
+ "hostname": "foo.example.com",
71
+ "id": 45,
55
72
  "severity": "low",
56
73
  "title": "Not enough credits",
57
74
  },
75
+ Object {
76
+ "flags": Array [],
77
+ "hostname": "foo.example.com",
78
+ "id": 46,
79
+ "severity": "medium",
80
+ "title": "SELinux is turned off",
81
+ },
82
+ Object {
83
+ "flags": Array [],
84
+ "hostname": "foo.example.com",
85
+ "id": 47,
86
+ "severity": "medium",
87
+ "title": "Root password is too short",
88
+ },
89
+ Object {
90
+ "flags": Array [],
91
+ "hostname": "foo.example.com",
92
+ "id": 49,
93
+ "severity": "high",
94
+ "title": "No chocolate chip cookies in cookie jar",
95
+ },
58
96
  ],
59
97
  "hostId": 6,
60
98
  },
61
99
  ],
100
+ "reportsExpected": true,
62
101
  }
63
102
  `;
@@ -14,10 +14,16 @@ Array [
14
14
  Object {
15
15
  "entries": Array [
16
16
  Object {
17
- "severity": "Too severe to talk about",
17
+ "flags": Array [],
18
+ "hostname": "host.example.com",
19
+ "id": 42,
20
+ "severity": "info",
18
21
  "title": "Fix me!",
19
22
  },
20
23
  Object {
24
+ "flags": Array [],
25
+ "hostname": "host.example.com",
26
+ "id": 43,
21
27
  "severity": "medium",
22
28
  "title": "I am broken too",
23
29
  },
@@ -27,13 +33,42 @@ Array [
27
33
  Object {
28
34
  "entries": Array [
29
35
  Object {
36
+ "flags": Array [
37
+ "inhibitor",
38
+ ],
39
+ "hostname": "foo.example.com",
40
+ "id": 44,
30
41
  "severity": "high",
31
42
  "title": "Octocat is not happy",
32
43
  },
33
44
  Object {
45
+ "flags": Array [],
46
+ "hostname": "foo.example.com",
47
+ "id": 45,
34
48
  "severity": "low",
35
49
  "title": "Not enough credits",
36
50
  },
51
+ Object {
52
+ "flags": Array [],
53
+ "hostname": "foo.example.com",
54
+ "id": 46,
55
+ "severity": "medium",
56
+ "title": "SELinux is turned off",
57
+ },
58
+ Object {
59
+ "flags": Array [],
60
+ "hostname": "foo.example.com",
61
+ "id": 47,
62
+ "severity": "medium",
63
+ "title": "Root password is too short",
64
+ },
65
+ Object {
66
+ "flags": Array [],
67
+ "hostname": "foo.example.com",
68
+ "id": 49,
69
+ "severity": "high",
70
+ "title": "No chocolate chip cookies in cookie jar",
71
+ },
37
72
  ],
38
73
  "hostId": 6,
39
74
  },
@@ -0,0 +1,121 @@
1
+ import React from 'react';
2
+ import { DebounceInput } from 'react-debounce-input';
3
+ import { DropdownButton, MenuItem, Form, Col, Row } from 'patternfly-react';
4
+ import PropTypes from 'prop-types';
5
+
6
+ import { translate as __ } from 'foremanReact/common/I18n';
7
+
8
+ import './EntriesFilter.scss';
9
+
10
+ const EntriesFilter = ({
11
+ filterType,
12
+ filterValue,
13
+ onFilterValueChange,
14
+ onFilterTypeChange,
15
+ }) => {
16
+ let filterValueField;
17
+
18
+ const filterTypes = [
19
+ { value: 'title', label: __('Title') },
20
+ { value: 'severity', label: __('Risk Factor') },
21
+ { value: 'hostname', label: __('Host') },
22
+ { value: 'fix', label: __('Fix Type') },
23
+ { value: 'inhibitor', label: __('Inhibitor') },
24
+ ];
25
+
26
+ const severityTypes = [
27
+ { value: '', label: __('All') },
28
+ { value: 'low', label: __('Low') },
29
+ { value: 'medium', label: __('Medium') },
30
+ { value: 'high', label: __('High') },
31
+ { value: 'info', label: __('Info') },
32
+ ];
33
+
34
+ const fixTypes = [
35
+ { value: '', label: __('All') },
36
+ { value: 'hint', label: __('Hint') },
37
+ { value: 'command', label: __('Command') },
38
+ ];
39
+
40
+ const inhibitorTypes = [
41
+ { value: '', label: __('All') },
42
+ { value: 'yes', label: __('Yes') },
43
+ { value: 'no', label: __('No') },
44
+ ];
45
+
46
+ const selectOptionMapping = {
47
+ severity: severityTypes,
48
+ fix: fixTypes,
49
+ inhibitor: inhibitorTypes,
50
+ };
51
+
52
+ const findLabel = (selectOptions, currentValue) =>
53
+ selectOptions.find(opt => opt.value === currentValue).label;
54
+
55
+ if (['title', 'hostname'].includes(filterType)) {
56
+ filterValueField = (
57
+ <DebounceInput
58
+ className="form-control entries-filter-reset-height"
59
+ debounceTimeout={300}
60
+ onChange={event => onFilterValueChange(event.target.value)}
61
+ />
62
+ );
63
+ }
64
+
65
+ if (['severity', 'fix', 'inhibitor'].includes(filterType)) {
66
+ const options = selectOptionMapping[filterType];
67
+
68
+ filterValueField = (
69
+ <DropdownButton
70
+ id="entry-value-filter"
71
+ title={findLabel(options, filterValue)}
72
+ >
73
+ {options.map(type => (
74
+ <MenuItem
75
+ key={type.value}
76
+ active={filterValue === type.value}
77
+ onClick={() => onFilterValueChange(type.value)}
78
+ >
79
+ {type.label}
80
+ </MenuItem>
81
+ ))}
82
+ </DropdownButton>
83
+ );
84
+ }
85
+
86
+ return (
87
+ <Row>
88
+ <Col md={4}>
89
+ <Form.FormGroup>
90
+ <Form.InputGroup>
91
+ <DropdownButton
92
+ id="entry-filter"
93
+ title={findLabel(filterTypes, filterType)}
94
+ componentClass={Form.InputGroup.Button}
95
+ >
96
+ {filterTypes.map(type => (
97
+ <MenuItem
98
+ key={type.value}
99
+ active={filterType === type.value}
100
+ onClick={() => onFilterTypeChange(type.value)}
101
+ >
102
+ {type.label}
103
+ </MenuItem>
104
+ ))}
105
+ </DropdownButton>
106
+ {filterValueField}
107
+ </Form.InputGroup>
108
+ </Form.FormGroup>
109
+ </Col>
110
+ </Row>
111
+ );
112
+ };
113
+
114
+ EntriesFilter.propTypes = {
115
+ filterType: PropTypes.string.isRequired,
116
+ filterValue: PropTypes.string.isRequired,
117
+ onFilterTypeChange: PropTypes.func.isRequired,
118
+ onFilterValueChange: PropTypes.func.isRequired,
119
+ };
120
+
121
+ export default EntriesFilter;
@@ -0,0 +1,3 @@
1
+ .entries-filter-reset-height {
2
+ height: inherit;
3
+ }
@@ -0,0 +1,30 @@
1
+ import { testComponentSnapshotsWithFixtures } from '@theforeman/test';
2
+
3
+ import EntriesFilter from './EntriesFilter';
4
+
5
+ const onFilterValueChange = () => {};
6
+ const onFilterTypeChange = () => {};
7
+
8
+ const fixtures = {
9
+ 'should render for title filter': {
10
+ onFilterTypeChange,
11
+ onFilterValueChange,
12
+ filterType: 'title',
13
+ filterValue: 'version',
14
+ },
15
+ 'should render for severity filter': {
16
+ onFilterTypeChange,
17
+ onFilterValueChange,
18
+ filterType: 'severity',
19
+ filterValue: 'low',
20
+ },
21
+ 'should render for host filter': {
22
+ onFilterTypeChange,
23
+ onFilterValueChange,
24
+ filterType: 'hostname',
25
+ filterValue: 'foo',
26
+ },
27
+ };
28
+
29
+ describe('EntriresFilter', () =>
30
+ testComponentSnapshotsWithFixtures(EntriesFilter, fixtures));
@@ -0,0 +1,35 @@
1
+ import React from 'react';
2
+ import PropTypes from 'prop-types';
3
+ import { Button } from 'patternfly-react';
4
+ import { translate as __ } from 'foremanReact/common/I18n';
5
+
6
+ const FixSelectedButton = ({ ids, postUrl, disabled, csrfToken }) => {
7
+ const { hostIds, entryIds } = ids;
8
+
9
+ return (
10
+ <form action={postUrl} method="post">
11
+ <Button type="submit" disabled={disabled}>
12
+ {__('Fix Selected')}
13
+ </Button>
14
+ <input type="hidden" name="authenticity_token" value={csrfToken} />
15
+ <input type="hidden" name="feature" value="leapp_remediation_plan" />
16
+ {hostIds.map(hostId => (
17
+ <input type="hidden" name="host_ids[]" key={hostId} value={hostId} />
18
+ ))}
19
+ <input
20
+ type="hidden"
21
+ name="inputs[remediation_ids]"
22
+ value={entryIds.join(',')}
23
+ />
24
+ </form>
25
+ );
26
+ };
27
+
28
+ FixSelectedButton.propTypes = {
29
+ ids: PropTypes.object.isRequired,
30
+ postUrl: PropTypes.string.isRequired,
31
+ disabled: PropTypes.bool.isRequired,
32
+ csrfToken: PropTypes.string.isRequired,
33
+ };
34
+
35
+ export default FixSelectedButton;
@@ -0,0 +1,15 @@
1
+ import { testComponentSnapshotsWithFixtures } from '@theforeman/test';
2
+
3
+ import FixSelectedButton from './FixSelectedButton';
4
+
5
+ const fixtures = {
6
+ 'should render': {
7
+ ids: { hostIds: [5], entryIds: [115] },
8
+ postUrl: '/job_invocations/new',
9
+ disabled: false,
10
+ csrfToken: 'abcd',
11
+ },
12
+ };
13
+
14
+ describe('FixSelectedButton', () =>
15
+ testComponentSnapshotsWithFixtures(FixSelectedButton, fixtures));
@@ -0,0 +1,35 @@
1
+ import React from 'react';
2
+ import PropTypes from 'prop-types';
3
+
4
+ import { EmptyStatePattern as EmptyState } from 'foremanReact/components/common/EmptyState';
5
+ import { translate as __ } from 'foremanReact/common/I18n';
6
+
7
+ const NoReports = ({ reportsExpected }) => {
8
+ let text;
9
+ let icon;
10
+
11
+ if (reportsExpected) {
12
+ text = __(
13
+ 'The preupgrade report could not be generated, check the job details for the reason'
14
+ );
15
+ icon = 'warning-triangle-o';
16
+ } else {
17
+ text = __('The preupgrade report will be available after the job finishes');
18
+ icon = 'in-progress';
19
+ }
20
+
21
+ return (
22
+ <EmptyState
23
+ iconType="pf"
24
+ icon={icon}
25
+ header={__('No Preupgrade Report Available')}
26
+ description={text}
27
+ />
28
+ );
29
+ };
30
+
31
+ NoReports.propTypes = {
32
+ reportsExpected: PropTypes.bool.isRequired,
33
+ };
34
+
35
+ export default NoReports;
@@ -0,0 +1,15 @@
1
+ import { testComponentSnapshotsWithFixtures } from '@theforeman/test';
2
+
3
+ import NoReports from './NoReports';
4
+
5
+ const fixtures = {
6
+ 'should render when reports expected': {
7
+ reportsExpected: true,
8
+ },
9
+ 'should render when reports not expected': {
10
+ reportsExpected: false,
11
+ },
12
+ };
13
+
14
+ describe('NoReports', () =>
15
+ testComponentSnapshotsWithFixtures(NoReports, fixtures));
@@ -0,0 +1,29 @@
1
+ import React from 'react';
2
+ import PropTypes from 'prop-types';
3
+ import { Button } from 'patternfly-react';
4
+ import { translate as __ } from 'foremanReact/common/I18n';
5
+
6
+ import { idsForInvocationFromReports } from '../PreupgradeReportsHelpers';
7
+
8
+ const UpgradeAllButton = ({ preupgradeReports, postUrl, csrfToken }) => {
9
+ const { hostIds } = idsForInvocationFromReports(preupgradeReports);
10
+
11
+ return (
12
+ <form action={postUrl} method="post">
13
+ <Button type="submit">{__('Run Upgrade')}</Button>
14
+ <input type="hidden" name="authenticity_token" value={csrfToken} />
15
+ <input type="hidden" name="feature" value="leapp_upgrade" />
16
+ {hostIds.map(hostId => (
17
+ <input type="hidden" name="host_ids[]" key={hostId} value={hostId} />
18
+ ))}
19
+ </form>
20
+ );
21
+ };
22
+
23
+ UpgradeAllButton.propTypes = {
24
+ preupgradeReports: PropTypes.array.isRequired,
25
+ postUrl: PropTypes.string.isRequired,
26
+ csrfToken: PropTypes.string.isRequired,
27
+ };
28
+
29
+ export default UpgradeAllButton;
@@ -0,0 +1,17 @@
1
+ import { testComponentSnapshotsWithFixtures } from '@theforeman/test';
2
+
3
+ import UpgradeAllButton from './UpgradeAllButton';
4
+
5
+ import { preupgradeReports } from '../__tests__/PreupgradeReports.fixtures';
6
+
7
+ const fixtures = {
8
+ 'should render': {
9
+ preupgradeReports,
10
+ postUrl: '/job_invocations/new',
11
+ title: 'Button title',
12
+ csrfToken: 'abcd',
13
+ },
14
+ };
15
+
16
+ describe('UpgradeAllButton', () =>
17
+ testComponentSnapshotsWithFixtures(UpgradeAllButton, fixtures));