foreman_remote_execution 16.0.4 → 16.0.5
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/job_invocations_controller.rb +28 -1
- data/app/controllers/template_invocations_controller.rb +1 -1
- data/config/routes.rb +1 -0
- data/lib/foreman_remote_execution/engine.rb +9 -256
- data/lib/foreman_remote_execution/plugin.rb +246 -0
- data/lib/foreman_remote_execution/version.rb +1 -1
- data/test/functional/api/v2/job_invocations_controller_test.rb +1 -1
- data/test/unit/job_invocation_report_template_test.rb +6 -6
- data/webpack/JobInvocationDetail/CheckboxesActions.js +196 -0
- data/webpack/JobInvocationDetail/{JobInvocationHostTableToolbar.js → DropdownFilter.js} +3 -6
- data/webpack/JobInvocationDetail/JobInvocationConstants.js +6 -6
- data/webpack/JobInvocationDetail/JobInvocationDetail.scss +18 -0
- data/webpack/JobInvocationDetail/JobInvocationHostTable.js +205 -89
- data/webpack/JobInvocationDetail/JobInvocationSelectors.js +30 -3
- data/webpack/JobInvocationDetail/JobInvocationToolbarButtons.js +20 -27
- data/webpack/JobInvocationDetail/OpenAllInvocationsModal.js +118 -0
- data/webpack/JobInvocationDetail/TemplateInvocation.js +54 -24
- data/webpack/JobInvocationDetail/TemplateInvocationComponents/TemplateActionButtons.js +8 -10
- data/webpack/JobInvocationDetail/TemplateInvocationPage.js +1 -1
- data/webpack/JobInvocationDetail/__tests__/MainInformation.test.js +1 -1
- data/webpack/JobInvocationDetail/__tests__/TableToolbarActions.test.js +202 -0
- data/webpack/JobInvocationDetail/__tests__/TemplateInvocation.test.js +34 -28
- data/webpack/JobInvocationDetail/index.js +61 -30
- data/webpack/JobWizard/steps/HostsAndInputs/buildHostQuery.js +26 -7
- data/webpack/react_app/components/TargetingHosts/TargetingHostsLabelsRow.scss +1 -1
- metadata +8 -6
- data/webpack/JobInvocationDetail/OpenAlInvocations.js +0 -111
- data/webpack/JobInvocationDetail/__tests__/OpenAlInvocations.test.js +0 -110
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: f0af6a4d6d568edd8bf5d878940d19f72d3f2b2ad2c67e767cd7764e2287ba3f
|
4
|
+
data.tar.gz: 5b7f5b64a90c38b6b65df711be7bf93c586c73400386c96c6ae280285b4a9349
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 408d5714fba95e7213fa42c2510021231cd2d5c61b7ecc502a0d76c96ca80f97758e03928da5a1c1acc9547fe4fcbfbe2f836991954b78a09cbe7b6ef0644e95
|
7
|
+
data.tar.gz: c0468bdebd334affe636a1aa34dff3689707084a0d0f141b05c0a09428f6700aa48b1a43b2e9e61262d8bd8968ab4c22b3d1ab68ad48cf8527b930989fac8994
|
@@ -149,6 +149,33 @@ class JobInvocationsController < ApplicationController
|
|
149
149
|
render :json => {:job_invocations => job_invocations}
|
150
150
|
end
|
151
151
|
|
152
|
+
def list_jobs_hosts
|
153
|
+
@job_invocation = resource_base.find(params[:id])
|
154
|
+
hosts = @job_invocation.targeting.hosts.authorized(:view_hosts, Host)
|
155
|
+
hosts = hosts.search_for(params[:search])
|
156
|
+
template_invocations_task_by_hosts = {}
|
157
|
+
hosts.each do |host|
|
158
|
+
template_invocation = @job_invocation.template_invocations.find { |template_inv| template_inv.host_id == host.id }
|
159
|
+
next unless template_invocation
|
160
|
+
template_invocation_task = template_invocation.run_host_job_task
|
161
|
+
template_invocations_task_by_hosts[host.id] =
|
162
|
+
{
|
163
|
+
:host_name => host.name,
|
164
|
+
:id => host.id,
|
165
|
+
:task => template_invocation_task.attributes.merge({cancellable: template_invocation_task.cancellable? }),
|
166
|
+
:permissions => {
|
167
|
+
:view_foreman_tasks => authorized_for(:permission => :view_foreman_tasks, :auth_object => template_invocation_task),
|
168
|
+
:cancel_job_invocations => authorized_for(:permission => :cancel_job_invocations, :auth_object => @job_invocation),
|
169
|
+
:execute_jobs => authorized_for(controller: :job_invocations, action: :create) && (!host.infrastructure_host? || User.current.can?(:execute_jobs_on_infrastructure_hosts)),
|
170
|
+
},
|
171
|
+
}
|
172
|
+
end
|
173
|
+
|
174
|
+
render json: {
|
175
|
+
:template_invocations_task_by_hosts => template_invocations_task_by_hosts,
|
176
|
+
}
|
177
|
+
end
|
178
|
+
|
152
179
|
private
|
153
180
|
|
154
181
|
def action_permission
|
@@ -159,7 +186,7 @@ class JobInvocationsController < ApplicationController
|
|
159
186
|
'create'
|
160
187
|
when 'cancel'
|
161
188
|
'cancel'
|
162
|
-
when 'chart', 'preview_job_invocations_per_host'
|
189
|
+
when 'chart', 'preview_job_invocations_per_host', 'list_jobs_hosts'
|
163
190
|
'view'
|
164
191
|
else
|
165
192
|
super
|
@@ -48,7 +48,7 @@ class TemplateInvocationsController < ApplicationController
|
|
48
48
|
|
49
49
|
auto_refresh = @job_invocation.task.try(:pending?)
|
50
50
|
finished = @job_invocation.status_label == 'failed' || @job_invocation.status_label == 'succeeded' || @job_invocation.status_label == 'cancelled'
|
51
|
-
render :json => { :output => lines, :preview => template_invocation_preview(@template_invocation, @host), :proxy => proxy, :input_values => transformed_input_values, :job_invocation_description => @job_invocation.description, :
|
51
|
+
render :json => { :output => lines, :preview => template_invocation_preview(@template_invocation, @host), :proxy => proxy, :input_values => transformed_input_values, :job_invocation_description => @job_invocation.description, :task => @template_invocation_task.attributes.merge({cancellable: @template_invocation_task.cancellable? }), :host_name => @host.name, :permissions => {
|
52
52
|
:view_foreman_tasks => User.current.allowed_to?(:view_foreman_tasks),
|
53
53
|
:cancel_job_invocations => User.current.allowed_to?(:cancel_job_invocations),
|
54
54
|
:execute_jobs => User.current.allowed_to?(:create_job_invocations) && (!@host.infrastructure_host? || User.current.can?(:execute_jobs_on_infrastructure_hosts)),
|
data/config/routes.rb
CHANGED
@@ -7,13 +7,14 @@ module ForemanRemoteExecution
|
|
7
7
|
# Precompile any JS or CSS files under app/assets/
|
8
8
|
# If requiring files from each other, list them explicitly here to avoid precompiling the same
|
9
9
|
# content twice.
|
10
|
-
assets_to_precompile
|
11
|
-
Dir.chdir(root) do
|
10
|
+
def self.assets_to_precompile
|
11
|
+
assets = Dir.chdir(root) do
|
12
12
|
Dir['app/assets/javascripts/**/*'].map do |f|
|
13
13
|
f.split(File::SEPARATOR, 4).last
|
14
14
|
end
|
15
15
|
end
|
16
|
-
|
16
|
+
assets << 'foreman_remote_execution/foreman_remote_execution.css'
|
17
|
+
end
|
17
18
|
|
18
19
|
# Add any db migrations
|
19
20
|
initializer 'foreman_remote_execution.load_app_instance_data' do |app|
|
@@ -34,260 +35,16 @@ module ForemanRemoteExecution
|
|
34
35
|
|
35
36
|
initializer 'foreman_remote_execution.register_plugin', before: :finisher_hook do |app|
|
36
37
|
app.reloader.to_prepare do
|
37
|
-
|
38
|
-
|
39
|
-
register_global_js_file 'global'
|
40
|
-
register_gettext
|
41
|
-
|
42
|
-
apipie_documented_controllers ["#{ForemanRemoteExecution::Engine.root}/app/controllers/api/v2/*.rb"]
|
43
|
-
ApipieDSL.configuration.dsl_classes_matchers += [
|
44
|
-
"#{ForemanRemoteExecution::Engine.root}/app/lib/foreman_remote_execution/renderer/**/*.rb",
|
45
|
-
]
|
46
|
-
automatic_assets(false)
|
47
|
-
precompile_assets(*assets_to_precompile)
|
48
|
-
|
49
|
-
# Add settings to a Remote Execution category
|
50
|
-
settings do
|
51
|
-
category :remote_execution, N_('Remote Execution') do
|
52
|
-
setting 'remote_execution_fallback_proxy',
|
53
|
-
type: :boolean,
|
54
|
-
description: N_('Search the host for any proxy with Remote Execution, useful when the host has no subnet or the subnet does not have an execution proxy'),
|
55
|
-
default: false,
|
56
|
-
full_name: N_('Fallback to Any Proxy')
|
57
|
-
setting 'remote_execution_global_proxy',
|
58
|
-
type: :boolean,
|
59
|
-
description: N_('Search for remote execution proxy outside of the proxies assigned to the host. The search will be limited to the host\'s organization and location.'),
|
60
|
-
default: true,
|
61
|
-
full_name: N_('Enable Global Proxy')
|
62
|
-
setting 'remote_execution_ssh_user',
|
63
|
-
type: :string,
|
64
|
-
description: N_('Default user to use for SSH. You may override per host by setting a parameter called remote_execution_ssh_user.'),
|
65
|
-
default: 'root',
|
66
|
-
full_name: N_('SSH User')
|
67
|
-
setting 'remote_execution_effective_user',
|
68
|
-
type: :string,
|
69
|
-
description: N_('Default user to use for executing the script. If the user differs from the SSH user, su or sudo is used to switch the user.'),
|
70
|
-
default: 'root',
|
71
|
-
full_name: N_('Effective User')
|
72
|
-
setting 'remote_execution_effective_user_method',
|
73
|
-
type: :string,
|
74
|
-
description: N_('What command should be used to switch to the effective user. One of %s') % ::ScriptExecutionProvider::EFFECTIVE_USER_METHODS.inspect,
|
75
|
-
default: 'sudo',
|
76
|
-
full_name: N_('Effective User Method'),
|
77
|
-
collection: proc { Hash[::ScriptExecutionProvider::EFFECTIVE_USER_METHODS.map { |method| [method, method] }] }
|
78
|
-
setting 'remote_execution_effective_user_password',
|
79
|
-
type: :string,
|
80
|
-
description: N_('Effective user password'),
|
81
|
-
default: '',
|
82
|
-
full_name: N_('Effective user password'),
|
83
|
-
encrypted: true
|
84
|
-
setting 'remote_execution_sync_templates',
|
85
|
-
type: :boolean,
|
86
|
-
description: N_('Whether we should sync templates from disk when running db:seed.'),
|
87
|
-
default: true,
|
88
|
-
full_name: N_('Sync Job Templates')
|
89
|
-
setting 'remote_execution_ssh_port',
|
90
|
-
type: :integer,
|
91
|
-
description: N_('Port to use for SSH communication. Default port 22. You may override per host by setting a parameter called remote_execution_ssh_port.'),
|
92
|
-
default: 22,
|
93
|
-
full_name: N_('SSH Port')
|
94
|
-
setting 'remote_execution_connect_by_ip',
|
95
|
-
type: :boolean,
|
96
|
-
description: N_('Should the ip addresses on host interfaces be preferred over the fqdn? '\
|
97
|
-
'It is useful when DNS not resolving the fqdns properly. You may override this per host by setting a parameter called remote_execution_connect_by_ip. '\
|
98
|
-
'For dual-stacked hosts you should consider the remote_execution_connect_by_ip_prefer_ipv6 setting'),
|
99
|
-
default: false,
|
100
|
-
full_name: N_('Connect by IP')
|
101
|
-
setting 'remote_execution_connect_by_ip_prefer_ipv6',
|
102
|
-
type: :boolean,
|
103
|
-
description: N_('When connecting using ip address, should the IPv6 addresses be preferred? '\
|
104
|
-
'If no IPv6 address is set, it falls back to IPv4 automatically. You may override this per host by setting a parameter called remote_execution_connect_by_ip_prefer_ipv6. '\
|
105
|
-
'By default and for compatibility, IPv4 will be preferred over IPv6 by default'),
|
106
|
-
default: false,
|
107
|
-
full_name: N_('Prefer IPv6 over IPv4')
|
108
|
-
setting 'remote_execution_ssh_password',
|
109
|
-
type: :string,
|
110
|
-
description: N_('Default password to use for SSH. You may override per host by setting a parameter called remote_execution_ssh_password'),
|
111
|
-
default: nil,
|
112
|
-
full_name: N_('Default SSH password'),
|
113
|
-
encrypted: true
|
114
|
-
setting 'remote_execution_ssh_key_passphrase',
|
115
|
-
type: :string,
|
116
|
-
description: N_('Default key passphrase to use for SSH. You may override per host by setting a parameter called remote_execution_ssh_key_passphrase'),
|
117
|
-
default: nil,
|
118
|
-
full_name: N_('Default SSH key passphrase'),
|
119
|
-
encrypted: true
|
120
|
-
setting 'remote_execution_cleanup_working_dirs',
|
121
|
-
type: :boolean,
|
122
|
-
description: N_('When enabled, working directories will be removed after task completion. You may override this per host by setting a parameter called remote_execution_cleanup_working_dirs.'),
|
123
|
-
default: true,
|
124
|
-
full_name: N_('Cleanup working directories')
|
125
|
-
setting 'remote_execution_cockpit_url',
|
126
|
-
type: :string,
|
127
|
-
description: N_('Where to find the Cockpit instance for the Web Console button. By default, no button is shown.'),
|
128
|
-
default: nil,
|
129
|
-
full_name: N_('Cockpit URL')
|
130
|
-
setting 'remote_execution_form_job_template',
|
131
|
-
type: :string,
|
132
|
-
description: N_('Choose a job template that is pre-selected in job invocation form'),
|
133
|
-
default: 'Run Command - Script Default',
|
134
|
-
full_name: N_('Form Job Template'),
|
135
|
-
collection: proc { Hash[JobTemplate.unscoped.map { |template| [template.name, template.name] }] }
|
136
|
-
setting 'remote_execution_job_invocation_report_template',
|
137
|
-
type: :string,
|
138
|
-
description: N_('Select a report template used for generating a report for a particular remote execution job'),
|
139
|
-
default: 'Job - Invocation Report',
|
140
|
-
full_name: N_('Job Invocation Report Template'),
|
141
|
-
collection: proc { ForemanRemoteExecution.job_invocation_report_templates_select }
|
142
|
-
setting 'remote_execution_time_to_pickup',
|
143
|
-
type: :integer,
|
144
|
-
description: N_('Time in seconds within which the host has to pick up a job. If the job is not picked up within this limit, the job will be cancelled. Defaults to 1 day. Applies only to pull-mqtt based jobs.'),
|
145
|
-
default: 24 * 60 * 60,
|
146
|
-
full_name: N_('Time to pickup')
|
147
|
-
end
|
148
|
-
end
|
149
|
-
|
150
|
-
# Add permissions
|
151
|
-
security_block :foreman_remote_execution do
|
152
|
-
permission :view_job_templates, { :job_templates => [:index, :show, :revision, :auto_complete_search, :auto_complete_job_category, :preview, :export],
|
153
|
-
:'api/v2/job_templates' => [:index, :show, :revision, :export],
|
154
|
-
:'api/v2/template_inputs' => [:index, :show],
|
155
|
-
:'api/v2/foreign_input_sets' => [:index, :show],
|
156
|
-
:ui_job_wizard => [:categories, :template, :resources, :job_invocation]}, :resource_type => 'JobTemplate'
|
157
|
-
permission :create_job_templates, { :job_templates => [:new, :create, :clone_template, :import],
|
158
|
-
:'api/v2/job_templates' => [:create, :clone, :import] }, :resource_type => 'JobTemplate'
|
159
|
-
permission :edit_job_templates, { :job_templates => [:edit, :update],
|
160
|
-
:'api/v2/job_templates' => [:update],
|
161
|
-
:'api/v2/template_inputs' => [:create, :update, :destroy],
|
162
|
-
:'api/v2/foreign_input_sets' => [:create, :update, :destroy]}, :resource_type => 'JobTemplate'
|
163
|
-
permission :view_remote_execution_features, { :remote_execution_features => [:index, :show],
|
164
|
-
:'api/v2/remote_execution_features' => [:index, :show, :available_remote_execution_features]},
|
165
|
-
:resource_type => 'RemoteExecutionFeature'
|
166
|
-
permission :edit_remote_execution_features, { :remote_execution_features => [:update],
|
167
|
-
:'api/v2/remote_execution_features' => [:update ]}, :resource_type => 'RemoteExecutionFeature'
|
168
|
-
permission :destroy_job_templates, { :job_templates => [:destroy],
|
169
|
-
:'api/v2/job_templates' => [:destroy] }, :resource_type => 'JobTemplate'
|
170
|
-
permission :lock_job_templates, { :job_templates => [:lock, :unlock] }, :resource_type => 'JobTemplate'
|
171
|
-
permission :create_job_invocations, { :job_invocations => [:new, :create, :legacy_create, :refresh, :rerun, :preview_hosts],
|
172
|
-
'api/v2/job_invocations' => [:create, :rerun] }, :resource_type => 'JobInvocation'
|
173
|
-
permission :view_job_invocations, { :job_invocations => [:index, :chart, :show, :auto_complete_search, :preview_job_invocations_per_host], :template_invocations => [:show, :show_template_invocation_by_host],
|
174
|
-
'api/v2/job_invocations' => [:index, :show, :output, :raw_output, :outputs, :hosts] }, :resource_type => 'JobInvocation'
|
175
|
-
permission :view_template_invocations, { :template_invocations => [:show, :template_invocation_preview, :show_template_invocation_by_host],
|
176
|
-
'api/v2/template_invocations' => [:template_invocations], :ui_job_wizard => [:job_invocation] }, :resource_type => 'TemplateInvocation'
|
177
|
-
permission :create_template_invocations, {}, :resource_type => 'TemplateInvocation'
|
178
|
-
permission :execute_jobs_on_infrastructure_hosts, {}, :resource_type => 'JobInvocation'
|
179
|
-
permission :cancel_job_invocations, { :job_invocations => [:cancel], 'api/v2/job_invocations' => [:cancel] }, :resource_type => 'JobInvocation'
|
180
|
-
# this permissions grants user to get auto completion hints when setting up filters
|
181
|
-
permission :filter_autocompletion_for_template_invocation, { :template_invocations => [ :auto_complete_search, :index ] },
|
182
|
-
:resource_type => 'TemplateInvocation'
|
183
|
-
permission :cockpit_hosts, { 'cockpit' => [:redirect, :host_ssh_params] }, :resource_type => 'Host'
|
184
|
-
end
|
185
|
-
|
186
|
-
USER_PERMISSIONS = [
|
187
|
-
:view_job_templates,
|
188
|
-
:view_job_invocations,
|
189
|
-
:create_job_invocations,
|
190
|
-
:create_template_invocations,
|
191
|
-
:view_hosts,
|
192
|
-
:view_smart_proxies,
|
193
|
-
:view_remote_execution_features,
|
194
|
-
].freeze
|
195
|
-
MANAGER_PERMISSIONS = USER_PERMISSIONS + [
|
196
|
-
:cancel_job_invocations,
|
197
|
-
:destroy_job_templates,
|
198
|
-
:edit_job_templates,
|
199
|
-
:create_job_templates,
|
200
|
-
:lock_job_templates,
|
201
|
-
:view_audit_logs,
|
202
|
-
:filter_autocompletion_for_template_invocation,
|
203
|
-
:edit_remote_execution_features,
|
204
|
-
]
|
205
|
-
|
206
|
-
# Add a new role called 'Remote Execution User ' if it doesn't exist
|
207
|
-
role 'Remote Execution User', USER_PERMISSIONS, 'Role with permissions to run remote execution jobs against hosts'
|
208
|
-
role 'Remote Execution Manager', MANAGER_PERMISSIONS, 'Role with permissions to manage job templates, remote execution features, cancel jobs and view audit logs'
|
209
|
-
|
210
|
-
add_all_permissions_to_default_roles(except: [:execute_jobs_on_infrastructure_hosts])
|
211
|
-
add_permissions_to_default_roles({
|
212
|
-
Role::MANAGER => [:execute_jobs_on_infrastructure_hosts],
|
213
|
-
Role::SITE_MANAGER => USER_PERMISSIONS + [:execute_jobs_on_infrastructure_hosts],
|
214
|
-
})
|
215
|
-
|
216
|
-
# add menu entry
|
217
|
-
menu :top_menu, :job_templates,
|
218
|
-
url_hash: { controller: :job_templates, action: :index },
|
219
|
-
caption: N_('Job Templates'),
|
220
|
-
parent: :hosts_menu,
|
221
|
-
after: :provisioning_templates
|
222
|
-
menu :admin_menu, :remote_execution_features,
|
223
|
-
url_hash: { controller: :remote_execution_features, action: :index },
|
224
|
-
caption: N_('Remote Execution Features'),
|
225
|
-
parent: :administer_menu,
|
226
|
-
after: :bookmarks
|
227
|
-
|
228
|
-
menu :top_menu, :job_invocations,
|
229
|
-
url_hash: { controller: :job_invocations, action: :index },
|
230
|
-
caption: N_('Jobs'),
|
231
|
-
parent: :monitor_menu,
|
232
|
-
after: :audits
|
233
|
-
|
234
|
-
menu :labs_menu, :job_invocations_detail,
|
235
|
-
url_hash: { controller: :job_invocations, action: :show },
|
236
|
-
caption: N_('Job invocations detail'),
|
237
|
-
parent: :lab_features_menu,
|
238
|
-
url: '/experimental/job_invocations_detail/1'
|
239
|
-
|
240
|
-
register_custom_status HostStatus::ExecutionStatus
|
241
|
-
# add dashboard widget
|
242
|
-
# widget 'foreman_remote_execution_widget', name: N_('Foreman plugin template widget'), sizex: 4, sizey: 1
|
243
|
-
widget 'dashboard/latest-jobs', :name => N_('Latest Jobs'), :sizex => 6, :sizey => 1
|
244
|
-
|
245
|
-
parameter_filter Subnet, :remote_execution_proxies, :remote_execution_proxy_ids => []
|
246
|
-
parameter_filter Nic::Interface do |ctx|
|
247
|
-
ctx.permit :execution
|
248
|
-
end
|
249
|
-
|
250
|
-
register_graphql_query_field :job_invocations, '::Types::JobInvocation', :collection_field
|
251
|
-
register_graphql_query_field :job_invocation, '::Types::JobInvocation', :record_field
|
252
|
-
|
253
|
-
register_graphql_mutation_field :create_job_invocation, ::Mutations::JobInvocations::Create
|
254
|
-
|
255
|
-
extend_template_helpers ForemanRemoteExecution::RendererMethods
|
256
|
-
|
257
|
-
extend_rabl_template 'api/v2/smart_proxies/main', 'api/v2/smart_proxies/pubkey'
|
258
|
-
extend_rabl_template 'api/v2/interfaces/main', 'api/v2/interfaces/execution_flag'
|
259
|
-
extend_rabl_template 'api/v2/subnets/show', 'api/v2/subnets/remote_execution_proxies'
|
260
|
-
extend_rabl_template 'api/v2/hosts/main', 'api/v2/host/main'
|
261
|
-
parameter_filter ::Subnet, :remote_execution_proxy_ids
|
262
|
-
|
263
|
-
describe_host do
|
264
|
-
multiple_actions_provider :rex_hosts_multiple_actions
|
265
|
-
overview_buttons_provider :rex_host_overview_buttons
|
266
|
-
end
|
267
|
-
|
268
|
-
# Extend Registration module
|
269
|
-
extend_allowed_registration_vars :remote_execution_interface
|
270
|
-
extend_allowed_registration_vars :setup_remote_execution_pull
|
271
|
-
ForemanTasks.dynflow.eager_load_actions!
|
272
|
-
extend_observable_events(
|
273
|
-
::Dynflow::Action.descendants.select do |klass|
|
274
|
-
klass <= ::Actions::ObservableAction
|
275
|
-
end.map(&:namespaced_event_names) +
|
276
|
-
RemoteExecutionFeature.all.pluck(:label).flat_map do |label|
|
277
|
-
[::Actions::RemoteExecution::RunHostJob, ::Actions::RemoteExecution::RunHostsJob].map do |klass|
|
278
|
-
klass.feature_job_event_names(label)
|
279
|
-
end
|
280
|
-
end
|
281
|
-
)
|
282
|
-
end
|
38
|
+
# Allow plugin registration to call application code once on boot
|
39
|
+
require_relative 'plugin'
|
283
40
|
end
|
284
41
|
end
|
285
42
|
|
286
43
|
initializer 'foreman_remote_execution.assets.precompile' do |app|
|
287
|
-
app.config.assets.precompile += assets_to_precompile
|
44
|
+
app.config.assets.precompile += Engine.assets_to_precompile
|
288
45
|
end
|
289
46
|
initializer 'foreman_remote_execution.configure_assets', group: :assets do
|
290
|
-
SETTINGS[:foreman_remote_execution] = { assets: { precompile: assets_to_precompile } }
|
47
|
+
SETTINGS[:foreman_remote_execution] = { assets: { precompile: Engine.assets_to_precompile } }
|
291
48
|
end
|
292
49
|
|
293
50
|
# Include concerns in this config.to_prepare block
|
@@ -300,8 +57,7 @@ module ForemanRemoteExecution
|
|
300
57
|
# e.g. having ProvisioningTemplate < Template, adding has_many :template_inputs to Template from concern
|
301
58
|
# Template.reflect_on_association :template_inputs # => <#Association...
|
302
59
|
# ProvisioningTemplate.reflect_on_association :template_inputs # => nil
|
303
|
-
|
304
|
-
(Template.descendants + [Template]).each { |klass| klass.send(:include, ForemanRemoteExecution::TemplateExtensions) }
|
60
|
+
(Template.descendants + [JobTemplate, Template]).each { |klass| klass.send(:include, ForemanRemoteExecution::TemplateExtensions) }
|
305
61
|
Template.prepend ForemanRemoteExecution::TemplateOverrides
|
306
62
|
|
307
63
|
(Taxonomy.descendants + [Taxonomy]).each { |klass| klass.send(:include, ForemanRemoteExecution::TaxonomyExtensions) }
|
@@ -323,9 +79,6 @@ module ForemanRemoteExecution
|
|
323
79
|
Subnet.include ForemanRemoteExecution::SubnetExtensions
|
324
80
|
|
325
81
|
::Api::V2::InterfacesController.include Api::V2::InterfacesControllerExtensions
|
326
|
-
# We need to explicitly force to load the Task model due to Rails loader
|
327
|
-
# having issues with resolving it to Rake::Task otherwise
|
328
|
-
require_dependency 'foreman_tasks/task'
|
329
82
|
ForemanTasks::Task.include ForemanRemoteExecution::ForemanTasksTaskExtensions
|
330
83
|
ForemanTasks::Cleaner.include ForemanRemoteExecution::ForemanTasksCleanerExtensions
|
331
84
|
RemoteExecutionProvider.register(:SSH, ::ScriptExecutionProvider)
|
@@ -0,0 +1,246 @@
|
|
1
|
+
Foreman::Plugin.register :foreman_remote_execution do
|
2
|
+
requires_foreman '>= 3.15'
|
3
|
+
register_global_js_file 'global'
|
4
|
+
register_gettext
|
5
|
+
|
6
|
+
apipie_documented_controllers ["#{ForemanRemoteExecution::Engine.root}/app/controllers/api/v2/*.rb"]
|
7
|
+
ApipieDSL.configuration.dsl_classes_matchers += [
|
8
|
+
"#{ForemanRemoteExecution::Engine.root}/app/lib/foreman_remote_execution/renderer/**/*.rb",
|
9
|
+
]
|
10
|
+
automatic_assets(false)
|
11
|
+
precompile_assets(ForemanRemoteExecution::Engine.assets_to_precompile)
|
12
|
+
|
13
|
+
# Add settings to a Remote Execution category
|
14
|
+
settings do
|
15
|
+
category :remote_execution, N_('Remote Execution') do
|
16
|
+
setting 'remote_execution_fallback_proxy',
|
17
|
+
type: :boolean,
|
18
|
+
description: N_('Search the host for any proxy with Remote Execution, useful when the host has no subnet or the subnet does not have an execution proxy'),
|
19
|
+
default: false,
|
20
|
+
full_name: N_('Fallback to Any Proxy')
|
21
|
+
setting 'remote_execution_global_proxy',
|
22
|
+
type: :boolean,
|
23
|
+
description: N_('Search for remote execution proxy outside of the proxies assigned to the host. The search will be limited to the host\'s organization and location.'),
|
24
|
+
default: true,
|
25
|
+
full_name: N_('Enable Global Proxy')
|
26
|
+
setting 'remote_execution_ssh_user',
|
27
|
+
type: :string,
|
28
|
+
description: N_('Default user to use for SSH. You may override per host by setting a parameter called remote_execution_ssh_user.'),
|
29
|
+
default: 'root',
|
30
|
+
full_name: N_('SSH User')
|
31
|
+
setting 'remote_execution_effective_user',
|
32
|
+
type: :string,
|
33
|
+
description: N_('Default user to use for executing the script. If the user differs from the SSH user, su or sudo is used to switch the user.'),
|
34
|
+
default: 'root',
|
35
|
+
full_name: N_('Effective User')
|
36
|
+
setting 'remote_execution_effective_user_method',
|
37
|
+
type: :string,
|
38
|
+
description: N_('What command should be used to switch to the effective user. One of %s') % ::ScriptExecutionProvider::EFFECTIVE_USER_METHODS.inspect,
|
39
|
+
default: 'sudo',
|
40
|
+
full_name: N_('Effective User Method'),
|
41
|
+
collection: proc { Hash[::ScriptExecutionProvider::EFFECTIVE_USER_METHODS.map { |method| [method, method] }] }
|
42
|
+
setting 'remote_execution_effective_user_password',
|
43
|
+
type: :string,
|
44
|
+
description: N_('Effective user password'),
|
45
|
+
default: '',
|
46
|
+
full_name: N_('Effective user password'),
|
47
|
+
encrypted: true
|
48
|
+
setting 'remote_execution_sync_templates',
|
49
|
+
type: :boolean,
|
50
|
+
description: N_('Whether we should sync templates from disk when running db:seed.'),
|
51
|
+
default: true,
|
52
|
+
full_name: N_('Sync Job Templates')
|
53
|
+
setting 'remote_execution_ssh_port',
|
54
|
+
type: :integer,
|
55
|
+
description: N_('Port to use for SSH communication. Default port 22. You may override per host by setting a parameter called remote_execution_ssh_port.'),
|
56
|
+
default: 22,
|
57
|
+
full_name: N_('SSH Port')
|
58
|
+
setting 'remote_execution_connect_by_ip',
|
59
|
+
type: :boolean,
|
60
|
+
description: N_('Should the ip addresses on host interfaces be preferred over the fqdn? '\
|
61
|
+
'It is useful when DNS not resolving the fqdns properly. You may override this per host by setting a parameter called remote_execution_connect_by_ip. '\
|
62
|
+
'For dual-stacked hosts you should consider the remote_execution_connect_by_ip_prefer_ipv6 setting'),
|
63
|
+
default: false,
|
64
|
+
full_name: N_('Connect by IP')
|
65
|
+
setting 'remote_execution_connect_by_ip_prefer_ipv6',
|
66
|
+
type: :boolean,
|
67
|
+
description: N_('When connecting using ip address, should the IPv6 addresses be preferred? '\
|
68
|
+
'If no IPv6 address is set, it falls back to IPv4 automatically. You may override this per host by setting a parameter called remote_execution_connect_by_ip_prefer_ipv6. '\
|
69
|
+
'By default and for compatibility, IPv4 will be preferred over IPv6 by default'),
|
70
|
+
default: false,
|
71
|
+
full_name: N_('Prefer IPv6 over IPv4')
|
72
|
+
setting 'remote_execution_ssh_password',
|
73
|
+
type: :string,
|
74
|
+
description: N_('Default password to use for SSH. You may override per host by setting a parameter called remote_execution_ssh_password'),
|
75
|
+
default: nil,
|
76
|
+
full_name: N_('Default SSH password'),
|
77
|
+
encrypted: true
|
78
|
+
setting 'remote_execution_ssh_key_passphrase',
|
79
|
+
type: :string,
|
80
|
+
description: N_('Default key passphrase to use for SSH. You may override per host by setting a parameter called remote_execution_ssh_key_passphrase'),
|
81
|
+
default: nil,
|
82
|
+
full_name: N_('Default SSH key passphrase'),
|
83
|
+
encrypted: true
|
84
|
+
setting 'remote_execution_cleanup_working_dirs',
|
85
|
+
type: :boolean,
|
86
|
+
description: N_('When enabled, working directories will be removed after task completion. You may override this per host by setting a parameter called remote_execution_cleanup_working_dirs.'),
|
87
|
+
default: true,
|
88
|
+
full_name: N_('Cleanup working directories')
|
89
|
+
setting 'remote_execution_cockpit_url',
|
90
|
+
type: :string,
|
91
|
+
description: N_('Where to find the Cockpit instance for the Web Console button. By default, no button is shown.'),
|
92
|
+
default: nil,
|
93
|
+
full_name: N_('Cockpit URL')
|
94
|
+
setting 'remote_execution_form_job_template',
|
95
|
+
type: :string,
|
96
|
+
description: N_('Choose a job template that is pre-selected in job invocation form'),
|
97
|
+
default: 'Run Command - Script Default',
|
98
|
+
full_name: N_('Form Job Template'),
|
99
|
+
collection: proc { Hash[JobTemplate.unscoped.map { |template| [template.name, template.name] }] }
|
100
|
+
setting 'remote_execution_job_invocation_report_template',
|
101
|
+
type: :string,
|
102
|
+
description: N_('Select a report template used for generating a report for a particular remote execution job'),
|
103
|
+
default: 'Job - Invocation Report',
|
104
|
+
full_name: N_('Job Invocation Report Template'),
|
105
|
+
collection: proc { ForemanRemoteExecution.job_invocation_report_templates_select }
|
106
|
+
setting 'remote_execution_time_to_pickup',
|
107
|
+
type: :integer,
|
108
|
+
description: N_('Time in seconds within which the host has to pick up a job. If the job is not picked up within this limit, the job will be cancelled. Defaults to 1 day. Applies only to pull-mqtt based jobs.'),
|
109
|
+
default: 24 * 60 * 60,
|
110
|
+
full_name: N_('Time to pickup')
|
111
|
+
end
|
112
|
+
end
|
113
|
+
|
114
|
+
# Add permissions
|
115
|
+
security_block :foreman_remote_execution do
|
116
|
+
permission :view_job_templates, { :job_templates => [:index, :show, :revision, :auto_complete_search, :auto_complete_job_category, :preview, :export],
|
117
|
+
:'api/v2/job_templates' => [:index, :show, :revision, :export],
|
118
|
+
:'api/v2/template_inputs' => [:index, :show],
|
119
|
+
:'api/v2/foreign_input_sets' => [:index, :show],
|
120
|
+
:ui_job_wizard => [:categories, :template, :resources, :job_invocation]}, :resource_type => 'JobTemplate'
|
121
|
+
permission :create_job_templates, { :job_templates => [:new, :create, :clone_template, :import],
|
122
|
+
:'api/v2/job_templates' => [:create, :clone, :import] }, :resource_type => 'JobTemplate'
|
123
|
+
permission :edit_job_templates, { :job_templates => [:edit, :update],
|
124
|
+
:'api/v2/job_templates' => [:update],
|
125
|
+
:'api/v2/template_inputs' => [:create, :update, :destroy],
|
126
|
+
:'api/v2/foreign_input_sets' => [:create, :update, :destroy]}, :resource_type => 'JobTemplate'
|
127
|
+
permission :view_remote_execution_features, { :remote_execution_features => [:index, :show],
|
128
|
+
:'api/v2/remote_execution_features' => [:index, :show, :available_remote_execution_features]},
|
129
|
+
:resource_type => 'RemoteExecutionFeature'
|
130
|
+
permission :edit_remote_execution_features, { :remote_execution_features => [:update],
|
131
|
+
:'api/v2/remote_execution_features' => [:update]}, :resource_type => 'RemoteExecutionFeature'
|
132
|
+
permission :destroy_job_templates, { :job_templates => [:destroy],
|
133
|
+
:'api/v2/job_templates' => [:destroy] }, :resource_type => 'JobTemplate'
|
134
|
+
permission :lock_job_templates, { :job_templates => [:lock, :unlock] }, :resource_type => 'JobTemplate'
|
135
|
+
permission :create_job_invocations, { :job_invocations => [:new, :create, :legacy_create, :refresh, :rerun, :preview_hosts],
|
136
|
+
'api/v2/job_invocations' => [:create, :rerun] }, :resource_type => 'JobInvocation'
|
137
|
+
permission :view_job_invocations, { :job_invocations => [:index, :chart, :show, :auto_complete_search, :preview_job_invocations_per_host, :list_jobs_hosts], :template_invocations => [:show, :show_template_invocation_by_host],
|
138
|
+
'api/v2/job_invocations' => [:index, :show, :output, :raw_output, :outputs, :hosts] }, :resource_type => 'JobInvocation'
|
139
|
+
permission :view_template_invocations, { :template_invocations => [:show, :template_invocation_preview, :show_template_invocation_by_host], :job_invocations => [:list_jobs_hosts],
|
140
|
+
'api/v2/template_invocations' => [:template_invocations], :ui_job_wizard => [:job_invocation] }, :resource_type => 'TemplateInvocation'
|
141
|
+
permission :create_template_invocations, {}, :resource_type => 'TemplateInvocation'
|
142
|
+
permission :execute_jobs_on_infrastructure_hosts, {}, :resource_type => 'JobInvocation'
|
143
|
+
permission :cancel_job_invocations, { :job_invocations => [:cancel], 'api/v2/job_invocations' => [:cancel] }, :resource_type => 'JobInvocation'
|
144
|
+
# this permissions grants user to get auto completion hints when setting up filters
|
145
|
+
permission :filter_autocompletion_for_template_invocation, { :template_invocations => [:auto_complete_search, :index] },
|
146
|
+
:resource_type => 'TemplateInvocation'
|
147
|
+
permission :cockpit_hosts, { 'cockpit' => [:redirect, :host_ssh_params] }, :resource_type => 'Host'
|
148
|
+
end
|
149
|
+
|
150
|
+
user_permissions = [
|
151
|
+
:view_job_templates,
|
152
|
+
:view_job_invocations,
|
153
|
+
:create_job_invocations,
|
154
|
+
:create_template_invocations,
|
155
|
+
:view_hosts,
|
156
|
+
:view_smart_proxies,
|
157
|
+
:view_remote_execution_features,
|
158
|
+
].freeze
|
159
|
+
manager_permissions = user_permissions + [
|
160
|
+
:cancel_job_invocations,
|
161
|
+
:destroy_job_templates,
|
162
|
+
:edit_job_templates,
|
163
|
+
:create_job_templates,
|
164
|
+
:lock_job_templates,
|
165
|
+
:view_audit_logs,
|
166
|
+
:filter_autocompletion_for_template_invocation,
|
167
|
+
:edit_remote_execution_features,
|
168
|
+
]
|
169
|
+
|
170
|
+
# Add a new role called 'Remote Execution User ' if it doesn't exist
|
171
|
+
role 'Remote Execution User', user_permissions, 'Role with permissions to run remote execution jobs against hosts'
|
172
|
+
role 'Remote Execution Manager', manager_permissions, 'Role with permissions to manage job templates, remote execution features, cancel jobs and view audit logs'
|
173
|
+
|
174
|
+
add_all_permissions_to_default_roles(except: [:execute_jobs_on_infrastructure_hosts])
|
175
|
+
add_permissions_to_default_roles({
|
176
|
+
Role::MANAGER => [:execute_jobs_on_infrastructure_hosts],
|
177
|
+
Role::SITE_MANAGER => user_permissions + [:execute_jobs_on_infrastructure_hosts],
|
178
|
+
})
|
179
|
+
|
180
|
+
# add menu entry
|
181
|
+
menu :top_menu, :job_templates,
|
182
|
+
url_hash: { controller: :job_templates, action: :index },
|
183
|
+
caption: N_('Job Templates'),
|
184
|
+
parent: :hosts_menu,
|
185
|
+
after: :provisioning_templates
|
186
|
+
menu :admin_menu, :remote_execution_features,
|
187
|
+
url_hash: { controller: :remote_execution_features, action: :index },
|
188
|
+
caption: N_('Remote Execution Features'),
|
189
|
+
parent: :administer_menu,
|
190
|
+
after: :bookmarks
|
191
|
+
|
192
|
+
menu :top_menu, :job_invocations,
|
193
|
+
url_hash: { controller: :job_invocations, action: :index },
|
194
|
+
caption: N_('Jobs'),
|
195
|
+
parent: :monitor_menu,
|
196
|
+
after: :audits
|
197
|
+
|
198
|
+
menu :labs_menu, :job_invocations_detail,
|
199
|
+
url_hash: { controller: :job_invocations, action: :show },
|
200
|
+
caption: N_('Job invocations detail'),
|
201
|
+
parent: :lab_features_menu,
|
202
|
+
url: '/experimental/job_invocations_detail/1'
|
203
|
+
|
204
|
+
register_custom_status HostStatus::ExecutionStatus
|
205
|
+
# add dashboard widget
|
206
|
+
# widget 'foreman_remote_execution_widget', name: N_('Foreman plugin template widget'), sizex: 4, sizey: 1
|
207
|
+
widget 'dashboard/latest-jobs', :name => N_('Latest Jobs'), :sizex => 6, :sizey => 1
|
208
|
+
|
209
|
+
parameter_filter Subnet, :remote_execution_proxies, :remote_execution_proxy_ids => []
|
210
|
+
parameter_filter Nic::Interface do |ctx|
|
211
|
+
ctx.permit :execution
|
212
|
+
end
|
213
|
+
|
214
|
+
register_graphql_query_field :job_invocations, '::Types::JobInvocation', :collection_field
|
215
|
+
register_graphql_query_field :job_invocation, '::Types::JobInvocation', :record_field
|
216
|
+
|
217
|
+
register_graphql_mutation_field :create_job_invocation, ::Mutations::JobInvocations::Create
|
218
|
+
|
219
|
+
extend_template_helpers ForemanRemoteExecution::RendererMethods
|
220
|
+
|
221
|
+
extend_rabl_template 'api/v2/smart_proxies/main', 'api/v2/smart_proxies/pubkey'
|
222
|
+
extend_rabl_template 'api/v2/interfaces/main', 'api/v2/interfaces/execution_flag'
|
223
|
+
extend_rabl_template 'api/v2/subnets/show', 'api/v2/subnets/remote_execution_proxies'
|
224
|
+
extend_rabl_template 'api/v2/hosts/main', 'api/v2/host/main'
|
225
|
+
parameter_filter ::Subnet, :remote_execution_proxy_ids
|
226
|
+
|
227
|
+
describe_host do
|
228
|
+
multiple_actions_provider :rex_hosts_multiple_actions
|
229
|
+
overview_buttons_provider :rex_host_overview_buttons
|
230
|
+
end
|
231
|
+
|
232
|
+
# Extend Registration module
|
233
|
+
extend_allowed_registration_vars :remote_execution_interface
|
234
|
+
extend_allowed_registration_vars :setup_remote_execution_pull
|
235
|
+
ForemanTasks.dynflow.eager_load_actions!
|
236
|
+
extend_observable_events(
|
237
|
+
::Dynflow::Action.descendants.select do |klass|
|
238
|
+
klass <= ::Actions::ObservableAction
|
239
|
+
end.map(&:namespaced_event_names) +
|
240
|
+
RemoteExecutionFeature.all.pluck(:label).flat_map do |label|
|
241
|
+
[::Actions::RemoteExecution::RunHostJob, ::Actions::RemoteExecution::RunHostsJob].map do |klass|
|
242
|
+
klass.feature_job_event_names(label)
|
243
|
+
end
|
244
|
+
end
|
245
|
+
)
|
246
|
+
end
|
@@ -91,7 +91,7 @@ module Api
|
|
91
91
|
end
|
92
92
|
|
93
93
|
test 'should create with schedule' do
|
94
|
-
@attrs[:scheduling] = { start_at: Time.now.to_s }
|
94
|
+
@attrs[:scheduling] = { start_at: (Time.now + 1.hour).to_s }
|
95
95
|
post :create, params: { job_invocation: @attrs }
|
96
96
|
invocation = ActiveSupport::JSON.decode(@response.body)
|
97
97
|
assert_equal invocation['mode'], 'future'
|