foreman_remote_execution 3.3.5 → 4.2.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.github/workflows/ci.yml +1 -1
- data/app/controllers/api/v2/job_invocations_controller.rb +20 -2
- data/app/controllers/foreman_remote_execution/concerns/api/v2/registration_controller_extensions.rb +26 -0
- data/app/controllers/foreman_remote_execution/concerns/api/v2/subnets_controller_extensions.rb +21 -0
- data/app/controllers/job_invocations_controller.rb +22 -8
- data/app/controllers/job_templates_controller.rb +1 -1
- data/app/helpers/job_invocations_helper.rb +3 -2
- data/app/lib/actions/remote_execution/run_host_job.rb +1 -1
- data/app/lib/actions/remote_execution/run_hosts_job.rb +12 -3
- data/app/lib/foreman_remote_execution/renderer/scope/input.rb +35 -0
- data/app/models/concerns/api/v2/interfaces_controller_extensions.rb +13 -0
- data/app/models/concerns/foreman_remote_execution/host_extensions.rb +38 -14
- data/app/models/job_invocation.rb +12 -4
- data/app/models/job_invocation_composer.rb +2 -2
- data/app/models/remote_execution_feature.rb +5 -2
- data/app/models/remote_execution_provider.rb +8 -3
- data/app/models/setting/remote_execution.rb +2 -2
- data/app/models/ssh_execution_provider.rb +1 -1
- data/app/services/remote_execution_proxy_selector.rb +3 -0
- data/app/views/api/v2/interfaces/execution_flag.json.rabl +1 -0
- data/app/views/api/v2/job_invocations/base.json.rabl +1 -0
- data/app/views/api/v2/job_invocations/main.json.rabl +2 -2
- data/app/views/api/v2/registration/_form.html.erb +12 -0
- data/app/views/api/v2/subnets/remote_execution_proxies.json.rabl +3 -0
- data/app/views/job_invocations/_form.html.erb +1 -1
- data/app/views/job_invocations/_tab_hosts.html.erb +1 -20
- data/app/views/job_invocations/_tab_overview.html.erb +13 -1
- data/app/views/job_invocations/show.html.erb +3 -0
- data/app/views/job_invocations/show.json.erb +2 -1
- data/app/views/template_invocations/_output_line_set.html.erb +1 -1
- data/app/views/templates/ssh/package_action.erb +1 -0
- data/config/routes.rb +1 -0
- data/db/migrate/20200623073022_rename_sudo_password_to_effective_user_password.rb +34 -0
- data/db/migrate/20200820122057_add_proxy_selector_override_to_remote_execution_feature.rb +5 -0
- data/db/seeds.d/20-permissions.rb +9 -0
- data/lib/foreman_remote_execution/engine.rb +28 -2
- data/lib/foreman_remote_execution/version.rb +1 -1
- data/package.json +6 -6
- data/test/functional/api/v2/job_invocations_controller_test.rb +84 -2
- data/test/functional/api/v2/registration_controller_test.rb +82 -0
- data/test/functional/job_invocations_controller_test.rb +71 -0
- data/test/support/remote_execution_helper.rb +5 -0
- data/test/unit/actions/run_host_job_test.rb +3 -3
- data/test/unit/actions/run_hosts_job_test.rb +3 -2
- data/test/unit/job_invocation_composer_test.rb +5 -5
- data/test/unit/remote_execution_provider_test.rb +6 -6
- data/webpack/__mocks__/foremanReact/components/Pagination/PaginationWrapper.js +2 -0
- data/webpack/__mocks__/foremanReact/components/SearchBar.js +2 -0
- data/webpack/__mocks__/foremanReact/constants.js +21 -0
- data/webpack/__mocks__/foremanReact/redux/API/APISelectors.js +2 -0
- data/webpack/__mocks__/foremanReact/redux/middlewares/IntervalMiddleware/IntervalSelectors.js +1 -0
- data/webpack/react_app/components/TargetingHosts/TargetingHosts.js +25 -15
- data/webpack/react_app/components/TargetingHosts/TargetingHostsHelpers.js +10 -0
- data/webpack/react_app/components/TargetingHosts/TargetingHostsPage.js +66 -0
- data/webpack/react_app/components/TargetingHosts/TargetingHostsPage.scss +6 -0
- data/webpack/react_app/components/TargetingHosts/TargetingHostsSelectors.js +10 -2
- data/webpack/react_app/components/TargetingHosts/__tests__/TargetingHostsPage.test.js +9 -0
- data/webpack/react_app/components/TargetingHosts/__tests__/TargetingHostsSelectors.test.js +26 -0
- data/webpack/react_app/components/TargetingHosts/__tests__/__snapshots__/TargetingHosts.test.js.snap +16 -1
- data/webpack/react_app/components/TargetingHosts/__tests__/__snapshots__/TargetingHostsPage.test.js.snap +68 -0
- data/webpack/react_app/components/TargetingHosts/__tests__/__snapshots__/TargetingHostsSelectors.test.js.snap +11 -0
- data/webpack/react_app/components/TargetingHosts/__tests__/fixtures.js +35 -19
- data/webpack/react_app/components/TargetingHosts/index.js +73 -13
- metadata +30 -7
- data/webpack/react_app/components/TargetingHosts/TargetingHostsActions.js +0 -8
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: db51f6eb1c4c3513b55e3420cd28ee22e956980ef8b82845e7e65cf5389afe32
|
4
|
+
data.tar.gz: ce148bbcf61c208f646a68153ba36331d1a994476690d4a5d37551fda47fc25b
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 28dda5271e680ab81d7d38aea31e250b01c930a6793417deb4d2204975298e48d14c17880699d4354662ad35381566b60e6fd04f8b2ebdb5d89599cab9bf5e74
|
7
|
+
data.tar.gz: 298f020eacc63c41e0ef3d198ba45723f629ce991931126c3cf3a446677439dccf4a1a24d1b1c14b110423964ab5f04aac44a3fb8acab10b6e5d2d4f994a9f2f
|
data/.github/workflows/ci.yml
CHANGED
@@ -6,7 +6,7 @@ module Api
|
|
6
6
|
|
7
7
|
before_action :find_optional_nested_object, :only => %w{output raw_output}
|
8
8
|
before_action :find_host, :only => %w{output raw_output}
|
9
|
-
before_action :find_resource, :only => %w{show update destroy clone cancel rerun}
|
9
|
+
before_action :find_resource, :only => %w{show update destroy clone cancel rerun outputs}
|
10
10
|
|
11
11
|
wrap_parameters JobInvocation, :include => (JobInvocation.attribute_names + [:ssh])
|
12
12
|
|
@@ -137,6 +137,24 @@ module Api
|
|
137
137
|
end
|
138
138
|
end
|
139
139
|
|
140
|
+
api :GET, '/job_invocations/:id/outputs', N_('Get outputs of hosts in a job')
|
141
|
+
param :id, :identifier, :required => true
|
142
|
+
param :search_query, :identifier, :required => false
|
143
|
+
param :since, String, :required => false
|
144
|
+
param :raw, String, :required => false
|
145
|
+
def outputs
|
146
|
+
hosts = @job_invocation.targeting.hosts.authorized(:view_hosts, Host)
|
147
|
+
hosts = hosts.search_for(params['search_query']) if params['search_query']
|
148
|
+
raw = ActiveRecord::Type::Boolean.new.cast params['raw']
|
149
|
+
default_value = raw ? '' : []
|
150
|
+
outputs = hosts.map do |host|
|
151
|
+
host_output(@job_invocation, host, :default => default_value, :since => params['since'], :raw => raw)
|
152
|
+
.merge(host_id: host.id)
|
153
|
+
end
|
154
|
+
|
155
|
+
render :json => { :outputs => outputs }
|
156
|
+
end
|
157
|
+
|
140
158
|
private
|
141
159
|
|
142
160
|
def allowed_nested_id
|
@@ -145,7 +163,7 @@ module Api
|
|
145
163
|
|
146
164
|
def action_permission
|
147
165
|
case params[:action]
|
148
|
-
when 'output', 'raw_output'
|
166
|
+
when 'output', 'raw_output', 'outputs'
|
149
167
|
:view
|
150
168
|
when 'cancel'
|
151
169
|
:cancel
|
data/app/controllers/foreman_remote_execution/concerns/api/v2/registration_controller_extensions.rb
ADDED
@@ -0,0 +1,26 @@
|
|
1
|
+
module ForemanRemoteExecution
|
2
|
+
module Concerns
|
3
|
+
module Api::V2::RegistrationControllerExtensions
|
4
|
+
module ApipieExtensions
|
5
|
+
extend Apipie::DSL::Concern
|
6
|
+
|
7
|
+
update_api(:global, :host) do
|
8
|
+
param :remote_execution_interface, String, desc: N_("Identifier of the Host interface for Remote execution")
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
12
|
+
extend ActiveSupport::Concern
|
13
|
+
|
14
|
+
def host_setup_extension
|
15
|
+
remote_execution_interface
|
16
|
+
super
|
17
|
+
end
|
18
|
+
|
19
|
+
def remote_execution_interface
|
20
|
+
return unless params['remote_execution_interface'].present?
|
21
|
+
|
22
|
+
@host.set_execution_interface(params['remote_execution_interface'])
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
data/app/controllers/foreman_remote_execution/concerns/api/v2/subnets_controller_extensions.rb
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
module ForemanRemoteExecution
|
2
|
+
module Concerns
|
3
|
+
module Api::V2::SubnetsControllerExtensions
|
4
|
+
module ApiPieExtensions
|
5
|
+
extend ::Apipie::DSL::Concern
|
6
|
+
|
7
|
+
update_api(:create, :update) do
|
8
|
+
param :subnet, Hash do
|
9
|
+
param :remote_execution_proxy_ids, Array, _('List of proxy IDs to be used for remote execution')
|
10
|
+
end
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
extend ActiveSupport::Concern
|
15
|
+
|
16
|
+
included do
|
17
|
+
include ApiPieExtensions
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
@@ -52,16 +52,18 @@ class JobInvocationsController < ApplicationController
|
|
52
52
|
|
53
53
|
def show
|
54
54
|
@job_invocation = resource_base.includes(:template_invocations => :run_host_job_task).find(params[:id])
|
55
|
-
@auto_refresh = @job_invocation.task.try(:pending?)
|
56
|
-
@resource_base = @job_invocation.targeting.hosts.authorized(:view_hosts, Host)
|
57
|
-
# There's no need to do the joining if we're not filtering
|
58
|
-
unless params[:search].nil?
|
59
|
-
@resource_base = @resource_base.joins(:template_invocations)
|
60
|
-
.where(:template_invocations => { :job_invocation_id => @job_invocation.id})
|
61
|
-
end
|
62
|
-
@hosts = resource_base_search_and_page
|
63
55
|
@job_organization = Taxonomy.find_by(id: @job_invocation.task.input[:current_organization_id])
|
64
56
|
@job_location = Taxonomy.find_by(id: @job_invocation.task.input[:current_location_id])
|
57
|
+
@auto_refresh = @job_invocation.task.try(:pending?)
|
58
|
+
|
59
|
+
respond_to do |format|
|
60
|
+
format.json do
|
61
|
+
targeting_hosts_resources
|
62
|
+
end
|
63
|
+
|
64
|
+
format.html
|
65
|
+
format.js
|
66
|
+
end
|
65
67
|
end
|
66
68
|
|
67
69
|
def index
|
@@ -153,4 +155,16 @@ class JobInvocationsController < ApplicationController
|
|
153
155
|
JobInvocationComposer.from_ui_params(with_triggering)
|
154
156
|
end
|
155
157
|
end
|
158
|
+
|
159
|
+
def targeting_hosts_resources
|
160
|
+
@auto_refresh = @job_invocation.task.try(:pending?)
|
161
|
+
@resource_base = @job_invocation.targeting.hosts.authorized(:view_hosts, Host)
|
162
|
+
|
163
|
+
unless params[:search].nil?
|
164
|
+
@resource_base = @resource_base.joins(:template_invocations)
|
165
|
+
.where(:template_invocations => { :job_invocation_id => @job_invocation.id})
|
166
|
+
end
|
167
|
+
@hosts = resource_base_search_and_page
|
168
|
+
@total_hosts = resource_base_with_search.size
|
169
|
+
end
|
156
170
|
end
|
@@ -36,7 +36,7 @@ class JobTemplatesController < ::TemplatesController
|
|
36
36
|
|
37
37
|
@template = JobTemplate.import_raw(contents, :update => Foreman::Cast.to_bool(params[:imported_template][:overwrite]))
|
38
38
|
if @template&.save
|
39
|
-
flash[:
|
39
|
+
flash[:success] = _('Job template imported successfully.')
|
40
40
|
redirect_to job_templates_path(:search => "name = \"#{@template.name}\"")
|
41
41
|
else
|
42
42
|
@template ||= JobTemplate.import_raw(contents, :build_new => true)
|
@@ -1,10 +1,11 @@
|
|
1
1
|
# frozen_string_literal:true
|
2
2
|
|
3
3
|
module JobInvocationsHelper
|
4
|
-
def minicard(icon, number, text)
|
4
|
+
def minicard(icon, number, text, tooltip: nil)
|
5
|
+
tooltip_options = tooltip ? { :'data-original-title' => tooltip, :rel => 'twipsy' } : {}
|
5
6
|
content_tag(:div, :class => 'card-pf card-pf-accented
|
6
7
|
card-pf-aggregate-status card-pf-aggregate-status-mini') do
|
7
|
-
content_tag(:h2, :class => 'card-pf-title', :style => 'line-height: 1.1') do
|
8
|
+
content_tag(:h2, { :class => 'card-pf-title', :style => 'line-height: 1.1' }.merge(tooltip_options)) do
|
8
9
|
icon_text(icon, '', :kind => 'pficon') +
|
9
10
|
content_tag(:span, number, :class =>'card-pf-aggregate-status-count') +
|
10
11
|
text
|
@@ -60,7 +60,7 @@ module Actions
|
|
60
60
|
def secrets(host, job_invocation, provider)
|
61
61
|
job_secrets = { :ssh_password => job_invocation.password,
|
62
62
|
:key_passphrase => job_invocation.key_passphrase,
|
63
|
-
:
|
63
|
+
:effective_user_password => job_invocation.effective_user_password }
|
64
64
|
|
65
65
|
job_secrets.merge(provider.secrets(host)) { |_key, job_secret, provider_secret| job_secret || provider_secret }
|
66
66
|
end
|
@@ -47,7 +47,7 @@ module Actions
|
|
47
47
|
end
|
48
48
|
|
49
49
|
def finalize
|
50
|
-
job_invocation.password = job_invocation.key_passphrase = job_invocation.
|
50
|
+
job_invocation.password = job_invocation.key_passphrase = job_invocation.effective_user_password = nil
|
51
51
|
job_invocation.save!
|
52
52
|
|
53
53
|
Rails.logger.debug "cleaning cache for keys that begin with 'job_invocation_#{job_invocation.id}'"
|
@@ -57,15 +57,24 @@ module Actions
|
|
57
57
|
end
|
58
58
|
|
59
59
|
def job_invocation
|
60
|
-
|
60
|
+
id = input[:job_invocation_id] || input.fetch(:job_invocation, {})[:id]
|
61
|
+
@job_invocation ||= JobInvocation.find(id)
|
61
62
|
end
|
62
63
|
|
63
64
|
def batch(from, size)
|
64
65
|
hosts.offset(from).limit(size)
|
65
66
|
end
|
66
67
|
|
68
|
+
def initiate
|
69
|
+
output[:host_count] = total_count
|
70
|
+
super
|
71
|
+
end
|
72
|
+
|
67
73
|
def total_count
|
68
|
-
|
74
|
+
# For compatibility with already existing tasks
|
75
|
+
return output[:total_count] unless output.has_key?(:host_count) || task.pending?
|
76
|
+
|
77
|
+
output[:host_count] || hosts.count
|
69
78
|
end
|
70
79
|
|
71
80
|
def hosts
|
@@ -3,14 +3,33 @@ module ForemanRemoteExecution
|
|
3
3
|
module Scope
|
4
4
|
class Input < ::Foreman::Renderer::Scope::Template
|
5
5
|
include Foreman::Renderer::Scope::Macros::HostTemplate
|
6
|
+
extend ApipieDSL::Class
|
6
7
|
|
7
8
|
attr_reader :template, :host, :invocation, :input_template_instance, :current_user
|
8
9
|
delegate :input, to: :input_template_instance
|
9
10
|
|
11
|
+
apipie :class, 'Macros related to template rendering' do
|
12
|
+
name 'Template Input Render'
|
13
|
+
sections only: %w[all jobs]
|
14
|
+
end
|
15
|
+
|
16
|
+
apipie :method, 'Always raises an error with a description provided as an argument' do
|
17
|
+
desc 'This method is useful for aborting script execution if some of the conditions are not met'
|
18
|
+
required :message, String, desc: 'Description for the error'
|
19
|
+
raises error: ::InputTemplateRenderer::RenderError, desc: 'The error is always being raised'
|
20
|
+
returns nil, desc: "Doesn't return anything"
|
21
|
+
example "<%
|
22
|
+
@host.operatingsystem #=> nil
|
23
|
+
render_error(N_('Unsupported or no operating system found for this host.')) unless @host.operatingsystem #=> InputTemplateRenderer::RenderError is raised and the execution of the script is aborted
|
24
|
+
%>"
|
25
|
+
end
|
10
26
|
def render_error(message)
|
11
27
|
raise ::InputTemplateRenderer::RenderError.new(message)
|
12
28
|
end
|
13
29
|
|
30
|
+
apipie :method, 'Check whether the template in preview mode or not' do
|
31
|
+
returns one_of: [true, false], desc: 'Returns true if the template in preview mode, false otherwise'
|
32
|
+
end
|
14
33
|
def preview?
|
15
34
|
!!@preview
|
16
35
|
end
|
@@ -23,6 +42,16 @@ module ForemanRemoteExecution
|
|
23
42
|
Rails.cache.fetch(cache_key, &block)
|
24
43
|
end
|
25
44
|
|
45
|
+
# rubocop:disable Lint/InterpolationCheck
|
46
|
+
apipie :method, 'Render template by given name' do
|
47
|
+
required :template_name, String, desc: 'name of the template to render'
|
48
|
+
optional :input_values, Hash, desc: 'key:value list of input values for the template'
|
49
|
+
optional :options, Hash, desc: 'Additional options such as :with_foreign_input_set. Set to true if a foreign input set should be considered when rendering the template'
|
50
|
+
raises error: StandardError, desc: 'raises an error if there is no template or template input with such name'
|
51
|
+
returns String, desc: 'Rendered template'
|
52
|
+
example '<%= render_template("Run Command - Ansible Default", command: "yum -y group install #{input("package")}") %>'
|
53
|
+
end
|
54
|
+
# rubocop:enable Lint/InterpolationCheck
|
26
55
|
def render_template(template_name, input_values = {}, options = {})
|
27
56
|
options.assert_valid_keys(:with_foreign_input_set)
|
28
57
|
with_foreign_input_set = options.fetch(:with_foreign_input_set, true)
|
@@ -59,6 +88,12 @@ module ForemanRemoteExecution
|
|
59
88
|
input_values.merge(overrides).with_indifferent_access
|
60
89
|
end
|
61
90
|
|
91
|
+
apipie :method, 'Returns the value of template input' do
|
92
|
+
required :name, String, desc: 'name of the template input'
|
93
|
+
raises error: UndefinedInput, desc: 'when there is no input with such name defined for the current template'
|
94
|
+
returns Object, desc: 'The value of template input'
|
95
|
+
example 'input("Include Facts") #=> "yes"'
|
96
|
+
end
|
62
97
|
def input(name)
|
63
98
|
return template_input_values[name.to_s] if template_input_values.key?(name.to_s)
|
64
99
|
|
@@ -0,0 +1,13 @@
|
|
1
|
+
module Api
|
2
|
+
module V2
|
3
|
+
module InterfacesControllerExtensions
|
4
|
+
extend Apipie::DSL::Concern
|
5
|
+
|
6
|
+
update_api(:create, :update) do
|
7
|
+
param :interface, Hash do
|
8
|
+
param :execution, :bool, :desc => N_('Should this interface be used for remote execution?')
|
9
|
+
end
|
10
|
+
end
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
@@ -44,29 +44,33 @@ module ForemanRemoteExecution
|
|
44
44
|
@execution_status_label ||= get_status(HostStatus::ExecutionStatus).to_label(options)
|
45
45
|
end
|
46
46
|
|
47
|
+
# rubocop:disable Naming/MemoizedInstanceVariableName
|
47
48
|
def host_params_hash
|
48
|
-
|
49
|
-
keys = remote_execution_ssh_keys
|
50
|
-
source = 'global'
|
51
|
-
if keys.present?
|
52
|
-
value, safe_value = params.fetch('remote_execution_ssh_keys', {}).values_at(:value, :safe_value).map { |v| [v].flatten.compact }
|
53
|
-
params['remote_execution_ssh_keys'] = {:value => value + keys, :safe_value => safe_value + keys, :source => source}
|
54
|
-
end
|
55
|
-
[:remote_execution_ssh_user, :remote_execution_effective_user_method,
|
56
|
-
:remote_execution_connect_by_ip].each do |key|
|
57
|
-
value = Setting[key]
|
58
|
-
params[key.to_s] = {:value => value, :safe_value => value, :source => source} unless params.key?(key.to_s)
|
59
|
-
end
|
60
|
-
params
|
49
|
+
@cached_rex_host_params_hash ||= extend_host_params_hash(super)
|
61
50
|
end
|
51
|
+
# rubocop:enable Naming/MemoizedInstanceVariableName
|
62
52
|
|
63
53
|
def execution_interface
|
64
54
|
get_interface_by_flag(:execution)
|
65
55
|
end
|
66
56
|
|
57
|
+
def set_execution_interface(identifier)
|
58
|
+
if interfaces.find_by(identifier: identifier).nil?
|
59
|
+
msg = (N_("Interface with the '%s' identifier was specified as a remote execution interface, however the interface was not found on the host. If the interface exists, it needs to be created in Foreman during the registration.") % identifier)
|
60
|
+
raise ActiveRecord::RecordNotFound, msg
|
61
|
+
end
|
62
|
+
|
63
|
+
# Only one interface at time can be used for REX, all other must be set to false
|
64
|
+
interfaces.each { |int| int.execution = (int.identifier == identifier) }
|
65
|
+
interfaces.each(&:save!)
|
66
|
+
end
|
67
|
+
|
67
68
|
def remote_execution_proxies(provider, authorized = true)
|
68
69
|
proxies = {}
|
69
|
-
proxies[:subnet]
|
70
|
+
proxies[:subnet] = []
|
71
|
+
proxies[:subnet] += execution_interface.subnet6.remote_execution_proxies.with_features(provider) if execution_interface&.subnet6
|
72
|
+
proxies[:subnet] += execution_interface.subnet.remote_execution_proxies.with_features(provider) if execution_interface&.subnet
|
73
|
+
proxies[:subnet].uniq!
|
70
74
|
proxies[:fallback] = smart_proxies.with_features(provider) if Setting[:remote_execution_fallback_proxy]
|
71
75
|
|
72
76
|
if Setting[:remote_execution_global_proxy]
|
@@ -102,8 +106,28 @@ module ForemanRemoteExecution
|
|
102
106
|
super(*args)
|
103
107
|
end
|
104
108
|
|
109
|
+
def clear_host_parameters_cache!
|
110
|
+
super
|
111
|
+
@cached_rex_host_params_hash = nil
|
112
|
+
end
|
113
|
+
|
105
114
|
private
|
106
115
|
|
116
|
+
def extend_host_params_hash(params)
|
117
|
+
keys = remote_execution_ssh_keys
|
118
|
+
source = 'global'
|
119
|
+
if keys.present?
|
120
|
+
value, safe_value = params.fetch('remote_execution_ssh_keys', {}).values_at(:value, :safe_value).map { |v| [v].flatten.compact }
|
121
|
+
params['remote_execution_ssh_keys'] = {:value => value + keys, :safe_value => safe_value + keys, :source => source}
|
122
|
+
end
|
123
|
+
[:remote_execution_ssh_user, :remote_execution_effective_user_method,
|
124
|
+
:remote_execution_connect_by_ip].each do |key|
|
125
|
+
value = Setting[key]
|
126
|
+
params[key.to_s] = {:value => value, :safe_value => value, :source => source} unless params.key?(key.to_s)
|
127
|
+
end
|
128
|
+
params
|
129
|
+
end
|
130
|
+
|
107
131
|
def build_required_interfaces(attrs = {})
|
108
132
|
super(attrs)
|
109
133
|
self.primary_interface.execution = true if self.execution_interface.nil?
|
@@ -22,6 +22,7 @@ class JobInvocation < ApplicationRecord
|
|
22
22
|
validates :job_category, :presence => true
|
23
23
|
validates_associated :targeting, :all_template_invocations
|
24
24
|
|
25
|
+
scoped_search :on => :id, :complete_value => true
|
25
26
|
scoped_search :on => :job_category, :complete_value => true
|
26
27
|
scoped_search :on => :description, :complete_value => true
|
27
28
|
|
@@ -41,7 +42,10 @@ class JobInvocation < ApplicationRecord
|
|
41
42
|
has_many :template_invocation_tasks, :through => :template_invocations,
|
42
43
|
:class_name => 'ForemanTasks::Task',
|
43
44
|
:source => 'run_host_job_task'
|
44
|
-
|
45
|
+
has_one :user, through: :task
|
46
|
+
scoped_search relation: :user, on: :login, rename: 'user', complete_value: true,
|
47
|
+
value_translation: ->(value) { value == 'current_user' ? User.current.login : value },
|
48
|
+
special_values: [:current_user], aliases: ['owner'], :only_explicit => true
|
45
49
|
scoped_search :relation => :task, :on => :started_at, :rename => 'started_at', :complete_value => true
|
46
50
|
scoped_search :relation => :task, :on => :start_at, :rename => 'start_at', :complete_value => true
|
47
51
|
scoped_search :relation => :task, :on => :ended_at, :rename => 'ended_at', :complete_value => true
|
@@ -70,7 +74,7 @@ class JobInvocation < ApplicationRecord
|
|
70
74
|
|
71
75
|
delegate :start_at, :to => :task, :allow_nil => true
|
72
76
|
|
73
|
-
encrypts :password, :key_passphrase, :
|
77
|
+
encrypts :password, :key_passphrase, :effective_user_password
|
74
78
|
|
75
79
|
def self.search_by_status(key, operator, value)
|
76
80
|
conditions = HostStatus::ExecutionStatus::ExecutionTaskStatusMapper.sql_conditions_for(value)
|
@@ -139,7 +143,7 @@ class JobInvocation < ApplicationRecord
|
|
139
143
|
invocation.pattern_template_invocations = self.pattern_template_invocations.map(&:deep_clone)
|
140
144
|
invocation.password = self.password
|
141
145
|
invocation.key_passphrase = self.key_passphrase
|
142
|
-
invocation.
|
146
|
+
invocation.effective_user_password = self.effective_user_password
|
143
147
|
end
|
144
148
|
end
|
145
149
|
|
@@ -170,7 +174,7 @@ class JobInvocation < ApplicationRecord
|
|
170
174
|
|
171
175
|
def total_hosts_count
|
172
176
|
if targeting.resolved?
|
173
|
-
targeting.hosts.count
|
177
|
+
task&.main_action&.total_count || targeting.hosts.count
|
174
178
|
else
|
175
179
|
_('N/A')
|
176
180
|
end
|
@@ -240,6 +244,10 @@ class JobInvocation < ApplicationRecord
|
|
240
244
|
!task.pending?
|
241
245
|
end
|
242
246
|
|
247
|
+
def missing_hosts_count
|
248
|
+
targeting.resolved? ? total_hosts_count - targeting.hosts.count : 0
|
249
|
+
end
|
250
|
+
|
243
251
|
private
|
244
252
|
|
245
253
|
def failed_template_invocations
|
@@ -15,7 +15,7 @@ class JobInvocationComposer
|
|
15
15
|
:description_format => job_invocation_base[:description_format],
|
16
16
|
:password => blank_to_nil(job_invocation_base[:password]),
|
17
17
|
:key_passphrase => blank_to_nil(job_invocation_base[:key_passphrase]),
|
18
|
-
:
|
18
|
+
:effective_user_password => blank_to_nil(job_invocation_base[:effective_user_password]),
|
19
19
|
:concurrency_control => concurrency_control_params,
|
20
20
|
:execution_timeout_interval => execution_timeout_interval,
|
21
21
|
:template_invocations => template_invocations_params }.with_indifferent_access
|
@@ -348,7 +348,7 @@ class JobInvocationComposer
|
|
348
348
|
job_invocation.execution_timeout_interval = params[:execution_timeout_interval]
|
349
349
|
job_invocation.password = params[:password]
|
350
350
|
job_invocation.key_passphrase = params[:key_passphrase]
|
351
|
-
job_invocation.
|
351
|
+
job_invocation.effective_user_password = params[:effective_user_password]
|
352
352
|
|
353
353
|
if @reruns && job_invocation.targeting.static?
|
354
354
|
job_invocation.targeting.host_ids = JobInvocation.find(@reruns).targeting.host_ids
|