foreman_rh_cloud 4.0.21.1 → 4.0.24.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (66) hide show
  1. checksums.yaml +4 -4
  2. data/app/controllers/api/v2/rh_cloud/inventory_controller.rb +50 -0
  3. data/app/controllers/concerns/inventory_upload/report_actions.rb +26 -0
  4. data/app/controllers/concerns/inventory_upload/task_actions.rb +25 -0
  5. data/app/controllers/foreman_inventory_upload/reports_controller.rb +3 -1
  6. data/app/controllers/foreman_inventory_upload/tasks_controller.rb +5 -13
  7. data/app/controllers/foreman_inventory_upload/uploads_controller.rb +4 -4
  8. data/app/controllers/insights_cloud/api/machine_telemetries_controller.rb +6 -3
  9. data/app/controllers/insights_cloud/hits_controller.rb +7 -3
  10. data/app/helpers/foreman_insights_host_helper.rb +19 -0
  11. data/app/models/insights_client_report_status.rb +11 -22
  12. data/app/services/foreman_rh_cloud/cloud_auth.rb +12 -0
  13. data/app/services/foreman_rh_cloud/cloud_request.rb +14 -0
  14. data/app/services/foreman_rh_cloud/cloud_request_forwarder.rb +1 -14
  15. data/app/services/foreman_rh_cloud/insights_status_cleaner.rb +17 -0
  16. data/app/services/foreman_rh_cloud/remediations_retriever.rb +1 -4
  17. data/config/package-lock.json.plugin +30931 -0
  18. data/config/routes.rb +19 -0
  19. data/db/migrate/20210720000001_remove_old_insights_statuses.foreman_rh_cloud.rb +6 -0
  20. data/lib/foreman_inventory_upload.rb +9 -1
  21. data/lib/foreman_inventory_upload/generators/fact_helpers.rb +19 -0
  22. data/lib/foreman_inventory_upload/generators/queries.rb +1 -0
  23. data/lib/foreman_inventory_upload/generators/slice.rb +6 -5
  24. data/lib/foreman_rh_cloud/engine.rb +17 -10
  25. data/lib/foreman_rh_cloud/version.rb +1 -1
  26. data/lib/insights_cloud/async/insights_client_status_aging.rb +23 -0
  27. data/lib/insights_cloud/async/insights_full_sync.rb +4 -14
  28. data/lib/insights_cloud/async/insights_resolutions_sync.rb +1 -4
  29. data/lib/insights_cloud/async/insights_rules_sync.rb +2 -7
  30. data/lib/inventory_sync/async/host_result.rb +4 -0
  31. data/lib/inventory_sync/async/inventory_full_sync.rb +2 -1
  32. data/lib/inventory_sync/async/inventory_hosts_sync.rb +16 -2
  33. data/lib/inventory_sync/async/inventory_scheduled_sync.rb +12 -0
  34. data/lib/inventory_sync/async/inventory_self_host_sync.rb +30 -0
  35. data/lib/inventory_sync/async/query_inventory_job.rb +6 -5
  36. data/lib/tasks/insights.rake +15 -0
  37. data/lib/tasks/rh_cloud_inventory.rake +8 -1
  38. data/package.json +1 -1
  39. data/test/controllers/insights_cloud/api/machine_telemetries_controller_test.rb +41 -0
  40. data/test/controllers/inventory_upload/api/inventory_controller_test.rb +53 -0
  41. data/test/factories/inventory_upload_factories.rb +1 -1
  42. data/test/jobs/insights_client_status_aging_test.rb +33 -0
  43. data/test/jobs/inventory_hosts_sync_test.rb +267 -0
  44. data/test/jobs/inventory_scheduled_sync_test.rb +22 -0
  45. data/test/jobs/inventory_self_host_sync_test.rb +103 -0
  46. data/test/models/insights_client_report_status_test.rb +70 -72
  47. data/test/test_plugin_helper.rb +2 -1
  48. data/test/unit/services/foreman_rh_cloud/cloud_request_forwarder_test.rb +3 -3
  49. data/test/unit/services/foreman_rh_cloud/insights_status_cleaner_test.rb +31 -0
  50. data/test/unit/slice_generator_test.rb +70 -27
  51. data/webpack/ForemanInventoryUpload/Components/PageHeader/components/PageDescription/PageDescription.js +11 -0
  52. data/webpack/ForemanInventoryUpload/Components/PageHeader/components/PageDescription/__tests__/__snapshots__/PageDescription.test.js.snap +11 -0
  53. data/webpack/ForemanInventoryUpload/Components/PageHeader/components/SyncButton/SyncButtonActions.js +28 -63
  54. data/webpack/ForemanInventoryUpload/Components/PageHeader/components/SyncButton/__tests__/__snapshots__/integrations.test.js.snap +2 -3
  55. data/webpack/InsightsCloudSync/Components/InsightsTable/InsightsTableActions.js +19 -19
  56. data/webpack/InsightsCloudSync/Components/InsightsTable/__tests__/__snapshots__/InsightsTable.test.js.snap +0 -2
  57. data/webpack/InsightsCloudSync/Components/InsightsTable/__tests__/__snapshots__/InsightsTableActions.test.js.snap +14 -14
  58. data/webpack/InsightsCloudSync/InsightsCloudSync.js +4 -1
  59. data/webpack/InsightsCloudSync/InsightsCloudSyncActions.js +44 -20
  60. data/webpack/InsightsCloudSync/InsightsCloudSyncConstants.js +2 -0
  61. data/webpack/InsightsCloudSync/__tests__/__snapshots__/InsightsCloudSyncActions.test.js.snap +11 -7
  62. data/webpack/common/ForemanTasks/ForemanTasksActions.js +64 -0
  63. data/webpack/common/ForemanTasks/ForemanTasksHelpers.js +7 -0
  64. data/webpack/common/ForemanTasks/index.js +1 -0
  65. metadata +28 -4
  66. data/app/subscribers/foreman_rh_cloud/insights_subscriber.rb +0 -9
@@ -31,6 +31,17 @@ export const PageDescription = () => (
31
31
  About subscription watch
32
32
  </a>
33
33
  </p>
34
+ <p>
35
+ {__('For more information about Insights and Cloud Connector read')}
36
+ &nbsp;
37
+ <a
38
+ href="https://console.redhat.com/security/insights/"
39
+ target="_blank"
40
+ rel="noopener noreferrer"
41
+ >
42
+ Red Hat Insights Data and Application Security
43
+ </a>
44
+ </p>
34
45
  </div>
35
46
  );
36
47
 
@@ -24,5 +24,16 @@ exports[`PageDescription rendering render without Props 1`] = `
24
24
  About subscription watch
25
25
  </a>
26
26
  </p>
27
+ <p>
28
+ For more information about Insights and Cloud Connector read
29
+  
30
+ <a
31
+ href="https://console.redhat.com/security/insights/"
32
+ rel="noopener noreferrer"
33
+ target="_blank"
34
+ >
35
+ Red Hat Insights Data and Application Security
36
+ </a>
37
+ </p>
27
38
  </div>
28
39
  `;
@@ -1,6 +1,5 @@
1
1
  import React from 'react';
2
- import { get, post } from 'foremanReact/redux/API';
3
- import { withInterval } from 'foremanReact/redux/middlewares/IntervalMiddleware';
2
+ import { post } from 'foremanReact/redux/API';
4
3
  import { addToast } from 'foremanReact/redux/actions/toasts';
5
4
  import { translate as __ } from 'foremanReact/common/I18n';
6
5
  import { inventoryUrl } from '../../../../ForemanInventoryHelpers';
@@ -9,7 +8,10 @@ import {
9
8
  INVENTORY_SYNC,
10
9
  INVENTORY_SYNC_TASK_UPDATE,
11
10
  } from './SyncButtonConstants';
12
- import { foremanUrl } from '../../../../../ForemanRhCloudHelpers';
11
+ import {
12
+ setupTaskPolling,
13
+ taskRelatedToast,
14
+ } from '../../../../../common/ForemanTasks';
13
15
 
14
16
  export const handleSync = () => dispatch => {
15
17
  dispatch(
@@ -21,9 +23,9 @@ export const handleSync = () => dispatch => {
21
23
  task: { id },
22
24
  },
23
25
  }) => {
24
- dispatch(getSyncTaskInterval(id));
26
+ dispatch(setupInventorySyncTaskPolling(id, dispatch));
25
27
  return dispatch(
26
- taskPageRefererToast(id, 'info', __('Inventory sync has started:'))
28
+ taskRelatedToast(id, 'info', __('Inventory sync has started:'))
27
29
  );
28
30
  },
29
31
  errorToast: inventorySyncErrorToast,
@@ -31,62 +33,25 @@ export const handleSync = () => dispatch => {
31
33
  );
32
34
  };
33
35
 
34
- export const getSyncTaskInterval = id => dispatch => {
35
- dispatch(
36
- withInterval(
37
- get({
38
- key: INVENTORY_SYNC_TASK_UPDATE,
39
- url: inventoryUrl(`tasks/${id}`),
40
- handleSuccess: ({ data: { result, output } }, stopTaskInterval) => {
41
- if (result === 'success') {
42
- const {
43
- host_statuses: { sync, disconnect },
44
- } = output;
45
- dispatch(
46
- addToast({
47
- sticky: true,
48
- type: 'success',
49
- message: (
50
- <Toast syncHosts={sync} disconnectHosts={disconnect} />
51
- ),
52
- })
53
- );
54
- }
55
- if (result === 'error') {
56
- dispatch(
57
- taskPageRefererToast(
58
- id,
59
- 'error',
60
- __('Inventory sync has failed:'),
61
- true
62
- )
63
- );
64
- }
65
- stopTaskInterval();
66
- },
67
- errorToast: inventorySyncErrorToast,
68
- })
69
- )
70
- );
71
- };
72
-
73
- const inventorySyncErrorToast = ({ message, response }) =>
74
- `${__('Inventory sync has failed: ')} ${response.data?.message || message}`;
75
-
76
- const taskPageRefererToast = (taskID, toastType, prefix, sticky = false) =>
77
- addToast({
78
- sticky,
79
- type: toastType,
80
- message: (
81
- <span>
82
- {prefix}{' '}
83
- <a
84
- target="_blank"
85
- rel="noopener noreferrer"
86
- href={foremanUrl(`/foreman_tasks/tasks/${taskID}`)}
87
- >
88
- {__('view the task page for more details')}
89
- </a>
90
- </span>
91
- ),
36
+ export const setupInventorySyncTaskPolling = (id, dispatch) =>
37
+ setupTaskPolling({
38
+ taskId: id,
39
+ key: INVENTORY_SYNC_TASK_UPDATE,
40
+ onTaskSuccess: ({
41
+ output: {
42
+ host_statuses: { sync, disconnect },
43
+ },
44
+ }) =>
45
+ dispatch(
46
+ addToast({
47
+ sticky: true,
48
+ type: 'success',
49
+ message: <Toast syncHosts={sync} disconnectHosts={disconnect} />,
50
+ })
51
+ ),
52
+ dispatch,
92
53
  });
54
+
55
+ const inventorySyncErrorToast = message =>
56
+ `${__('Inventory sync has failed: ')} ${message.response?.data?.message ||
57
+ message}`;
@@ -22,7 +22,7 @@ Array [
22
22
  "errorToast": [Function],
23
23
  "interval": 3000,
24
24
  "type": "API_GET",
25
- "url": "/foreman_inventory_upload/tasks/1",
25
+ "url": "/foreman_tasks/api/tasks/1/details?include_permissions",
26
26
  },
27
27
  ],
28
28
  Array [
@@ -31,7 +31,7 @@ Array [
31
31
  "message": Object {
32
32
  "message": <span>
33
33
  Inventory sync has started:
34
-
34
+ <br />
35
35
  <a
36
36
  href="/foreman_tasks/tasks/1"
37
37
  rel="noopener noreferrer"
@@ -40,7 +40,6 @@ Array [
40
40
  view the task page for more details
41
41
  </a>
42
42
  </span>,
43
- "sticky": false,
44
43
  "type": "info",
45
44
  },
46
45
  },
@@ -19,25 +19,6 @@ export const fetchInsights = (queryParams = {}) => (dispatch, getState) => {
19
19
  ...queryParams,
20
20
  };
21
21
 
22
- dispatch(
23
- get({
24
- key: INSIGHTS_HITS_API_KEY,
25
- url: INSIGHTS_HITS_PATH,
26
- params: {
27
- page,
28
- per_page: perPage,
29
- search: query,
30
- order: `${sortBy} ${sortOrder}`,
31
- },
32
- handleSuccess: response => {
33
- if (isSelectAll) {
34
- selectAllIds(dispatch, response.data.hits || []);
35
- dispatch(selectAll());
36
- }
37
- },
38
- })
39
- );
40
-
41
22
  const uri = new URI();
42
23
  uri.search({
43
24
  page,
@@ -58,6 +39,25 @@ export const fetchInsights = (queryParams = {}) => (dispatch, getState) => {
58
39
  if (!isSelectAll) {
59
40
  dispatch(setSelectAllAlert(false));
60
41
  }
42
+
43
+ return dispatch(
44
+ get({
45
+ key: INSIGHTS_HITS_API_KEY,
46
+ url: INSIGHTS_HITS_PATH,
47
+ params: {
48
+ page,
49
+ per_page: perPage,
50
+ search: query,
51
+ order: `${sortBy} ${sortOrder}`,
52
+ },
53
+ handleSuccess: response => {
54
+ if (isSelectAll) {
55
+ selectAllIds(dispatch, response.data.hits || []);
56
+ dispatch(selectAll());
57
+ }
58
+ },
59
+ })
60
+ );
61
61
  };
62
62
 
63
63
  const selectAllIds = (dispatch, results, prevSelectedIds = {}) => {
@@ -61,7 +61,6 @@ exports[`InsightsTable rendering render with Props 1`] = `
61
61
  expandId="expandable-toggle"
62
62
  gridBreakPoint="grid-md"
63
63
  isStickyHeader={false}
64
- isTreeTable={false}
65
64
  onSelect={[Function]}
66
65
  onSort={[Function]}
67
66
  ouiaSafe={true}
@@ -138,7 +137,6 @@ exports[`InsightsTable rendering render with Props 1`] = `
138
137
  "currPage": "Current page",
139
138
  "items": "",
140
139
  "itemsPerPage": "Items per page",
141
- "ofWord": "of",
142
140
  "optionsToggle": "Items per page",
143
141
  "page": "",
144
142
  "paginationTitle": "Pagination",
@@ -26,6 +26,20 @@ Array [
26
26
 
27
27
  exports[`insights table actions should fetchInsights 1`] = `
28
28
  Array [
29
+ Array [
30
+ Object {
31
+ "payload": Object {
32
+ "args": Array [
33
+ Object {
34
+ "pathname": "/foreman_rh_cloud/insights_cloud",
35
+ "search": "?page=2&per_page=7&search=&sort_by=&sort_order=&select_all=true",
36
+ },
37
+ ],
38
+ "method": "push",
39
+ },
40
+ "type": "@@router/CALL_HISTORY_METHOD",
41
+ },
42
+ ],
29
43
  Array [
30
44
  Object {
31
45
  "payload": Object {
@@ -61,20 +75,6 @@ Array [
61
75
  "url": "/insights_cloud/hits",
62
76
  },
63
77
  ],
64
- Array [
65
- Object {
66
- "payload": Object {
67
- "args": Array [
68
- Object {
69
- "pathname": "/foreman_rh_cloud/insights_cloud",
70
- "search": "?page=2&per_page=7&search=&sort_by=&sort_order=&select_all=true",
71
- },
72
- ],
73
- "method": "push",
74
- },
75
- "type": "@@router/CALL_HISTORY_METHOD",
76
- },
77
- ],
78
78
  ]
79
79
  `;
80
80
 
@@ -36,7 +36,10 @@ const InsightsCloudSync = ({
36
36
  toolbarButtons={
37
37
  <>
38
38
  <RemediationModal />
39
- <Button variant="secondary" onClick={syncInsights}>
39
+ <Button
40
+ variant="secondary"
41
+ onClick={() => syncInsights(fetchInsights, query)}
42
+ >
40
43
  {__('Start recommendations sync')}
41
44
  </Button>
42
45
  </>
@@ -1,25 +1,49 @@
1
- import React from 'react';
2
1
  import { post } from 'foremanReact/redux/API';
3
2
  import { translate as __ } from 'foremanReact/common/I18n';
4
3
  import { insightsCloudUrl } from './InsightsCloudSyncHelpers';
5
- import { INSIGHTS_CLOUD_SYNC } from './InsightsCloudSyncConstants';
6
- import { foremanUrl } from '../ForemanRhCloudHelpers';
4
+ import {
5
+ INSIGHTS_CLOUD_SYNC,
6
+ INSIGHTS_CLOUD_SYNC_TASK,
7
+ } from './InsightsCloudSyncConstants';
8
+ import { setupTaskPolling, taskRelatedToast } from '../common/ForemanTasks';
7
9
 
8
- export const syncInsights = () =>
9
- post({
10
- key: INSIGHTS_CLOUD_SYNC,
11
- url: insightsCloudUrl('tasks'),
12
- successToast: response => (
13
- <span>
14
- {__('Recommendation sync has started: ')}
15
- <a
16
- target="_blank"
17
- rel="noopener noreferrer"
18
- href={foremanUrl(`/foreman_tasks/tasks/${response.data?.task?.id}`)}
19
- >
20
- {__('view the task in progress')}
21
- </a>
22
- </span>
23
- ),
24
- errorToast: error => `${__('Recommendation sync has failed: ')} ${error}`,
10
+ export const syncInsights = (fetchInsights, query) => dispatch =>
11
+ dispatch(
12
+ post({
13
+ key: INSIGHTS_CLOUD_SYNC,
14
+ url: insightsCloudUrl('tasks'),
15
+ handleSuccess: ({
16
+ data: {
17
+ task: { id },
18
+ },
19
+ }) => {
20
+ dispatch(syncInsightsStartedToast(id));
21
+ dispatch(setupInsightsTaskPolling(id, fetchInsights, query, dispatch));
22
+ },
23
+ errorToast: error => syncInsightsError(error),
24
+ })
25
+ );
26
+
27
+ const syncInsightsError = error =>
28
+ `${__('Recommendation sync has failed: ')} ${error}`;
29
+
30
+ const syncInsightsStartedToast = taskId =>
31
+ taskRelatedToast(taskId, 'info', __('Recommendation sync has started: '));
32
+
33
+ const setupInsightsTaskPolling = (taskId, fetchInsights, query, dispatch) =>
34
+ setupTaskPolling({
35
+ taskId,
36
+ key: INSIGHTS_CLOUD_SYNC_TASK,
37
+ onTaskSuccess: () => {
38
+ fetchInsights({ query, page: 1 });
39
+ dispatch(
40
+ taskRelatedToast(
41
+ taskId,
42
+ 'success',
43
+ __('Recommendations synced successfully')
44
+ )
45
+ );
46
+ },
47
+ taskErrorMessage: data => syncInsightsError(data.humanized.errors),
48
+ dispatch,
25
49
  });
@@ -4,6 +4,8 @@ import { foremanUrl } from '../ForemanRhCloudHelpers';
4
4
 
5
5
  export const INSIGHTS_CLOUD_SYNC = 'INSIGHTS_CLOUD_SYNC';
6
6
 
7
+ export const INSIGHTS_CLOUD_SYNC_TASK = 'INSIGHTS_CLOUD_SYNC_TASK';
8
+
7
9
  export const INSIGHTS_SYNC_PAGE_TITLE = __('Red Hat Insights');
8
10
 
9
11
  export const INSIGHTS_PATH = foremanUrl('/foreman_rh_cloud/insights_cloud');
@@ -1,11 +1,15 @@
1
1
  // Jest Snapshot v1, https://goo.gl/fbAQLP
2
2
 
3
3
  exports[`Insights cloud sync actions should syncInsights 1`] = `
4
- Object {
5
- "errorToast": [Function],
6
- "key": "INSIGHTS_CLOUD_SYNC",
7
- "successToast": [Function],
8
- "type": "post-some-type",
9
- "url": "/insights_cloud/tasks",
10
- }
4
+ Array [
5
+ Array [
6
+ Object {
7
+ "errorToast": [Function],
8
+ "handleSuccess": [Function],
9
+ "key": "INSIGHTS_CLOUD_SYNC",
10
+ "type": "post-some-type",
11
+ "url": "/insights_cloud/tasks",
12
+ },
13
+ ],
14
+ ]
11
15
  `;
@@ -0,0 +1,64 @@
1
+ import React from 'react';
2
+ import { get } from 'foremanReact/redux/API';
3
+ import { withInterval } from 'foremanReact/redux/middlewares/IntervalMiddleware';
4
+ import { addToast } from 'foremanReact/redux/actions/toasts';
5
+ import { translate as __ } from 'foremanReact/common/I18n';
6
+ import { foremanTaskDetailsUrl } from './ForemanTasksHelpers';
7
+ import { foremanUrl } from '../../ForemanRhCloudHelpers';
8
+
9
+ export const setupTaskPolling = ({
10
+ taskId,
11
+ key,
12
+ onTaskSuccess,
13
+ onTaskError,
14
+ taskErrorMessage,
15
+ dispatch,
16
+ }) =>
17
+ withInterval(
18
+ get({
19
+ key,
20
+ url: foremanTaskDetailsUrl(taskId),
21
+ handleSuccess: ({ data }, stopTaskInterval) => {
22
+ if (data.result === 'success') {
23
+ stopTaskInterval();
24
+ onTaskSuccess(data, dispatch);
25
+ }
26
+ if (data.result === 'error') {
27
+ stopTaskInterval();
28
+ if (taskErrorMessage === undefined) {
29
+ taskErrorMessage = errorData =>
30
+ `${__('The task failed with the following error:')} ${
31
+ errorData.humanized.errors
32
+ }`;
33
+ }
34
+ if (onTaskError === undefined) {
35
+ onTaskError = errorData =>
36
+ dispatch(defaultTaskErrorHandler(errorData, taskErrorMessage));
37
+ }
38
+ onTaskError(data, dispatch);
39
+ }
40
+ },
41
+ errorToast: error => `Could not get task details: ${error}`,
42
+ })
43
+ );
44
+
45
+ export const taskRelatedToast = (taskID, type, message) =>
46
+ addToast({
47
+ type,
48
+ message: (
49
+ <span>
50
+ {message}
51
+ <br />
52
+ <a
53
+ target="_blank"
54
+ rel="noopener noreferrer"
55
+ href={foremanUrl(`/foreman_tasks/tasks/${taskID}`)}
56
+ >
57
+ {__('view the task page for more details')}
58
+ </a>
59
+ </span>
60
+ ),
61
+ });
62
+
63
+ const defaultTaskErrorHandler = (data, taskErrorMessage) =>
64
+ taskRelatedToast(data.id, 'error', taskErrorMessage(data));