foreman_remote_execution 4.4.0 → 4.5.3
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/app/controllers/api/v2/job_invocations_controller.rb +13 -24
- data/app/controllers/job_invocations_controller.rb +1 -1
- data/app/controllers/job_templates_controller.rb +4 -4
- data/app/controllers/ui_job_wizard_controller.rb +19 -0
- data/app/helpers/job_invocations_helper.rb +2 -2
- data/app/helpers/remote_execution_helper.rb +13 -9
- data/app/lib/actions/remote_execution/run_host_job.rb +36 -6
- data/app/models/concerns/foreman_remote_execution/host_extensions.rb +7 -5
- data/app/models/concerns/foreman_remote_execution/smart_proxy_extensions.rb +6 -0
- data/app/models/host_proxy_invocation.rb +4 -0
- data/app/models/host_status/execution_status.rb +5 -5
- data/app/models/job_invocation.rb +31 -12
- data/app/models/job_invocation_composer.rb +61 -19
- data/app/models/remote_execution_provider.rb +1 -1
- data/app/models/setting/remote_execution.rb +2 -2
- data/app/models/ssh_execution_provider.rb +4 -4
- data/app/models/targeting.rb +5 -1
- data/app/overrides/execution_interface.rb +8 -8
- data/app/overrides/subnet_proxies.rb +6 -6
- data/app/views/job_invocations/index.html.erb +1 -1
- data/app/views/templates/ssh/module_action.erb +1 -0
- data/app/views/templates/ssh/puppet_run_once.erb +1 -0
- data/config/routes.rb +1 -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/2021051713291621250977_add_host_proxy_invocations.rb +12 -0
- data/extra/cockpit/foreman-cockpit-session +6 -6
- data/lib/foreman_remote_execution/engine.rb +11 -8
- data/lib/foreman_remote_execution/version.rb +1 -1
- data/package.json +2 -1
- data/test/functional/api/v2/job_invocations_controller_test.rb +14 -1
- data/test/unit/job_invocation_composer_test.rb +59 -2
- data/test/unit/job_invocation_test.rb +1 -1
- data/webpack/JobWizard/JobWizard.js +80 -19
- data/webpack/JobWizard/JobWizard.scss +42 -1
- data/webpack/JobWizard/JobWizardConstants.js +11 -0
- data/webpack/JobWizard/JobWizardSelectors.js +27 -1
- data/webpack/JobWizard/__tests__/__snapshots__/integration.test.js.snap +43 -0
- data/webpack/JobWizard/__tests__/fixtures.js +128 -0
- data/webpack/JobWizard/__tests__/integration.test.js +84 -0
- data/webpack/JobWizard/steps/AdvancedFields/AdvancedFields.js +110 -0
- data/webpack/JobWizard/steps/AdvancedFields/DescriptionField.js +67 -0
- data/webpack/JobWizard/steps/AdvancedFields/Fields.js +195 -0
- data/webpack/JobWizard/steps/AdvancedFields/__tests__/AdvancedFields.test.js +144 -0
- data/webpack/JobWizard/steps/AdvancedFields/__tests__/DescriptionField.test.js +23 -0
- data/webpack/JobWizard/steps/CategoryAndTemplate/CategoryAndTemplate.js +34 -2
- data/webpack/JobWizard/steps/CategoryAndTemplate/CategoryAndTemplate.test.js +122 -44
- data/webpack/JobWizard/steps/CategoryAndTemplate/index.js +9 -1
- data/webpack/JobWizard/steps/Schedule/QueryType.js +48 -0
- data/webpack/JobWizard/steps/Schedule/RepeatOn.js +61 -0
- data/webpack/JobWizard/steps/Schedule/ScheduleType.js +25 -0
- data/webpack/JobWizard/steps/Schedule/StartEndDates.js +51 -0
- data/webpack/JobWizard/steps/Schedule/__tests__/StartEndDates.test.js +22 -0
- data/webpack/JobWizard/steps/Schedule/index.js +41 -0
- data/webpack/JobWizard/steps/form/FormHelpers.js +20 -0
- data/webpack/JobWizard/steps/form/Formatter.js +149 -0
- data/webpack/JobWizard/steps/form/GroupedSelectField.js +3 -0
- data/webpack/JobWizard/steps/form/NumberInput.js +33 -0
- data/webpack/JobWizard/steps/form/SelectField.js +24 -3
- data/webpack/JobWizard/steps/form/__tests__/Formatter.test.js.example +76 -0
- data/webpack/__mocks__/foremanReact/components/SearchBar.js +18 -1
- data/webpack/__mocks__/foremanReact/redux/API/APISelectors.js +21 -2
- data/webpack/global_index.js +5 -3
- data/webpack/index.js +3 -0
- data/webpack/react_app/components/RecentJobsCard/RecentJobsCard.js +1 -5
- 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 -0
- data/webpack/react_app/components/TargetingHosts/__tests__/__snapshots__/TargetingHostsSelectors.test.js.snap +7 -2
- data/webpack/react_app/extend/{fills.js → fillRecentJobsCard.js} +7 -6
- data/webpack/react_app/extend/fillregistrationAdvanced.js +11 -0
- data/webpack/react_app/extend/reducers.js +2 -1
- metadata +24 -14
- data/app/models/concerns/foreman_remote_execution/orchestration/ssh.rb +0 -70
- data/test/models/orchestration/ssh_test.rb +0 -56
- data/webpack/JobWizard/__tests__/JobWizard.test.js +0 -20
- data/webpack/JobWizard/__tests__/__snapshots__/JobWizard.test.js.snap +0 -83
- data/webpack/JobWizard/steps/CategoryAndTemplate/__snapshots__/CategoryAndTemplate.test.js.snap +0 -64
- data/webpack/JobWizard/steps/form/__tests__/GroupedSelectField.test.js +0 -38
- data/webpack/JobWizard/steps/form/__tests__/SelectField.test.js +0 -23
- data/webpack/JobWizard/steps/form/__tests__/__snapshots__/GroupedSelectField.test.js.snap +0 -36
- data/webpack/JobWizard/steps/form/__tests__/__snapshots__/SelectField.test.js.snap +0 -22
- data/webpack/fills_index.js +0 -11
|
@@ -1,4 +1,7 @@
|
|
|
1
1
|
class JobInvocationComposer
|
|
2
|
+
class JobTemplateNotFound < StandardError; end
|
|
3
|
+
|
|
4
|
+
class FeatureNotFound < StandardError; end
|
|
2
5
|
|
|
3
6
|
class UiParams
|
|
4
7
|
attr_reader :ui_params
|
|
@@ -100,6 +103,17 @@ class JobInvocationComposer
|
|
|
100
103
|
|
|
101
104
|
def initialize(api_params)
|
|
102
105
|
@api_params = api_params
|
|
106
|
+
|
|
107
|
+
if api_params[:feature]
|
|
108
|
+
# set a default targeting type for backward compatibility
|
|
109
|
+
# when `for_feature` was used by the API it automatically set a default
|
|
110
|
+
api_params[:targeting_type] = Targeting::STATIC_TYPE
|
|
111
|
+
end
|
|
112
|
+
|
|
113
|
+
if api_params[:search_query].blank? && api_params[:host_ids].present?
|
|
114
|
+
translator = HostIdsTranslator.new(api_params[:host_ids])
|
|
115
|
+
api_params[:search_query] = translator.scoped_search
|
|
116
|
+
end
|
|
103
117
|
end
|
|
104
118
|
|
|
105
119
|
def params
|
|
@@ -107,12 +121,16 @@ class JobInvocationComposer
|
|
|
107
121
|
:targeting => targeting_params,
|
|
108
122
|
:triggering => triggering_params,
|
|
109
123
|
:description_format => api_params[:description_format],
|
|
110
|
-
:remote_execution_feature_id =>
|
|
124
|
+
:remote_execution_feature_id => remote_execution_feature_id,
|
|
111
125
|
:concurrency_control => concurrency_control_params,
|
|
112
126
|
:execution_timeout_interval => api_params[:execution_timeout_interval] || template.execution_timeout_interval,
|
|
113
127
|
:template_invocations => template_invocations_params }.with_indifferent_access
|
|
114
128
|
end
|
|
115
129
|
|
|
130
|
+
def remote_execution_feature_id
|
|
131
|
+
feature&.id || api_params[:remote_execution_feature_id]
|
|
132
|
+
end
|
|
133
|
+
|
|
116
134
|
def targeting_params
|
|
117
135
|
raise ::Foreman::Exception, _('Cannot specify both bookmark_id and search_query') if api_params[:bookmark_id] && api_params[:search_query]
|
|
118
136
|
|
|
@@ -156,7 +174,7 @@ class JobInvocationComposer
|
|
|
156
174
|
input = template.template_inputs_with_foreign.find { |i| i.name == name }
|
|
157
175
|
unless input
|
|
158
176
|
raise ::Foreman::Exception, _('Unknown input %{input_name} for template %{template_name}') %
|
|
159
|
-
|
|
177
|
+
{ :input_name => name, :template_name => template.name }
|
|
160
178
|
end
|
|
161
179
|
{ :template_input_id => input.id, :value => value }
|
|
162
180
|
end
|
|
@@ -170,8 +188,20 @@ class JobInvocationComposer
|
|
|
170
188
|
inputs.select { |key, value| provider_input_names.include? key }.map { |key, value| { :name => key, :value => value } }
|
|
171
189
|
end
|
|
172
190
|
|
|
191
|
+
def feature
|
|
192
|
+
@feature ||= RemoteExecutionFeature.feature(api_params[:feature]) if api_params[:feature]
|
|
193
|
+
rescue => e
|
|
194
|
+
raise(FeatureNotFound, e.message)
|
|
195
|
+
end
|
|
196
|
+
|
|
197
|
+
def job_template_id
|
|
198
|
+
feature&.job_template_id || api_params[:job_template_id]
|
|
199
|
+
end
|
|
200
|
+
|
|
173
201
|
def template
|
|
174
|
-
@template ||= JobTemplate.authorized(:view_job_templates).find(
|
|
202
|
+
@template ||= JobTemplate.authorized(:view_job_templates).find(job_template_id)
|
|
203
|
+
rescue ActiveRecord::RecordNotFound
|
|
204
|
+
raise(JobTemplateNotFound, _("Template with id '%{id}' was not found") % { id: job_template_id })
|
|
175
205
|
end
|
|
176
206
|
|
|
177
207
|
private
|
|
@@ -239,25 +269,38 @@ class JobInvocationComposer
|
|
|
239
269
|
end
|
|
240
270
|
end
|
|
241
271
|
|
|
272
|
+
class HostIdsTranslator
|
|
273
|
+
attr_reader :bookmark, :hosts, :scoped_search, :host_ids
|
|
274
|
+
|
|
275
|
+
def initialize(input)
|
|
276
|
+
case input
|
|
277
|
+
when Bookmark
|
|
278
|
+
@bookmark = input
|
|
279
|
+
when Host::Base
|
|
280
|
+
@hosts = [input]
|
|
281
|
+
when Array
|
|
282
|
+
@hosts = input.map do |id|
|
|
283
|
+
Host::Managed.authorized.friendly.find(id)
|
|
284
|
+
end
|
|
285
|
+
when String
|
|
286
|
+
@scoped_search = input
|
|
287
|
+
else
|
|
288
|
+
@hosts = input
|
|
289
|
+
end
|
|
290
|
+
|
|
291
|
+
@scoped_search ||= Targeting.build_query_from_hosts(hosts.map(&:id)) if @hosts
|
|
292
|
+
end
|
|
293
|
+
end
|
|
294
|
+
|
|
242
295
|
class ParamsForFeature
|
|
243
296
|
attr_reader :feature_label, :feature, :provided_inputs
|
|
244
297
|
|
|
245
298
|
def initialize(feature_label, hosts, provided_inputs = {})
|
|
246
299
|
@feature = RemoteExecutionFeature.feature(feature_label)
|
|
247
300
|
@provided_inputs = provided_inputs
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
@host_objects = [hosts]
|
|
252
|
-
elsif hosts.is_a? Array
|
|
253
|
-
@host_objects = hosts.map do |id|
|
|
254
|
-
Host::Managed.authorized.friendly.find(id)
|
|
255
|
-
end
|
|
256
|
-
elsif hosts.is_a? String
|
|
257
|
-
@host_scoped_search = hosts
|
|
258
|
-
else
|
|
259
|
-
@host_objects = hosts
|
|
260
|
-
end
|
|
301
|
+
translator = HostIdsTranslator.new(hosts)
|
|
302
|
+
@host_bookmark = translator.bookmark
|
|
303
|
+
@host_scoped_search = translator.scoped_search
|
|
261
304
|
end
|
|
262
305
|
|
|
263
306
|
def params
|
|
@@ -275,7 +318,6 @@ class JobInvocationComposer
|
|
|
275
318
|
ret = {}
|
|
276
319
|
ret['targeting_type'] = Targeting::STATIC_TYPE
|
|
277
320
|
ret['search_query'] = @host_scoped_search if @host_scoped_search
|
|
278
|
-
ret['search_query'] = Targeting.build_query_from_hosts(@host_objects) if @host_objects
|
|
279
321
|
ret['bookmark_id'] = @host_bookmark.id if @host_bookmark
|
|
280
322
|
ret['user_id'] = User.current.id
|
|
281
323
|
ret
|
|
@@ -363,7 +405,7 @@ class JobInvocationComposer
|
|
|
363
405
|
job_invocation.effective_user_password = params[:effective_user_password]
|
|
364
406
|
|
|
365
407
|
if @reruns && job_invocation.targeting.static?
|
|
366
|
-
job_invocation.targeting.
|
|
408
|
+
job_invocation.targeting.assign_host_ids(JobInvocation.find(@reruns).targeting.host_ids)
|
|
367
409
|
job_invocation.targeting.mark_resolved!
|
|
368
410
|
end
|
|
369
411
|
|
|
@@ -553,7 +595,7 @@ class JobInvocationComposer
|
|
|
553
595
|
|
|
554
596
|
params[:template_invocations].select { |t| valid_template_ids.include?(t[:template_id].to_i) }.map do |template_invocation_params|
|
|
555
597
|
template_invocation = job_invocation.pattern_template_invocations.build(:template_id => template_invocation_params[:template_id],
|
|
556
|
-
|
|
598
|
+
:effective_user => build_effective_user(template_invocation_params))
|
|
557
599
|
build_input_values_for(template_invocation, template_invocation_params)
|
|
558
600
|
template_invocation
|
|
559
601
|
end
|
|
@@ -50,7 +50,7 @@ class RemoteExecutionProvider
|
|
|
50
50
|
method = host_setting(host, :remote_execution_effective_user_method)
|
|
51
51
|
unless EFFECTIVE_USER_METHODS.include?(method)
|
|
52
52
|
raise _('Effective user method "%{current_value}" is not one of %{valid_methods}') %
|
|
53
|
-
|
|
53
|
+
{ :current_value => method, :valid_methods => EFFECTIVE_USER_METHODS}
|
|
54
54
|
end
|
|
55
55
|
method
|
|
56
56
|
end
|
|
@@ -70,13 +70,13 @@ class Setting::RemoteExecution < Setting
|
|
|
70
70
|
self.set('remote_execution_form_job_template',
|
|
71
71
|
N_('Choose a job template that is pre-selected in job invocation form'),
|
|
72
72
|
'Run Command - SSH Default',
|
|
73
|
-
|
|
73
|
+
N_('Form Job Template'),
|
|
74
74
|
nil,
|
|
75
75
|
{ :collection => proc { Hash[JobTemplate.unscoped.map { |template| [template.name, template.name] }] } }),
|
|
76
76
|
self.set('remote_execution_job_invocation_report_template',
|
|
77
77
|
N_('Select a report template used for generating a report for a particular remote execution job'),
|
|
78
78
|
'Jobs - Invocation report template',
|
|
79
|
-
|
|
79
|
+
N_('Job Invocation Report Template'),
|
|
80
80
|
nil,
|
|
81
81
|
{ :collection => proc { self.job_invocation_report_templates_select } }),
|
|
82
82
|
]
|
|
@@ -2,10 +2,10 @@ class SSHExecutionProvider < RemoteExecutionProvider
|
|
|
2
2
|
class << self
|
|
3
3
|
def proxy_command_options(template_invocation, host)
|
|
4
4
|
super.merge(:ssh_user => ssh_user(host),
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
5
|
+
:effective_user => effective_user(template_invocation),
|
|
6
|
+
:effective_user_method => effective_user_method(host),
|
|
7
|
+
:cleanup_working_dirs => cleanup_working_dirs?(host),
|
|
8
|
+
:ssh_port => ssh_port(host))
|
|
9
9
|
end
|
|
10
10
|
|
|
11
11
|
def humanized_name
|
data/app/models/targeting.rb
CHANGED
|
@@ -46,9 +46,13 @@ class Targeting < ApplicationRecord
|
|
|
46
46
|
# pluck(:id) returns duplicate results for HostCollections
|
|
47
47
|
host_ids = User.as(user.login) { Host.authorized(RESOLVE_PERMISSION, Host).search_for(search_query).order(:name, :id).pluck(:id).uniq }
|
|
48
48
|
host_ids.shuffle!(random: Random.new) if randomized_ordering
|
|
49
|
+
self.assign_host_ids(host_ids)
|
|
50
|
+
self.save(:validate => false)
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
def assign_host_ids(host_ids)
|
|
49
54
|
# this can be optimized even more, by introducing bulk insert
|
|
50
55
|
self.targeting_hosts.build(host_ids.map { |id| { :host_id => id } })
|
|
51
|
-
self.save(:validate => false)
|
|
52
56
|
end
|
|
53
57
|
|
|
54
58
|
def dynamic?
|
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
Deface::Override.new(:virtual_path
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
1
|
+
Deface::Override.new(:virtual_path => 'hosts/_form',
|
|
2
|
+
:name => 'add_execution_interface_js',
|
|
3
|
+
:insert_before => 'div#primary',
|
|
4
|
+
:text => '<%= javascript "foreman_remote_execution/execution_interface" %>')
|
|
5
5
|
|
|
6
|
-
Deface::Override.new(:virtual_path
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
6
|
+
Deface::Override.new(:virtual_path => 'nic/_base_form',
|
|
7
|
+
:name => 'add_execution_interface',
|
|
8
|
+
:insert_after => 'erb[loud]:contains("interface_provision")',
|
|
9
|
+
:partial => 'overrides/nics/execution_interface')
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
Deface::Override.new(:virtual_path => 'subnets/_form',
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
2
|
+
:name => 'add_remote_execution_proxies_tab',
|
|
3
|
+
:insert_after => 'li.active',
|
|
4
|
+
:partial => 'overrides/subnets/rex_tab')
|
|
5
5
|
|
|
6
6
|
Deface::Override.new(:virtual_path => 'subnets/_form',
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
7
|
+
:name => 'add_remote_execution_proxies_tab_pane',
|
|
8
|
+
:insert_after => 'div#proxies',
|
|
9
|
+
:partial => 'overrides/subnets/rex_tab_pane')
|
|
@@ -21,7 +21,7 @@
|
|
|
21
21
|
<% @job_invocations.each do |invocation| %>
|
|
22
22
|
<tr>
|
|
23
23
|
<td class="text_warp"><%= link_to_if_authorized invocation_description(invocation), hash_for_job_invocation_path(invocation).merge(:auth_object => invocation, :permission => :view_job_invocations, :authorizer => authorizer) %></td>
|
|
24
|
-
<td><%= trunc_with_tooltip(invocation
|
|
24
|
+
<td><%= trunc_with_tooltip(invocation.targeting.search_query, 15) %></td>
|
|
25
25
|
<td><%= link_to_invocation_task_if_authorized(invocation) %></td>
|
|
26
26
|
<td><%= invocation_result(invocation, :success_count) %></td>
|
|
27
27
|
<td><%= invocation_result(invocation, :failed_count) %></td>
|
data/config/routes.rb
CHANGED
|
@@ -44,6 +44,7 @@ Rails.application.routes.draw do
|
|
|
44
44
|
end
|
|
45
45
|
get 'cockpit/redirect', to: 'cockpit#redirect'
|
|
46
46
|
get 'ui_job_wizard/categories', to: 'ui_job_wizard#categories'
|
|
47
|
+
get 'ui_job_wizard/template/:id', to: 'ui_job_wizard#template'
|
|
47
48
|
|
|
48
49
|
match '/experimental/job_wizard', to: 'react#index', :via => [:get]
|
|
49
50
|
|
|
@@ -16,7 +16,7 @@ class RenameTemplateInvocationPermission < ActiveRecord::Migration[4.2]
|
|
|
16
16
|
return if old_permission.nil?
|
|
17
17
|
|
|
18
18
|
new_permission = Permission.find_or_create_by(:name => new,
|
|
19
|
-
|
|
19
|
+
:resource_type => 'TemplateInvocation')
|
|
20
20
|
old_permission.filterings.each do |filtering|
|
|
21
21
|
filtering.permission_id = new_permission.id
|
|
22
22
|
filtering.save!
|
|
@@ -5,9 +5,9 @@ class RemoveRemoteExecutionWithoutProxySetting < ActiveRecord::Migration[5.2]
|
|
|
5
5
|
|
|
6
6
|
def down
|
|
7
7
|
Setting.create!(:name => 'remote_execution_without_proxy',
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
8
|
+
:description => N_('When enabled, the remote execution will try to run '\
|
|
9
|
+
'the commands directly, when no proxy with remote execution '\
|
|
10
|
+
'feature is configured for the host.'),
|
|
11
|
+
:default => false, :full_name => N_('Fallback Without Proxy'))
|
|
12
12
|
end
|
|
13
13
|
end
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
class AddHostProxyInvocations < ActiveRecord::Migration[6.0]
|
|
2
|
+
def change
|
|
3
|
+
# rubocop:disable Rails/CreateTableWithTimestamps
|
|
4
|
+
create_table :host_proxy_invocations do |t|
|
|
5
|
+
t.references :host, :null => false
|
|
6
|
+
t.references :smart_proxy, :null => false
|
|
7
|
+
end
|
|
8
|
+
# rubocop:enable Rails/CreateTableWithTimestamps
|
|
9
|
+
|
|
10
|
+
add_index :host_proxy_invocations, [:host_id, :smart_proxy_id], unique: true
|
|
11
|
+
end
|
|
12
|
+
end
|
|
@@ -56,13 +56,13 @@ end
|
|
|
56
56
|
|
|
57
57
|
def send_auth_challenge(challenge)
|
|
58
58
|
send_control({ "command" => "authorize",
|
|
59
|
-
|
|
60
|
-
|
|
59
|
+
"cookie" => "1234", # must be present, but value doesn't matter
|
|
60
|
+
"challenge" => challenge})
|
|
61
61
|
end
|
|
62
62
|
|
|
63
63
|
def send_auth_response(response)
|
|
64
64
|
send_control({ "command" => "authorize",
|
|
65
|
-
|
|
65
|
+
"response" => response})
|
|
66
66
|
end
|
|
67
67
|
|
|
68
68
|
def read_auth_reply
|
|
@@ -76,9 +76,9 @@ end
|
|
|
76
76
|
def exit_with_problem(problem, message, auth_methods)
|
|
77
77
|
LOG.error("#{problem} - #{message}")
|
|
78
78
|
send_control({ "command" => "init",
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
79
|
+
"problem" => problem,
|
|
80
|
+
"message" => message,
|
|
81
|
+
"auth-method-results" => auth_methods})
|
|
82
82
|
exit 1
|
|
83
83
|
end
|
|
84
84
|
|
|
@@ -51,14 +51,13 @@ module ForemanRemoteExecution
|
|
|
51
51
|
|
|
52
52
|
initializer 'foreman_remote_execution.register_plugin', before: :finisher_hook do |_app|
|
|
53
53
|
Foreman::Plugin.register :foreman_remote_execution do
|
|
54
|
-
register_global_js_file 'global'
|
|
55
54
|
requires_foreman '>= 2.2'
|
|
55
|
+
register_global_js_file 'global'
|
|
56
56
|
|
|
57
57
|
apipie_documented_controllers ["#{ForemanRemoteExecution::Engine.root}/app/controllers/api/v2/*.rb"]
|
|
58
58
|
ApipieDSL.configuration.dsl_classes_matchers += [
|
|
59
59
|
"#{ForemanRemoteExecution::Engine.root}/app/lib/foreman_remote_execution/renderer/**/*.rb",
|
|
60
60
|
]
|
|
61
|
-
register_global_js_file 'global'
|
|
62
61
|
automatic_assets(false)
|
|
63
62
|
precompile_assets(*assets_to_precompile)
|
|
64
63
|
|
|
@@ -68,7 +67,7 @@ module ForemanRemoteExecution
|
|
|
68
67
|
:'api/v2/job_templates' => [:index, :show, :revision, :export],
|
|
69
68
|
:'api/v2/template_inputs' => [:index, :show],
|
|
70
69
|
:'api/v2/foreign_input_sets' => [:index, :show],
|
|
71
|
-
:ui_job_wizard => [:categories]}, :resource_type => 'JobTemplate'
|
|
70
|
+
:ui_job_wizard => [:categories, :template]}, :resource_type => 'JobTemplate'
|
|
72
71
|
permission :create_job_templates, { :job_templates => [:new, :create, :clone_template, :import],
|
|
73
72
|
:'api/v2/job_templates' => [:create, :clone, :import] }, :resource_type => 'JobTemplate'
|
|
74
73
|
permission :edit_job_templates, { :job_templates => [:edit, :update],
|
|
@@ -141,7 +140,7 @@ module ForemanRemoteExecution
|
|
|
141
140
|
url_hash: { controller: 'job_wizard', action: :index },
|
|
142
141
|
caption: N_('Job wizard'),
|
|
143
142
|
parent: :lab_features_menu,
|
|
144
|
-
url: 'experimental/job_wizard',
|
|
143
|
+
url: '/experimental/job_wizard',
|
|
145
144
|
after: :host_wizard
|
|
146
145
|
|
|
147
146
|
register_custom_status HostStatus::ExecutionStatus
|
|
@@ -163,9 +162,15 @@ module ForemanRemoteExecution
|
|
|
163
162
|
|
|
164
163
|
# Extend Registration module
|
|
165
164
|
extend_allowed_registration_vars :remote_execution_interface
|
|
166
|
-
register_global_js_file 'fills'
|
|
167
165
|
ForemanTasks.dynflow.eager_load_actions!
|
|
168
|
-
extend_observable_events(
|
|
166
|
+
extend_observable_events(
|
|
167
|
+
::Dynflow::Action.descendants.select do |klass|
|
|
168
|
+
klass <= ::Actions::ObservableAction
|
|
169
|
+
end.map(&:namespaced_event_names) +
|
|
170
|
+
RemoteExecutionFeature.all.pluck(:label).map do |label|
|
|
171
|
+
::Actions::RemoteExecution::RunHostJob.feature_job_event_name(label)
|
|
172
|
+
end
|
|
173
|
+
)
|
|
169
174
|
end
|
|
170
175
|
end
|
|
171
176
|
|
|
@@ -196,12 +201,10 @@ module ForemanRemoteExecution
|
|
|
196
201
|
|
|
197
202
|
Host::Managed.prepend ForemanRemoteExecution::HostExtensions
|
|
198
203
|
Host::Managed.include ForemanTasks::Concerns::HostActionSubject
|
|
199
|
-
Host::Managed.include ForemanRemoteExecution::Orchestration::SSH
|
|
200
204
|
|
|
201
205
|
(Nic::Base.descendants + [Nic::Base]).each do |klass|
|
|
202
206
|
klass.send(:include, ForemanRemoteExecution::NicExtensions)
|
|
203
207
|
end
|
|
204
|
-
Nic::Managed.include ForemanRemoteExecution::Orchestration::SSH
|
|
205
208
|
|
|
206
209
|
Bookmark.include ForemanRemoteExecution::BookmarkExtensions
|
|
207
210
|
HostsHelper.prepend ForemanRemoteExecution::HostsHelperExtensions
|
data/package.json
CHANGED
|
@@ -29,7 +29,8 @@
|
|
|
29
29
|
"babel-eslint": "^10.0.0",
|
|
30
30
|
"eslint": "^6.8.0",
|
|
31
31
|
"prettier": "^1.19.1",
|
|
32
|
-
"@patternfly/react-catalog-view-extension": "^4.8.126"
|
|
32
|
+
"@patternfly/react-catalog-view-extension": "^4.8.126",
|
|
33
|
+
"redux-mock-store": "^1.2.2"
|
|
33
34
|
},
|
|
34
35
|
"peerDependencies": {
|
|
35
36
|
"@theforeman/vendor": "^8.3.0"
|
|
@@ -114,11 +114,24 @@ module Api
|
|
|
114
114
|
assert_response :success
|
|
115
115
|
end
|
|
116
116
|
|
|
117
|
-
test 'search_query' do
|
|
117
|
+
test 'host ids as search_query' do
|
|
118
118
|
@attrs[:host_ids] = 'name = testfqdn'
|
|
119
119
|
post :create, params: { job_invocation: @attrs }
|
|
120
120
|
assert_response :success
|
|
121
121
|
end
|
|
122
|
+
|
|
123
|
+
test 'with search_query param' do
|
|
124
|
+
@attrs[:targeting_type] = 'static_query'
|
|
125
|
+
@attrs[:search_query] = 'name = testfqdn'
|
|
126
|
+
post :create, params: { job_invocation: @attrs }
|
|
127
|
+
assert_response :success
|
|
128
|
+
end
|
|
129
|
+
|
|
130
|
+
test 'with job_template_id param' do
|
|
131
|
+
@attrs[:job_template_id] = 12_345
|
|
132
|
+
post :create, params: { job_invocation: @attrs }
|
|
133
|
+
assert_response :error
|
|
134
|
+
end
|
|
122
135
|
end
|
|
123
136
|
end
|
|
124
137
|
|