foreman_remote_execution 3.2.1 → 3.3.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 (68) hide show
  1. checksums.yaml +4 -4
  2. data/.eslintrc +5 -30
  3. data/.github/workflows/ci.yml +101 -0
  4. data/.gitignore +1 -0
  5. data/.rubocop_todo.yml +3 -0
  6. data/Gemfile +1 -0
  7. data/app/assets/stylesheets/foreman_remote_execution/job_invocations.scss +6 -5
  8. data/app/controllers/api/v2/job_invocations_controller.rb +22 -1
  9. data/app/controllers/api/v2/template_invocations_controller.rb +4 -1
  10. data/app/helpers/job_invocations_helper.rb +1 -1
  11. data/app/helpers/remote_execution_helper.rb +38 -33
  12. data/app/lib/actions/remote_execution/run_host_job.rb +3 -2
  13. data/app/models/concerns/foreman_remote_execution/host_extensions.rb +1 -1
  14. data/app/models/concerns/foreman_remote_execution/orchestration/ssh.rb +10 -5
  15. data/app/models/remote_execution_provider.rb +5 -0
  16. data/app/services/default_proxy_proxy_selector.rb +18 -0
  17. data/app/views/api/v2/job_invocations/main.json.rabl +8 -2
  18. data/app/views/job_invocations/_card_target_hosts.html.erb +1 -1
  19. data/app/views/job_invocations/_tab_hosts.html.erb +3 -23
  20. data/app/views/job_invocations/index.html.erb +2 -1
  21. data/app/views/job_invocations/show.html.erb +0 -6
  22. data/app/views/job_invocations/show.json.erb +4 -0
  23. data/app/views/templates/ssh/package_action.erb +1 -0
  24. data/app/views/templates/ssh/puppet_agent_disable.erb +3 -0
  25. data/app/views/templates/ssh/puppet_agent_enable.erb +3 -0
  26. data/app/views/templates/ssh/puppet_install_modules_from_forge.erb +3 -0
  27. data/app/views/templates/ssh/puppet_run_once.erb +3 -0
  28. data/db/seeds.d/70-job_templates.rb +1 -1
  29. data/foreman_remote_execution.gemspec +4 -5
  30. data/lib/foreman_remote_execution/version.rb +1 -1
  31. data/locale/action_names.rb +0 -1
  32. data/package.json +16 -33
  33. data/test/functional/api/v2/job_invocations_controller_test.rb +42 -14
  34. data/test/models/orchestration/ssh_test.rb +32 -0
  35. data/test/unit/concerns/host_extensions_test.rb +7 -0
  36. data/webpack/__mocks__/foremanReact/common/I18n.js +1 -0
  37. data/webpack/__mocks__/foremanReact/components/common/ActionButtons/ActionButtons.js +3 -0
  38. data/webpack/__mocks__/foremanReact/constants.js +3 -0
  39. data/webpack/index.js +9 -7
  40. data/webpack/react_app/components/TargetingHosts/TargetingHosts.js +52 -0
  41. data/webpack/react_app/components/TargetingHosts/TargetingHostsActions.js +8 -0
  42. data/webpack/react_app/components/TargetingHosts/TargetingHostsConsts.js +1 -0
  43. data/webpack/react_app/components/TargetingHosts/TargetingHostsSelectors.js +12 -0
  44. data/webpack/react_app/components/TargetingHosts/__tests__/HostItem.test.js +6 -0
  45. data/webpack/react_app/components/TargetingHosts/__tests__/HostStatus.test.js +6 -0
  46. data/webpack/react_app/components/TargetingHosts/__tests__/TargetingHosts.test.js +6 -0
  47. data/webpack/react_app/components/TargetingHosts/__tests__/__snapshots__/HostItem.test.js.snap +31 -0
  48. data/webpack/react_app/components/TargetingHosts/__tests__/__snapshots__/HostStatus.test.js.snap +12 -0
  49. data/webpack/react_app/components/TargetingHosts/__tests__/__snapshots__/TargetingHosts.test.js.snap +81 -0
  50. data/webpack/react_app/components/TargetingHosts/__tests__/fixtures.js +43 -0
  51. data/webpack/react_app/components/TargetingHosts/components/HostItem.js +39 -0
  52. data/webpack/react_app/components/TargetingHosts/components/HostStatus.js +54 -0
  53. data/webpack/react_app/components/TargetingHosts/index.js +37 -0
  54. data/webpack/react_app/components/jobInvocations/AggregateStatus/index.js +10 -0
  55. data/webpack/react_app/components/jobInvocations/AggregateStatus/index.test.js +6 -3
  56. data/webpack/react_app/components/jobInvocations/index.js +19 -7
  57. data/webpack/react_app/redux/actions/jobInvocations/index.js +12 -8
  58. data/webpack/react_app/redux/consts.js +1 -2
  59. data/webpack/react_app/redux/reducers/jobInvocations/index.fixtures.js +8 -40
  60. data/webpack/react_app/redux/reducers/jobInvocations/index.test.js +17 -11
  61. data/webpack/test_setup.js +2 -1
  62. metadata +26 -12
  63. data/.hound.yml +0 -19
  64. data/.travis.yml +0 -6
  65. data/app/views/job_invocations/_host_actions_td.html.erb +0 -3
  66. data/app/views/job_invocations/_host_name_td.html.erb +0 -8
  67. data/app/views/job_invocations/_host_status_td.html.erb +0 -1
  68. data/app/views/job_invocations/show.js.erb +0 -23
@@ -4,14 +4,18 @@ import Immutable from 'seamless-immutable';
4
4
  import PropTypes from 'prop-types';
5
5
  // eslint-disable-next-line import/no-extraneous-dependencies
6
6
  import DonutChart from 'foremanReact/components/common/charts/DonutChart';
7
- import AggregateStatus from './AggregateStatus/index.js';
7
+ import AggregateStatus from './AggregateStatus';
8
8
  import * as JobInvocationActions from '../../redux/actions/jobInvocations';
9
9
 
10
- const colIndexOfMaxValue = columns => columns.reduce((iMax, x, i, arr) => (x[1] > arr[iMax][1] ? i : iMax), 0);
10
+ const colIndexOfMaxValue = columns =>
11
+ columns.reduce((iMax, x, i, arr) => (x[1] > arr[iMax][1] ? i : iMax), 0);
11
12
 
12
13
  class JobInvocationContainer extends React.Component {
13
14
  componentDidMount() {
14
- const { startJobInvocationsPolling, data: { url } } = this.props;
15
+ const {
16
+ startJobInvocationsPolling,
17
+ data: { url },
18
+ } = this.props;
15
19
 
16
20
  startJobInvocationsPolling(url);
17
21
  }
@@ -22,15 +26,20 @@ class JobInvocationContainer extends React.Component {
22
26
 
23
27
  return (
24
28
  <div id="job_invocations_chart_container">
25
- <DonutChart data={Immutable.asMutable(jobInvocations)}
26
- title={{type: 'percent', secondary: (jobInvocations[iMax] || [])[0]}}/>
29
+ <DonutChart
30
+ data={Immutable.asMutable(jobInvocations)}
31
+ title={{
32
+ type: 'percent',
33
+ secondary: (jobInvocations[iMax] || [])[0],
34
+ }}
35
+ />
27
36
  <AggregateStatus statuses={statuses} />
28
37
  </div>
29
38
  );
30
39
  }
31
40
  }
32
41
 
33
- const mapStateToProps = (state) => {
42
+ const mapStateToProps = state => {
34
43
  const {
35
44
  jobInvocations,
36
45
  statuses,
@@ -62,4 +71,7 @@ JobInvocationContainer.defaultProps = {
62
71
  jobInvocations: [['property', 3, 'color']],
63
72
  statuses: {},
64
73
  };
65
- export default connect(mapStateToProps, JobInvocationActions)(JobInvocationContainer);
74
+ export default connect(
75
+ mapStateToProps,
76
+ JobInvocationActions
77
+ )(JobInvocationContainer);
@@ -8,10 +8,10 @@ import {
8
8
  } from '../../consts';
9
9
 
10
10
  const defaultJobInvocationsPollingInterval = 1000;
11
- const jobInvocationsInterval = process.env.JOB_INVOCATIONS_POLLING ||
12
- defaultJobInvocationsPollingInterval;
11
+ const jobInvocationsInterval =
12
+ process.env.JOB_INVOCATIONS_POLLING || defaultJobInvocationsPollingInterval;
13
13
 
14
- const getJobInvocations = url => (dispatch, getState) => {
14
+ const getJobInvocations = url => async (dispatch, getState) => {
15
15
  function onGetJobInvocationsSuccess({ data }) {
16
16
  // If the job has finished, stop polling
17
17
  if (data.finished) {
@@ -41,7 +41,7 @@ const getJobInvocations = url => (dispatch, getState) => {
41
41
  if (jobInvocationsInterval) {
42
42
  setTimeout(
43
43
  () => dispatch(getJobInvocations(url)),
44
- jobInvocationsInterval,
44
+ jobInvocationsInterval
45
45
  );
46
46
  }
47
47
  }
@@ -52,10 +52,14 @@ const getJobInvocations = url => (dispatch, getState) => {
52
52
 
53
53
  if (getState().foremanRemoteExecutionReducers.jobInvocations.isPolling) {
54
54
  if (isDocumentVisible) {
55
- API.get(url)
56
- .then(onGetJobInvocationsSuccess)
57
- .catch(onGetJobInvocationsFailed)
58
- .then(triggerPolling);
55
+ try {
56
+ const data = await API.get(url);
57
+ onGetJobInvocationsSuccess(data);
58
+ } catch (error) {
59
+ onGetJobInvocationsFailed(error);
60
+ } finally {
61
+ triggerPolling();
62
+ }
59
63
  } else {
60
64
  // document is not visible, keep polling without api call
61
65
  triggerPolling();
@@ -2,5 +2,4 @@ export const JOB_INVOCATIONS_POLLING_STARTED =
2
2
  'JOB_INVOCATIONS_POLLING_STARTED';
3
3
  export const JOB_INVOCATIONS_GET_JOB_INVOCATIONS =
4
4
  'JOB_INVOCATIONS_GET_JOB_INVOCATIONS';
5
- export const JOB_INVOCATIONS_JOB_FINISHED =
6
- 'JOB_INVOCATIONS_JOB_FINISHED';
5
+ export const JOB_INVOCATIONS_JOB_FINISHED = 'JOB_INVOCATIONS_JOB_FINISHED';
@@ -15,26 +15,10 @@ export const pollingStarted = Immutable({
15
15
  export const jobInvocationsPayload = Immutable({
16
16
  jobInvocations: {
17
17
  job_invocations: [
18
- [
19
- 'Success',
20
- 100,
21
- '#B7312D',
22
- ],
23
- [
24
- 'Failed',
25
- 20,
26
- '#B7312D',
27
- ],
28
- [
29
- 'Pending',
30
- 40,
31
- '#B7312D',
32
- ],
33
- [
34
- 'Cancelled',
35
- 0,
36
- '#B7312D',
37
- ],
18
+ ['Success', 100, '#B7312D'],
19
+ ['Failed', 20, '#B7312D'],
20
+ ['Pending', 40, '#B7312D'],
21
+ ['Cancelled', 0, '#B7312D'],
38
22
  ],
39
23
  statuses: {
40
24
  cancelled: 0,
@@ -48,26 +32,10 @@ export const jobInvocationsPayload = Immutable({
48
32
  export const jobInvocationsReceived = Immutable({
49
33
  isPolling: true,
50
34
  jobInvocations: [
51
- [
52
- 'Success',
53
- 100,
54
- '#B7312D',
55
- ],
56
- [
57
- 'Failed',
58
- 20,
59
- '#B7312D',
60
- ],
61
- [
62
- 'Pending',
63
- 40,
64
- '#B7312D',
65
- ],
66
- [
67
- 'Cancelled',
68
- 0,
69
- '#B7312D',
70
- ],
35
+ ['Success', 100, '#B7312D'],
36
+ ['Failed', 20, '#B7312D'],
37
+ ['Pending', 40, '#B7312D'],
38
+ ['Cancelled', 0, '#B7312D'],
71
39
  ],
72
40
  statuses: {
73
41
  cancelled: 0,
@@ -18,20 +18,26 @@ describe('job invocations chart reducer', () => {
18
18
  expect(reducer(undefined, {})).toEqual(initialState);
19
19
  });
20
20
  it('should start polling given POLLING_STARTED', () => {
21
- expect(reducer(initialState, {
22
- type: JOB_INVOCATIONS_POLLING_STARTED,
23
- })).toEqual(pollingStarted);
21
+ expect(
22
+ reducer(initialState, {
23
+ type: JOB_INVOCATIONS_POLLING_STARTED,
24
+ })
25
+ ).toEqual(pollingStarted);
24
26
  });
25
27
  it('should stop polling given JOB_FINISHED', () => {
26
- expect(reducer(pollingStarted, {
27
- type: JOB_INVOCATIONS_JOB_FINISHED,
28
- payload: { jobInvocations: { job_invocations: [], statuses: {} } },
29
- })).toEqual(initialState);
28
+ expect(
29
+ reducer(pollingStarted, {
30
+ type: JOB_INVOCATIONS_JOB_FINISHED,
31
+ payload: { jobInvocations: { job_invocations: [], statuses: {} } },
32
+ })
33
+ ).toEqual(initialState);
30
34
  });
31
35
  it('should receive job invocations given GET_JOB_INVOCATIONS', () => {
32
- expect(reducer(pollingStarted, {
33
- type: JOB_INVOCATIONS_GET_JOB_INVOCATIONS,
34
- payload: jobInvocationsPayload,
35
- })).toEqual(jobInvocationsReceived);
36
+ expect(
37
+ reducer(pollingStarted, {
38
+ type: JOB_INVOCATIONS_GET_JOB_INVOCATIONS,
39
+ payload: jobInvocationsPayload,
40
+ })
41
+ ).toEqual(jobInvocationsReceived);
36
42
  });
37
43
  });
@@ -1,7 +1,8 @@
1
1
  import 'core-js/shim';
2
2
  import 'regenerator-runtime/runtime';
3
3
 
4
- import { configure } from 'enzyme';
4
+ import { configure } from '@theforeman/test';
5
+ // eslint-disable-next-line import/no-extraneous-dependencies
5
6
  import Adapter from 'enzyme-adapter-react-16';
6
7
 
7
8
  configure({ adapter: new Adapter() });
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: foreman_remote_execution
3
3
  version: !ruby/object:Gem::Version
4
- version: 3.2.1
4
+ version: 3.3.3
5
5
  platform: ruby
6
6
  authors:
7
7
  - Foreman Remote Execution team
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2020-05-14 00:00:00.000000000 Z
11
+ date: 2020-07-14 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: deface
@@ -90,16 +90,16 @@ dependencies:
90
90
  name: rubocop
91
91
  requirement: !ruby/object:Gem::Requirement
92
92
  requirements:
93
- - - ">="
93
+ - - "~>"
94
94
  - !ruby/object:Gem::Version
95
- version: '0'
95
+ version: 0.80.0
96
96
  type: :development
97
97
  prerelease: false
98
98
  version_requirements: !ruby/object:Gem::Requirement
99
99
  requirements:
100
- - - ">="
100
+ - - "~>"
101
101
  - !ruby/object:Gem::Version
102
- version: '0'
102
+ version: 0.80.0
103
103
  - !ruby/object:Gem::Dependency
104
104
  name: rdoc
105
105
  requirement: !ruby/object:Gem::Requirement
@@ -127,11 +127,10 @@ files:
127
127
  - ".babelrc.js"
128
128
  - ".eslintignore"
129
129
  - ".eslintrc"
130
+ - ".github/workflows/ci.yml"
130
131
  - ".gitignore"
131
- - ".hound.yml"
132
132
  - ".rubocop.yml"
133
133
  - ".rubocop_todo.yml"
134
- - ".travis.yml"
135
134
  - ".tx/config"
136
135
  - Gemfile
137
136
  - LICENSE
@@ -205,6 +204,7 @@ files:
205
204
  - app/models/template_invocation_input_value.rb
206
205
  - app/overrides/execution_interface.rb
207
206
  - app/overrides/subnet_proxies.rb
207
+ - app/services/default_proxy_proxy_selector.rb
208
208
  - app/services/remote_execution_proxy_selector.rb
209
209
  - app/services/ui_notifications/remote_execution_jobs/base_job_finish.rb
210
210
  - app/views/api/v2/foreign_input_sets/base.json.rabl
@@ -238,9 +238,6 @@ files:
238
238
  - app/views/job_invocations/_card_user_input.html.erb
239
239
  - app/views/job_invocations/_description_fields.html.erb
240
240
  - app/views/job_invocations/_form.html.erb
241
- - app/views/job_invocations/_host_actions_td.html.erb
242
- - app/views/job_invocations/_host_name_td.html.erb
243
- - app/views/job_invocations/_host_status_td.html.erb
244
241
  - app/views/job_invocations/_preview_hosts_list.html.erb
245
242
  - app/views/job_invocations/_preview_hosts_modal.html.erb
246
243
  - app/views/job_invocations/_rerun_taxonomies.html.erb
@@ -252,7 +249,7 @@ files:
252
249
  - app/views/job_invocations/new.html.erb
253
250
  - app/views/job_invocations/refresh.js.erb
254
251
  - app/views/job_invocations/show.html.erb
255
- - app/views/job_invocations/show.js.erb
252
+ - app/views/job_invocations/show.json.erb
256
253
  - app/views/job_invocations/welcome.html.erb
257
254
  - app/views/job_templates/_custom_tab_headers.html.erb
258
255
  - app/views/job_templates/_custom_tabs.html.erb
@@ -396,7 +393,24 @@ files:
396
393
  - test/unit/renderer_scope_input.rb
397
394
  - test/unit/targeting_test.rb
398
395
  - test/unit/template_invocation_input_value_test.rb
396
+ - webpack/__mocks__/foremanReact/common/I18n.js
397
+ - webpack/__mocks__/foremanReact/components/common/ActionButtons/ActionButtons.js
398
+ - webpack/__mocks__/foremanReact/constants.js
399
399
  - webpack/index.js
400
+ - webpack/react_app/components/TargetingHosts/TargetingHosts.js
401
+ - webpack/react_app/components/TargetingHosts/TargetingHostsActions.js
402
+ - webpack/react_app/components/TargetingHosts/TargetingHostsConsts.js
403
+ - webpack/react_app/components/TargetingHosts/TargetingHostsSelectors.js
404
+ - webpack/react_app/components/TargetingHosts/__tests__/HostItem.test.js
405
+ - webpack/react_app/components/TargetingHosts/__tests__/HostStatus.test.js
406
+ - webpack/react_app/components/TargetingHosts/__tests__/TargetingHosts.test.js
407
+ - webpack/react_app/components/TargetingHosts/__tests__/__snapshots__/HostItem.test.js.snap
408
+ - webpack/react_app/components/TargetingHosts/__tests__/__snapshots__/HostStatus.test.js.snap
409
+ - webpack/react_app/components/TargetingHosts/__tests__/__snapshots__/TargetingHosts.test.js.snap
410
+ - webpack/react_app/components/TargetingHosts/__tests__/fixtures.js
411
+ - webpack/react_app/components/TargetingHosts/components/HostItem.js
412
+ - webpack/react_app/components/TargetingHosts/components/HostStatus.js
413
+ - webpack/react_app/components/TargetingHosts/index.js
400
414
  - webpack/react_app/components/jobInvocations/AggregateStatus/index.js
401
415
  - webpack/react_app/components/jobInvocations/AggregateStatus/index.test.js
402
416
  - webpack/react_app/components/jobInvocations/index.js
data/.hound.yml DELETED
@@ -1,19 +0,0 @@
1
- scss:
2
- enabled: false
3
-
4
- stylelint:
5
- enabled: true
6
-
7
- rubocop:
8
- config_file: .rubocop.yml
9
- version: 0.80.0
10
-
11
- jshint:
12
- enabled: false
13
-
14
- eslint:
15
- enabled: true
16
- config_file: .eslintrc
17
- ignore_file: .eslintignore
18
-
19
- fail_on_violations: true
@@ -1,6 +0,0 @@
1
- language: node_js
2
- node_js:
3
- - '6.10' # current EPEL 7
4
- - '6' # previous LTS
5
- - '8' # current LTS
6
- script: ./scripts/travis_run_js_tests.sh
@@ -1,3 +0,0 @@
1
- <td class="host_actions" id="<%= dom_id(host) %>-actions" data-refresh_required="" data-id="<%= host.id %>">
2
- <%= action_buttons(template_invocation_actions(task, host, job_invocation, template_invocation)) %>
3
- </td>
@@ -1,8 +0,0 @@
1
- <td class="host_name" id="<%= dom_id(host) %>-name" data-refresh_required="<%= task.nil? ? 'true' : '' %>" data-id="<%= host.id %>">
2
- <% if task %>
3
- <%= link_to_if_authorized host.name, hash_for_template_invocation_path(:id => template_invocation).merge(:auth_object => host, :permission => :view_hosts, :authorizer => job_hosts_authorizer) %>
4
-
5
- <% else %>
6
- <%= host.name %>
7
- <% end %>
8
- </td>
@@ -1 +0,0 @@
1
- <td class="host_status" id="<%= dom_id(host) %>-status" data-refresh_required="<%= task.nil? || task.pending? ? 'true' : '' %>" data-id="<%= host.id %>"><%= template_invocation_status(task, job_invocation.task) %></td>
@@ -1,23 +0,0 @@
1
- $('div#title_action div.btn-group').html('<%= button_group(job_invocation_task_buttons(@job_invocation.task)).html_safe %>');
2
- <% if params[:hosts_needs_refresh] == 'true' && @job_invocation.resolved? %>
3
- var hosts_table = $('div#hosts');
4
- hosts_table.html('<%=j render('tab_hosts', :job_invocation => @job_invocation, :hosts => @hosts) %>');
5
- hosts_table.data('refresh_required', '');
6
- <% end %>
7
-
8
- <% ['name', 'status', 'actions', 'provider'].each do |attribute| %>
9
- <% if params["host_ids_needing_#{attribute}_update"].present? %>
10
- var td_element;
11
- <% Host.authorized(:view_hosts, Host).where(:id => params["host_ids_needing_#{attribute}_update"]).each do |host| %>
12
- <% template_invocation = @job_invocation.template_invocations.find { |template_invocation| template_invocation.host_id == host.id } %>
13
- <% task = template_invocation.try(:run_host_job_task) %>
14
- <% options = { :host => host, :task => task, :job_invocation => @job_invocation, :template_invocation => template_invocation } %>
15
- td_element= $('#<%= dom_id(host) %>-<%= attribute %>');
16
- td_element.replaceWith('<%=j render("host_#{attribute}_td", options) %>');
17
- <% end %>
18
- <% end %>
19
- <% end %>
20
-
21
- <% if @auto_refresh %>
22
- delayed_refresh($('script#job_invocation_refresh').data('refresh-url'), job_invocation_refresh_data());
23
- <% end %>