foreman_remote_execution 4.2.2 → 4.5.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 +28 -23
- data/app/controllers/foreman_remote_execution/concerns/api/v2/registration_commands_controller_extensions.rb +19 -0
- data/app/controllers/job_templates_controller.rb +4 -4
- data/app/controllers/ui_job_wizard_controller.rb +30 -0
- data/app/helpers/job_invocations_helper.rb +2 -2
- data/app/helpers/remote_execution_helper.rb +35 -8
- data/app/lib/actions/remote_execution/run_host_job.rb +68 -5
- 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/concerns/foreman_remote_execution/host_extensions.rb +5 -5
- data/app/models/host_status/execution_status.rb +12 -5
- data/app/models/invocation_provider_input_value.rb +12 -0
- data/app/models/job_invocation.rb +28 -8
- data/app/models/job_invocation_composer.rb +72 -17
- data/app/models/remote_execution_provider.rb +17 -2
- data/app/models/setting/remote_execution.rb +10 -0
- data/app/models/ssh_execution_provider.rb +4 -4
- data/app/models/template_invocation.rb +2 -0
- data/app/overrides/execution_interface.rb +8 -8
- data/app/overrides/subnet_proxies.rb +6 -6
- 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 +5 -0
- data/db/migrate/20180110104432_rename_template_invocation_permission.rb +1 -1
- data/db/migrate/20190111153330_remove_remote_execution_without_proxy_setting.rb +4 -4
- data/db/migrate/20210312074713_add_provider_inputs.rb +10 -0
- data/extra/cockpit/foreman-cockpit-session +6 -6
- data/foreman_remote_execution.gemspec +1 -2
- data/lib/foreman_remote_execution/engine.rb +22 -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 +4 -2
- data/test/functional/api/v2/job_invocations_controller_test.rb +38 -5
- 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 +86 -2
- data/test/unit/job_invocation_report_template_test.rb +57 -0
- data/webpack/JobWizard/JobWizard.js +96 -0
- data/webpack/JobWizard/JobWizard.scss +14 -0
- data/webpack/JobWizard/JobWizardConstants.js +6 -0
- data/webpack/JobWizard/JobWizardSelectors.js +38 -0
- data/webpack/JobWizard/__tests__/JobWizard.test.js +13 -0
- data/webpack/JobWizard/__tests__/__snapshots__/JobWizard.test.js.snap +32 -0
- data/webpack/JobWizard/__tests__/__snapshots__/integration.test.js.snap +43 -0
- data/webpack/JobWizard/__tests__/fixtures.js +26 -0
- data/webpack/JobWizard/__tests__/integration.test.js +156 -0
- data/webpack/JobWizard/index.js +32 -0
- data/webpack/JobWizard/steps/AdvancedFields/AdvancedFields.js +93 -0
- data/webpack/JobWizard/steps/AdvancedFields/Fields.js +181 -0
- data/webpack/JobWizard/steps/AdvancedFields/__tests__/AdvancedFields.test.js +25 -0
- data/webpack/JobWizard/steps/AdvancedFields/__tests__/__snapshots__/AdvancedFields.test.js.snap +249 -0
- data/webpack/JobWizard/steps/CategoryAndTemplate/CategoryAndTemplate.js +109 -0
- data/webpack/JobWizard/steps/CategoryAndTemplate/CategoryAndTemplate.test.js +52 -0
- data/webpack/JobWizard/steps/CategoryAndTemplate/__snapshots__/CategoryAndTemplate.test.js.snap +113 -0
- data/webpack/JobWizard/steps/CategoryAndTemplate/index.js +94 -0
- data/webpack/JobWizard/steps/form/FormHelpers.js +19 -0
- data/webpack/JobWizard/steps/form/GroupedSelectField.js +91 -0
- data/webpack/JobWizard/steps/form/SelectField.js +48 -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 +37 -0
- data/webpack/JobWizard/steps/form/__tests__/__snapshots__/SelectField.test.js.snap +23 -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/APISelectors.js +21 -2
- data/webpack/__mocks__/foremanReact/redux/API/index.js +5 -0
- data/webpack/__mocks__/foremanReact/routes/common/PageLayout/PageLayout.js +10 -0
- data/webpack/global_index.js +10 -0
- data/webpack/index.js +3 -4
- data/webpack/react_app/components/RecentJobsCard/RecentJobsCard.js +83 -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__/TargetingHostsSelectors.test.js +8 -3
- data/webpack/react_app/components/TargetingHosts/__tests__/__snapshots__/TargetingHostsPage.test.js.snap +1 -1
- data/webpack/react_app/components/TargetingHosts/__tests__/__snapshots__/TargetingHostsSelectors.test.js.snap +7 -2
- data/webpack/react_app/extend/fillRecentJobsCard.js +11 -0
- data/webpack/react_app/extend/fillregistrationAdvanced.js +11 -0
- data/webpack/react_app/extend/reducers.js +5 -0
- metadata +58 -20
- data/app/views/api/v2/registration/_form.html.erb +0 -12
data/Gemfile
CHANGED
|
@@ -64,24 +64,31 @@ 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
|
|
|
70
80
|
api :POST, '/job_invocations/', N_('Create a job invocation')
|
|
71
81
|
param_group :job_invocation, :as => :create
|
|
72
82
|
def create
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
validate_template
|
|
77
|
-
composer = JobInvocationComposer.from_api_params(
|
|
78
|
-
job_invocation_params
|
|
79
|
-
)
|
|
80
|
-
end
|
|
83
|
+
composer = JobInvocationComposer.from_api_params(
|
|
84
|
+
job_invocation_params
|
|
85
|
+
)
|
|
81
86
|
composer.trigger!
|
|
82
87
|
@job_invocation = composer.job_invocation
|
|
83
88
|
@hosts = @job_invocation.targeting.hosts
|
|
84
89
|
process_response @job_invocation
|
|
90
|
+
rescue JobInvocationComposer::JobTemplateNotFound, JobInvocationComposer::FeatureNotFound => e
|
|
91
|
+
not_found(error: { message: e.message })
|
|
85
92
|
end
|
|
86
93
|
|
|
87
94
|
api :GET, '/job_invocations/:id/hosts/:host_id', N_('Get output for a host')
|
|
@@ -118,7 +125,7 @@ module Api
|
|
|
118
125
|
render :json => { :cancelled => result, :id => @job_invocation.id }
|
|
119
126
|
else
|
|
120
127
|
render :json => { :message => _('The job could not be cancelled.') },
|
|
121
|
-
|
|
128
|
+
:status => :unprocessable_entity
|
|
122
129
|
end
|
|
123
130
|
end
|
|
124
131
|
|
|
@@ -133,7 +140,7 @@ module Api
|
|
|
133
140
|
process_response @job_invocation
|
|
134
141
|
else
|
|
135
142
|
render :json => { :error => _('Could not rerun job %{id} because its template could not be found') % { :id => composer.reruns } },
|
|
136
|
-
|
|
143
|
+
:status => :not_found
|
|
137
144
|
end
|
|
138
145
|
end
|
|
139
146
|
|
|
@@ -180,30 +187,28 @@ module Api
|
|
|
180
187
|
not_found({ :error => { :message => (_("Host with id '%{id}' was not found") % { :id => params['host_id'] }) } })
|
|
181
188
|
end
|
|
182
189
|
|
|
183
|
-
def validate_template
|
|
184
|
-
JobTemplate.authorized(:view_job_templates).find(job_invocation_params['job_template_id'])
|
|
185
|
-
rescue ActiveRecord::RecordNotFound
|
|
186
|
-
not_found({ :error => { :message => (_("Template with id '%{id}' was not found") % { :id => job_invocation_params['job_template_id'] }) } })
|
|
187
|
-
end
|
|
188
|
-
|
|
189
190
|
def job_invocation_params
|
|
190
191
|
return @job_invocation_params if @job_invocation_params.present?
|
|
191
192
|
|
|
192
193
|
job_invocation_params = params.fetch(:job_invocation, {}).dup
|
|
194
|
+
|
|
195
|
+
if job_invocation_params[:feature].present? && job_invocation_params[:job_template_id].present?
|
|
196
|
+
raise _("Only one of feature or job_template_id can be specified")
|
|
197
|
+
end
|
|
198
|
+
|
|
193
199
|
if job_invocation_params.key?(:ssh)
|
|
194
200
|
job_invocation_params.merge!(job_invocation_params.delete(:ssh).permit(:effective_user))
|
|
195
201
|
end
|
|
202
|
+
|
|
196
203
|
job_invocation_params[:inputs] ||= {}
|
|
197
204
|
job_invocation_params[:inputs].permit!
|
|
205
|
+
permit_provider_inputs job_invocation_params
|
|
198
206
|
@job_invocation_params = job_invocation_params
|
|
199
207
|
end
|
|
200
208
|
|
|
201
|
-
def
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
job_invocation_params[:host_ids],
|
|
205
|
-
job_invocation_params[:inputs].to_hash
|
|
206
|
-
)
|
|
209
|
+
def permit_provider_inputs(invocation_params)
|
|
210
|
+
providers = RemoteExecutionProvider.providers.values.reject { |provider| !provider.respond_to?(:provider_input_namespace) || provider.provider_input_namespace.empty? }
|
|
211
|
+
providers.each { |provider| invocation_params[provider.provider_input_namespace]&.permit! }
|
|
207
212
|
end
|
|
208
213
|
|
|
209
214
|
def output_lines_since(task, time)
|
|
@@ -214,7 +219,7 @@ module Api
|
|
|
214
219
|
end
|
|
215
220
|
|
|
216
221
|
def host_output(job_invocation, host, default: nil, since: nil, raw: false)
|
|
217
|
-
refresh =
|
|
222
|
+
refresh = !job_invocation.finished?
|
|
218
223
|
|
|
219
224
|
if (task = job_invocation.sub_task_for_host(host))
|
|
220
225
|
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
|
|
@@ -24,10 +24,10 @@ class JobTemplatesController < ::TemplatesController
|
|
|
24
24
|
render :plain => output
|
|
25
25
|
else
|
|
26
26
|
render status: :not_acceptable,
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
27
|
+
plain: _(
|
|
28
|
+
'Problem with previewing the template: %{error}. Note that you must save template input changes before you try to preview it.' %
|
|
29
|
+
{:error => renderer.error_message}
|
|
30
|
+
)
|
|
31
31
|
end
|
|
32
32
|
end
|
|
33
33
|
|
|
@@ -0,0 +1,30 @@
|
|
|
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 template
|
|
12
|
+
job_template = JobTemplate.authorized.find(params[:id])
|
|
13
|
+
render :json => {
|
|
14
|
+
:job_template => job_template,
|
|
15
|
+
:effective_user => job_template.effective_user,
|
|
16
|
+
}
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
def resource_name(nested_resource = nil)
|
|
20
|
+
nested_resource || 'job_template'
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
def resource_class
|
|
24
|
+
JobTemplate
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
def action_permission
|
|
28
|
+
:view_job_templates
|
|
29
|
+
end
|
|
30
|
+
end
|
|
@@ -34,8 +34,8 @@ module JobInvocationsHelper
|
|
|
34
34
|
hosts.map do |host|
|
|
35
35
|
collapsed_preview(host) +
|
|
36
36
|
render(:partial => 'job_invocations/user_input',
|
|
37
|
-
|
|
38
|
-
|
|
37
|
+
:locals => { :template_invocation => template_invocation,
|
|
38
|
+
:target => host })
|
|
39
39
|
end.reduce(:+)
|
|
40
40
|
end
|
|
41
41
|
|
|
@@ -27,19 +27,19 @@ module RemoteExecutionHelper
|
|
|
27
27
|
|
|
28
28
|
if authorized_for(hash_for_host_path(host).merge(auth_object: host, permission: :view_hosts, authorizer: job_hosts_authorizer))
|
|
29
29
|
links << { title: _('Host detail'),
|
|
30
|
-
|
|
30
|
+
action: { href: host_path(host), 'data-method': 'get', id: "#{host.name}-actions-detail" } }
|
|
31
31
|
end
|
|
32
32
|
|
|
33
33
|
if authorized_for(hash_for_rerun_job_invocation_path(id: job_invocation, host_ids: [ host.id ], authorizer: job_hosts_authorizer))
|
|
34
34
|
links << { title: (_('Rerun on %s') % host.name),
|
|
35
|
-
|
|
36
|
-
|
|
35
|
+
action: { href: rerun_job_invocation_path(job_invocation, host_ids: [ host.id ]),
|
|
36
|
+
'data-method': 'get', id: "#{host.name}-actions-rerun" } }
|
|
37
37
|
end
|
|
38
38
|
|
|
39
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
40
|
links << { title: _('Host task'),
|
|
41
|
-
|
|
42
|
-
|
|
41
|
+
action: { href: foreman_tasks_task_path(host_task),
|
|
42
|
+
'data-method': 'get', id: "#{host.name}-actions-task" } }
|
|
43
43
|
end
|
|
44
44
|
|
|
45
45
|
links
|
|
@@ -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',
|
|
@@ -153,11 +159,11 @@ module RemoteExecutionHelper
|
|
|
153
159
|
content_tag :pre, preview
|
|
154
160
|
elsif target.nil?
|
|
155
161
|
alert :text => _('Could not render the preview because no host matches the search query.'),
|
|
156
|
-
|
|
157
|
-
|
|
162
|
+
:class => 'alert alert-block alert-warning base',
|
|
163
|
+
:close => false
|
|
158
164
|
else
|
|
159
165
|
alert :class => 'alert-block alert-danger base in fade has-error',
|
|
160
|
-
|
|
166
|
+
:text => renderer.error_message.html_safe # rubocop:disable Rails/OutputSafety
|
|
161
167
|
end
|
|
162
168
|
end
|
|
163
169
|
|
|
@@ -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,9 @@ module Actions
|
|
|
3
3
|
class RunHostJob < Actions::EntryAction
|
|
4
4
|
include ::Actions::Helpers::WithContinuousOutput
|
|
5
5
|
include ::Actions::Helpers::WithDelegatedAction
|
|
6
|
+
include ::Actions::ObservableAction
|
|
7
|
+
|
|
8
|
+
execution_plan_hooks.use :emit_feature_event, :on => :success
|
|
6
9
|
|
|
7
10
|
middleware.do_not_use Dynflow::Middleware::Common::Transaction
|
|
8
11
|
middleware.use Actions::Middleware::HideSecrets
|
|
@@ -16,7 +19,12 @@ module Actions
|
|
|
16
19
|
end
|
|
17
20
|
|
|
18
21
|
def plan(job_invocation, host, template_invocation, proxy_selector = ::RemoteExecutionProxySelector.new, options = {})
|
|
19
|
-
|
|
22
|
+
features = template_invocation.template.remote_execution_features.pluck(:label).uniq
|
|
23
|
+
action_subject(host,
|
|
24
|
+
:job_category => job_invocation.job_category,
|
|
25
|
+
:description => job_invocation.description,
|
|
26
|
+
:job_invocation_id => job_invocation.id,
|
|
27
|
+
:job_features => features)
|
|
20
28
|
|
|
21
29
|
template_invocation.host_id = host.id
|
|
22
30
|
template_invocation.run_host_job_task_id = task.id
|
|
@@ -57,6 +65,22 @@ module Actions
|
|
|
57
65
|
check_exit_status
|
|
58
66
|
end
|
|
59
67
|
|
|
68
|
+
def self.feature_job_event_name(label, suffix = :success)
|
|
69
|
+
::Foreman::Observable.event_name_for("#{::Actions::RemoteExecution::RunHostJob.event_name_base}_#{label}_#{::Actions::RemoteExecution::RunHostJob.event_name_suffix(suffix)}")
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
def emit_feature_event(execution_plan, hook = :success)
|
|
73
|
+
return unless root_action?
|
|
74
|
+
|
|
75
|
+
payload = event_payload(execution_plan)
|
|
76
|
+
if input["job_features"]&.any?
|
|
77
|
+
input['job_features'].each do |feature|
|
|
78
|
+
name = "#{self.class.event_name_base}_#{feature}_#{self.class.event_name_suffix(hook)}"
|
|
79
|
+
trigger_hook name, payload: payload
|
|
80
|
+
end
|
|
81
|
+
end
|
|
82
|
+
end
|
|
83
|
+
|
|
60
84
|
def secrets(host, job_invocation, provider)
|
|
61
85
|
job_secrets = { :ssh_password => job_invocation.password,
|
|
62
86
|
:key_passphrase => job_invocation.key_passphrase,
|
|
@@ -77,7 +101,7 @@ module Actions
|
|
|
77
101
|
|
|
78
102
|
def humanized_input
|
|
79
103
|
N_('%{description} on %{host}') % { :host => input[:host].try(:[], :name),
|
|
80
|
-
|
|
104
|
+
:description => input[:description].try(:capitalize) || input[:job_category] }
|
|
81
105
|
end
|
|
82
106
|
|
|
83
107
|
def humanized_name
|
|
@@ -121,6 +145,26 @@ module Actions
|
|
|
121
145
|
delegated_output[:exit_status]
|
|
122
146
|
end
|
|
123
147
|
|
|
148
|
+
def host_id
|
|
149
|
+
input['host']['id']
|
|
150
|
+
end
|
|
151
|
+
|
|
152
|
+
def host_name
|
|
153
|
+
input['host']['name']
|
|
154
|
+
end
|
|
155
|
+
|
|
156
|
+
def job_invocation_id
|
|
157
|
+
input['job_invocation_id']
|
|
158
|
+
end
|
|
159
|
+
|
|
160
|
+
def job_invocation
|
|
161
|
+
@job_invocation ||= ::JobInvocation.authorized.find(job_invocation_id)
|
|
162
|
+
end
|
|
163
|
+
|
|
164
|
+
def host
|
|
165
|
+
@host ||= ::Host.authorized.find(host_id)
|
|
166
|
+
end
|
|
167
|
+
|
|
124
168
|
private
|
|
125
169
|
|
|
126
170
|
def update_host_status
|
|
@@ -165,14 +209,33 @@ module Actions
|
|
|
165
209
|
'All %{count} applicable proxies are down. Tried %{proxy_names}',
|
|
166
210
|
offline_proxies.count) % settings
|
|
167
211
|
elsif proxy == :not_defined
|
|
168
|
-
settings = {
|
|
169
|
-
|
|
212
|
+
settings = {
|
|
213
|
+
global_proxy: 'remote_execution_global_proxy',
|
|
214
|
+
fallback_proxy: 'remote_execution_fallback_proxy',
|
|
215
|
+
provider: provider,
|
|
216
|
+
}
|
|
170
217
|
|
|
171
|
-
raise _('Could not use any proxy. Consider configuring %{global_proxy}, ' +
|
|
218
|
+
raise _('Could not use any proxy for the %{provider} job. Consider configuring %{global_proxy}, ' +
|
|
172
219
|
'%{fallback_proxy} in settings') % settings
|
|
173
220
|
end
|
|
174
221
|
proxy
|
|
175
222
|
end
|
|
223
|
+
|
|
224
|
+
extend ApipieDSL::Class
|
|
225
|
+
apipie :class, "An action representing execution of a job against a host" do
|
|
226
|
+
name 'Actions::RemoteExecution::RunHostJob'
|
|
227
|
+
refs 'Actions::RemoteExecution::RunHostJob'
|
|
228
|
+
sections only: %w[all webhooks]
|
|
229
|
+
property :task, object_of: 'Task', desc: 'Returns the task to which this action belongs'
|
|
230
|
+
property :host_name, String, desc: "Returns the name of the host"
|
|
231
|
+
property :host_id, Integer, desc: "Returns the id of the host"
|
|
232
|
+
property :host, object_of: 'Host', desc: "Returns the host"
|
|
233
|
+
property :job_invocation_id, Integer, desc: "Returns the id of the job invocation"
|
|
234
|
+
property :job_invocation, object_of: 'JobInvocation', desc: "Returns the job invocation"
|
|
235
|
+
end
|
|
236
|
+
class Jail < ::Actions::ObservableAction::Jail
|
|
237
|
+
allow :host_name, :host_id, :host, :job_invocation_id, :job_invocation
|
|
238
|
+
end
|
|
176
239
|
end
|
|
177
240
|
end
|
|
178
241
|
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
|
|
@@ -8,15 +8,15 @@ module ForemanRemoteExecution
|
|
|
8
8
|
has_many :run_host_job_tasks, :through => :template_invocations
|
|
9
9
|
|
|
10
10
|
scoped_search :relation => :run_host_job_tasks, :on => :result, :rename => 'job_invocation.result',
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
11
|
+
:ext_method => :search_by_job_invocation,
|
|
12
|
+
:only_explicit => true,
|
|
13
|
+
:complete_value => TemplateInvocation::TaskResultMap::REVERSE_MAP
|
|
14
14
|
|
|
15
15
|
scoped_search :relation => :template_invocations, :on => :job_invocation_id,
|
|
16
|
-
|
|
16
|
+
:rename => 'job_invocation.id', :only_explicit => true, :ext_method => :search_by_job_invocation
|
|
17
17
|
|
|
18
18
|
scoped_search :relation => :execution_status_object, :on => :status, :rename => :execution_status,
|
|
19
|
-
|
|
19
|
+
:complete_value => { :ok => HostStatus::ExecutionStatus::OK, :error => HostStatus::ExecutionStatus::ERROR }
|
|
20
20
|
|
|
21
21
|
def search_by_job_invocation(key, operator, value)
|
|
22
22
|
if key == 'job_invocation.result'
|