foreman_patch 1.1.1 → 1.1.3

Sign up to get free protection for your applications and to get access to all the features.
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