foreman_patch 1.1.1 → 1.1.3

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 (49) hide show
  1. checksums.yaml +4 -4
  2. data/Rakefile +0 -6
  3. data/app/controllers/foreman_patch/api/v2/invocations_controller.rb +23 -1
  4. data/app/lib/actions/foreman_patch/cycle/initiate.rb +6 -1
  5. data/app/lib/actions/foreman_patch/invocation/patch.rb +6 -2
  6. data/app/lib/actions/foreman_patch/invocation/wait_for_host.rb +9 -16
  7. data/app/lib/actions/foreman_patch/window/patch.rb +4 -4
  8. data/app/models/foreman_patch/invocation.rb +6 -0
  9. data/app/models/foreman_patch/plan.rb +1 -1
  10. data/app/models/foreman_patch/round.rb +9 -26
  11. data/app/models/foreman_patch/window.rb +1 -1
  12. data/app/views/foreman_patch/api/v2/rounds/base.json.rabl +1 -1
  13. data/app/views/foreman_patch/api/v2/rounds/status.json.rabl +2 -8
  14. data/app/views/templates/ensure_services.erb +7 -4
  15. data/config/api_routes.rb +7 -1
  16. data/lib/foreman_patch/version.rb +1 -1
  17. data/webpack/components/Invocations/Invocations.js +48 -16
  18. data/webpack/components/Invocations/InvocationsPage.js +24 -1
  19. data/webpack/components/Invocations/InvocationsSelectors.js +1 -1
  20. data/webpack/components/Invocations/components/{InvocationItem.js → InvocationActions.js} +4 -16
  21. data/webpack/components/Invocations/index.js +93 -10
  22. data/webpack/components/RoundProgress/AggregateStatus.js +6 -5
  23. data/webpack/components/RoundProgress/RoundProgress.js +7 -6
  24. data/webpack/components/RoundProgress/RoundProgressSelectors.js +3 -2
  25. metadata +7 -56
  26. data/app/lib/actions/foreman_patch/invocation/ensure_services.rb +0 -47
  27. data/app/lib/actions/foreman_patch/invocation/restart.rb +0 -101
  28. data/app/lib/actions/foreman_patch/invocation/update_packages.rb +0 -52
  29. data/app/lib/actions/helpers/failure_notification.rb +0 -20
  30. data/app/lib/actions/helpers/with_feature_action.rb +0 -102
  31. data/public/webpack/foreman_patch/bundle-200e97f4e2ad9ed413ea.css +0 -1
  32. data/public/webpack/foreman_patch/bundle-200e97f4e2ad9ed413ea.css.gz +0 -0
  33. data/public/webpack/foreman_patch/bundle-200e97f4e2ad9ed413ea.js +0 -6
  34. data/public/webpack/foreman_patch/bundle-200e97f4e2ad9ed413ea.js.gz +0 -0
  35. data/public/webpack/foreman_patch/bundle-200e97f4e2ad9ed413ea.js.map +0 -1
  36. data/public/webpack/foreman_patch/bundle-200e97f4e2ad9ed413ea.js.map.gz +0 -0
  37. data/public/webpack/foreman_patch/foreman_patch-1e4f2d5e6f040a27aa7a.css +0 -1
  38. data/public/webpack/foreman_patch/foreman_patch-1e4f2d5e6f040a27aa7a.css.gz +0 -0
  39. data/public/webpack/foreman_patch/foreman_patch-1e4f2d5e6f040a27aa7a.js +0 -6
  40. data/public/webpack/foreman_patch/foreman_patch-1e4f2d5e6f040a27aa7a.js.gz +0 -0
  41. data/public/webpack/foreman_patch/foreman_patch-1e4f2d5e6f040a27aa7a.js.map +0 -1
  42. data/public/webpack/foreman_patch/foreman_patch-1e4f2d5e6f040a27aa7a.js.map.gz +0 -0
  43. data/public/webpack/foreman_patch/manifest.json +0 -26
  44. data/public/webpack/foreman_patch/manifest.json.gz +0 -0
  45. data/public/webpack/foreman_patch/vendor-4b77c91f1e9103179596.js +0 -2
  46. data/public/webpack/foreman_patch/vendor-4b77c91f1e9103179596.js.gz +0 -0
  47. data/public/webpack/foreman_patch/vendor-4b77c91f1e9103179596.js.map +0 -1
  48. data/public/webpack/foreman_patch/vendor-4b77c91f1e9103179596.js.map.gz +0 -0
  49. /data/webpack/components/Invocations/{InvocationsPage.scss → Invocations.scss} +0 -0
@@ -1,6 +1,7 @@
1
1
  import React, { useEffect, useState } from 'react';
2
2
  import { useSelector, useDispatch } from 'react-redux';
3
3
  import PropTypes from 'prop-types';
4
+ import { Grid } from 'patternfly-react';
4
5
 
5
6
  import {
6
7
  withInterval,
@@ -8,7 +9,13 @@ import {
8
9
  } from 'foremanReact/redux/middlewares/IntervalMiddleware';
9
10
  import { get } from 'foremanReact/redux/API';
10
11
  import { useForemanSettings } from 'foremanReact/Root/Context/ForemanContext';
12
+ import { getControllerSearchProps } from 'foremanReact/constants';
13
+ import { translate as __ } from 'foremanReact/common/I18n';
14
+ import SearchBar from 'foremanReact/components/SearchBar';
15
+ import Pagination from 'foremanReact/components/Pagination/PaginationWrapper';
16
+ import { ActionButtons } from 'foremanReact/components/common/ActionButtons/ActionButtons';
11
17
 
18
+ import Invocations from './Invocations';
12
19
  import {
13
20
  selectItems,
14
21
  selectTotal,
@@ -18,7 +25,8 @@ import {
18
25
  } from './InvocationsSelectors';
19
26
  import { getUrl } from './InvocationsHelpers';
20
27
  import { INVOCATIONS } from './InvocationsConstants';
21
- import InvocationsPage from './InvocationsPage';
28
+
29
+ import './Invocations.scss';
22
30
 
23
31
  const WrappedInvocations = ({ round }) => {
24
32
  const dispatch = useDispatch();
@@ -36,6 +44,9 @@ const WrappedInvocations = ({ round }) => {
36
44
  });
37
45
  const [url, setUrl] = useState(getUrl(round, searchQuery, pagination));
38
46
  const intervalExists = useSelector(selectIntervalExists);
47
+ const [selectedItems, setSelectedItems] = useState([]);
48
+ const [recentSelectedItemIndex, setRecentSelectedRowIndex] = useState(null);
49
+ const [shifting, setShifting] = useState(false);
39
50
 
40
51
  const handleSearch = query => {
41
52
  const defaultPagination = { page: 1, perPage: pagination.perPage };
@@ -52,6 +63,32 @@ const WrappedInvocations = ({ round }) => {
52
63
  setUrl(getUrl(round, searchQuery, args));
53
64
  };
54
65
 
66
+ const selectAll = (isSelecting) => setSelectedItems(isSelecting ? items.map(item => item.id) : []);
67
+
68
+ const areAllSelected = selectedItems.length == items.length;
69
+
70
+ const setItemSelected = (item, isSelecting) =>
71
+ setSelectedItems(prevSelected => {
72
+ const otherSelectedItems = prevSelected.filter(i => i !== item.id);
73
+ return isSelecting ? [...otherSelectedItems, item.id] : otherSelectedItems;
74
+ });
75
+
76
+ const onSelect = (item, rowIndex, isSelecting) => {
77
+ if (shifting && recentSelectedRowIndex !== null) {
78
+ const numberSelected = rowIndex - recentSelectedRowIndex;
79
+ const intermediateIndexes =
80
+ numberSelected > 0
81
+ ? Array.from(new Array(numberSelected + 1), (_x, i) => i + recentSelectedRowIndex)
82
+ : Array.from(new Array(Math.abs(numberSelected) + 1), (_x, i) => i + rowIndex);
83
+ intermediateIndexes.forEach(index, setItemSelected(items[index], isSelecting));
84
+ } else {
85
+ setItemSelected(item, isSelecting);
86
+ }
87
+ setRecentSelectedRowIndex(rowIndex);
88
+ };
89
+
90
+ const isSelected = item => selectedItems.includes(item.id);
91
+
55
92
  const stopApiInterval = () => {
56
93
  if (intervalExists) {
57
94
  dispatch(stopInterval(INVOCATIONS));
@@ -67,27 +104,73 @@ const WrappedInvocations = ({ round }) => {
67
104
  }), 5000);
68
105
 
69
106
  useEffect(() => {
107
+ const onKeyDown = (e) => {
108
+ if (e.key === 'Shift') {
109
+ setShifting(true);
110
+ }
111
+ };
112
+ const onKeyUp = (e) => {
113
+ if (e.key === 'Shift') {
114
+ setShifting(false);
115
+ }
116
+ };
117
+
70
118
  dispatch(getData(url));
71
119
 
72
120
  if (!autoRefresh) {
73
121
  dispatch(stopInterval(INVOCATIONS));
74
122
  }
75
123
 
124
+ document.addEventListener('keydown', onKeyDown);
125
+ document.addEventListener('keyup', onKeyUp);
126
+
76
127
  return () => {
77
128
  dispatch(stopInterval(INVOCATIONS));
129
+ document.removeEventListener('keydown', onKeyDown);
130
+ document.removeEventListener('keyup', onKeyUp);
78
131
  };
79
132
  }, [dispatch, url, autoRefresh]);
80
133
 
81
134
  return (
82
- <InvocationsPage
83
- status={status}
84
- items={items}
85
- total={total}
86
- searchQuery={searchQuery}
87
- handleSearch={handleSearch}
88
- pagination={pagination}
89
- handlePagination={handlePagination}
90
- />
135
+ <React.Fragment>
136
+ <Grid.Row>
137
+ <Grid.Col md={6} className="title_filter">
138
+ <SearchBar
139
+ onSearch={handleSearch}
140
+ data={{
141
+ ...getControllerSearchProps('foreman_patch/invocations'),
142
+ autocomplete: {
143
+ id: 'invocations_search',
144
+ searchQuery,
145
+ url: '/foreman_patch/invocations/auto_complete_search',
146
+ useKeyShortcuts: true,
147
+ },
148
+ bookmarks: {},
149
+ }}
150
+ />
151
+ </Grid.Col>
152
+ <Grid.Col md={6}>
153
+ <ActionButtons buttons={actions} />
154
+ </Grid.Col>
155
+ </Grid.Row>
156
+ <br />
157
+ <Invocations
158
+ status={status}
159
+ items={items}
160
+ selectAll={selectAll}
161
+ areAllSelected={areAllSelected}
162
+ isSelected={isSelected}
163
+ onSelect={onSelect}
164
+ />
165
+ <Pagination
166
+ viewType="table"
167
+ itemCount={total}
168
+ pagination={pagination}
169
+ onChange={handlePagination}
170
+ dropdownButtonId="invocations-pagination-dropdown"
171
+ className="invocations-pagination"
172
+ />
173
+ </React.Fragment>
91
174
  );
92
175
  };
93
176
 
@@ -19,7 +19,7 @@ const AggregateStatus = ({ progress }) => (
19
19
  <span className="card-pf-aggregate-status-notification">
20
20
  <span id="failed_count">
21
21
  <span className="pficon pficon-error-circle-o" />
22
- {progress.failed}
22
+ {progress.error}
23
23
  </span>
24
24
  </span>
25
25
  <span className="card-pf-aggregate-status-notification">
@@ -31,7 +31,7 @@ const AggregateStatus = ({ progress }) => (
31
31
  <span className="card-pf-aggregate-status-notification">
32
32
  <span id="pending_count">
33
33
  <span className="pficon pficon-pending" />
34
- {progress.pending}
34
+ {progress.pending + progress.planned}
35
35
  </span>
36
36
  </span>
37
37
  <span className="card-pf-aggregate-status-notification">
@@ -46,11 +46,12 @@ const AggregateStatus = ({ progress }) => (
46
46
 
47
47
  AggregateStatus.propTypes = {
48
48
  progress: PropTypes.shape({
49
+ planned: PropTypes.number,
50
+ pending: PropTypes.number,
51
+ running: PropTypes.number,
49
52
  success: PropTypes.number,
50
53
  warning: PropTypes.number,
51
- failed: PropTypes.number,
52
- running: PropTypes.number,
53
- pending: PropTypes.number,
54
+ error: PropTypes.number,
54
55
  cancelled: PropTypes.number,
55
56
  }).isRequired,
56
57
  };
@@ -11,14 +11,14 @@ const RoundProgress = ({ progress }) => {
11
11
  const data = [
12
12
  [__('Success'), progress.success, '#5CB85C'],
13
13
  [__('Warning'), progress.warning, '#DB843D'],
14
- [__('Failed'), progress.failed, '#D9534F'],
14
+ [__('Failed'), progress.error, '#D9534F'],
15
15
  [__('Running'), progress.running, '#3D96AE'],
16
- [__('Pending'), progress.pending, '#DEDEDE'],
16
+ [__('Pending'), progress.pending + progress.planned, '#DEDEDE'],
17
17
  [__('Cancelled'), progress.cancelled, '#B7312D'],
18
18
  ];
19
19
 
20
20
  const iMax = data.reduce((im, e, i, arr) =>
21
- (e[1] > arr[im][i] ? i : im), 0);
21
+ (e[1] > arr[im][1] ? i : im), 0);
22
22
 
23
23
  return (
24
24
  <div id="round_progress">
@@ -36,11 +36,12 @@ const RoundProgress = ({ progress }) => {
36
36
 
37
37
  RoundProgress.propTypes = {
38
38
  progress: PropTypes.shape({
39
+ pending: PropTypes.number,
40
+ planned: PropTypes.number,
41
+ running: PropTypes.number,
39
42
  success: PropTypes.number,
40
43
  warning: PropTypes.number,
41
- failed: PropTypes.number,
42
- running: PropTypes.number,
43
- pending: PropTypes.number,
44
+ error: PropTypes.number,
44
45
  cancelled: PropTypes.number,
45
46
  }).isRequired,
46
47
  };
@@ -8,9 +8,10 @@ import { ROUND_PROGRESS } from './RoundProgressConstants';
8
8
  const defaultProgress = {
9
9
  success: 0,
10
10
  warning: 0,
11
- failed: 0,
11
+ error: 0,
12
12
  running: 0,
13
13
  pending: 0,
14
+ planned: 0,
14
15
  cancelled: 0,
15
16
  };
16
17
 
@@ -18,7 +19,7 @@ export const selectProgress = state =>
18
19
  selectAPIResponse(state, ROUND_PROGRESS).progress || defaultProgress;
19
20
 
20
21
  export const selectAutoRefresh = state =>
21
- !selectAPIResponse(state, ROUND_PROGRESS).complete;
22
+ selectAPIResponse(state, ROUND_PROGRESS).status != 'complete';
22
23
 
23
24
  export const selectStatus = state =>
24
25
  selectAPIStatus(state, ROUND_PROGRESS);
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: foreman_patch
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.1.1
4
+ version: 1.1.3
5
5
  platform: ruby
6
6
  authors:
7
7
  - Jason Galens
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2022-11-10 00:00:00.000000000 Z
11
+ date: 2023-04-17 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: katello
@@ -16,14 +16,14 @@ dependencies:
16
16
  requirements:
17
17
  - - "~>"
18
18
  - !ruby/object:Gem::Version
19
- version: '4'
19
+ version: '4.1'
20
20
  type: :runtime
21
21
  prerelease: false
22
22
  version_requirements: !ruby/object:Gem::Requirement
23
23
  requirements:
24
24
  - - "~>"
25
25
  - !ruby/object:Gem::Version
26
- version: '4'
26
+ version: '4.1'
27
27
  - !ruby/object:Gem::Dependency
28
28
  name: foreman-tasks
29
29
  requirement: !ruby/object:Gem::Requirement
@@ -31,9 +31,6 @@ dependencies:
31
31
  - - ">="
32
32
  - !ruby/object:Gem::Version
33
33
  version: '4.0'
34
- - - "<"
35
- - !ruby/object:Gem::Version
36
- version: '6.0'
37
34
  type: :runtime
38
35
  prerelease: false
39
36
  version_requirements: !ruby/object:Gem::Requirement
@@ -41,9 +38,6 @@ dependencies:
41
38
  - - ">="
42
39
  - !ruby/object:Gem::Version
43
40
  version: '4.0'
44
- - - "<"
45
- - !ruby/object:Gem::Version
46
- version: '6.0'
47
41
  - !ruby/object:Gem::Dependency
48
42
  name: foreman_remote_execution
49
43
  requirement: !ruby/object:Gem::Requirement
@@ -51,9 +45,6 @@ dependencies:
51
45
  - - ">="
52
46
  - !ruby/object:Gem::Version
53
47
  version: '4.0'
54
- - - "<"
55
- - !ruby/object:Gem::Version
56
- version: '6.0'
57
48
  type: :runtime
58
49
  prerelease: false
59
50
  version_requirements: !ruby/object:Gem::Requirement
@@ -61,23 +52,6 @@ dependencies:
61
52
  - - ">="
62
53
  - !ruby/object:Gem::Version
63
54
  version: '4.0'
64
- - - "<"
65
- - !ruby/object:Gem::Version
66
- version: '6.0'
67
- - !ruby/object:Gem::Dependency
68
- name: rake-version
69
- requirement: !ruby/object:Gem::Requirement
70
- requirements:
71
- - - "~>"
72
- - !ruby/object:Gem::Version
73
- version: 1.0.1
74
- type: :development
75
- prerelease: false
76
- version_requirements: !ruby/object:Gem::Requirement
77
- requirements:
78
- - - "~>"
79
- - !ruby/object:Gem::Version
80
- version: 1.0.1
81
55
  - !ruby/object:Gem::Dependency
82
56
  name: rubocop
83
57
  requirement: !ruby/object:Gem::Requirement
@@ -141,11 +115,8 @@ files:
141
115
  - app/lib/actions/foreman_patch/cycle/prepare_content.rb
142
116
  - app/lib/actions/foreman_patch/host/reschedule.rb
143
117
  - app/lib/actions/foreman_patch/invocation/action.rb
144
- - app/lib/actions/foreman_patch/invocation/ensure_services.rb
145
118
  - app/lib/actions/foreman_patch/invocation/patch.rb
146
119
  - app/lib/actions/foreman_patch/invocation/reschedule.rb
147
- - app/lib/actions/foreman_patch/invocation/restart.rb
148
- - app/lib/actions/foreman_patch/invocation/update_packages.rb
149
120
  - app/lib/actions/foreman_patch/invocation/wait_for_host.rb
150
121
  - app/lib/actions/foreman_patch/round/add_missing_hosts.rb
151
122
  - app/lib/actions/foreman_patch/round/create.rb
@@ -157,8 +128,6 @@ files:
157
128
  - app/lib/actions/foreman_patch/window/plan.rb
158
129
  - app/lib/actions/foreman_patch/window/publish.rb
159
130
  - app/lib/actions/foreman_patch/window/resolve_hosts.rb
160
- - app/lib/actions/helpers/failure_notification.rb
161
- - app/lib/actions/helpers/with_feature_action.rb
162
131
  - app/lib/actions/middleware/check_exit_status.rb
163
132
  - app/mailers/foreman_patch/cycle_mailer.rb
164
133
  - app/mailers/foreman_patch/group_mailer.rb
@@ -325,24 +294,6 @@ files:
325
294
  - public/assets/foreman_patch/foreman_patch.json
326
295
  - public/assets/foreman_patch/plan_edit_windows-e656ba411642a7f983b51958ab30ac49c056322d19295a603cff4d5e6c71c8ed.js
327
296
  - public/assets/foreman_patch/plan_edit_windows-e656ba411642a7f983b51958ab30ac49c056322d19295a603cff4d5e6c71c8ed.js.gz
328
- - public/webpack/foreman_patch/bundle-200e97f4e2ad9ed413ea.css
329
- - public/webpack/foreman_patch/bundle-200e97f4e2ad9ed413ea.css.gz
330
- - public/webpack/foreman_patch/bundle-200e97f4e2ad9ed413ea.js
331
- - public/webpack/foreman_patch/bundle-200e97f4e2ad9ed413ea.js.gz
332
- - public/webpack/foreman_patch/bundle-200e97f4e2ad9ed413ea.js.map
333
- - public/webpack/foreman_patch/bundle-200e97f4e2ad9ed413ea.js.map.gz
334
- - public/webpack/foreman_patch/foreman_patch-1e4f2d5e6f040a27aa7a.css
335
- - public/webpack/foreman_patch/foreman_patch-1e4f2d5e6f040a27aa7a.css.gz
336
- - public/webpack/foreman_patch/foreman_patch-1e4f2d5e6f040a27aa7a.js
337
- - public/webpack/foreman_patch/foreman_patch-1e4f2d5e6f040a27aa7a.js.gz
338
- - public/webpack/foreman_patch/foreman_patch-1e4f2d5e6f040a27aa7a.js.map
339
- - public/webpack/foreman_patch/foreman_patch-1e4f2d5e6f040a27aa7a.js.map.gz
340
- - public/webpack/foreman_patch/manifest.json
341
- - public/webpack/foreman_patch/manifest.json.gz
342
- - public/webpack/foreman_patch/vendor-4b77c91f1e9103179596.js
343
- - public/webpack/foreman_patch/vendor-4b77c91f1e9103179596.js.gz
344
- - public/webpack/foreman_patch/vendor-4b77c91f1e9103179596.js.map
345
- - public/webpack/foreman_patch/vendor-4b77c91f1e9103179596.js.map.gz
346
297
  - test/factories/foreman_patch_factories.rb
347
298
  - test/test_plugin_helper.rb
348
299
  - test/unit/foreman_patch_test.rb
@@ -363,12 +314,12 @@ files:
363
314
  - webpack/components/Invocation/InvocationSelectors.js
364
315
  - webpack/components/Invocation/index.js
365
316
  - webpack/components/Invocations/Invocations.js
317
+ - webpack/components/Invocations/Invocations.scss
366
318
  - webpack/components/Invocations/InvocationsConstants.js
367
319
  - webpack/components/Invocations/InvocationsHelpers.js
368
320
  - webpack/components/Invocations/InvocationsPage.js
369
- - webpack/components/Invocations/InvocationsPage.scss
370
321
  - webpack/components/Invocations/InvocationsSelectors.js
371
- - webpack/components/Invocations/components/InvocationItem.js
322
+ - webpack/components/Invocations/components/InvocationActions.js
372
323
  - webpack/components/Invocations/components/InvocationStatus.js
373
324
  - webpack/components/Invocations/index.js
374
325
  - webpack/components/Plan/Plan.js
@@ -428,7 +379,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
428
379
  - !ruby/object:Gem::Version
429
380
  version: '0'
430
381
  requirements: []
431
- rubygems_version: 3.1.4
382
+ rubygems_version: 3.3.25
432
383
  signing_key:
433
384
  specification_version: 4
434
385
  summary: Foreman Plugin for Managing Patching
@@ -1,47 +0,0 @@
1
- module Actions
2
- module ForemanPatch
3
- module Invocation
4
- class EnsureServices < Actions::EntryAction
5
- include Actions::Helpers::WithFeatureAction
6
-
7
- def resource_locks
8
- :link
9
- end
10
-
11
- def plan(host)
12
- action_subject(host)
13
-
14
- sequence do
15
- plan_feature_action('ensure_services', host)
16
- plan_self
17
- end
18
- end
19
-
20
- def run
21
- if exit_status != 0
22
- users = ::User.select { |user| user.receives?(:patch_invocation_failure) }.compact
23
-
24
- begin
25
- MailNotification[:patch_invocation_failure].deliver(users: users, host: host, output: live_output) unless users.blank?
26
- rescue => error
27
- message = _('Unable to send patch invocation failure: %{error}') % {error: error}
28
- Rails.logger.error(message)
29
- end
30
-
31
- fail _('Ensure services failed')
32
- end
33
- end
34
-
35
- def rescue_strategy
36
- ::Dynflow::Action::Rescue::Skip
37
- end
38
-
39
- def host
40
- @host ||= ::Host.find(input[:host][:id])
41
- end
42
-
43
- end
44
- end
45
- end
46
- end
47
-
@@ -1,101 +0,0 @@
1
- module Actions
2
- module ForemanPatch
3
- module Invocation
4
- class Restart < Actions::EntryAction
5
- include Actions::Helpers::WithFeatureAction
6
- include Dynflow::Action::Polling
7
-
8
- def plan(host)
9
- action_subject(host)
10
-
11
- sequence do
12
- plan_feature_action('power_action', host, action: 'restart')
13
- plan_self
14
- end
15
- end
16
-
17
- def done?
18
- external_task[:status] == :running
19
- end
20
-
21
- def invoke_external_task
22
- if exit_status != 0
23
- send_failure_notification
24
- fail(_('Restart command failed to execute'))
25
- end
26
-
27
- schedule_timeout(Setting[:host_max_wait_for_up]) if Setting[:host_max_wait_for_up]
28
-
29
- { status: :stopping }
30
- end
31
-
32
- def poll_external_task
33
- socket = TCPSocket.new(host.ip, Setting[:remote_execution_ssh_port])
34
- socket.close
35
-
36
- if external_task[:status] == :stopping
37
- log_poll_result(_('Server status: stopping'))
38
- { status: :stopping }
39
- else
40
- log_poll_result(_('Server status: running'))
41
- { status: :running }
42
- end
43
- rescue
44
- log_poll_result(_('Server status: starting'))
45
-
46
- { status: :starting }
47
- end
48
-
49
- def poll_intervals
50
- case external_task[:status]
51
- when :stopping
52
- [1]
53
- when :starting
54
- [10]
55
- else
56
- super
57
- end
58
- end
59
-
60
- def process_timeout
61
- continuous_output.add_output(_('Server did not respond within alloted time after restart.'))
62
-
63
- send_failure_notification
64
-
65
- fail("Timeout exceeded.")
66
- end
67
-
68
- def log_poll_result(status)
69
- results = delegated_output.fetch('result', [])
70
-
71
- results << {
72
- 'output_type' => 'debug',
73
- 'output' => status,
74
- 'timestamp' => Time.now.getlocal
75
- }
76
- end
77
-
78
- def send_failure_notification
79
- users = ::User.select { |user| user.receives?(:patch_invocation_failure) }.compact
80
-
81
- begin
82
- MailNotification[:patch_invocation_failure].deliver(user: users, host: host, output: live_output) unless users.blank?
83
- rescue => error
84
- message = _('Unable to send patch invocation failure: %{error}') % {error: error}
85
- Rails.logger.error(message)
86
- end
87
- end
88
-
89
- def rescue_strategy
90
- ::Dynflow::Action::Rescue::Fail
91
- end
92
-
93
- def host
94
- @host ||= ::Host.find(input[:host][:id])
95
- end
96
-
97
- end
98
- end
99
- end
100
- end
101
-
@@ -1,52 +0,0 @@
1
- module Actions
2
- module ForemanPatch
3
- module Invocation
4
- class UpdatePackages < Actions::EntryAction
5
- include Actions::Helpers::WithFeatureAction
6
-
7
- def resource_locks
8
- :link
9
- end
10
-
11
- def plan(host)
12
- action_subject(host)
13
-
14
- sequence do
15
- plan_feature_action('katello_package_update', host,
16
- pre_script: 'yum clean all; subscription-manager refresh',
17
- package: Setting[:skip_broken_patches] ? '--skip-broken' : nil)
18
- plan_self
19
- end
20
- end
21
-
22
- def run
23
- if exit_status != 0
24
- users = ::User.select { |user| user.receives?(:patch_invocation_failure) }.compact
25
-
26
- begin
27
- MailNotification[:patch_invocation_failure].deliver(users: users, host: host, output: live_output) unless users.blank?
28
- rescue => error
29
- message = _('Unable to send patch invocation failure: %{error}') % {error: error}
30
- Rails.logger.error(message)
31
- end
32
-
33
- fail _('Package update failed')
34
- else
35
- host.group_facet.last_patched_at = Time.current
36
- host.group_facet.save!
37
- end
38
- end
39
-
40
- def rescue_strategy
41
- ::Dynflow::Action::Rescue::Fail
42
- end
43
-
44
- def host
45
- @host ||= ::Host.find(input[:host][:id])
46
- end
47
-
48
- end
49
- end
50
- end
51
- end
52
-
@@ -1,20 +0,0 @@
1
- module Actions
2
- module Helpers
3
- module FailureNotification
4
-
5
- def send_failure_notification
6
- users = ::User.select { |user| user.receives?(:patch_invocation_failure) }.compact
7
-
8
- MailNotification[:patch_invocation_failure].deliver(
9
- users: users,
10
- host: host,
11
- output: live_output
12
- ) unless users.blank?
13
- rescue => error
14
- message = _('Unable to send patch invocation failure: %{error}') % {error: error}
15
- Rails.logger.error(message)
16
- end
17
-
18
- end
19
- end
20
- end