foreman_remote_execution 1.8.4 → 2.0.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.rubocop.yml +2 -0
- data/app/assets/stylesheets/foreman_remote_execution/job_invocations.css.scss +23 -0
- data/app/controllers/api/v2/job_templates_controller.rb +1 -0
- data/app/helpers/remote_execution_helper.rb +10 -10
- data/app/lib/actions/remote_execution/run_host_job.rb +9 -5
- data/app/models/concerns/foreman_remote_execution/host_extensions.rb +1 -1
- data/app/models/job_template.rb +2 -2
- data/app/models/remote_execution_provider.rb +4 -0
- data/app/models/setting/remote_execution.rb +65 -74
- data/app/models/ssh_execution_provider.rb +8 -1
- data/app/views/api/v2/job_templates/main.json.rabl +1 -1
- data/config/routes.rb +6 -10
- data/db/seeds.d/70-job_templates.rb +2 -2
- data/lib/foreman_remote_execution/engine.rb +1 -1
- data/lib/foreman_remote_execution/version.rb +1 -1
- data/package.json +2 -2
- data/test/factories/foreman_remote_execution_factories.rb +2 -2
- data/test/unit/actions/run_host_job_test.rb +35 -4
- data/test/unit/concerns/host_extensions_test.rb +0 -6
- data/test/unit/remote_execution_provider_test.rb +3 -1
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 766047d4727a67b60506ac42744f41cf0f70782e5b0a7d6bc2d0f44d2529fd44
|
4
|
+
data.tar.gz: bb9469b1b90526a88b596b5fb4b7f6e96210bd33d4050123bfca218b691527f0
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: cecd364c6bc6147a10dd6c9d5414e6d7e069caad3eab0b5fdec6633ced750c30cbf5787797ee84397fda682665d4dad964302fc1adfce9deb871504f10638b3f
|
7
|
+
data.tar.gz: 95bd2381ac1b1e4ecb1854536474939d4c21724a9db7859d4efe223386510fbda7704450b7e3c3c8e90a1ee77bdf54022c57b3e7dd56307c5969178ec5f54636
|
data/.rubocop.yml
CHANGED
@@ -6,3 +6,26 @@ div.infoblock {
|
|
6
6
|
margin-top: 5px;
|
7
7
|
}
|
8
8
|
}
|
9
|
+
|
10
|
+
#title_action {
|
11
|
+
.button_to {
|
12
|
+
display: inline-block;
|
13
|
+
}
|
14
|
+
|
15
|
+
.btn-toolbar {
|
16
|
+
.button_to {
|
17
|
+
float: left;
|
18
|
+
}
|
19
|
+
}
|
20
|
+
|
21
|
+
.btn-group {
|
22
|
+
.btn + .button_to,
|
23
|
+
.button_to + .button_to {
|
24
|
+
margin-left: -1px;
|
25
|
+
}
|
26
|
+
|
27
|
+
.button_to:not(:first-child):not(:last-child) .btn {
|
28
|
+
border-radius: 0;
|
29
|
+
}
|
30
|
+
}
|
31
|
+
}
|
@@ -47,6 +47,7 @@ module Api
|
|
47
47
|
def_param_group :job_template do
|
48
48
|
param :job_template, Hash, :required => true, :action_aware => true do
|
49
49
|
param :name, String, :required => true, :desc => N_('Template name')
|
50
|
+
param :description, String
|
50
51
|
param :job_category, String, :required => true, :desc => N_('Job category')
|
51
52
|
param :description_format, String, :required => false, :desc => N_('This template is used to generate the description. ' +
|
52
53
|
'Input values can be used using the syntax %{package}. ' +
|
@@ -83,16 +83,16 @@ module RemoteExecutionHelper
|
|
83
83
|
:title => _('See the last task details'))
|
84
84
|
end
|
85
85
|
if authorized_for(:permission => :cancel_job_invocations, :auth_object => job_invocation)
|
86
|
-
buttons <<
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
buttons <<
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
86
|
+
buttons << button_to(_('Cancel Job'), cancel_job_invocation_path(job_invocation),
|
87
|
+
:class => 'btn btn-danger',
|
88
|
+
:title => _('Try to cancel the job'),
|
89
|
+
:disabled => !task.cancellable?,
|
90
|
+
:method => :post)
|
91
|
+
buttons << button_to(_('Abort Job'), cancel_job_invocation_path(job_invocation, :force => true),
|
92
|
+
:class => 'btn btn-danger',
|
93
|
+
:title => _('Try to abort the job without waiting for the results from the remote hosts'),
|
94
|
+
:disabled => !task.cancellable?,
|
95
|
+
:method => :post)
|
96
96
|
end
|
97
97
|
return buttons
|
98
98
|
end
|
@@ -38,14 +38,10 @@ module Actions
|
|
38
38
|
|
39
39
|
provider = template_invocation.template.provider
|
40
40
|
|
41
|
-
secrets = { :ssh_password => job_invocation.password || provider.ssh_password(host),
|
42
|
-
:key_passphrase => job_invocation.key_passphrase || provider.ssh_key_passphrase(host),
|
43
|
-
:sudo_password => job_invocation.sudo_password || provider.sudo_password(host) }
|
44
|
-
|
45
41
|
additional_options = { :hostname => provider.find_ip_or_hostname(host),
|
46
42
|
:script => script,
|
47
43
|
:execution_timeout_interval => job_invocation.execution_timeout_interval,
|
48
|
-
:secrets => secrets,
|
44
|
+
:secrets => secrets(host, job_invocation, provider),
|
49
45
|
:use_batch_triggering => true}
|
50
46
|
action_options = provider.proxy_command_options(template_invocation, host)
|
51
47
|
.merge(additional_options)
|
@@ -59,6 +55,14 @@ module Actions
|
|
59
55
|
check_exit_status
|
60
56
|
end
|
61
57
|
|
58
|
+
def secrets(host, job_invocation, provider)
|
59
|
+
job_secrets = { :ssh_password => job_invocation.password,
|
60
|
+
:key_passphrase => job_invocation.key_passphrase,
|
61
|
+
:sudo_password => job_invocation.sudo_password }
|
62
|
+
|
63
|
+
job_secrets.merge(provider.secrets(host)) { |_key, job_secret, provider_secret| job_secret || provider_secret }
|
64
|
+
end
|
65
|
+
|
62
66
|
def check_exit_status
|
63
67
|
error! ForemanTasks::Task::TaskCancelledException.new(_('Task cancelled')) if delegated_action && delegated_action.output[:cancel_sent]
|
64
68
|
error! _('Job execution failed') if exit_status.to_s != '0'
|
@@ -71,7 +71,7 @@ module ForemanRemoteExecution
|
|
71
71
|
proxies[:fallback] = smart_proxies.with_features(provider) if Setting[:remote_execution_fallback_proxy]
|
72
72
|
|
73
73
|
if Setting[:remote_execution_global_proxy]
|
74
|
-
proxy_scope = if
|
74
|
+
proxy_scope = if User.current.present?
|
75
75
|
::SmartProxy.with_taxonomy_scope_override(location, organization)
|
76
76
|
else
|
77
77
|
::SmartProxy.unscoped
|
data/app/models/job_template.rb
CHANGED
@@ -119,8 +119,8 @@ class JobTemplate < ::Template
|
|
119
119
|
|
120
120
|
def assign_taxonomies
|
121
121
|
if default
|
122
|
-
organizations << Organization.all
|
123
|
-
locations << Location.all
|
122
|
+
organizations << Organization.all
|
123
|
+
locations << Location.all
|
124
124
|
end
|
125
125
|
end
|
126
126
|
|
@@ -3,80 +3,71 @@ class Setting::RemoteExecution < Setting
|
|
3
3
|
::Setting::BLANK_ATTRS.concat %w{remote_execution_ssh_password remote_execution_ssh_key_passphrase remote_execution_sudo_password remote_execution_cockpit_url}
|
4
4
|
|
5
5
|
# rubocop:disable Metrics/MethodLength,Metrics/AbcSize
|
6
|
-
def self.
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
self.set('remote_execution_cockpit_url',
|
72
|
-
N_('Where to find the Cockpit instance for the Web Console button. By default, no button is shown.'),
|
73
|
-
nil,
|
74
|
-
N_('Cockpit URL'),
|
75
|
-
nil)
|
76
|
-
].each { |s| self.create! s.update(:category => 'Setting::RemoteExecution') }
|
77
|
-
end
|
78
|
-
|
79
|
-
true
|
6
|
+
def self.default_settings
|
7
|
+
[
|
8
|
+
self.set('remote_execution_fallback_proxy',
|
9
|
+
N_('Search the host for any proxy with Remote Execution, useful when the host has no subnet or the subnet does not have an execution proxy'),
|
10
|
+
false,
|
11
|
+
N_('Fallback to Any Proxy')),
|
12
|
+
self.set('remote_execution_global_proxy',
|
13
|
+
N_('Search for remote execution proxy outside of the proxies assigned to the host. ' +
|
14
|
+
"The search will be limited to the host's organization and location."),
|
15
|
+
true,
|
16
|
+
N_('Enable Global Proxy')),
|
17
|
+
self.set('remote_execution_ssh_user',
|
18
|
+
N_('Default user to use for SSH. You may override per host by setting a parameter called remote_execution_ssh_user.'),
|
19
|
+
'root',
|
20
|
+
N_('SSH User')),
|
21
|
+
self.set('remote_execution_effective_user',
|
22
|
+
N_('Default user to use for executing the script. If the user differs from the SSH user, su or sudo is used to switch the user.'),
|
23
|
+
'root',
|
24
|
+
N_('Effective User')),
|
25
|
+
self.set('remote_execution_effective_user_method',
|
26
|
+
N_('What command should be used to switch to the effective user. One of %s') % SSHExecutionProvider::EFFECTIVE_USER_METHODS.inspect,
|
27
|
+
'sudo',
|
28
|
+
N_('Effective User Method'),
|
29
|
+
nil,
|
30
|
+
{ :collection => proc { Hash[SSHExecutionProvider::EFFECTIVE_USER_METHODS.map { |method| [method, method] }] } }),
|
31
|
+
self.set('remote_execution_sudo_password', N_("Sudo password"), '', N_("Sudo password"), nil, {:encrypted => true}),
|
32
|
+
self.set('remote_execution_sync_templates',
|
33
|
+
N_('Whether we should sync templates from disk when running db:seed.'),
|
34
|
+
true,
|
35
|
+
N_('Sync Job Templates')),
|
36
|
+
self.set('remote_execution_ssh_port',
|
37
|
+
N_('Port to use for SSH communication. Default port 22. You may override per host by setting a parameter called remote_execution_ssh_port.'),
|
38
|
+
'22',
|
39
|
+
N_('SSH Port')),
|
40
|
+
self.set('remote_execution_connect_by_ip',
|
41
|
+
N_('Should the ip addresses on host interfaces be preferred over the fqdn? '\
|
42
|
+
'It is useful, when DNS not resolving the fqdns properly. You may override this per host by setting a parameter called remote_execution_connect_by_ip.'),
|
43
|
+
false,
|
44
|
+
N_('Connect by IP')),
|
45
|
+
self.set('remote_execution_ssh_password',
|
46
|
+
N_('Default password to use for SSH. You may override per host by setting a parameter called remote_execution_ssh_password'),
|
47
|
+
nil,
|
48
|
+
N_('Default SSH password'),
|
49
|
+
nil,
|
50
|
+
{ :encrypted => true }),
|
51
|
+
self.set('remote_execution_ssh_key_passphrase',
|
52
|
+
N_('Default key passphrase to use for SSH. You may override per host by setting a parameter called remote_execution_ssh_key_passphrase'),
|
53
|
+
nil,
|
54
|
+
N_('Default SSH key passphrase'),
|
55
|
+
nil,
|
56
|
+
{ :encrypted => true }),
|
57
|
+
self.set('remote_execution_workers_pool_size',
|
58
|
+
N_('Amount of workers in the pool to handle the execution of the remote execution jobs. Restart of the dynflowd/foreman-tasks service is required.'),
|
59
|
+
5,
|
60
|
+
N_('Workers pool size')),
|
61
|
+
self.set('remote_execution_cleanup_working_dirs',
|
62
|
+
N_('When enabled, working directories will be removed after task completion. You may override this per host by setting a parameter called remote_execution_cleanup_working_dirs.'),
|
63
|
+
true,
|
64
|
+
N_('Cleanup working directories')),
|
65
|
+
self.set('remote_execution_cockpit_url',
|
66
|
+
N_('Where to find the Cockpit instance for the Web Console button. By default, no button is shown.'),
|
67
|
+
nil,
|
68
|
+
N_('Cockpit URL'),
|
69
|
+
nil)
|
70
|
+
]
|
80
71
|
end
|
81
72
|
# rubocop:enable AbcSize
|
82
73
|
# rubocop:enable Metrics/MethodLength,Metrics/AbcSize
|
@@ -5,7 +5,6 @@ class SSHExecutionProvider < RemoteExecutionProvider
|
|
5
5
|
:effective_user => effective_user(template_invocation),
|
6
6
|
:effective_user_method => effective_user_method(host),
|
7
7
|
:cleanup_working_dirs => cleanup_working_dirs?(host),
|
8
|
-
:sudo_password => sudo_password(host),
|
9
8
|
:ssh_port => ssh_port(host))
|
10
9
|
end
|
11
10
|
|
@@ -29,6 +28,14 @@ class SSHExecutionProvider < RemoteExecutionProvider
|
|
29
28
|
'ssh'
|
30
29
|
end
|
31
30
|
|
31
|
+
def secrets(host)
|
32
|
+
{
|
33
|
+
:ssh_password => ssh_password(host),
|
34
|
+
:key_passphrase => ssh_key_passphrase(host),
|
35
|
+
:sudo_password => sudo_password(host)
|
36
|
+
}
|
37
|
+
end
|
38
|
+
|
32
39
|
def ssh_params(host)
|
33
40
|
proxy_selector = ::RemoteExecutionProxySelector.new
|
34
41
|
proxy = proxy_selector.determine_proxy(host, 'SSH')
|
@@ -2,7 +2,7 @@ object @job_template
|
|
2
2
|
|
3
3
|
extends 'api/v2/job_templates/base'
|
4
4
|
|
5
|
-
attributes :audit_comment, :description_format, :created_at, :updated_at, :template, :locked
|
5
|
+
attributes :description, :audit_comment, :description_format, :created_at, :updated_at, :template, :locked
|
6
6
|
|
7
7
|
child :template_inputs do
|
8
8
|
extends 'api/v2/template_inputs/base'
|
data/config/routes.rb
CHANGED
@@ -58,8 +58,8 @@ Rails.application.routes.draw do
|
|
58
58
|
end
|
59
59
|
|
60
60
|
resources :job_templates, :except => [:new, :edit] do
|
61
|
-
|
62
|
-
|
61
|
+
resources :locations, :only => [:index, :show]
|
62
|
+
resources :organizations, :only => [:index, :show]
|
63
63
|
get :export, :on => :member
|
64
64
|
post :clone, :on => :member
|
65
65
|
collection do
|
@@ -68,16 +68,12 @@ Rails.application.routes.draw do
|
|
68
68
|
end
|
69
69
|
end
|
70
70
|
|
71
|
-
|
72
|
-
resources :
|
73
|
-
resources :job_templates, :only => [:index, :show]
|
74
|
-
end
|
71
|
+
resources :organizations, :only => [:index] do
|
72
|
+
resources :job_templates, :only => [:index, :show]
|
75
73
|
end
|
76
74
|
|
77
|
-
|
78
|
-
resources :
|
79
|
-
resources :job_templates, :only => [:index, :show]
|
80
|
-
end
|
75
|
+
resources :locations, :only => [:index] do
|
76
|
+
resources :job_templates, :only => [:index, :show]
|
81
77
|
end
|
82
78
|
|
83
79
|
resources :templates, :only => :none do
|
@@ -5,8 +5,8 @@ User.as_anonymous_admin do
|
|
5
5
|
Dir[File.join("#{ForemanRemoteExecution::Engine.root}/app/views/templates/**/*.erb")].each do |template|
|
6
6
|
sync = !Rails.env.test? && Setting[:remote_execution_sync_templates]
|
7
7
|
template = JobTemplate.import_raw!(File.read(template), :default => true, :locked => true, :update => sync)
|
8
|
-
template.organizations = organizations if
|
9
|
-
template.locations = locations if
|
8
|
+
template.organizations = organizations if template.present?
|
9
|
+
template.locations = locations if template.present?
|
10
10
|
end
|
11
11
|
end
|
12
12
|
end
|
@@ -34,7 +34,7 @@ module ForemanRemoteExecution
|
|
34
34
|
|
35
35
|
initializer 'foreman_remote_execution.register_plugin', before: :finisher_hook do |_app|
|
36
36
|
Foreman::Plugin.register :foreman_remote_execution do
|
37
|
-
requires_foreman '>= 1.
|
37
|
+
requires_foreman '>= 1.24'
|
38
38
|
|
39
39
|
apipie_documented_controllers ["#{ForemanRemoteExecution::Engine.root}/app/controllers/api/v2/*.rb"]
|
40
40
|
|
data/package.json
CHANGED
@@ -31,7 +31,7 @@
|
|
31
31
|
"url": "http://projects.theforeman.org/projects/foreman_remote_execution/issues"
|
32
32
|
},
|
33
33
|
"devDependencies": {
|
34
|
-
"@theforeman/vendor-dev": "^
|
34
|
+
"@theforeman/vendor-dev": "^1.4.0",
|
35
35
|
"babel-eslint": "^8.2.1",
|
36
36
|
"babel-plugin-lodash": "^3.3.2",
|
37
37
|
"babel-plugin-transform-class-properties": "^6.24.1",
|
@@ -51,6 +51,6 @@
|
|
51
51
|
"jest": "^21.2.1"
|
52
52
|
},
|
53
53
|
"dependencies": {
|
54
|
-
"@theforeman/vendor": "^
|
54
|
+
"@theforeman/vendor": "^1.4.0"
|
55
55
|
}
|
56
56
|
}
|
@@ -4,8 +4,8 @@ FactoryBot.define do
|
|
4
4
|
sequence(:job_category) { |n| "Job name #{n}" }
|
5
5
|
template { 'id' }
|
6
6
|
provider_type { 'SSH' }
|
7
|
-
organizations { [Organization.find_by(name: 'Organization 1')] }
|
8
|
-
locations { [Location.find_by(name: 'Location 1')] }
|
7
|
+
organizations { [Organization.find_by(name: 'Organization 1')] }
|
8
|
+
locations { [Location.find_by(name: 'Location 1')] }
|
9
9
|
|
10
10
|
trait :with_input do
|
11
11
|
after(:build) do |template, evaluator|
|
@@ -5,14 +5,45 @@ module ForemanRemoteExecution
|
|
5
5
|
include Dynflow::Testing
|
6
6
|
|
7
7
|
subject { create_action(Actions::RemoteExecution::RunHostJob) }
|
8
|
-
let(:host) { FactoryBot.create(:host, :with_execution) }
|
9
8
|
|
10
|
-
|
11
|
-
|
12
|
-
|
9
|
+
describe '#secrets' do
|
10
|
+
let(:job_invocation) { FactoryBot.create(:job_invocation, :with_task) }
|
11
|
+
let(:host) { job_invocation.template_invocations.first.host }
|
12
|
+
let(:provider) do
|
13
|
+
provider = ::SSHExecutionProvider
|
14
|
+
provider.expects(:ssh_password).with(host).returns('sshpass')
|
15
|
+
provider.expects(:sudo_password).with(host).returns('sudopass')
|
16
|
+
provider.expects(:ssh_key_passphrase).with(host).returns('keypass')
|
17
|
+
provider
|
18
|
+
end
|
19
|
+
|
20
|
+
it 'uses provider secrets' do
|
21
|
+
secrets = subject.secrets(host, job_invocation, provider)
|
22
|
+
|
23
|
+
assert_equal 'sshpass', secrets[:ssh_password]
|
24
|
+
assert_equal 'sudopass', secrets[:sudo_password]
|
25
|
+
assert_equal 'keypass', secrets[:key_passphrase]
|
26
|
+
end
|
27
|
+
|
28
|
+
it 'prefers job secrets over provider secrets' do
|
29
|
+
job_invocation.password = 'jobsshpass'
|
30
|
+
job_invocation.key_passphrase = 'jobkeypass'
|
31
|
+
secrets = subject.secrets(host, job_invocation, provider)
|
32
|
+
|
33
|
+
assert_equal 'jobsshpass', secrets[:ssh_password]
|
34
|
+
assert_equal 'sudopass', secrets[:sudo_password]
|
35
|
+
assert_equal 'jobkeypass', secrets[:key_passphrase]
|
36
|
+
end
|
13
37
|
end
|
14
38
|
|
15
39
|
describe '#finalize' do
|
40
|
+
let(:host) { FactoryBot.create(:host, :with_execution) }
|
41
|
+
|
42
|
+
before do
|
43
|
+
subject.stubs(:input).returns({ host: { id: host.id } })
|
44
|
+
Host.expects(:find).with(host.id).returns(host)
|
45
|
+
end
|
46
|
+
|
16
47
|
describe 'updates the host status' do
|
17
48
|
before do
|
18
49
|
subject.expects(:check_exit_status).returns(nil)
|
@@ -158,12 +158,6 @@ class ForemanRemoteExecutionHostExtensionsTest < ActiveSupport::TestCase
|
|
158
158
|
host.remote_execution_proxies(provider)[:global].must_include proxy_in_taxonomies
|
159
159
|
host.remote_execution_proxies(provider)[:global].wont_include proxy_no_taxonomies
|
160
160
|
end
|
161
|
-
|
162
|
-
it 'returns all proxies when there\'s no taxonomies' do
|
163
|
-
Taxonomy.stubs(:enabled_taxonomies).returns([])
|
164
|
-
host.remote_execution_proxies(provider)[:global].must_include proxy_in_taxonomies
|
165
|
-
host.remote_execution_proxies(provider)[:global].must_include proxy_no_taxonomies
|
166
|
-
end
|
167
161
|
end
|
168
162
|
|
169
163
|
context 'disabled' do
|
@@ -62,6 +62,7 @@ class RemoteExecutionProviderTest < ActiveSupport::TestCase
|
|
62
62
|
let(:template_invocation) { job_invocation.pattern_template_invocations.first }
|
63
63
|
let(:host) { FactoryBot.create(:host) }
|
64
64
|
let(:proxy_options) { SSHExecutionProvider.proxy_command_options(template_invocation, host) }
|
65
|
+
let(:secrets) { SSHExecutionProvider.secrets(host) }
|
65
66
|
|
66
67
|
describe 'effective user' do
|
67
68
|
it 'takes the effective user from value from the template invocation' do
|
@@ -81,7 +82,8 @@ class RemoteExecutionProviderTest < ActiveSupport::TestCase
|
|
81
82
|
it 'uses the remote_execution_sudo_password on the host param' do
|
82
83
|
host.params['remote_execution_sudo_password'] = 'mypassword'
|
83
84
|
host.host_parameters << FactoryBot.create(:host_parameter, :host => host, :name => 'remote_execution_sudo_password', :value => 'mypassword')
|
84
|
-
proxy_options
|
85
|
+
assert_not proxy_options.key?(:sudo_password)
|
86
|
+
secrets[:sudo_password].must_equal 'mypassword'
|
85
87
|
end
|
86
88
|
end
|
87
89
|
|
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:
|
4
|
+
version: 2.0.0
|
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: 2019-
|
11
|
+
date: 2019-10-04 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: deface
|