foreman_remote_execution 4.2.1 → 4.4.0
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/.github/workflows/js_ci.yml +29 -0
- data/.github/workflows/{ci.yml → ruby_ci.yml} +22 -50
- data/.prettierrc +4 -0
- data/.rubocop.yml +13 -49
- data/.rubocop_todo.yml +326 -102
- data/Gemfile +1 -4
- data/app/controllers/api/v2/job_invocations_controller.rb +17 -1
- data/app/controllers/foreman_remote_execution/concerns/api/v2/registration_commands_controller_extensions.rb +19 -0
- data/app/controllers/ui_job_wizard_controller.rb +18 -0
- data/app/helpers/remote_execution_helper.rb +27 -0
- data/app/lib/actions/remote_execution/run_host_job.rb +38 -1
- data/app/lib/foreman_remote_execution/provider_input.rb +29 -0
- data/app/lib/foreman_remote_execution/renderer/scope/input.rb +1 -0
- data/app/models/foreign_input_set.rb +1 -1
- data/app/models/host_status/execution_status.rb +7 -0
- data/app/models/invocation_provider_input_value.rb +12 -0
- data/app/models/job_invocation.rb +5 -1
- data/app/models/job_invocation_composer.rb +13 -0
- data/app/models/remote_execution_provider.rb +17 -2
- data/app/models/setting/remote_execution.rb +10 -0
- data/app/models/template_invocation.rb +2 -0
- data/app/services/renderer_methods.rb +12 -0
- data/app/views/job_invocations/_form.html.erb +8 -0
- data/app/views/template_invocations/show.html.erb +30 -23
- data/config/routes.rb +4 -0
- data/db/migrate/20210312074713_add_provider_inputs.rb +10 -0
- data/foreman_remote_execution.gemspec +1 -2
- data/lib/foreman_remote_execution/engine.rb +17 -7
- data/lib/foreman_remote_execution/version.rb +1 -1
- data/lib/tasks/foreman_remote_execution_tasks.rake +1 -18
- data/locale/action_names.rb +1 -0
- data/locale/de/foreman_remote_execution.po +77 -27
- data/locale/en/foreman_remote_execution.po +77 -27
- data/locale/en_GB/foreman_remote_execution.po +77 -27
- data/locale/es/foreman_remote_execution.po +77 -27
- data/locale/foreman_remote_execution.pot +241 -163
- data/locale/fr/foreman_remote_execution.po +77 -27
- data/locale/ja/foreman_remote_execution.po +77 -27
- data/locale/ko/foreman_remote_execution.po +77 -27
- data/locale/pt_BR/foreman_remote_execution.po +77 -27
- data/locale/ru/foreman_remote_execution.po +77 -27
- data/locale/zh_CN/foreman_remote_execution.po +77 -27
- data/locale/zh_TW/foreman_remote_execution.po +77 -27
- data/package.json +3 -2
- data/test/functional/api/v2/job_invocations_controller_test.rb +24 -4
- data/test/functional/api/v2/registration_controller_test.rb +4 -13
- data/test/functional/ui_job_wizard_controller_test.rb +16 -0
- data/test/helpers/remote_execution_helper_test.rb +16 -0
- data/test/unit/job_invocation_composer_test.rb +41 -1
- data/test/unit/job_invocation_report_template_test.rb +57 -0
- data/webpack/JobWizard/JobWizard.js +55 -0
- data/webpack/JobWizard/JobWizard.scss +12 -0
- data/webpack/JobWizard/JobWizardConstants.js +5 -0
- data/webpack/JobWizard/JobWizardSelectors.js +21 -0
- data/webpack/JobWizard/__tests__/JobWizard.test.js +20 -0
- data/webpack/JobWizard/__tests__/__snapshots__/JobWizard.test.js.snap +83 -0
- data/webpack/JobWizard/index.js +32 -0
- data/webpack/JobWizard/steps/CategoryAndTemplate/CategoryAndTemplate.js +77 -0
- data/webpack/JobWizard/steps/CategoryAndTemplate/CategoryAndTemplate.test.js +45 -0
- data/webpack/JobWizard/steps/CategoryAndTemplate/__snapshots__/CategoryAndTemplate.test.js.snap +64 -0
- data/webpack/JobWizard/steps/CategoryAndTemplate/index.js +86 -0
- data/webpack/JobWizard/steps/form/GroupedSelectField.js +88 -0
- data/webpack/JobWizard/steps/form/SelectField.js +39 -0
- data/webpack/JobWizard/steps/form/__tests__/GroupedSelectField.test.js +38 -0
- data/webpack/JobWizard/steps/form/__tests__/SelectField.test.js +23 -0
- data/webpack/JobWizard/steps/form/__tests__/__snapshots__/GroupedSelectField.test.js.snap +36 -0
- data/webpack/JobWizard/steps/form/__tests__/__snapshots__/SelectField.test.js.snap +22 -0
- data/webpack/Routes/routes.js +12 -0
- data/webpack/__mocks__/foremanReact/common/helpers.js +1 -0
- data/webpack/__mocks__/foremanReact/history.js +1 -0
- data/webpack/__mocks__/foremanReact/redux/API/index.js +5 -0
- data/webpack/__mocks__/foremanReact/routes/common/PageLayout/PageLayout.js +10 -0
- data/webpack/fills_index.js +11 -0
- data/webpack/global_index.js +8 -0
- data/webpack/index.js +0 -4
- data/webpack/react_app/components/RecentJobsCard/RecentJobsCard.js +87 -0
- data/webpack/react_app/components/RecentJobsCard/constants.js +1 -0
- data/webpack/react_app/components/RecentJobsCard/index.js +1 -0
- data/webpack/react_app/components/RecentJobsCard/styles.css +15 -0
- data/webpack/react_app/components/RegistrationExtension/RexInterface.js +50 -0
- data/webpack/react_app/components/RegistrationExtension/__tests__/RexInterface.test.js +9 -0
- data/webpack/react_app/components/RegistrationExtension/__tests__/__snapshots__/RexInterface.test.js.snap +35 -0
- data/webpack/react_app/components/TargetingHosts/TargetingHostsPage.js +1 -1
- data/webpack/react_app/components/TargetingHosts/TargetingHostsPage.scss +0 -3
- data/webpack/react_app/components/TargetingHosts/__tests__/__snapshots__/TargetingHostsPage.test.js.snap +1 -1
- data/webpack/react_app/extend/fills.js +10 -0
- data/webpack/react_app/extend/reducers.js +4 -0
- metadata +54 -24
- data/app/views/api/v2/registration/_form.html.erb +0 -12
data/Gemfile
CHANGED
|
@@ -64,6 +64,16 @@ module Api
|
|
|
64
64
|
param :description_format, String, :required => false, :desc => N_('Override the description format from the template for this invocation only')
|
|
65
65
|
param :execution_timeout_interval, Integer, :required => false, :desc => N_('Override the timeout interval from the template for this invocation only')
|
|
66
66
|
param :feature, String, :required => false, :desc => N_('Remote execution feature label that should be triggered, job template assigned to this feature will be used')
|
|
67
|
+
|
|
68
|
+
RemoteExecutionProvider.providers.each_value do |provider|
|
|
69
|
+
next if !provider.respond_to?(:provider_inputs_doc) || provider.provider_inputs_doc.empty?
|
|
70
|
+
doc = provider.provider_inputs_doc
|
|
71
|
+
param doc[:namespace], Hash, doc[:opts] do
|
|
72
|
+
doc[:children].map do |input|
|
|
73
|
+
param input[:name], input[:type], input[:opts]
|
|
74
|
+
end
|
|
75
|
+
end
|
|
76
|
+
end
|
|
67
77
|
end
|
|
68
78
|
end
|
|
69
79
|
|
|
@@ -195,9 +205,15 @@ module Api
|
|
|
195
205
|
end
|
|
196
206
|
job_invocation_params[:inputs] ||= {}
|
|
197
207
|
job_invocation_params[:inputs].permit!
|
|
208
|
+
permit_provider_inputs job_invocation_params
|
|
198
209
|
@job_invocation_params = job_invocation_params
|
|
199
210
|
end
|
|
200
211
|
|
|
212
|
+
def permit_provider_inputs(invocation_params)
|
|
213
|
+
providers = RemoteExecutionProvider.providers.values.reject { |provider| !provider.respond_to?(:provider_input_namespace) || provider.provider_input_namespace.empty? }
|
|
214
|
+
providers.each { |provider| invocation_params[provider.provider_input_namespace]&.permit! }
|
|
215
|
+
end
|
|
216
|
+
|
|
201
217
|
def composer_for_feature
|
|
202
218
|
JobInvocationComposer.for_feature(
|
|
203
219
|
job_invocation_params[:feature],
|
|
@@ -214,7 +230,7 @@ module Api
|
|
|
214
230
|
end
|
|
215
231
|
|
|
216
232
|
def host_output(job_invocation, host, default: nil, since: nil, raw: false)
|
|
217
|
-
refresh =
|
|
233
|
+
refresh = !job_invocation.finished?
|
|
218
234
|
|
|
219
235
|
if (task = job_invocation.sub_task_for_host(host))
|
|
220
236
|
refresh = task.pending?
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
module ForemanRemoteExecution
|
|
2
|
+
module Concerns
|
|
3
|
+
module Api
|
|
4
|
+
module V2
|
|
5
|
+
module RegistrationCommandsControllerExtensions
|
|
6
|
+
module ApipieExtensions
|
|
7
|
+
extend Apipie::DSL::Concern
|
|
8
|
+
|
|
9
|
+
update_api(:create) do
|
|
10
|
+
param :registration_command, Hash do
|
|
11
|
+
param :remote_execution_interface, String, desc: N_("Identifier of the Host interface for Remote execution")
|
|
12
|
+
end
|
|
13
|
+
end
|
|
14
|
+
end
|
|
15
|
+
end
|
|
16
|
+
end
|
|
17
|
+
end
|
|
18
|
+
end
|
|
19
|
+
end
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
class UiJobWizardController < ::Api::V2::BaseController
|
|
2
|
+
def categories
|
|
3
|
+
job_categories = resource_scope
|
|
4
|
+
.search_for("job_category ~ \"#{params[:search]}\"")
|
|
5
|
+
.select(:job_category).distinct
|
|
6
|
+
.reorder(:job_category)
|
|
7
|
+
.pluck(:job_category)
|
|
8
|
+
render :json => {:job_categories =>job_categories}
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
def resource_class
|
|
12
|
+
JobTemplate
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
def action_permission
|
|
16
|
+
:view_job_templates
|
|
17
|
+
end
|
|
18
|
+
end
|
|
@@ -60,6 +60,12 @@ module RemoteExecutionHelper
|
|
|
60
60
|
job_invocation = task.task_groups.find { |group| group.class == JobInvocationTaskGroup }.job_invocation
|
|
61
61
|
task_authorizer = Authorizer.new(User.current, :collection => [task])
|
|
62
62
|
buttons = []
|
|
63
|
+
if (template = job_report_template) && authorized_for(controller: :report_templates, action: :generate)
|
|
64
|
+
buttons << link_to(_('Create Report'), generate_report_template_path(template, job_report_template_parameters(job_invocation, template)),
|
|
65
|
+
class: 'btn btn-default',
|
|
66
|
+
title: _('Create report for this job'),
|
|
67
|
+
disabled: task.pending?)
|
|
68
|
+
end
|
|
63
69
|
if authorized_for(hash_for_new_job_invocation_path)
|
|
64
70
|
buttons << link_to(_('Rerun'), rerun_job_invocation_path(:id => job_invocation.id),
|
|
65
71
|
:class => 'btn btn-default',
|
|
@@ -230,6 +236,27 @@ module RemoteExecutionHelper
|
|
|
230
236
|
task.execution_plan.actions[1].try(:input).try(:[], 'script')
|
|
231
237
|
end
|
|
232
238
|
|
|
239
|
+
def job_report_template
|
|
240
|
+
template = ReportTemplate.where(name: Setting['remote_execution_job_invocation_report_template']).first
|
|
241
|
+
|
|
242
|
+
template if template.template_inputs.where(name: 'job_id').exists?
|
|
243
|
+
end
|
|
244
|
+
|
|
245
|
+
def job_report_template_parameters(job_invocation, template)
|
|
246
|
+
template_input = template.template_inputs.where(name: 'job_id').first
|
|
247
|
+
raise "#job_report_template_parameters need template that has 'job_id' input" unless template_input
|
|
248
|
+
|
|
249
|
+
{
|
|
250
|
+
report_template_report: {
|
|
251
|
+
input_values: {
|
|
252
|
+
"#{template_input.id}": {
|
|
253
|
+
value: job_invocation.id,
|
|
254
|
+
},
|
|
255
|
+
},
|
|
256
|
+
},
|
|
257
|
+
}
|
|
258
|
+
end
|
|
259
|
+
|
|
233
260
|
def targeting_hosts(job_invocation, hosts)
|
|
234
261
|
hosts.map do |host|
|
|
235
262
|
template_invocation = job_invocation.template_invocations.find { |template_inv| template_inv.host_id == host.id }
|
|
@@ -3,6 +3,7 @@ module Actions
|
|
|
3
3
|
class RunHostJob < Actions::EntryAction
|
|
4
4
|
include ::Actions::Helpers::WithContinuousOutput
|
|
5
5
|
include ::Actions::Helpers::WithDelegatedAction
|
|
6
|
+
include ::Actions::ObservableAction
|
|
6
7
|
|
|
7
8
|
middleware.do_not_use Dynflow::Middleware::Common::Transaction
|
|
8
9
|
middleware.use Actions::Middleware::HideSecrets
|
|
@@ -16,7 +17,7 @@ module Actions
|
|
|
16
17
|
end
|
|
17
18
|
|
|
18
19
|
def plan(job_invocation, host, template_invocation, proxy_selector = ::RemoteExecutionProxySelector.new, options = {})
|
|
19
|
-
action_subject(host, :job_category => job_invocation.job_category, :description => job_invocation.description)
|
|
20
|
+
action_subject(host, :job_category => job_invocation.job_category, :description => job_invocation.description, :job_invocation_id => job_invocation.id)
|
|
20
21
|
|
|
21
22
|
template_invocation.host_id = host.id
|
|
22
23
|
template_invocation.run_host_job_task_id = task.id
|
|
@@ -121,6 +122,26 @@ module Actions
|
|
|
121
122
|
delegated_output[:exit_status]
|
|
122
123
|
end
|
|
123
124
|
|
|
125
|
+
def host_id
|
|
126
|
+
input['host']['id']
|
|
127
|
+
end
|
|
128
|
+
|
|
129
|
+
def host_name
|
|
130
|
+
input['host']['name']
|
|
131
|
+
end
|
|
132
|
+
|
|
133
|
+
def job_invocation_id
|
|
134
|
+
input['job_invocation_id']
|
|
135
|
+
end
|
|
136
|
+
|
|
137
|
+
def job_invocation
|
|
138
|
+
@job_invocation ||= ::JobInvocation.authorized.find(job_invocation_id)
|
|
139
|
+
end
|
|
140
|
+
|
|
141
|
+
def host
|
|
142
|
+
@host ||= ::Host.authorized.find(host_id)
|
|
143
|
+
end
|
|
144
|
+
|
|
124
145
|
private
|
|
125
146
|
|
|
126
147
|
def update_host_status
|
|
@@ -173,6 +194,22 @@ module Actions
|
|
|
173
194
|
end
|
|
174
195
|
proxy
|
|
175
196
|
end
|
|
197
|
+
|
|
198
|
+
extend ApipieDSL::Class
|
|
199
|
+
apipie :class, "An action representing execution of a job against a host" do
|
|
200
|
+
name 'Actions::RemoteExecution::RunHostJob'
|
|
201
|
+
refs 'Actions::RemoteExecution::RunHostJob'
|
|
202
|
+
sections only: %w[all webhooks]
|
|
203
|
+
property :task, object_of: 'Task', desc: 'Returns the task to which this action belongs'
|
|
204
|
+
property :host_name, String, desc: "Returns the name of the host"
|
|
205
|
+
property :host_id, Integer, desc: "Returns the id of the host"
|
|
206
|
+
property :host, object_of: 'Host', desc: "Returns the host"
|
|
207
|
+
property :job_invocation_id, Integer, desc: "Returns the id of the job invocation"
|
|
208
|
+
property :job_invocation, object_of: 'JobInvocation', desc: "Returns the job invocation"
|
|
209
|
+
end
|
|
210
|
+
class Jail < ::Actions::ObservableAction::Jail
|
|
211
|
+
allow :host_name, :host_id, :host, :job_invocation_id, :job_invocation
|
|
212
|
+
end
|
|
176
213
|
end
|
|
177
214
|
end
|
|
178
215
|
end
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
module ForemanRemoteExecution
|
|
2
|
+
class ProviderInput
|
|
3
|
+
attr_reader :name, :label, :description, :options, :value_type, :required
|
|
4
|
+
attr_accessor :value
|
|
5
|
+
|
|
6
|
+
def initialize(name:, label:, value:, description: nil, options: nil, value_type: nil, required: false, hidden: false)
|
|
7
|
+
@name = name
|
|
8
|
+
@label = label
|
|
9
|
+
@value = value
|
|
10
|
+
@description = description
|
|
11
|
+
@options = options
|
|
12
|
+
@value_type = value_type
|
|
13
|
+
@required = required
|
|
14
|
+
@hidden = hidden
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
def template_input
|
|
18
|
+
self
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
def hidden_value?
|
|
22
|
+
@hidden
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
def options_array
|
|
26
|
+
options.blank? ? [] : options.split(/\r?\n/).map(&:strip)
|
|
27
|
+
end
|
|
28
|
+
end
|
|
29
|
+
end
|
|
@@ -6,6 +6,7 @@ module ForemanRemoteExecution
|
|
|
6
6
|
extend ApipieDSL::Class
|
|
7
7
|
|
|
8
8
|
attr_reader :template, :host, :invocation, :input_template_instance, :current_user
|
|
9
|
+
attr_accessor :error_message
|
|
9
10
|
delegate :input, to: :input_template_instance
|
|
10
11
|
|
|
11
12
|
apipie :class, 'Macros related to template rendering' do
|
|
@@ -4,7 +4,7 @@ class ForeignInputSet < ApplicationRecord
|
|
|
4
4
|
class CircularDependencyError < Foreman::Exception
|
|
5
5
|
end
|
|
6
6
|
|
|
7
|
-
attr_exportable :exclude, :include, :include_all, :template => ->(input_set) { input_set.
|
|
7
|
+
attr_exportable :exclude, :include, :include_all, :template => ->(input_set) { input_set.target_template.name }
|
|
8
8
|
|
|
9
9
|
belongs_to :template
|
|
10
10
|
belongs_to :target_template, :class_name => 'Template'
|
|
@@ -49,6 +49,13 @@ class HostStatus::ExecutionStatus < HostStatus::Status
|
|
|
49
49
|
end
|
|
50
50
|
end
|
|
51
51
|
|
|
52
|
+
def status_link
|
|
53
|
+
job_invocation = last_stopped_task.parent_task.job_invocations.first
|
|
54
|
+
return nil unless User.current.can?(:view_job_invocations, job_invocation)
|
|
55
|
+
|
|
56
|
+
Rails.application.routes.url_helpers.job_invocation_path(job_invocation)
|
|
57
|
+
end
|
|
58
|
+
|
|
52
59
|
class ExecutionTaskStatusMapper
|
|
53
60
|
attr_accessor :task
|
|
54
61
|
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
class InvocationProviderInputValue < ApplicationRecord
|
|
2
|
+
belongs_to :template_invocation
|
|
3
|
+
|
|
4
|
+
validates :name, :presence => true
|
|
5
|
+
|
|
6
|
+
validates :value, :inclusion => { :in => proc { |v| v.provider_input.options_array } },
|
|
7
|
+
:if => proc { |v| v.provider_input.options_array.present? }
|
|
8
|
+
|
|
9
|
+
def provider_input
|
|
10
|
+
template_invocation.template.provider.provider_inputs.find { |item| item.name == name }
|
|
11
|
+
end
|
|
12
|
+
end
|
|
@@ -76,6 +76,10 @@ class JobInvocation < ApplicationRecord
|
|
|
76
76
|
|
|
77
77
|
encrypts :password, :key_passphrase, :effective_user_password
|
|
78
78
|
|
|
79
|
+
class Jail < Safemode::Jail
|
|
80
|
+
allow :sub_task_for_host, :template_invocations_hosts
|
|
81
|
+
end
|
|
82
|
+
|
|
79
83
|
def self.search_by_status(key, operator, value)
|
|
80
84
|
conditions = HostStatus::ExecutionStatus::ExecutionTaskStatusMapper.sql_conditions_for(value)
|
|
81
85
|
conditions[0] = "NOT (#{conditions[0]})" if operator == '<>'
|
|
@@ -241,7 +245,7 @@ class JobInvocation < ApplicationRecord
|
|
|
241
245
|
end
|
|
242
246
|
|
|
243
247
|
def finished?
|
|
244
|
-
!task.pending?
|
|
248
|
+
!(task.nil? || task.pending?)
|
|
245
249
|
end
|
|
246
250
|
|
|
247
251
|
def missing_hosts_count
|
|
@@ -64,6 +64,10 @@ class JobInvocationComposer
|
|
|
64
64
|
values.merge(:template_input_id => id)
|
|
65
65
|
end
|
|
66
66
|
|
|
67
|
+
provider_values_params = template_base.fetch(:provider_input_values, {})
|
|
68
|
+
template_base[:provider_input_values] = provider_values_params.map do |key, hash|
|
|
69
|
+
{ :name => key, :value => hash[:value] }
|
|
70
|
+
end
|
|
67
71
|
template_base
|
|
68
72
|
end
|
|
69
73
|
end
|
|
@@ -147,6 +151,7 @@ class JobInvocationComposer
|
|
|
147
151
|
|
|
148
152
|
def template_invocations_params
|
|
149
153
|
template_invocation_params = { :template_id => template.id, :effective_user => api_params[:effective_user] }
|
|
154
|
+
template_invocation_params[:provider_input_values] = filter_provider_inputs api_params
|
|
150
155
|
template_invocation_params[:input_values] = api_params.fetch(:inputs, {}).to_h.map do |name, value|
|
|
151
156
|
input = template.template_inputs_with_foreign.find { |i| i.name == name }
|
|
152
157
|
unless input
|
|
@@ -158,6 +163,13 @@ class JobInvocationComposer
|
|
|
158
163
|
[template_invocation_params]
|
|
159
164
|
end
|
|
160
165
|
|
|
166
|
+
def filter_provider_inputs(api_params)
|
|
167
|
+
return [] if template.provider.provider_input_namespace.empty?
|
|
168
|
+
inputs = api_params[template.provider.provider_input_namespace].to_h
|
|
169
|
+
provider_input_names = template.provider.provider_inputs.map(&:name)
|
|
170
|
+
inputs.select { |key, value| provider_input_names.include? key }.map { |key, value| { :name => key, :value => value } }
|
|
171
|
+
end
|
|
172
|
+
|
|
161
173
|
def template
|
|
162
174
|
@template ||= JobTemplate.authorized(:view_job_templates).find(api_params[:job_template_id])
|
|
163
175
|
end
|
|
@@ -503,6 +515,7 @@ class JobInvocationComposer
|
|
|
503
515
|
input = template_invocation.template.template_inputs_with_foreign.find { |i| i.id.to_s == attributes[:template_input_id].to_s }
|
|
504
516
|
input ? input.template_invocation_input_values.build(attributes) : nil
|
|
505
517
|
end.compact
|
|
518
|
+
template_invocation.provider_input_values.build job_template_base.fetch('provider_input_values', [])
|
|
506
519
|
end
|
|
507
520
|
|
|
508
521
|
def build_targeting
|
|
@@ -20,7 +20,7 @@ class RemoteExecutionProvider
|
|
|
20
20
|
end
|
|
21
21
|
|
|
22
22
|
def proxy_command_options(template_invocation, host)
|
|
23
|
-
{:proxy_operation_name => proxy_operation_name}
|
|
23
|
+
{:proxy_operation_name => proxy_operation_name}.merge(proxy_command_provider_inputs(template_invocation))
|
|
24
24
|
end
|
|
25
25
|
|
|
26
26
|
def secrets(_host)
|
|
@@ -35,6 +35,9 @@ class RemoteExecutionProvider
|
|
|
35
35
|
self.name
|
|
36
36
|
end
|
|
37
37
|
|
|
38
|
+
def provider_input_namespace
|
|
39
|
+
end
|
|
40
|
+
|
|
38
41
|
def supports_effective_user?
|
|
39
42
|
false
|
|
40
43
|
end
|
|
@@ -95,8 +98,20 @@ class RemoteExecutionProvider
|
|
|
95
98
|
def ssh_key_passphrase(_host)
|
|
96
99
|
end
|
|
97
100
|
|
|
101
|
+
def provider_inputs
|
|
102
|
+
[]
|
|
103
|
+
end
|
|
104
|
+
|
|
105
|
+
def provider_inputs_doc
|
|
106
|
+
{}
|
|
107
|
+
end
|
|
108
|
+
|
|
109
|
+
def proxy_command_provider_inputs(template_invocation)
|
|
110
|
+
{}
|
|
111
|
+
end
|
|
112
|
+
|
|
98
113
|
def proxy_action_class
|
|
99
|
-
ForemanRemoteExecutionCore::Actions::RunScript
|
|
114
|
+
'ForemanRemoteExecutionCore::Actions::RunScript'
|
|
100
115
|
end
|
|
101
116
|
|
|
102
117
|
# Return a specific proxy selector to use for running a given template
|
|
@@ -73,6 +73,16 @@ class Setting::RemoteExecution < Setting
|
|
|
73
73
|
_('Form Job Template'),
|
|
74
74
|
nil,
|
|
75
75
|
{ :collection => proc { Hash[JobTemplate.unscoped.map { |template| [template.name, template.name] }] } }),
|
|
76
|
+
self.set('remote_execution_job_invocation_report_template',
|
|
77
|
+
N_('Select a report template used for generating a report for a particular remote execution job'),
|
|
78
|
+
'Jobs - Invocation report template',
|
|
79
|
+
_('Job Invocation Report Template'),
|
|
80
|
+
nil,
|
|
81
|
+
{ :collection => proc { self.job_invocation_report_templates_select } }),
|
|
76
82
|
]
|
|
77
83
|
end
|
|
84
|
+
|
|
85
|
+
def self.job_invocation_report_templates_select
|
|
86
|
+
Hash[ReportTemplate.unscoped.joins(:template_inputs).where(template_inputs: TemplateInput.where(name: 'job_id')).map { |template| [template.name, template.name] }]
|
|
87
|
+
end
|
|
78
88
|
end
|
|
@@ -11,6 +11,7 @@ class TemplateInvocation < ApplicationRecord
|
|
|
11
11
|
belongs_to :template, :class_name => 'JobTemplate', :foreign_key => 'template_id'
|
|
12
12
|
belongs_to :job_invocation, :inverse_of => :template_invocations
|
|
13
13
|
has_many :input_values, :class_name => 'TemplateInvocationInputValue', :dependent => :destroy
|
|
14
|
+
has_many :provider_input_values, :class_name => 'InvocationProviderInputValue', :dependent => :destroy
|
|
14
15
|
has_one :targeting, :through => :job_invocation
|
|
15
16
|
belongs_to :host, :class_name => 'Host::Managed', :foreign_key => :host_id
|
|
16
17
|
has_one :host_group, :through => :host, :source => :hostgroup
|
|
@@ -77,6 +78,7 @@ class TemplateInvocation < ApplicationRecord
|
|
|
77
78
|
def deep_clone
|
|
78
79
|
self.dup.tap do |invocation|
|
|
79
80
|
invocation.input_values = self.input_values.map(&:dup)
|
|
81
|
+
invocation.provider_input_values = self.provider_input_values.map(&:dup)
|
|
80
82
|
end
|
|
81
83
|
end
|
|
82
84
|
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
# macros to fetch information about invoked jobs
|
|
4
|
+
module RendererMethods
|
|
5
|
+
extend ActiveSupport::Concern
|
|
6
|
+
|
|
7
|
+
def find_job_invocation_by_id(job_id, preload: nil)
|
|
8
|
+
JobInvocation.preload(preload).find_by(id: job_id)
|
|
9
|
+
rescue ActiveRecord::NotFound => _e
|
|
10
|
+
raise ::Foreman::Exception.new(N_("Can't find Job Invocation for an id %s"), job_id)
|
|
11
|
+
end
|
|
12
|
+
end
|
|
@@ -74,6 +74,14 @@
|
|
|
74
74
|
<% end %>
|
|
75
75
|
|
|
76
76
|
<div class="advanced hidden">
|
|
77
|
+
<%= job_template_fields.fields_for :provider_input_values do |provider_input_fields| %>
|
|
78
|
+
<% job_template.provider.provider_inputs.each do |input| %>
|
|
79
|
+
<%= provider_input_fields.fields_for input.name, input do |input_fields| %>
|
|
80
|
+
<%= template_input_f(input_fields) %>
|
|
81
|
+
<% end %>
|
|
82
|
+
<% end %>
|
|
83
|
+
<% end %>
|
|
84
|
+
|
|
77
85
|
<% if job_template.effective_user.overridable? %>
|
|
78
86
|
<%= text_f job_template_fields, :effective_user, :value => @composer.template_invocation(job_template).try(:effective_user), :label => _('Effective user'), :label_help => N_("A user to be used for executing the script. If it differs from the SSH user, su or sudo is used to switch the accounts.") %>
|
|
79
87
|
<% end %>
|