foreman_remote_execution 4.4.0 → 4.5.3
Sign up to get free protection for your applications and to get access to all the features.
- 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
|
|