foreman_remote_execution 0.1.2 → 0.2.1
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/.rubocop.yml +3 -0
- data/.rubocop_todo.yml +0 -6
- data/app/assets/javascripts/template_input.js +5 -0
- data/app/assets/javascripts/template_invocation.js +44 -12
- data/app/controllers/api/v2/foreign_input_sets_controller.rb +80 -0
- data/app/controllers/api/v2/job_invocations_controller.rb +28 -14
- data/app/controllers/api/v2/job_templates_controller.rb +24 -20
- data/app/controllers/api/v2/template_inputs_controller.rb +10 -7
- data/app/controllers/job_invocations_controller.rb +18 -6
- data/app/controllers/job_templates_controller.rb +14 -4
- data/app/controllers/template_invocations_controller.rb +5 -3
- data/app/helpers/concerns/foreman_remote_execution/hosts_helper_extensions.rb +1 -1
- data/app/helpers/concerns/foreman_remote_execution/job_templates_extensions.rb +19 -0
- data/app/helpers/remote_execution_helper.rb +88 -39
- data/app/lib/actions/remote_execution/run_host_job.rb +11 -8
- data/app/lib/actions/remote_execution/run_hosts_job.rb +5 -2
- data/app/lib/actions/remote_execution/run_proxy_command.rb +9 -4
- data/app/models/concerns/foreman_remote_execution/errors_flattener.rb +2 -2
- data/app/models/concerns/foreman_remote_execution/host_extensions.rb +2 -2
- data/app/models/concerns/foreman_remote_execution/smart_proxy_extensions.rb +1 -1
- data/app/models/concerns/foreman_remote_execution/template_extensions.rb +9 -1
- data/app/models/foreign_input_set.rb +49 -0
- data/app/models/host_status/execution_status.rb +50 -5
- data/app/models/input_template_renderer.rb +52 -7
- data/app/models/job_invocation.rb +89 -32
- data/app/models/job_invocation_composer.rb +71 -55
- data/app/models/job_template.rb +43 -7
- data/app/models/remote_execution_provider.rb +1 -1
- data/app/models/setting/remote_execution.rb +7 -7
- data/app/models/ssh_execution_provider.rb +1 -1
- data/app/models/targeting.rb +1 -1
- data/app/models/template_invocation.rb +9 -4
- data/app/views/api/v2/foreign_input_sets/base.json.rabl +3 -0
- data/app/views/api/v2/foreign_input_sets/create.json.rabl +3 -0
- data/app/views/api/v2/foreign_input_sets/index.json.rabl +3 -0
- data/app/views/api/v2/foreign_input_sets/main.json.rabl +5 -0
- data/app/views/api/v2/foreign_input_sets/show.json.rabl +3 -0
- data/app/views/api/v2/job_invocations/base.json.rabl +10 -1
- data/app/views/api/v2/job_invocations/main.json.rabl +14 -1
- data/app/views/api/v2/job_templates/base.json.rabl +1 -1
- data/app/views/api/v2/job_templates/main.json.rabl +9 -1
- data/app/views/api/v2/job_templates/show.json.rabl +0 -10
- data/app/views/api/v2/template_inputs/main.json.rabl +2 -1
- data/app/views/job_invocation_task_groups/_job_invocation_task_group.html.erb +1 -1
- data/app/views/job_invocations/_description_fields.html.erb +4 -0
- data/app/views/job_invocations/_form.html.erb +73 -91
- data/app/views/job_invocations/_host_actions_td.html.erb +2 -2
- data/app/views/job_invocations/_host_name_td.html.erb +7 -0
- data/app/views/job_invocations/_tab_hosts.html.erb +6 -6
- data/app/views/job_invocations/_tab_overview.html.erb +3 -3
- data/app/views/job_invocations/index.html.erb +6 -4
- data/app/views/job_invocations/refresh.js.erb +1 -0
- data/app/views/job_invocations/show.html.erb +1 -1
- data/app/views/job_invocations/show.js.erb +6 -3
- data/app/views/job_templates/_custom_tabs.html.erb +24 -14
- data/app/views/job_templates/index.html.erb +3 -1
- data/app/views/template_inputs/_foreign_input_set_form.html.erb +12 -0
- data/app/views/template_inputs/_form.html.erb +11 -12
- data/app/views/template_invocations/show.html.erb +2 -2
- data/app/views/templates/package_action.erb +2 -2
- data/app/views/templates/puppet_run_once.erb +3 -3
- data/app/views/templates/run_command.erb +3 -3
- data/app/views/templates/service_action.erb +2 -2
- data/app/views/unattended/snippets/_remote_execution_ssh_keys.erb +1 -1
- data/config/routes.rb +5 -3
- data/db/migrate/20150616080015_create_template_input.rb +1 -1
- data/db/migrate/20150708133241_add_targeting.rb +7 -7
- data/db/migrate/20150708133242_add_invocation.rb +2 -2
- data/db/migrate/20150708133305_add_template_invocation.rb +6 -6
- data/db/migrate/20151215114631_add_host_id_to_template_invocation.rb +3 -3
- data/db/migrate/20151217092555_migrate_to_task_groups.rb +1 -1
- data/db/migrate/20160108134600_create_template_input_sets.rb +16 -0
- data/db/migrate/20160108141144_make_job_name_default_to_something.rb +9 -0
- data/db/migrate/20160111113032_upcase_ssh_feature.rb +19 -0
- data/db/migrate/20160113161916_add_run_host_job_task_id_to_template_invocation.rb +6 -0
- data/db/migrate/20160113162007_expand_all_template_invocations.rb +45 -0
- data/db/migrate/20160114120200_rename_job_categories.rb +20 -0
- data/db/migrate/20160114125628_rename_job_name_to_job_category.rb +19 -0
- data/db/seeds.d/60-ssh_proxy_feature.rb +1 -1
- data/db/seeds.d/80-provision_templates.rb +2 -2
- data/db/seeds.d/90-bookmarks.rb +19 -0
- data/doc/plugins/graphviz.rb +5 -5
- data/doc/plugins/plantuml.rb +6 -6
- data/doc/plugins/tags.rb +4 -4
- data/foreman_remote_execution.gemspec +3 -4
- data/lib/foreman_remote_execution/engine.rb +12 -9
- data/lib/foreman_remote_execution/version.rb +1 -1
- data/test/factories/foreman_remote_execution_factories.rb +11 -9
- data/test/functional/api/v2/foreign_input_sets_controller_test.rb +63 -0
- data/test/functional/api/v2/job_invocations_controller_test.rb +45 -13
- data/test/functional/api/v2/job_templates_controller_test.rb +6 -6
- data/test/functional/api/v2/template_inputs_controller_test.rb +3 -3
- data/test/unit/actions/run_hosts_job_test.rb +3 -4
- data/test/unit/actions/run_proxy_command_test.rb +7 -7
- data/test/unit/concerns/host_extensions_test.rb +1 -1
- data/test/unit/execution_task_status_mapper_test.rb +93 -0
- data/test/unit/input_template_renderer_test.rb +182 -9
- data/test/unit/job_invocation_composer_test.rb +144 -168
- data/test/unit/job_invocation_test.rb +67 -15
- data/test/unit/job_template_effective_user_test.rb +2 -2
- data/test/unit/job_template_test.rb +36 -12
- data/test/unit/remote_execution_provider_test.rb +6 -6
- data/test/unit/targeting_test.rb +2 -2
- metadata +27 -21
- data/app/models/concerns/foreman_remote_execution/template_relations.rb +0 -10
- data/app/views/job_invocations/_host_provider_td.html.erb +0 -3
- data/app/views/job_templates/auto_complete_job_name.json.erb +0 -3
|
@@ -4,14 +4,24 @@ class JobInvocationsController < ApplicationController
|
|
|
4
4
|
before_filter :find_or_create_triggering, :only => [:create, :refresh]
|
|
5
5
|
|
|
6
6
|
def new
|
|
7
|
-
|
|
7
|
+
ui_params = {
|
|
8
8
|
:host_ids => params[:host_ids],
|
|
9
|
-
:job_invocation => {
|
|
10
|
-
},
|
|
11
9
|
:targeting => {
|
|
12
10
|
:targeting_type => Targeting::STATIC_TYPE,
|
|
13
11
|
:bookmark_id => params[:bookmark_id]
|
|
14
|
-
}
|
|
12
|
+
}
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
if (template = JobTemplate.find_by_id(params[:template_id]))
|
|
16
|
+
ui_params[:job_invocation] = {
|
|
17
|
+
:job_category => template.job_category,
|
|
18
|
+
:providers => {
|
|
19
|
+
template.provider_type => {:job_template_id => template.id}
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
@composer = JobInvocationComposer.from_ui_params(ui_params)
|
|
15
25
|
end
|
|
16
26
|
|
|
17
27
|
def rerun
|
|
@@ -34,23 +44,25 @@ class JobInvocationsController < ApplicationController
|
|
|
34
44
|
@composer.triggering.trigger(::Actions::RemoteExecution::RunHostsJob, job_invocation)
|
|
35
45
|
redirect_to job_invocation_path(job_invocation)
|
|
36
46
|
else
|
|
47
|
+
@composer.job_invocation.description_format = nil if params[:job_invocation].key?(:description_override)
|
|
37
48
|
render :action => 'new'
|
|
38
49
|
end
|
|
39
50
|
end
|
|
40
51
|
|
|
41
52
|
def show
|
|
42
|
-
@job_invocation = resource_base.find(params[:id])
|
|
53
|
+
@job_invocation = resource_base.includes(:template_invocations => :run_host_job_task).find(params[:id])
|
|
43
54
|
@auto_refresh = @job_invocation.task.try(:pending?)
|
|
44
55
|
hosts_base = @job_invocation.targeting.hosts.authorized(:view_hosts, Host)
|
|
45
56
|
@hosts = hosts_base.search_for(params[:search], :order => params[:order] || 'name ASC').paginate(:page => params[:page])
|
|
46
57
|
end
|
|
47
58
|
|
|
48
59
|
def index
|
|
49
|
-
@job_invocations = resource_base.search_for(params[:search]).paginate(:page => params[:page]).with_task.order(
|
|
60
|
+
@job_invocations = resource_base.search_for(params[:search], :order => params[:order]).paginate(:page => params[:page]).with_task.order('job_invocations.id DESC')
|
|
50
61
|
end
|
|
51
62
|
|
|
52
63
|
# refreshes the form
|
|
53
64
|
def refresh
|
|
65
|
+
params[:job_invocation].delete :description_format if params[:job_invocation].key?(:description_override)
|
|
54
66
|
@composer = JobInvocationComposer.from_ui_params(params)
|
|
55
67
|
end
|
|
56
68
|
|
|
@@ -6,11 +6,13 @@ class JobTemplatesController < ::TemplatesController
|
|
|
6
6
|
@organizations = @template.organizations
|
|
7
7
|
end
|
|
8
8
|
|
|
9
|
-
def
|
|
10
|
-
@
|
|
9
|
+
def auto_complete_job_category
|
|
10
|
+
@job_categories = resource_base.where(['job_category LIKE ?', "%#{params[:search]}%"]).pluck(:job_category).uniq
|
|
11
|
+
render :json => @job_categories.map { |name| { 'completed' => '', 'part' => name, 'label' => name, 'category' => '' } }.to_json
|
|
11
12
|
end
|
|
12
13
|
|
|
13
14
|
def preview
|
|
15
|
+
find_resource unless @template.present?
|
|
14
16
|
base = Host.authorized(:view_hosts, Host)
|
|
15
17
|
host = params[:preview_host_id].present? ? base.find(params[:preview_host_id]) : base.first
|
|
16
18
|
@template.template = params[:template]
|
|
@@ -18,15 +20,23 @@ class JobTemplatesController < ::TemplatesController
|
|
|
18
20
|
if (output = renderer.preview)
|
|
19
21
|
render :text => output
|
|
20
22
|
else
|
|
21
|
-
render :status => 406, :text => renderer.error_message
|
|
23
|
+
render :status => 406, :text => renderer.error_message + _(', note that you must save template input changes before you try to preview it.')
|
|
22
24
|
end
|
|
23
25
|
end
|
|
24
26
|
|
|
25
27
|
private
|
|
26
28
|
|
|
29
|
+
def find_resource
|
|
30
|
+
if params[:id]
|
|
31
|
+
super
|
|
32
|
+
else
|
|
33
|
+
@template = resource_class.new(params[type_name_plural])
|
|
34
|
+
end
|
|
35
|
+
end
|
|
36
|
+
|
|
27
37
|
def action_permission
|
|
28
38
|
case params[:action]
|
|
29
|
-
when '
|
|
39
|
+
when 'auto_complete_job_category'
|
|
30
40
|
:view_job_templates
|
|
31
41
|
else
|
|
32
42
|
super
|
|
@@ -6,9 +6,11 @@ class TemplateInvocationsController < ApplicationController
|
|
|
6
6
|
end
|
|
7
7
|
|
|
8
8
|
def show
|
|
9
|
-
@
|
|
10
|
-
|
|
11
|
-
|
|
9
|
+
@template_invocation = TemplateInvocation.find(params[:id])
|
|
10
|
+
raise ActiveRecord::RecordNotFound unless User.current.can?(:view_job_invocations, @template_invocation.job_invocation)
|
|
11
|
+
|
|
12
|
+
@template_invocation_task = @template_invocation.run_host_job_task
|
|
13
|
+
@host = @template_invocation.host
|
|
12
14
|
@auto_refresh = @template_invocation_task.pending?
|
|
13
15
|
@since = params[:since].to_f if params[:since].present?
|
|
14
16
|
@line_sets = @template_invocation_task.main_action.live_output
|
|
@@ -15,7 +15,7 @@ module ForemanRemoteExecution
|
|
|
15
15
|
end
|
|
16
16
|
|
|
17
17
|
def host_title_actions_with_run_button(*args)
|
|
18
|
-
title_actions(button_group(link_to(_(
|
|
18
|
+
title_actions(button_group(link_to(_('Run Job'), new_job_invocation_path(:host_ids => [args.first.id]), :id => :run_button)))
|
|
19
19
|
host_title_actions_without_run_button(*args)
|
|
20
20
|
end
|
|
21
21
|
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
module ForemanRemoteExecution
|
|
2
|
+
module JobTemplatesExtensions
|
|
3
|
+
extend ActiveSupport::Concern
|
|
4
|
+
|
|
5
|
+
included do
|
|
6
|
+
alias_method_chain :permitted_actions, :run_button
|
|
7
|
+
end
|
|
8
|
+
|
|
9
|
+
def permitted_actions_with_run_button(template)
|
|
10
|
+
original = permitted_actions_without_run_button(template)
|
|
11
|
+
|
|
12
|
+
if template.is_a?(JobTemplate) && !template.snippet
|
|
13
|
+
original.unshift(display_link_if_authorized(_('Run'), hash_for_new_job_invocation_path(:template_id => template.id)))
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
original
|
|
17
|
+
end
|
|
18
|
+
end
|
|
19
|
+
end
|
|
@@ -30,15 +30,17 @@ module RemoteExecutionHelper
|
|
|
30
30
|
end
|
|
31
31
|
|
|
32
32
|
def job_invocation_status(invocation)
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
33
|
+
case invocation.status
|
|
34
|
+
when HostStatus::ExecutionStatus::QUEUED
|
|
35
|
+
_('queued')
|
|
36
|
+
when HostStatus::ExecutionStatus::RUNNING
|
|
37
|
+
_('running %s%') % invocation.progress
|
|
38
|
+
when HostStatus::ExecutionStatus::OK
|
|
39
|
+
_('succeeded')
|
|
40
|
+
when HostStatus::ExecutionStatus::ERROR
|
|
41
|
+
_('failed')
|
|
42
|
+
else
|
|
43
|
+
_('unknown status')
|
|
42
44
|
end
|
|
43
45
|
end
|
|
44
46
|
|
|
@@ -77,43 +79,48 @@ module RemoteExecutionHelper
|
|
|
77
79
|
end
|
|
78
80
|
end
|
|
79
81
|
|
|
80
|
-
def template_invocation_actions(task, host)
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
end
|
|
82
|
+
def template_invocation_actions(task, host, job_invocation, template_invocation)
|
|
83
|
+
[
|
|
84
|
+
display_link_if_authorized(_('Host detail'), hash_for_host_path(host).merge(:auth_object => host, :permission => :view_hosts)),
|
|
85
|
+
display_link_if_authorized(_('Rerun on %s') % host.name, hash_for_rerun_job_invocation_path(:id => job_invocation, :host_ids => [ host.id ])),
|
|
86
|
+
]
|
|
86
87
|
end
|
|
87
88
|
|
|
88
|
-
def remote_execution_provider_for(
|
|
89
|
-
template_invocation = task.locks.where(:resource_type => 'TemplateInvocation').first.try(:resource) unless task.nil?
|
|
89
|
+
def remote_execution_provider_for(template_invocation)
|
|
90
90
|
template_invocation.nil? ? _('N/A') : template_invocation.template.provider.humanized_name
|
|
91
91
|
end
|
|
92
92
|
|
|
93
|
+
def job_invocations_buttons
|
|
94
|
+
[
|
|
95
|
+
documentation_button_rex('3.2ExecutingaJob'),
|
|
96
|
+
display_link_if_authorized(_('Run Job'), hash_for_new_job_invocation_path)
|
|
97
|
+
]
|
|
98
|
+
end
|
|
99
|
+
|
|
93
100
|
# rubocop:disable Metrics/AbcSize
|
|
94
101
|
def job_invocation_task_buttons(task)
|
|
95
102
|
job_invocation = task.task_groups.find { |group| group.class == JobInvocationTaskGroup }.job_invocation
|
|
96
103
|
buttons = []
|
|
97
104
|
buttons << link_to(_('Refresh'), {}, :class => 'btn btn-default', :title => _('Refresh this page'))
|
|
98
105
|
if authorized_for(hash_for_new_job_invocation_path)
|
|
99
|
-
buttons << link_to(_(
|
|
100
|
-
:class =>
|
|
106
|
+
buttons << link_to(_('Rerun'), rerun_job_invocation_path(:id => job_invocation.id),
|
|
107
|
+
:class => 'btn btn-default',
|
|
101
108
|
:title => _('Rerun the job'))
|
|
102
109
|
end
|
|
103
110
|
if authorized_for(hash_for_new_job_invocation_path)
|
|
104
|
-
buttons << link_to(_(
|
|
105
|
-
:class =>
|
|
111
|
+
buttons << link_to(_('Rerun failed'), rerun_job_invocation_path(:id => job_invocation.id, :failed_only => 1),
|
|
112
|
+
:class => 'btn btn-default',
|
|
106
113
|
:disabled => !task.sub_tasks.any? { |sub_task| task_failed?(sub_task) },
|
|
107
114
|
:title => _('Rerun on failed hosts'))
|
|
108
115
|
end
|
|
109
116
|
if authorized_for(:permission => :view_foreman_tasks, :auth_object => task)
|
|
110
|
-
buttons << link_to(_(
|
|
111
|
-
:class =>
|
|
117
|
+
buttons << link_to(_('Job Task'), foreman_tasks_task_path(task),
|
|
118
|
+
:class => 'btn btn-default',
|
|
112
119
|
:title => _('See the last task details'))
|
|
113
120
|
end
|
|
114
121
|
if authorized_for(:permission => :edit_foreman_tasks, :auth_object => task)
|
|
115
|
-
buttons << link_to(_(
|
|
116
|
-
:class =>
|
|
122
|
+
buttons << link_to(_('Cancel Job'), cancel_foreman_tasks_task_path(task),
|
|
123
|
+
:class => 'btn btn-danger',
|
|
117
124
|
:title => _('Try to cancel the job'),
|
|
118
125
|
:disabled => !task.cancellable?,
|
|
119
126
|
:method => :post)
|
|
@@ -125,13 +132,13 @@ module RemoteExecutionHelper
|
|
|
125
132
|
def template_invocation_task_buttons(task)
|
|
126
133
|
buttons = []
|
|
127
134
|
if authorized_for(:permission => :view_foreman_tasks, :auth_object => task)
|
|
128
|
-
buttons << link_to(_(
|
|
129
|
-
:class =>
|
|
135
|
+
buttons << link_to(_('Task Details'), foreman_tasks_task_path(task),
|
|
136
|
+
:class => 'btn btn-default',
|
|
130
137
|
:title => _('See the task details'))
|
|
131
138
|
end
|
|
132
139
|
if authorized_for(:permission => :edit_foreman_tasks, :auth_object => task)
|
|
133
|
-
buttons << link_to(_(
|
|
134
|
-
:class =>
|
|
140
|
+
buttons << link_to(_('Cancel Job'), cancel_foreman_tasks_task_path(task),
|
|
141
|
+
:class => 'btn btn-danger',
|
|
135
142
|
:title => _('Try to cancel the job on a host'),
|
|
136
143
|
:disabled => !task.cancellable?,
|
|
137
144
|
:method => :post)
|
|
@@ -140,20 +147,20 @@ module RemoteExecutionHelper
|
|
|
140
147
|
end
|
|
141
148
|
|
|
142
149
|
def link_to_invocation_task_if_authorized(invocation)
|
|
143
|
-
if invocation.
|
|
150
|
+
if invocation.queued?
|
|
151
|
+
job_invocation_status(invocation)
|
|
152
|
+
else
|
|
144
153
|
link_to_if_authorized job_invocation_status(invocation),
|
|
145
154
|
hash_for_foreman_tasks_task_path(invocation.task).merge(:auth_object => invocation.task, :permission => :view_foreman_tasks)
|
|
146
|
-
else
|
|
147
|
-
job_invocation_status(invocation)
|
|
148
155
|
end
|
|
149
156
|
end
|
|
150
157
|
|
|
151
158
|
def invocation_count(invocation, options = {})
|
|
152
159
|
options = { :unknown_string => 'N/A' }.merge(options)
|
|
153
|
-
if invocation.
|
|
154
|
-
(invocation.task.try(:output) || {}).fetch(options[:output_key], options[:unknown_string])
|
|
155
|
-
else
|
|
160
|
+
if invocation.queued?
|
|
156
161
|
options[:unknown_string]
|
|
162
|
+
else
|
|
163
|
+
(invocation.task.try(:output) || {}).fetch(options[:output_key], options[:unknown_string])
|
|
157
164
|
end
|
|
158
165
|
end
|
|
159
166
|
|
|
@@ -162,7 +169,7 @@ module RemoteExecutionHelper
|
|
|
162
169
|
if (preview = renderer.preview)
|
|
163
170
|
content_tag :pre, preview
|
|
164
171
|
else
|
|
165
|
-
alert :class =>
|
|
172
|
+
alert :class => 'alert-block alert-danger base in fade has-error',
|
|
166
173
|
:text => renderer.error_message.html_safe
|
|
167
174
|
end
|
|
168
175
|
end
|
|
@@ -178,13 +185,55 @@ module RemoteExecutionHelper
|
|
|
178
185
|
end
|
|
179
186
|
end
|
|
180
187
|
|
|
181
|
-
def
|
|
188
|
+
def time_in_words_span(time)
|
|
182
189
|
if time.nil?
|
|
183
|
-
_('
|
|
190
|
+
_('N/A')
|
|
184
191
|
else
|
|
185
|
-
content_tag :span, _(
|
|
192
|
+
content_tag :span, (time > Time.now ? _('in %s') : _('%s ago')) % time_ago_in_words(time),
|
|
186
193
|
{ :'data-original-title' => time.try(:in_time_zone), :rel => 'twipsy' }
|
|
187
194
|
end
|
|
188
195
|
end
|
|
189
196
|
|
|
197
|
+
def documentation_button_rex(section = '')
|
|
198
|
+
url = 'http://theforeman.org/plugins/foreman_remote_execution/' +
|
|
199
|
+
"#{ForemanRemoteExecution::VERSION.split('.').take(2).join('.')}/index.html#" +
|
|
200
|
+
section
|
|
201
|
+
link_to(
|
|
202
|
+
icon_text('help', _('Documentation'),
|
|
203
|
+
:class => 'icon-white', :kind => 'pficon'),
|
|
204
|
+
url,
|
|
205
|
+
:rel => 'external', :class => 'btn btn-info', :target => '_blank')
|
|
206
|
+
end
|
|
207
|
+
|
|
208
|
+
def template_input_header(f, template)
|
|
209
|
+
header = _('Template input')
|
|
210
|
+
header += ' ' + remove_child_link('x', f, {:rel => 'twipsy', :'data-title' => _('remove template input'), :'data-placement' => 'left',
|
|
211
|
+
:class => 'fr badge badge-danger'}) unless template.locked?
|
|
212
|
+
header.html_safe
|
|
213
|
+
end
|
|
214
|
+
|
|
215
|
+
def description_checkbox_f(f, job_template, disabled)
|
|
216
|
+
check_box_tag('description_format_override',
|
|
217
|
+
job_template.generate_description_format,
|
|
218
|
+
f.object.description_format.nil?,
|
|
219
|
+
:class => 'description_format_override',
|
|
220
|
+
:name => f.object_name + '[description_override]',
|
|
221
|
+
:disabled => disabled,
|
|
222
|
+
:onchange => 'description_override(this);') + ' ' + _('Use default description template')
|
|
223
|
+
end
|
|
224
|
+
|
|
225
|
+
def description_format_textarea_f(f, job_template, disabled)
|
|
226
|
+
textarea_f f, 'description_format',
|
|
227
|
+
:label => _('Description template'),
|
|
228
|
+
:value => f.object.description_format || job_template.generate_description_format,
|
|
229
|
+
:rows => 2,
|
|
230
|
+
:onchange => 'regenerate_description(this);',
|
|
231
|
+
:class => 'description_format',
|
|
232
|
+
:disabled => disabled,
|
|
233
|
+
:help_inline => popover(_('Explanation'),
|
|
234
|
+
_('This template is used to generate the description.
|
|
235
|
+
Input values can be used using the syntax %{package}.
|
|
236
|
+
You may also include the job category and template
|
|
237
|
+
name using %{job_category} and %{template_name}.'))
|
|
238
|
+
end
|
|
190
239
|
end
|
|
@@ -10,26 +10,29 @@ module Actions
|
|
|
10
10
|
end
|
|
11
11
|
|
|
12
12
|
def plan(job_invocation, host, template_invocation, proxy)
|
|
13
|
-
action_subject(host, :
|
|
13
|
+
action_subject(host, :job_category => job_invocation.job_category, :description => job_invocation.description)
|
|
14
|
+
|
|
15
|
+
template_invocation.host_id = host.id
|
|
16
|
+
template_invocation.run_host_job_task_id = task.id
|
|
17
|
+
template_invocation.save!
|
|
14
18
|
|
|
15
|
-
template_invocation.update_attribute :host_id, host.id
|
|
16
19
|
link!(job_invocation)
|
|
17
20
|
link!(template_invocation)
|
|
18
21
|
|
|
19
22
|
verify_permissions(host, template_invocation)
|
|
20
23
|
hostname = find_ip_or_hostname(host)
|
|
21
24
|
|
|
22
|
-
raise _(
|
|
25
|
+
raise _('Could not use any template used in the job invocation') if template_invocation.blank?
|
|
23
26
|
|
|
24
27
|
settings = { :global_proxy => 'remote_execution_global_proxy',
|
|
25
28
|
:fallback_proxy => 'remote_execution_fallback_proxy' }
|
|
26
29
|
|
|
27
|
-
raise _(
|
|
28
|
-
|
|
30
|
+
raise _('Could not use any proxy. Consider configuring %{global_proxy} ' +
|
|
31
|
+
'or %{fallback_proxy} in settings') % settings if proxy.blank?
|
|
29
32
|
|
|
30
33
|
renderer = InputTemplateRenderer.new(template_invocation.template, host, template_invocation)
|
|
31
34
|
script = renderer.render
|
|
32
|
-
raise _(
|
|
35
|
+
raise _('Failed rendering template: %s') % renderer.error_message unless script
|
|
33
36
|
|
|
34
37
|
provider = template_invocation.template.provider
|
|
35
38
|
plan_action(RunProxyCommand, proxy, hostname, script, provider.proxy_command_options(template_invocation, host))
|
|
@@ -57,9 +60,9 @@ module Actions
|
|
|
57
60
|
end
|
|
58
61
|
|
|
59
62
|
def humanized_name
|
|
60
|
-
_('%{description} on %{host}') % { :
|
|
63
|
+
_('%{description} on %{host}') % { :job_category => input[:job_category],
|
|
61
64
|
:host => input[:host][:name],
|
|
62
|
-
:description => input[:description].try(:capitalize) || input[:
|
|
65
|
+
:description => input[:description].try(:capitalize) || input[:job_category] }
|
|
63
66
|
end
|
|
64
67
|
|
|
65
68
|
def find_ip_or_hostname(host)
|
|
@@ -16,7 +16,7 @@ module Actions
|
|
|
16
16
|
task.add_missing_task_groups(job_invocation.task_group) if job_invocation.task_group
|
|
17
17
|
action_subject(job_invocation) unless locked
|
|
18
18
|
job_invocation.targeting.resolve_hosts! if job_invocation.targeting.dynamic? || !locked
|
|
19
|
-
input.update(:
|
|
19
|
+
input.update(:job_category => job_invocation.job_category)
|
|
20
20
|
plan_self(:job_invocation_id => job_invocation.id)
|
|
21
21
|
end
|
|
22
22
|
|
|
@@ -24,8 +24,11 @@ module Actions
|
|
|
24
24
|
job_invocation = JobInvocation.find(input[:job_invocation_id])
|
|
25
25
|
load_balancer = ProxyLoadBalancer.new
|
|
26
26
|
|
|
27
|
+
# composer creates just "pattern" for template_invocations because target is evaluated
|
|
28
|
+
# during actual run (here) so we build template invocations from these patterns
|
|
27
29
|
job_invocation.targeting.hosts.map do |host|
|
|
28
|
-
template_invocation = job_invocation.
|
|
30
|
+
template_invocation = job_invocation.pattern_template_invocation_for_host(host).deep_clone
|
|
31
|
+
template_invocation.host_id = host.id
|
|
29
32
|
proxy = determine_proxy(template_invocation, host, load_balancer)
|
|
30
33
|
trigger(RunHostJob, job_invocation, host, template_invocation, proxy)
|
|
31
34
|
end
|
|
@@ -21,7 +21,7 @@ module Actions
|
|
|
21
21
|
.new(data[:metadata][:exception_message]))
|
|
22
22
|
else
|
|
23
23
|
super(data)
|
|
24
|
-
error! _(
|
|
24
|
+
error! _('Script execution failed') if failed_run?
|
|
25
25
|
end
|
|
26
26
|
end
|
|
27
27
|
|
|
@@ -63,7 +63,7 @@ module Actions
|
|
|
63
63
|
proxy_data.fetch('output', {}).fetch('result', [])
|
|
64
64
|
rescue => e
|
|
65
65
|
::Foreman::Logging.exception("Failed to load data for task #{task.id} from proxy #{ input[:proxy_url] }", e)
|
|
66
|
-
[exception_to_output(_(
|
|
66
|
+
[exception_to_output(_('Error loading data from proxy'), e)]
|
|
67
67
|
end
|
|
68
68
|
|
|
69
69
|
def finalized_output
|
|
@@ -76,13 +76,18 @@ module Actions
|
|
|
76
76
|
end
|
|
77
77
|
|
|
78
78
|
if exit_status
|
|
79
|
-
records << format_output(_(
|
|
79
|
+
records << format_output(_('Exit status: %s') % exit_status, 'stdout', final_timestamp(records))
|
|
80
80
|
elsif run_step && run_step.error
|
|
81
|
-
records << format_output(_(
|
|
81
|
+
records << format_output(_('Job finished with error') + ": #{run_step.error.exception_class} - #{run_step.error.message}", 'debug', final_timestamp(records))
|
|
82
82
|
end
|
|
83
83
|
return records
|
|
84
84
|
end
|
|
85
85
|
|
|
86
|
+
def final_timestamp(records)
|
|
87
|
+
return task.ended_at if records.blank?
|
|
88
|
+
records.last.fetch('timestamp', task.ended_at) + 1
|
|
89
|
+
end
|
|
90
|
+
|
|
86
91
|
def proxy_result
|
|
87
92
|
self.output.fetch(:proxy_output, {}).fetch(:result, []) || []
|
|
88
93
|
end
|