foreman_remote_execution 3.1.0 → 3.3.2
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 +4 -4
- data/.eslintrc +5 -30
- data/.github/workflows/ci.yml +100 -0
- data/.gitignore +1 -0
- data/.rubocop_todo.yml +3 -0
- data/Gemfile +1 -0
- data/app/controllers/api/v2/job_invocations_controller.rb +22 -1
- data/app/controllers/api/v2/template_invocations_controller.rb +4 -1
- data/app/helpers/job_invocations_chart_helper.rb +2 -0
- data/app/helpers/job_invocations_helper.rb +6 -1
- data/app/helpers/remote_execution_helper.rb +39 -30
- data/app/lib/actions/remote_execution/run_host_job.rb +3 -2
- data/app/lib/proxy_api/remote_execution_ssh.rb +6 -0
- data/app/models/concerns/foreman_remote_execution/host_extensions.rb +1 -1
- data/app/models/concerns/foreman_remote_execution/orchestration/ssh.rb +63 -0
- data/app/models/concerns/foreman_remote_execution/smart_proxy_extensions.rb +4 -0
- data/app/models/host_status/execution_status.rb +9 -1
- data/app/models/remote_execution_provider.rb +5 -0
- data/app/services/default_proxy_proxy_selector.rb +18 -0
- data/app/views/api/v2/job_invocations/main.json.rabl +8 -2
- data/app/views/job_invocations/_card_results.html.erb +1 -0
- data/app/views/job_invocations/_card_user_input.html.erb +1 -1
- data/app/views/job_invocations/_tab_hosts.html.erb +3 -23
- data/app/views/job_invocations/_tab_overview.html.erb +1 -1
- data/app/views/job_invocations/_user_input.html.erb +1 -1
- data/app/views/job_invocations/show.html.erb +1 -7
- data/app/views/job_invocations/show.json.erb +4 -0
- data/config/routes.rb +2 -1
- data/db/seeds.d/70-job_templates.rb +1 -1
- data/foreman_remote_execution.gemspec +5 -6
- data/lib/foreman_remote_execution/engine.rb +2 -0
- data/lib/foreman_remote_execution/version.rb +1 -1
- data/locale/action_names.rb +3 -3
- data/locale/de/LC_MESSAGES/foreman_remote_execution.mo +0 -0
- data/locale/de/foreman_remote_execution.po +65 -16
- data/locale/en/foreman_remote_execution.po +63 -15
- data/locale/en_GB/LC_MESSAGES/foreman_remote_execution.mo +0 -0
- data/locale/en_GB/foreman_remote_execution.po +64 -15
- data/locale/es/LC_MESSAGES/foreman_remote_execution.mo +0 -0
- data/locale/es/foreman_remote_execution.po +66 -17
- data/locale/foreman_remote_execution.pot +193 -148
- data/locale/fr/LC_MESSAGES/foreman_remote_execution.mo +0 -0
- data/locale/fr/foreman_remote_execution.po +66 -17
- data/locale/ja/LC_MESSAGES/foreman_remote_execution.mo +0 -0
- data/locale/ja/foreman_remote_execution.po +66 -17
- data/locale/ko/LC_MESSAGES/foreman_remote_execution.mo +0 -0
- data/locale/ko/foreman_remote_execution.po +65 -15
- data/locale/pt_BR/LC_MESSAGES/foreman_remote_execution.mo +0 -0
- data/locale/pt_BR/foreman_remote_execution.po +66 -17
- data/locale/ru/LC_MESSAGES/foreman_remote_execution.mo +0 -0
- data/locale/ru/foreman_remote_execution.po +65 -18
- data/locale/zh_CN/LC_MESSAGES/foreman_remote_execution.mo +0 -0
- data/locale/zh_CN/foreman_remote_execution.po +66 -17
- data/locale/zh_TW/LC_MESSAGES/foreman_remote_execution.mo +0 -0
- data/locale/zh_TW/foreman_remote_execution.po +65 -16
- data/package.json +16 -33
- data/test/functional/api/v2/job_invocations_controller_test.rb +42 -14
- data/test/functional/job_invocations_controller_test.rb +12 -0
- data/test/models/orchestration/ssh_test.rb +56 -0
- data/test/unit/concerns/host_extensions_test.rb +7 -0
- data/test/unit/remote_execution_provider_test.rb +4 -1
- data/webpack/__mocks__/foremanReact/common/I18n.js +1 -0
- data/webpack/__mocks__/foremanReact/components/common/ActionButtons/ActionButtons.js +3 -0
- data/webpack/__mocks__/foremanReact/constants.js +3 -0
- data/webpack/index.js +9 -22
- data/webpack/react_app/components/TargetingHosts/TargetingHosts.js +52 -0
- data/webpack/react_app/components/TargetingHosts/TargetingHostsActions.js +8 -0
- data/webpack/react_app/components/TargetingHosts/TargetingHostsConsts.js +1 -0
- data/webpack/react_app/components/TargetingHosts/TargetingHostsSelectors.js +12 -0
- data/webpack/react_app/components/TargetingHosts/__tests__/HostItem.test.js +6 -0
- data/webpack/react_app/components/TargetingHosts/__tests__/HostStatus.test.js +6 -0
- data/webpack/react_app/components/TargetingHosts/__tests__/TargetingHosts.test.js +6 -0
- data/webpack/react_app/components/TargetingHosts/__tests__/__snapshots__/HostItem.test.js.snap +31 -0
- data/webpack/react_app/components/TargetingHosts/__tests__/__snapshots__/HostStatus.test.js.snap +12 -0
- data/webpack/react_app/components/TargetingHosts/__tests__/__snapshots__/TargetingHosts.test.js.snap +81 -0
- data/webpack/react_app/components/TargetingHosts/__tests__/fixtures.js +43 -0
- data/webpack/react_app/components/TargetingHosts/components/HostItem.js +39 -0
- data/webpack/react_app/components/TargetingHosts/components/HostStatus.js +54 -0
- data/webpack/react_app/components/TargetingHosts/index.js +37 -0
- data/webpack/react_app/components/jobInvocations/AggregateStatus/index.js +10 -0
- data/webpack/react_app/components/jobInvocations/AggregateStatus/index.test.js +6 -3
- data/webpack/react_app/components/jobInvocations/index.js +19 -7
- data/webpack/react_app/redux/actions/jobInvocations/index.js +12 -8
- data/webpack/react_app/redux/consts.js +1 -2
- data/webpack/react_app/redux/reducers/jobInvocations/index.fixtures.js +8 -40
- data/webpack/react_app/redux/reducers/jobInvocations/index.test.js +17 -11
- data/webpack/test_setup.js +2 -1
- metadata +31 -14
- data/.hound.yml +0 -19
- data/.travis.yml +0 -6
- data/app/views/job_invocations/_host_actions_td.html.erb +0 -3
- data/app/views/job_invocations/_host_name_td.html.erb +0 -8
- data/app/views/job_invocations/_host_status_td.html.erb +0 -1
- data/app/views/job_invocations/show.js.erb +0 -23
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: d093d837d0009e477549fba4700f3e0090045ba23f8b2c50fb05439fee53e403
|
|
4
|
+
data.tar.gz: 54dffc56caa3fa1bb72bb159b152d267d2e348b64b57322ea74cdf0ad9289cc1
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: e3524503031c73f86a0f3ed0b6c8dd39499f85df47052eca941f455552665b93ff041e5d6df9870cfb95ac1219017a561a483556306905bdc005caf252a5e088
|
|
7
|
+
data.tar.gz: 537da427406ce7c794d5e589e7e82f8c6fbda33a3a4231129905b69171421f41e98563c0496d9c7cc748f675d200729ec52f4d9067a8f7879972922358a2a868
|
data/.eslintrc
CHANGED
|
@@ -1,32 +1,7 @@
|
|
|
1
1
|
{
|
|
2
|
-
"
|
|
3
|
-
"extends": [
|
|
4
|
-
|
|
5
|
-
"
|
|
6
|
-
]
|
|
7
|
-
"env": {
|
|
8
|
-
"browser": true,
|
|
9
|
-
"es6": true,
|
|
10
|
-
"node": true,
|
|
11
|
-
"jasmine": true,
|
|
12
|
-
"jest": true
|
|
13
|
-
},
|
|
14
|
-
"parser": "babel-eslint",
|
|
15
|
-
"rules": {
|
|
16
|
-
"react/jsx-uses-vars": "error",
|
|
17
|
-
"react/jsx-uses-react": "error",
|
|
18
|
-
"no-unused-vars": [
|
|
19
|
-
"error",
|
|
20
|
-
{
|
|
21
|
-
"vars": "all",
|
|
22
|
-
"args": "none"
|
|
23
|
-
}
|
|
24
|
-
],
|
|
25
|
-
"no-underscore-dangle": "off",
|
|
26
|
-
"no-use-before-define": "off",
|
|
27
|
-
"import/prefer-default-export": "off",
|
|
28
|
-
// Import rules off for now due to HoundCI issue
|
|
29
|
-
"import/no-unresolved": "off",
|
|
30
|
-
"import/extensions": "off"
|
|
31
|
-
}
|
|
2
|
+
"plugins": ["@theforeman/foreman"],
|
|
3
|
+
"extends": [
|
|
4
|
+
"plugin:@theforeman/foreman/core",
|
|
5
|
+
"plugin:@theforeman/foreman/plugins"
|
|
6
|
+
]
|
|
32
7
|
}
|
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
name: CI
|
|
2
|
+
on: [pull_request]
|
|
3
|
+
env:
|
|
4
|
+
RAILS_ENV: test
|
|
5
|
+
DATABASE_URL: postgresql://postgres:@localhost/test
|
|
6
|
+
DATABASE_CLEANER_ALLOW_REMOTE_DATABASE_URL: true
|
|
7
|
+
jobs:
|
|
8
|
+
rubocop:
|
|
9
|
+
runs-on: ubuntu-latest
|
|
10
|
+
steps:
|
|
11
|
+
- uses: actions/checkout@v2
|
|
12
|
+
- name: Setup Ruby
|
|
13
|
+
uses: ruby/setup-ruby@v1
|
|
14
|
+
with:
|
|
15
|
+
ruby-version: 2.6
|
|
16
|
+
- name: Setup
|
|
17
|
+
run: |
|
|
18
|
+
gem install bundler
|
|
19
|
+
bundle install --jobs=3 --retry=3
|
|
20
|
+
- name: Run rubocop
|
|
21
|
+
run: bundle exec rubocop
|
|
22
|
+
test_ruby:
|
|
23
|
+
runs-on: ubuntu-latest
|
|
24
|
+
needs: rubocop
|
|
25
|
+
services:
|
|
26
|
+
postgres:
|
|
27
|
+
image: postgres:12.1
|
|
28
|
+
ports: ['5432:5432']
|
|
29
|
+
options: --health-cmd pg_isready --health-interval 10s --health-timeout 5s --health-retries 5
|
|
30
|
+
strategy:
|
|
31
|
+
fail-fast: false
|
|
32
|
+
matrix:
|
|
33
|
+
foreman-core-branch: [2.1-stable, develop]
|
|
34
|
+
ruby-version: [2.5, 2.6]
|
|
35
|
+
node-version: [12]
|
|
36
|
+
steps:
|
|
37
|
+
- run: sudo apt-get install build-essential libcurl4-openssl-dev zlib1g-dev libpq-dev
|
|
38
|
+
- uses: actions/checkout@v2
|
|
39
|
+
with:
|
|
40
|
+
repository: theforeman/foreman
|
|
41
|
+
ref: ${{ matrix.foreman-core-branch }}
|
|
42
|
+
- uses: actions/checkout@v2
|
|
43
|
+
with:
|
|
44
|
+
path: foreman_remote_execution
|
|
45
|
+
- name: Setup Ruby
|
|
46
|
+
uses: ruby/setup-ruby@v1
|
|
47
|
+
with:
|
|
48
|
+
ruby-version: ${{ matrix.ruby-version }}
|
|
49
|
+
- name: Setup Node
|
|
50
|
+
uses: actions/setup-node@v1
|
|
51
|
+
with:
|
|
52
|
+
node-version: ${{ matrix.node-version }}
|
|
53
|
+
- uses: actions/cache@v1
|
|
54
|
+
with:
|
|
55
|
+
path: vendor/bundle
|
|
56
|
+
key: ${{ runner.os }}-fgems-${{ matrix.ruby-version }}-${{ hashFiles('Gemfile.lock') }}
|
|
57
|
+
restore-keys: |
|
|
58
|
+
${{ runner.os }}-fgems-${{ matrix.ruby-version }}-
|
|
59
|
+
- name: Setup Bundler
|
|
60
|
+
run: |
|
|
61
|
+
echo "gem 'foreman_remote_execution', path: './foreman_remote_execution'" > bundler.d/foreman_remote_execution.local.rb
|
|
62
|
+
gem install bundler
|
|
63
|
+
bundle config set without journald development console libvirt
|
|
64
|
+
bundle config set path vendor/bundle
|
|
65
|
+
- name: Prepare test env
|
|
66
|
+
run: |
|
|
67
|
+
bundle install --jobs=3 --retry=3
|
|
68
|
+
bundle exec rake db:create
|
|
69
|
+
bundle exec rake db:migrate
|
|
70
|
+
- name: Run plugin tests
|
|
71
|
+
run: |
|
|
72
|
+
bundle exec rake test:foreman_remote_execution
|
|
73
|
+
bundle exec rake test TEST="test/unit/foreman/access_permissions_test.rb"
|
|
74
|
+
test_js:
|
|
75
|
+
runs-on: ubuntu-latest
|
|
76
|
+
needs: rubocop
|
|
77
|
+
strategy:
|
|
78
|
+
fail-fast: false
|
|
79
|
+
matrix:
|
|
80
|
+
ruby-version: [2.6]
|
|
81
|
+
node-version: [10, 12]
|
|
82
|
+
steps:
|
|
83
|
+
- uses: actions/checkout@v2
|
|
84
|
+
- name: Setup Ruby
|
|
85
|
+
uses: ruby/setup-ruby@v1
|
|
86
|
+
with:
|
|
87
|
+
ruby-version: ${{ matrix.ruby-version }}
|
|
88
|
+
- name: Setup Node
|
|
89
|
+
uses: actions/setup-node@v1
|
|
90
|
+
with:
|
|
91
|
+
node-version: ${{ matrix.node-version }}
|
|
92
|
+
- name: Nmp install
|
|
93
|
+
run: |
|
|
94
|
+
npm install
|
|
95
|
+
- name: Run plugin linter
|
|
96
|
+
run: |
|
|
97
|
+
npm run lint
|
|
98
|
+
- name: Run plugin tests
|
|
99
|
+
run: |
|
|
100
|
+
npm run test
|
data/.gitignore
CHANGED
data/.rubocop_todo.yml
CHANGED
|
@@ -6,6 +6,9 @@
|
|
|
6
6
|
# Note that changes in the inspected code, or installation of new
|
|
7
7
|
# versions of RuboCop, may require this file to be generated again.
|
|
8
8
|
|
|
9
|
+
Minitest/GlobalExpectations:
|
|
10
|
+
Enabled: false
|
|
11
|
+
|
|
9
12
|
# Offense count: 2
|
|
10
13
|
# Cop supports --auto-correct.
|
|
11
14
|
# Configuration parameters: TreatCommentsAsGroupSeparators, Include.
|
data/Gemfile
CHANGED
|
@@ -18,7 +18,17 @@ module Api
|
|
|
18
18
|
|
|
19
19
|
api :GET, '/job_invocations/:id', N_('Show job invocation')
|
|
20
20
|
param :id, :identifier, :required => true
|
|
21
|
+
param :host_status, String, required: false, allow_blank: true, desc: N_('Show Job status for the hosts.')
|
|
21
22
|
def show
|
|
23
|
+
@hosts = @job_invocation.targeting.hosts.authorized(:view_hosts, Host)
|
|
24
|
+
@template_invocations = @job_invocation.template_invocations
|
|
25
|
+
.where(host: @hosts)
|
|
26
|
+
.includes(:input_values)
|
|
27
|
+
|
|
28
|
+
if params[:host_status]
|
|
29
|
+
template_invocations = @template_invocations.includes(:run_host_job_task).to_a
|
|
30
|
+
@host_statuses = Hash[template_invocations.map { |ti| [ti.host_id, template_invocation_status(ti)] }]
|
|
31
|
+
end
|
|
22
32
|
end
|
|
23
33
|
|
|
24
34
|
def_param_group :job_invocation do
|
|
@@ -146,7 +156,7 @@ module Api
|
|
|
146
156
|
end
|
|
147
157
|
|
|
148
158
|
def find_host
|
|
149
|
-
@host =
|
|
159
|
+
@host = @nested_obj.targeting.hosts.authorized(:view_hosts, Host).find(params['host_id'])
|
|
150
160
|
rescue ActiveRecord::RecordNotFound
|
|
151
161
|
not_found({ :error => { :message => (_("Host with id '%{id}' was not found") % { :id => params['host_id'] }) } })
|
|
152
162
|
end
|
|
@@ -204,6 +214,17 @@ module Api
|
|
|
204
214
|
def parent_scope
|
|
205
215
|
resource_class.where(nil)
|
|
206
216
|
end
|
|
217
|
+
|
|
218
|
+
def template_invocation_status(template_invocation)
|
|
219
|
+
task = template_invocation.try(:run_host_job_task)
|
|
220
|
+
parent_task = @job_invocation.task
|
|
221
|
+
|
|
222
|
+
return(parent_task.result == 'cancelled' ? 'cancelled' : 'N/A') if task.nil?
|
|
223
|
+
return task.state if task.state == 'running' || task.state == 'planned'
|
|
224
|
+
return 'error' if task.result == 'warning'
|
|
225
|
+
|
|
226
|
+
task.result
|
|
227
|
+
end
|
|
207
228
|
end
|
|
208
229
|
end
|
|
209
230
|
end
|
|
@@ -26,7 +26,10 @@ module Api
|
|
|
26
26
|
private
|
|
27
27
|
|
|
28
28
|
def resource_scope_for_template_invocations
|
|
29
|
-
@job_invocation.template_invocations
|
|
29
|
+
@job_invocation.template_invocations
|
|
30
|
+
.includes(:host)
|
|
31
|
+
.where(host: Host.authorized(:view_hosts, Host))
|
|
32
|
+
.search_for(*search_options)
|
|
30
33
|
end
|
|
31
34
|
|
|
32
35
|
def find_job_invocation
|
|
@@ -37,6 +37,8 @@ module JobInvocationsChartHelper
|
|
|
37
37
|
_('running %{percent}%%') % {:percent => percent}
|
|
38
38
|
when HostStatus::ExecutionStatus::OK
|
|
39
39
|
_('succeeded')
|
|
40
|
+
when HostStatus::ExecutionStatus::CANCELLED
|
|
41
|
+
_('cancelled')
|
|
40
42
|
when HostStatus::ExecutionStatus::ERROR
|
|
41
43
|
_('failed')
|
|
42
44
|
else
|
|
@@ -29,7 +29,7 @@ module JobInvocationsHelper
|
|
|
29
29
|
end
|
|
30
30
|
|
|
31
31
|
def preview_hosts(template_invocation)
|
|
32
|
-
hosts = template_invocation.targeting.hosts.take(20)
|
|
32
|
+
hosts = template_invocation.targeting.hosts.authorized(:view_hosts, Host).take(20)
|
|
33
33
|
hosts.map do |host|
|
|
34
34
|
collapsed_preview(host) +
|
|
35
35
|
render(:partial => 'job_invocations/user_input',
|
|
@@ -55,4 +55,9 @@ module JobInvocationsHelper
|
|
|
55
55
|
def show_job_location(location)
|
|
56
56
|
location.presence || _('Any Location')
|
|
57
57
|
end
|
|
58
|
+
|
|
59
|
+
def input_safe_value(input)
|
|
60
|
+
template_input = input.template_input
|
|
61
|
+
template_input.respond_to?(:hidden_value) && template_input.hidden_value ? '*' * 5 : input.value
|
|
62
|
+
end
|
|
58
63
|
end
|
|
@@ -13,40 +13,36 @@ module RemoteExecutionHelper
|
|
|
13
13
|
end
|
|
14
14
|
end
|
|
15
15
|
|
|
16
|
-
def template_invocation_status(task)
|
|
17
|
-
if task.nil?
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
icon_text('build', _('planned'), :kind => 'pficon')
|
|
23
|
-
else
|
|
24
|
-
case task.result
|
|
25
|
-
when 'warning', 'error'
|
|
26
|
-
icon_text('error-circle-o', _('failed'), :kind => 'pficon')
|
|
27
|
-
when 'cancelled'
|
|
28
|
-
icon_text('warning-triangle-o', _('cancelled'), :kind => 'pficon')
|
|
29
|
-
when 'success'
|
|
30
|
-
icon_text('ok', _('success'), :kind => 'pficon')
|
|
31
|
-
else
|
|
32
|
-
task.result
|
|
33
|
-
end
|
|
34
|
-
end
|
|
16
|
+
def template_invocation_status(task, parent_task)
|
|
17
|
+
return(parent_task.result == 'cancelled' ? _('cancelled') : 'N/A') if task.nil?
|
|
18
|
+
return task.state if task.state == 'running' || task.state == 'planned'
|
|
19
|
+
return _('error') if task.result == 'warning'
|
|
20
|
+
|
|
21
|
+
task.result
|
|
35
22
|
end
|
|
36
23
|
|
|
37
24
|
def template_invocation_actions(task, host, job_invocation, template_invocation)
|
|
25
|
+
links = []
|
|
38
26
|
host_task = template_invocation.try(:run_host_job_task)
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
27
|
+
|
|
28
|
+
if authorized_for(hash_for_host_path(host).merge(auth_object: host, permission: :view_hosts, authorizer: job_hosts_authorizer))
|
|
29
|
+
links << { title: _('Host detail'),
|
|
30
|
+
action: { href: host_path(host), 'data-method': 'get', id: "#{host.name}-actions-detail" } }
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
if authorized_for(hash_for_rerun_job_invocation_path(id: job_invocation, host_ids: [ host.id ], authorizer: job_hosts_authorizer))
|
|
34
|
+
links << { title: (_('Rerun on %s') % host.name),
|
|
35
|
+
action: { href: rerun_job_invocation_path(job_invocation, host_ids: [ host.id ]),
|
|
36
|
+
'data-method': 'get', id: "#{host.name}-actions-rerun" } }
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
if host_task.present? && authorized_for(hash_for_foreman_tasks_task_path(host_task).merge(auth_object: host_task, permission: :view_foreman_tasks))
|
|
40
|
+
links << { title: _('Host task'),
|
|
41
|
+
action: { href: foreman_tasks_task_path(host_task),
|
|
42
|
+
'data-method': 'get', id: "#{host.name}-actions-task" } }
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
links
|
|
50
46
|
end
|
|
51
47
|
|
|
52
48
|
def remote_execution_provider_for(template_invocation)
|
|
@@ -233,4 +229,17 @@ module RemoteExecutionHelper
|
|
|
233
229
|
|
|
234
230
|
task.execution_plan.actions[1].try(:input).try(:[], 'script')
|
|
235
231
|
end
|
|
232
|
+
|
|
233
|
+
def targeting_hosts(job_invocation, hosts)
|
|
234
|
+
hosts.map do |host|
|
|
235
|
+
template_invocation = job_invocation.template_invocations.find { |template_inv| template_inv.host_id == host.id }
|
|
236
|
+
task = template_invocation.try(:run_host_job_task)
|
|
237
|
+
link_authorized = !task.nil? && authorized_for(hash_for_template_invocation_path(:id => template_invocation).merge(:auth_object => host, :permission => :view_hosts, :authorizer => job_hosts_authorizer))
|
|
238
|
+
|
|
239
|
+
{ name: host.name,
|
|
240
|
+
link: link_authorized ? template_invocation_path(:id => template_invocation) : '',
|
|
241
|
+
status: template_invocation_status(task, job_invocation.task),
|
|
242
|
+
actions: template_invocation_actions(task, host, job_invocation, template_invocation) }
|
|
243
|
+
end
|
|
244
|
+
end
|
|
236
245
|
end
|
|
@@ -29,6 +29,9 @@ module Actions
|
|
|
29
29
|
|
|
30
30
|
raise _('Could not use any template used in the job invocation') if template_invocation.blank?
|
|
31
31
|
|
|
32
|
+
provider = template_invocation.template.provider
|
|
33
|
+
proxy_selector = provider.required_proxy_selector_for(template_invocation.template) || proxy_selector
|
|
34
|
+
|
|
32
35
|
provider_type = template_invocation.template.provider_type.to_s
|
|
33
36
|
proxy = determine_proxy!(proxy_selector, provider_type, host)
|
|
34
37
|
|
|
@@ -36,8 +39,6 @@ module Actions
|
|
|
36
39
|
script = renderer.render
|
|
37
40
|
raise _('Failed rendering template: %s') % renderer.error_message unless script
|
|
38
41
|
|
|
39
|
-
provider = template_invocation.template.provider
|
|
40
|
-
|
|
41
42
|
additional_options = { :hostname => provider.find_ip_or_hostname(host),
|
|
42
43
|
:script => script,
|
|
43
44
|
:execution_timeout_interval => job_invocation.execution_timeout_interval,
|
|
@@ -10,5 +10,11 @@ module ::ProxyAPI
|
|
|
10
10
|
rescue => e
|
|
11
11
|
raise ProxyException.new(url, e, N_('Unable to fetch public key'))
|
|
12
12
|
end
|
|
13
|
+
|
|
14
|
+
def drop_from_known_hosts(hostname)
|
|
15
|
+
delete('known_hosts/' + hostname)
|
|
16
|
+
rescue => e
|
|
17
|
+
raise ProxyException.new(url, e, N_('Unable to remove host from known hosts'))
|
|
18
|
+
end
|
|
13
19
|
end
|
|
14
20
|
end
|
|
@@ -49,7 +49,7 @@ module ForemanRemoteExecution
|
|
|
49
49
|
keys = remote_execution_ssh_keys
|
|
50
50
|
source = 'global'
|
|
51
51
|
if keys.present?
|
|
52
|
-
value, safe_value = params.fetch('remote_execution_ssh_keys', {}).values_at(:value, :safe_value).map { |v| v
|
|
52
|
+
value, safe_value = params.fetch('remote_execution_ssh_keys', {}).values_at(:value, :safe_value).map { |v| [v].flatten.compact }
|
|
53
53
|
params['remote_execution_ssh_keys'] = {:value => value + keys, :safe_value => safe_value + keys, :source => source}
|
|
54
54
|
end
|
|
55
55
|
[:remote_execution_ssh_user, :remote_execution_effective_user_method,
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
module ForemanRemoteExecution
|
|
2
|
+
module Orchestration::SSH
|
|
3
|
+
extend ActiveSupport::Concern
|
|
4
|
+
|
|
5
|
+
included do
|
|
6
|
+
before_destroy :ssh_destroy
|
|
7
|
+
after_validation :queue_ssh_destroy
|
|
8
|
+
register_rebuild(:queue_ssh_destroy, N_("SSH_#{self.to_s.split('::').first}"))
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
def drop_from_known_hosts(proxy_id)
|
|
12
|
+
_, _, target = host_kind_target
|
|
13
|
+
return true if target.nil?
|
|
14
|
+
|
|
15
|
+
proxy = ::SmartProxy.find(proxy_id)
|
|
16
|
+
begin
|
|
17
|
+
proxy.drop_host_from_known_hosts(target)
|
|
18
|
+
rescue RestClient::ResourceNotFound => e
|
|
19
|
+
# ignore 404 when known_hosts entry is missing or the module was not enabled
|
|
20
|
+
Foreman::Logging.exception "Proxy failed to delete SSH known_hosts for #{name}, #{ip}", e, :level => :error
|
|
21
|
+
rescue => e
|
|
22
|
+
Rails.logger.warn e.message
|
|
23
|
+
return false
|
|
24
|
+
end
|
|
25
|
+
true
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
def ssh_destroy
|
|
29
|
+
logger.debug "Scheduling SSH known_hosts cleanup"
|
|
30
|
+
|
|
31
|
+
host, _kind, _target = host_kind_target
|
|
32
|
+
proxies = host.remote_execution_proxies('SSH').values
|
|
33
|
+
proxies.flatten.uniq.each do |proxy|
|
|
34
|
+
queue.create(id: queue_id(proxy.id), name: _("Remove SSH known hosts for %s") % self,
|
|
35
|
+
priority: 200, action: [self, :drop_from_known_hosts, proxy.id])
|
|
36
|
+
end
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
def queue_ssh_destroy
|
|
40
|
+
should_drop_from_known_hosts? && ssh_destroy
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
def should_drop_from_known_hosts?
|
|
44
|
+
host, = host_kind_target
|
|
45
|
+
host && !host.new_record? && host.build && host.changes.key?('build')
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
private
|
|
49
|
+
|
|
50
|
+
def host_kind_target
|
|
51
|
+
if self.is_a?(::Host::Base)
|
|
52
|
+
[self, 'host', name]
|
|
53
|
+
else
|
|
54
|
+
[self.host, 'interface', ip]
|
|
55
|
+
end
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
def queue_id(proxy_id)
|
|
59
|
+
_, kind, id = host_kind_target
|
|
60
|
+
"ssh_remove_known_hosts_#{kind}_#{id}_#{proxy_id}"
|
|
61
|
+
end
|
|
62
|
+
end
|
|
63
|
+
end
|