foreman_remote_execution 5.0.3 → 5.0.6

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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: b6101dc3457c93144c655cae80d5d7be64f420cb878166e025a527940d287a41
4
- data.tar.gz: 1840f3bf32f56c644de27c082a18c3241b145e4ac3d1696e672ffaa2cffd4099
3
+ metadata.gz: 0cf673db2c0b2db74e694d30821e53c7f49c54c9e055444d569d0fce165f4b73
4
+ data.tar.gz: f509f61d2bc18105f5c503372932f21b4c68449b2313e76e831aed128ce581ae
5
5
  SHA512:
6
- metadata.gz: f8f65034a64aa88c9ca2565b8e6543735dd726974751c5adb0a848192fe1098aee310d31b81c6d64862c91120d21766a7b204fe3c6d8b629faa6fa3452e70f79
7
- data.tar.gz: 5a440b76b2b4f7fd4f2dc5685e2e141fa9cf5811c271d1b067ab5b1d343826e97f6ce177f327cba9e2a4e76b53b7b1b50d1b2fa87873e782998d8aed0234a7e1
6
+ metadata.gz: 1fcb7c8c0f50e1cf5f82103555fc8ca87260b5a0da6fe92b6cc610d157776fa99349c38c9629cc283f7969191734d8dd46c0255a7bb9f847739a2bf941a4c2e0
7
+ data.tar.gz: 8a2af329625cf05dd0509837390a35cf2dc2b8ffabbdfb7d7d3588db4cf7cc01009d75687d0890a0472763c90c2b24316b2f1d362083e8668abe839acf01cd4f
@@ -13,6 +13,7 @@ module ForemanRemoteExecution
13
13
 
14
14
  def host_setup_extension
15
15
  remote_execution_interface
16
+ reset_host_known_keys! unless @host.new_record?
16
17
  super
17
18
  end
18
19
 
@@ -21,6 +22,10 @@ module ForemanRemoteExecution
21
22
 
22
23
  @host.set_execution_interface(params['remote_execution_interface'])
23
24
  end
25
+
26
+ def reset_host_known_keys!
27
+ @host.host_proxy_invocations.destroy_all
28
+ end
24
29
  end
25
30
  end
26
31
  end
@@ -46,6 +46,10 @@ module ForemanRemoteExecution
46
46
  end
47
47
  end
48
48
 
49
+ def cockpit_url
50
+ SSHExecutionProvider.cockpit_url_for_host(self.name)
51
+ end
52
+
49
53
  def execution_status(options = {})
50
54
  @execution_status ||= get_status(HostStatus::ExecutionStatus).to_status(options)
51
55
  end
@@ -3,16 +3,18 @@ module ForemanRemoteExecution
3
3
  extend ActiveSupport::Concern
4
4
 
5
5
  included do
6
- before_validation :set_execution_flag
7
6
  validate :exclusive_execution_interface
7
+ before_validation :move_execution_flag
8
8
  end
9
9
 
10
10
  private
11
11
 
12
- def set_execution_flag
13
- return unless primary? && host.present?
12
+ def move_execution_flag
13
+ return unless host && self.execution?
14
14
 
15
- self.execution = true if host.interfaces.detect(&:execution).nil?
15
+ host.interfaces
16
+ .select { |i| i.execution? && i != self }
17
+ .each { |i| i.execution = false }
16
18
  end
17
19
 
18
20
  def exclusive_execution_interface
@@ -217,7 +217,7 @@ class JobInvocationComposer
217
217
  def format_datetime(datetime)
218
218
  return datetime if datetime.blank?
219
219
 
220
- Time.parse(datetime).utc.strftime('%Y-%m-%d %H:%M')
220
+ Time.parse(datetime).in_time_zone.strftime('%Y-%m-%d %H:%M')
221
221
  end
222
222
  end
223
223
 
@@ -0,0 +1 @@
1
+ attributes :cockpit_url
@@ -69,8 +69,11 @@ handle_zypp_res_codes () {
69
69
 
70
70
  if [ "${ZYPP_RES_CODES[$RETVAL]}" != "" ]; then
71
71
  echo ${ZYPP_RES_CODES[$RETVAL]}
72
+ fi
73
+ if [[ $RETVAL -ge 100 && $RETVAL -le 103 ]]; then
72
74
  RETVAL=0
73
75
  fi
76
+
74
77
  return $RETVAL
75
78
  }
76
79
  <% end -%>
data/jsconfig.json ADDED
@@ -0,0 +1,8 @@
1
+ {
2
+ "compilerOptions": {
3
+ "target": "es6",
4
+ "paths": {
5
+ "foremanReact/*": ["../foreman/webpack/assets/javascripts/react_app/*"]
6
+ }
7
+ }
8
+ }
@@ -265,6 +265,7 @@ module ForemanRemoteExecution
265
265
  extend_rabl_template 'api/v2/smart_proxies/main', 'api/v2/smart_proxies/pubkey'
266
266
  extend_rabl_template 'api/v2/interfaces/main', 'api/v2/interfaces/execution_flag'
267
267
  extend_rabl_template 'api/v2/subnets/show', 'api/v2/subnets/remote_execution_proxies'
268
+ extend_rabl_template 'api/v2/hosts/main', 'api/v2/host/main'
268
269
  parameter_filter ::Subnet, :remote_execution_proxy_ids
269
270
  describe_host { overview_buttons_provider :host_overview_buttons }
270
271
 
@@ -1,3 +1,3 @@
1
1
  module ForemanRemoteExecution
2
- VERSION = '5.0.3'.freeze
2
+ VERSION = '5.0.6'.freeze
3
3
  end
data/package.json CHANGED
@@ -21,20 +21,19 @@
21
21
  },
22
22
  "devDependencies": {
23
23
  "@babel/core": "^7.7.0",
24
- "@theforeman/builder": "^8.16.0",
25
- "@theforeman/eslint-plugin-foreman": "^8.16.0",
26
- "@theforeman/stories": "^8.16.0",
27
- "@theforeman/test": "^8.16.0",
28
- "@theforeman/vendor-dev": "^8.16.0",
24
+ "@theforeman/builder": "^10.1.0",
25
+ "@theforeman/eslint-plugin-foreman": "^10.1.0",
26
+ "@theforeman/stories": "^10.1.0",
27
+ "@theforeman/test": "^10.1.0",
28
+ "@theforeman/vendor-dev": "^10.1.0",
29
29
  "babel-eslint": "^10.0.0",
30
30
  "eslint": "^6.8.0",
31
31
  "prettier": "^1.19.1",
32
- "@patternfly/react-catalog-view-extension": "^4.8.126",
33
32
  "redux-mock-store": "^1.2.2",
34
33
  "graphql-tag": "^2.11.0",
35
34
  "graphql": "^15.5.0"
36
35
  },
37
36
  "peerDependencies": {
38
- "@theforeman/vendor": "^8.16.0"
37
+ "@theforeman/vendor": "^10.1.0"
39
38
  }
40
39
  }
@@ -67,7 +67,8 @@ class ForemanRemoteExecutionHostExtensionsTest < ActiveSupport::TestCase
67
67
  it 'should only have one execution interface' do
68
68
  host.interfaces << FactoryBot.build(:nic_managed)
69
69
  host.interfaces.each { |interface| interface.execution = true }
70
- _(host).wont_be :valid?
70
+ _(host).must_be :valid?
71
+ _(host.interfaces.count(&:execution?)).must_equal 1
71
72
  end
72
73
 
73
74
  it 'returns the execution interface' do
@@ -69,6 +69,8 @@ export const GroupedSelectField = ({
69
69
  className="without_select2"
70
70
  onClear={onClear}
71
71
  menuAppendTo={() => document.body}
72
+ aria-labelledby={fieldId}
73
+ toggleAriaLabel={`${label} toggle`}
72
74
  {...props}
73
75
  >
74
76
  {options}
@@ -2,9 +2,13 @@ import { registerRoutes } from 'foremanReact/routes/RoutingService';
2
2
  import routes from './Routes/routes';
3
3
  import fillregistrationAdvanced from './react_app/extend/fillregistrationAdvanced';
4
4
  import fillRecentJobsCard from './react_app/extend/fillRecentJobsCard';
5
+ import fillFeaturesDropdown from './react_app/extend/fillRexFeaturesDropdown';
6
+ import fillKebabItems from './react_app/extend/fillKebabItems';
5
7
  import registerReducers from './react_app/extend/reducers';
6
8
 
7
9
  registerReducers();
8
10
  registerRoutes('foreman_remote_execution', routes);
11
+ fillFeaturesDropdown();
9
12
  fillRecentJobsCard();
10
13
  fillregistrationAdvanced();
14
+ fillKebabItems();
@@ -0,0 +1,13 @@
1
+ import { foremanUrl } from 'foremanReact/common/helpers';
2
+ import { sprintf, translate as __ } from 'foremanReact/common/I18n';
3
+ import { post } from 'foremanReact/redux/API';
4
+
5
+ export const runFeature = (hostId, feature, label) => dispatch => {
6
+ const url = foremanUrl(
7
+ `/job_invocations?feature=${feature}&host_ids%5B%5D=${hostId}`
8
+ );
9
+
10
+ const successToast = () => sprintf(__('%s job has been invoked'), label);
11
+ const errorToast = ({ message }) => message;
12
+ dispatch(post({ key: feature.toUpperCase(), url, successToast, errorToast }));
13
+ };
@@ -0,0 +1,2 @@
1
+ export const REX_FEATURES_API = '/api/remote_execution_features';
2
+ export const NEW_JOB_PAGE = '/job_invocations/new?host_ids%5B%5D';
@@ -0,0 +1,74 @@
1
+ import PropTypes from 'prop-types';
2
+ import React, { useState } from 'react';
3
+ import { useDispatch } from 'react-redux';
4
+ import {
5
+ DropdownItem,
6
+ Dropdown,
7
+ DropdownToggle,
8
+ DropdownToggleAction,
9
+ } from '@patternfly/react-core';
10
+ import { push } from 'connected-react-router';
11
+
12
+ import { useAPI } from 'foremanReact/common/hooks/API/APIHooks';
13
+ import { translate as __ } from 'foremanReact/common/I18n';
14
+ import { foremanUrl } from 'foremanReact/common/helpers';
15
+ import { STATUS } from 'foremanReact/constants';
16
+
17
+ import { REX_FEATURES_API, NEW_JOB_PAGE } from './constant';
18
+ import { runFeature } from './actions';
19
+
20
+ const FeaturesDropdown = ({ hostId }) => {
21
+ const [isOpen, setIsOpen] = useState(false);
22
+ const {
23
+ response: { results: features },
24
+ status,
25
+ } = useAPI('get', foremanUrl(REX_FEATURES_API));
26
+
27
+ const dispatch = useDispatch();
28
+ const dropdownItems = features
29
+ ?.filter(feature => feature.host_action_button)
30
+ ?.map(({ name, label, id, description }) => (
31
+ <DropdownItem
32
+ onClick={() => dispatch(runFeature(hostId, label, name))}
33
+ key={id}
34
+ description={description}
35
+ >
36
+ {name}
37
+ </DropdownItem>
38
+ ));
39
+ const scheduleJob = [
40
+ <DropdownToggleAction
41
+ onClick={() => dispatch(push(`${NEW_JOB_PAGE}=${hostId}`))}
42
+ key="schedule-job-action"
43
+ >
44
+ {__('Schedule a job')}
45
+ </DropdownToggleAction>,
46
+ ];
47
+
48
+ return (
49
+ <Dropdown
50
+ alignments={{ default: 'right' }}
51
+ onSelect={() => setIsOpen(false)}
52
+ toggle={
53
+ <DropdownToggle
54
+ splitButtonItems={scheduleJob}
55
+ toggleVariant="primary"
56
+ onToggle={() => setIsOpen(prev => !prev)}
57
+ isDisabled={status === STATUS.PENDING}
58
+ splitButtonVariant="action"
59
+ />
60
+ }
61
+ isOpen={isOpen}
62
+ dropdownItems={dropdownItems}
63
+ />
64
+ );
65
+ };
66
+
67
+ FeaturesDropdown.propTypes = {
68
+ hostId: PropTypes.number,
69
+ };
70
+ FeaturesDropdown.defaultProps = {
71
+ hostId: undefined,
72
+ };
73
+
74
+ export default FeaturesDropdown;
@@ -0,0 +1,22 @@
1
+ import React from 'react';
2
+ import { useSelector } from 'react-redux';
3
+ import { DropdownItem } from '@patternfly/react-core';
4
+ import { CodeIcon } from '@patternfly/react-icons';
5
+ import { selectAPIResponse } from 'foremanReact/redux/API/APISelectors';
6
+ import { translate as __ } from 'foremanReact/common/I18n';
7
+ import { HOST_DETAILS_KEY } from 'foremanReact/components/HostDetails/consts';
8
+
9
+ const HostKebabItems = () => {
10
+ const { cockpit_url: consoleUrl } = useSelector(state =>
11
+ selectAPIResponse(state, HOST_DETAILS_KEY)
12
+ );
13
+
14
+ if (!consoleUrl) return null;
15
+ return (
16
+ <DropdownItem icon={<CodeIcon />} href={consoleUrl}>
17
+ {__('Web Console')}
18
+ </DropdownItem>
19
+ );
20
+ };
21
+
22
+ export default HostKebabItems;
@@ -52,7 +52,12 @@ const RecentJobsCard = ({ hostDetails: { name, id } }) => {
52
52
  </DropdownItem>,
53
53
  ]}
54
54
  >
55
- <Tabs mountOnEnter activeKey={activeTab} onSelect={handleTabClick}>
55
+ <Tabs
56
+ mountOnEnter
57
+ unmountOnExit
58
+ activeKey={activeTab}
59
+ onSelect={handleTabClick}
60
+ >
56
61
  <Tab
57
62
  eventKey={FINISHED_TAB}
58
63
  title={<TabTitleText>{__('Finished')}</TabTitleText>}
@@ -19,7 +19,7 @@ import { translate as __ } from 'foremanReact/common/I18n';
19
19
  import { foremanUrl } from 'foremanReact/common/helpers';
20
20
 
21
21
  import JobStatusIcon from './JobStatusIcon';
22
- import { JOB_API_URL, JOBS_IN_CARD } from './constants';
22
+ import { JOB_API_URL, JOBS_IN_CARD, RECENT_JOBS_KEY } from './constants';
23
23
 
24
24
  const RecentJobsTable = ({ status, hostId }) => {
25
25
  const jobsUrl =
@@ -30,7 +30,7 @@ const RecentJobsTable = ({ status, hostId }) => {
30
30
  const {
31
31
  response: { results: jobs },
32
32
  status: responseStatus,
33
- } = useAPI('get', jobsUrl);
33
+ } = useAPI('get', jobsUrl, RECENT_JOBS_KEY);
34
34
 
35
35
  return (
36
36
  <DataList aria-label="recent-jobs-table" isCompact>
@@ -10,3 +10,4 @@ export const JOB_BASE_URL = '/job_invocations?search=host+%3D+';
10
10
  export const JOB_API_URL =
11
11
  '/api/job_invocations?order=start_at+DESC&search=targeted_host_id%3D';
12
12
  export const JOBS_IN_CARD = 3;
13
+ export const RECENT_JOBS_KEY = { key: 'RECENT_JOBS_KEY' };
@@ -0,0 +1,11 @@
1
+ import React from 'react';
2
+ import { addGlobalFill } from 'foremanReact/components/common/Fill/GlobalFill';
3
+ import KebabItems from '../components/HostKebab/KebabItems';
4
+
5
+ export default () =>
6
+ addGlobalFill(
7
+ 'host-details-kebab',
8
+ 'rex-host-details-kebab-job',
9
+ <KebabItems key="rex-host-details-kebab-job" />,
10
+ 100
11
+ );
@@ -0,0 +1,11 @@
1
+ import React from 'react';
2
+ import { addGlobalFill } from 'foremanReact/components/common/Fill/GlobalFill';
3
+ import FeaturesDropdown from '../components/FeaturesDropdown';
4
+
5
+ export default () =>
6
+ addGlobalFill(
7
+ '_rex-host-features',
8
+ '_rex-host-features',
9
+ <FeaturesDropdown key="_rex-host-features" />,
10
+ 1000
11
+ );
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: 5.0.3
4
+ version: 5.0.6
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: 2022-02-22 00:00:00.000000000 Z
11
+ date: 2022-04-21 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: deface
@@ -201,6 +201,7 @@ files:
201
201
  - app/views/api/v2/foreign_input_sets/index.json.rabl
202
202
  - app/views/api/v2/foreign_input_sets/main.json.rabl
203
203
  - app/views/api/v2/foreign_input_sets/show.json.rabl
204
+ - app/views/api/v2/host/main.rabl
204
205
  - app/views/api/v2/interfaces/execution_flag.json.rabl
205
206
  - app/views/api/v2/job_invocations/base.json.rabl
206
207
  - app/views/api/v2/job_invocations/create.json.rabl
@@ -334,6 +335,7 @@ files:
334
335
  - extra/cockpit/foreman-cockpit.service
335
336
  - extra/cockpit/settings.yml.example
336
337
  - foreman_remote_execution.gemspec
338
+ - jsconfig.json
337
339
  - lib/foreman_remote_execution.rb
338
340
  - lib/foreman_remote_execution/engine.rb
339
341
  - lib/foreman_remote_execution/version.rb
@@ -476,6 +478,10 @@ files:
476
478
  - webpack/global_index.js
477
479
  - webpack/helpers.js
478
480
  - webpack/index.js
481
+ - webpack/react_app/components/FeaturesDropdown/actions.js
482
+ - webpack/react_app/components/FeaturesDropdown/constant.js
483
+ - webpack/react_app/components/FeaturesDropdown/index.js
484
+ - webpack/react_app/components/HostKebab/KebabItems.js
479
485
  - webpack/react_app/components/RecentJobsCard/JobStatusIcon.js
480
486
  - webpack/react_app/components/RecentJobsCard/RecentJobsCard.js
481
487
  - webpack/react_app/components/RecentJobsCard/RecentJobsTable.js
@@ -508,7 +514,9 @@ files:
508
514
  - webpack/react_app/components/jobInvocations/AggregateStatus/index.js
509
515
  - webpack/react_app/components/jobInvocations/AggregateStatus/index.test.js
510
516
  - webpack/react_app/components/jobInvocations/index.js
517
+ - webpack/react_app/extend/fillKebabItems.js
511
518
  - webpack/react_app/extend/fillRecentJobsCard.js
519
+ - webpack/react_app/extend/fillRexFeaturesDropdown.js
512
520
  - webpack/react_app/extend/fillregistrationAdvanced.js
513
521
  - webpack/react_app/extend/reducers.js
514
522
  - webpack/react_app/redux/actions/jobInvocations/index.js
@@ -537,7 +545,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
537
545
  - !ruby/object:Gem::Version
538
546
  version: '0'
539
547
  requirements: []
540
- rubygems_version: 3.1.2
548
+ rubygems_version: 3.1.4
541
549
  signing_key:
542
550
  specification_version: 4
543
551
  summary: A plugin bringing remote execution to the Foreman, completing the config