foreman_remote_execution 0.0.6 → 0.0.7
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/app/assets/javascripts/execution_interface.js +6 -0
- data/app/assets/javascripts/template_invocation.js +18 -0
- data/app/assets/stylesheets/template_invocation.css.scss +53 -0
- data/app/controllers/api/v2/job_invocations_controller.rb +64 -0
- data/app/controllers/job_invocations_controller.rb +11 -2
- data/app/controllers/template_invocations_controller.rb +16 -0
- data/app/helpers/remote_execution_helper.rb +78 -15
- data/app/lib/actions/middleware/bind_job_invocation.rb +29 -0
- data/app/lib/actions/remote_execution/run_host_job.rb +20 -53
- data/app/lib/actions/remote_execution/run_hosts_job.rb +30 -9
- data/app/lib/actions/remote_execution/run_proxy_command.rb +64 -3
- data/app/models/concerns/foreman_remote_execution/host_extensions.rb +43 -5
- data/app/models/concerns/foreman_remote_execution/nic_extensions.rb +25 -0
- data/app/models/concerns/foreman_remote_execution/subnet_extensions.rb +10 -0
- data/app/models/concerns/foreman_remote_execution/taxonomy_extensions.rb +16 -0
- data/app/models/input_template_renderer.rb +5 -1
- data/app/models/job_invocation.rb +74 -7
- data/app/models/job_invocation_api_composer.rb +62 -0
- data/app/models/job_invocation_composer.rb +4 -1
- data/app/models/job_template.rb +2 -4
- data/app/models/setting/remote_execution.rb +6 -2
- data/app/models/target_remote_execution_proxy.rb +4 -0
- data/app/models/template_input.rb +14 -2
- data/app/models/template_invocation.rb +12 -1
- data/app/models/template_invocation_input_value.rb +1 -1
- data/app/overrides/execution_interface.rb +9 -0
- data/app/overrides/foreman/nics/_execution_interface.html.erb +1 -0
- data/app/overrides/foreman/subnets/_rex_tab.html.erb +1 -0
- data/app/overrides/foreman/subnets/_rex_tab_pane.html.erb +5 -0
- data/app/overrides/subnet_proxies.rb +9 -0
- data/app/services/proxy_load_balancer.rb +30 -0
- data/app/views/api/v2/job_invocations/base.json.rabl +3 -0
- data/app/views/api/v2/job_invocations/create.json.rabl +3 -0
- data/app/views/api/v2/job_invocations/index.json.rabl +3 -0
- data/app/views/api/v2/job_invocations/main.json.rabl +3 -0
- data/app/views/api/v2/job_invocations/show.json.rabl +18 -0
- data/app/views/api/v2/job_templates/base.json.rabl +1 -1
- data/app/views/job_invocations/_form.html.erb +9 -0
- data/app/views/job_invocations/_tab_hosts.html.erb +10 -14
- data/app/views/job_invocations/_tab_overview.html.erb +2 -9
- data/app/views/job_invocations/show.html.erb +8 -1
- data/app/views/job_invocations/show.js.erb +6 -0
- data/app/views/template_invocations/_output_line_set.html.erb +7 -0
- data/app/views/template_invocations/_refresh.js.erb +7 -0
- data/app/views/template_invocations/show.html.erb +38 -0
- data/app/views/template_invocations/show.js.erb +16 -0
- data/config/routes.rb +4 -0
- data/db/migrate/20150826191632_create_target_remote_execution_proxies.rb +14 -0
- data/db/migrate/20150903192731_add_execution_to_interface.rb +22 -0
- data/doc/source/design/index.md +5 -0
- data/doc/source/design/wireframes.pdf +0 -0
- data/lib/foreman_remote_execution.rb +1 -1
- data/lib/foreman_remote_execution/engine.rb +13 -4
- data/lib/foreman_remote_execution/version.rb +1 -1
- data/test/factories/foreman_remote_execution_factories.rb +46 -1
- data/test/functional/api/v2/job_invocations_controller_test.rb +45 -0
- data/test/test_plugin_helper.rb +18 -0
- data/test/unit/actions/run_hosts_job_test.rb +13 -8
- data/test/unit/actions/run_proxy_command_test.rb +109 -5
- data/test/unit/concerns/host_extensions_test.rb +90 -0
- data/test/unit/concerns/nic_extensions_test.rb +9 -0
- data/test/unit/input_template_renderer_test.rb +24 -10
- data/test/unit/job_invocation_api_composer_test.rb +117 -0
- data/test/unit/job_invocation_composer_test.rb +16 -1
- data/test/unit/job_invocation_test.rb +48 -3
- data/test/unit/proxy_load_balancer_test.rb +25 -0
- metadata +57 -4
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: f7b17c729ed77837816fc91f385aec89be98be24
|
4
|
+
data.tar.gz: 32d6a582df1ffb8e3d20163481176e651070127e
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 733f0235a691db6d71bc9ad72bcf1d3c45db6c95530ed9a57d39203d59401b92858ffb9954c2dccba622ae5a3819147fae35415a1073e1cb920fb138ef89ef46
|
7
|
+
data.tar.gz: 35cfdf9e050b3ebe132c955c0f21c41fbd97e33a3dee871f52e556b446a6d64625b66b0c558bd5d01a23465695b0a1cb233d2e39d5ac3f43c48e5aa6793e3d62
|
@@ -0,0 +1,6 @@
|
|
1
|
+
$(document).on('click', '.interface_execution', function () {
|
2
|
+
confirm_flag_change(this, '.interface_execution', __("Another interface is already set as execution. Are you sure you want to use this one instead?"));
|
3
|
+
|
4
|
+
var modal_form = $('#interfaceModal').find('.modal-body').contents();
|
5
|
+
$('#interfaceForms .interface_execution:checked').attr("checked", false);
|
6
|
+
});
|
@@ -31,6 +31,11 @@ function job_invocation_form_binds() {
|
|
31
31
|
$('#job_template_' + $(this).val()).show();
|
32
32
|
});
|
33
33
|
|
34
|
+
$('input.trigger_mode_selector').on('click', function () {
|
35
|
+
$("#trigger_mode_future").hide();
|
36
|
+
$('#trigger_mode_' + $(this).val()).show();
|
37
|
+
});
|
38
|
+
|
34
39
|
$('select#job_invocation_job_name').on('change', refresh_execution_form);
|
35
40
|
|
36
41
|
$('button#refresh_execution_form').on('click', refresh_execution_form);
|
@@ -39,3 +44,16 @@ function job_invocation_form_binds() {
|
|
39
44
|
|
40
45
|
$('select#targeting_bookmark_id').on('change', refresh_search_query);
|
41
46
|
}
|
47
|
+
|
48
|
+
function delayed_refresh(url, data){
|
49
|
+
setTimeout(function () {
|
50
|
+
$.ajax(
|
51
|
+
{
|
52
|
+
url: url,
|
53
|
+
data: data,
|
54
|
+
dataType: "script",
|
55
|
+
error: function() { $("div.terminal div.printable").append(__('<div class="line error">There was an error while updating the status, try <a href="javascript:window.location.href=window.location.href">refreshing</a> the page</div>')) }
|
56
|
+
}
|
57
|
+
)
|
58
|
+
}, 1000);
|
59
|
+
}
|
@@ -14,3 +14,56 @@ fieldset.provider_form {
|
|
14
14
|
margin-left: 90px;
|
15
15
|
}
|
16
16
|
}
|
17
|
+
|
18
|
+
div.terminal {
|
19
|
+
display: block;
|
20
|
+
padding: 9.5px;
|
21
|
+
margin: 0 0 10px;
|
22
|
+
font-size: 13px;
|
23
|
+
line-height: 1.428571429;
|
24
|
+
word-break: break-all;
|
25
|
+
word-wrap: break-word;
|
26
|
+
color: #B2B2B2;
|
27
|
+
background-color: #000000;
|
28
|
+
border: 1px solid #000000;
|
29
|
+
border-radius: 4px;
|
30
|
+
font-family: Menlo, Monaco, Consolas, "Courier New", monospace;
|
31
|
+
|
32
|
+
div.printable {
|
33
|
+
min-height: 50px;
|
34
|
+
}
|
35
|
+
|
36
|
+
div.line.error, div.line.debug {
|
37
|
+
color: #a9302a;
|
38
|
+
}
|
39
|
+
|
40
|
+
div.line.stderr {
|
41
|
+
background-color: rgba(205, 209, 207, 0.21);
|
42
|
+
color: #FFFFFF;
|
43
|
+
}
|
44
|
+
|
45
|
+
div.line span.counter {
|
46
|
+
float: left;
|
47
|
+
clear: left;
|
48
|
+
}
|
49
|
+
|
50
|
+
div.line div.content {
|
51
|
+
position: relative;
|
52
|
+
margin-left: 50px;
|
53
|
+
}
|
54
|
+
|
55
|
+
a {
|
56
|
+
color: #FFFFFF;
|
57
|
+
}
|
58
|
+
|
59
|
+
a.scroll-link-top {
|
60
|
+
position: relative;
|
61
|
+
bottom: 10px;
|
62
|
+
}
|
63
|
+
|
64
|
+
a.scroll-link-bottom {
|
65
|
+
position: relative;
|
66
|
+
z-index: 5;
|
67
|
+
}
|
68
|
+
|
69
|
+
}
|
@@ -0,0 +1,64 @@
|
|
1
|
+
module Api
|
2
|
+
module V2
|
3
|
+
class JobInvocationsController < ::Api::V2::BaseController
|
4
|
+
include ::Api::Version2
|
5
|
+
include ::Api::TaxonomyScope
|
6
|
+
include ::Foreman::Renderer
|
7
|
+
|
8
|
+
before_filter :find_optional_nested_object
|
9
|
+
before_filter :find_resource, :only => %w{show update destroy clone}
|
10
|
+
before_filter :validate_templates, :only => :create
|
11
|
+
|
12
|
+
api :GET, "/job_invocations/", N_("List job invocations")
|
13
|
+
param_group :search_and_pagination, ::Api::V2::BaseController
|
14
|
+
def index
|
15
|
+
@job_invocations = resource_scope_for_index
|
16
|
+
end
|
17
|
+
|
18
|
+
api :GET, "/job_invocations/:id", N_("Show job invocation")
|
19
|
+
param :id, :identifier, :required => true
|
20
|
+
def show
|
21
|
+
end
|
22
|
+
|
23
|
+
def_param_group :job_invocation do
|
24
|
+
param :job_invocation, Hash, :required => true, :action_aware => true do
|
25
|
+
param :job_name, String, :required => true, :desc => N_("Job name")
|
26
|
+
param :template_id, String, :required => false, :desc => N_("If using a specific template, the id of that template.")
|
27
|
+
param :targeting_type, String, :required => true, :desc => N_("Invocation type, one of %s") % Targeting::TYPES
|
28
|
+
param :inputs, Array, :required => false, :desc => N_("Inputs to use") do
|
29
|
+
param :name, String, :required => true
|
30
|
+
param :value, String, :required => true
|
31
|
+
end
|
32
|
+
param :bookmark_id, Integer, :required => false
|
33
|
+
param :search_query, Integer, :required => false
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
api :POST, "/job_invocations/", N_("Create a job template")
|
38
|
+
param_group :job_invocation, :as => :create
|
39
|
+
def create
|
40
|
+
composer = JobInvocationApiComposer.new(JobInvocation.new, User.current, params[:job_invocation])
|
41
|
+
composer.save!
|
42
|
+
ForemanTasks.async_task(::Actions::RemoteExecution::RunHostsJob, composer.job_invocation)
|
43
|
+
@job_invocation = composer.job_invocation
|
44
|
+
process_response @job_invocation
|
45
|
+
end
|
46
|
+
|
47
|
+
private
|
48
|
+
|
49
|
+
def validate_templates
|
50
|
+
templates = []
|
51
|
+
if params[:job_invocation][:template_id]
|
52
|
+
templates << JobTemplate.find(params[:job_invocation][:template_id])
|
53
|
+
else
|
54
|
+
templates = JobTemplate.where(:job_name => params[:job_invocation][:job_name])
|
55
|
+
if templates.pluck(:provider_type).uniq.length != templates.length
|
56
|
+
raise Foreman::Exception, _("Duplicate remote execution providers found for specified Job, please specify a single template_id.")
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
raise Foreman::Exception, _("No templates associated with specified Job Name") if templates.empty?
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
@@ -24,9 +24,17 @@ class JobInvocationsController < ApplicationController
|
|
24
24
|
|
25
25
|
def create
|
26
26
|
@composer = JobInvocationComposer.new.compose_from_params(params)
|
27
|
+
action = ::Actions::RemoteExecution::RunHostsJob
|
27
28
|
if @composer.save
|
28
|
-
|
29
|
-
|
29
|
+
job_invocation = @composer.job_invocation
|
30
|
+
if job_invocation.trigger_mode == :future
|
31
|
+
ForemanTasks.delay action,
|
32
|
+
job_invocation.delay_options,
|
33
|
+
job_invocation
|
34
|
+
else
|
35
|
+
ForemanTasks.async_task(action, job_invocation)
|
36
|
+
end
|
37
|
+
redirect_to job_invocation_path(job_invocation)
|
30
38
|
else
|
31
39
|
render :action => 'new'
|
32
40
|
end
|
@@ -34,6 +42,7 @@ class JobInvocationsController < ApplicationController
|
|
34
42
|
|
35
43
|
def show
|
36
44
|
@job_invocation = resource_base.find(params[:id])
|
45
|
+
@auto_refresh = @job_invocation.last_task.try(:pending?)
|
37
46
|
end
|
38
47
|
|
39
48
|
def index
|
@@ -0,0 +1,16 @@
|
|
1
|
+
class TemplateInvocationsController < ApplicationController
|
2
|
+
def controller_permission
|
3
|
+
'job_invocations'
|
4
|
+
end
|
5
|
+
|
6
|
+
def show
|
7
|
+
@template_invocation_task = ForemanTasks::Task.find(params[:id])
|
8
|
+
@template_invocation = @template_invocation_task.locks.where(:resource_type => 'TemplateInvocation').first.try(:resource)
|
9
|
+
@host = @template_invocation_task.locks.where(:resource_type => 'Host::Managed').first.try(:resource)
|
10
|
+
@auto_refresh = @template_invocation_task.pending?
|
11
|
+
@since = params[:since].to_f if params[:since].present?
|
12
|
+
@line_sets = @template_invocation_task.main_action.live_output
|
13
|
+
@line_sets = @line_sets.drop_while { |o| o['timestamp'].to_f <= @since } if @since
|
14
|
+
@line_counter = params[:line_counter].to_i
|
15
|
+
end
|
16
|
+
end
|
@@ -11,14 +11,18 @@ module RemoteExecutionHelper
|
|
11
11
|
options = { :class => 'statistics-pie small', :expandable => true, :border => 0, :show_title => true }
|
12
12
|
|
13
13
|
if (bulk_task = invocation.last_task)
|
14
|
+
failed_tasks = bulk_task.sub_tasks.select { |sub_task| %w(warning error).include? sub_task.result }
|
15
|
+
cancelled_tasks, failed_tasks = failed_tasks.partition { |task| task_cancelled? task }
|
14
16
|
success = bulk_task.output['success_count'] || 0
|
15
|
-
|
16
|
-
|
17
|
+
cancelled = cancelled_tasks.length
|
18
|
+
failed = failed_tasks.length
|
19
|
+
pending = (bulk_task.output['pending_count'] || bulk_task.sub_tasks.count)
|
17
20
|
|
18
21
|
flot_pie_chart('status', job_invocation_status(invocation),
|
19
22
|
[{:label => _('Success'), :data => success, :color => '#5CB85C'},
|
20
23
|
{:label => _('Failed'), :data => failed, :color => '#D9534F'},
|
21
|
-
{:label => _('Pending'), :data => pending, :color => '#DEDEDE'}
|
24
|
+
{:label => _('Pending'), :data => pending, :color => '#DEDEDE'},
|
25
|
+
{:label => _('Cancelled'), :data => cancelled, :color => '#B7312D'}],
|
22
26
|
options)
|
23
27
|
else
|
24
28
|
content_tag(:h4, job_invocation_status(invocation))
|
@@ -28,11 +32,18 @@ module RemoteExecutionHelper
|
|
28
32
|
def job_invocation_status(invocation)
|
29
33
|
if invocation.last_task.blank?
|
30
34
|
_('Job not started yet 0%')
|
35
|
+
elsif invocation.last_task.state == 'scheduled'
|
36
|
+
_('Job set to execute at %s') % invocation.last_task.start_at
|
37
|
+
elsif invocation.last_task.state == 'stopped' && invocation.last_task.result == 'error'
|
38
|
+
invocation.last_task.execution_plan.errors.map(&:message).join("\n")
|
31
39
|
else
|
32
40
|
label = invocation.last_task.pending ? _('Running') : _('Finished')
|
33
41
|
label + ' ' + (invocation.last_task.progress * 100).to_i.to_s + '%'
|
34
42
|
end
|
43
|
+
end
|
35
44
|
|
45
|
+
def task_cancelled?(task)
|
46
|
+
task.execution_plan.errors.map(&:exception).any? { |exception| exception.class == ::ForemanTasks::Task::TaskCancelledException }
|
36
47
|
end
|
37
48
|
|
38
49
|
def host_counter(label, count)
|
@@ -42,18 +53,39 @@ module RemoteExecutionHelper
|
|
42
53
|
end
|
43
54
|
|
44
55
|
def template_invocation_status(task)
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
56
|
+
if task.nil?
|
57
|
+
content_tag(:i, ' '.html_safe, :class => 'glyphicon glyphicon-question-sign') + content_tag(:span, _('N/A'))
|
58
|
+
else
|
59
|
+
case task.result
|
60
|
+
when 'warning', 'error'
|
61
|
+
if task_cancelled?(task)
|
62
|
+
content_tag(:i, ' '.html_safe, :class => 'glyphicon glyphicon-warning-sign') + content_tag(:span, _('cancelled'), :class => 'status-error')
|
63
|
+
else
|
64
|
+
content_tag(:i, ' '.html_safe, :class => 'glyphicon glyphicon-exclamation-sign') + content_tag(:span, _('failed'), :class => 'status-error')
|
65
|
+
end
|
66
|
+
when 'success'
|
67
|
+
content_tag(:i, ' '.html_safe, :class => 'glyphicon glyphicon-ok-sign') + content_tag(:span, _('success'), :class => 'status-ok')
|
68
|
+
when 'pending'
|
69
|
+
content_tag(:i, ' '.html_safe, :class => 'glyphicon glyphicon-question-sign') + content_tag(:span, _('pending'))
|
70
|
+
else
|
71
|
+
task.result
|
72
|
+
end
|
54
73
|
end
|
55
74
|
end
|
56
75
|
|
76
|
+
def template_invocation_actions(task, host)
|
77
|
+
if task.nil?
|
78
|
+
[]
|
79
|
+
else
|
80
|
+
[display_link_if_authorized(_("Details"), hash_for_template_invocation_path(:id => task).merge(:auth_object => host, :permission => :view_foreman_tasks))]
|
81
|
+
end
|
82
|
+
end
|
83
|
+
|
84
|
+
def remote_execution_provider_for(task)
|
85
|
+
template_invocation = task.locks.where(:resource_type => 'TemplateInvocation').first.try(:resource) unless task.nil?
|
86
|
+
template_invocation.nil? ? _('N/A') : _(RemoteExecutionProvider.provider_for(template_invocation.template.provider_type))
|
87
|
+
end
|
88
|
+
|
57
89
|
def job_invocation_task_buttons(task)
|
58
90
|
buttons = []
|
59
91
|
buttons << link_to(_('Refresh'), {}, :class => 'btn btn-default', :title => _('Refresh this page'))
|
@@ -79,11 +111,28 @@ module RemoteExecutionHelper
|
|
79
111
|
:disabled => !task.cancellable?,
|
80
112
|
:method => :post)
|
81
113
|
end
|
82
|
-
return
|
114
|
+
return buttons
|
115
|
+
end
|
116
|
+
|
117
|
+
def template_invocation_task_buttons(task)
|
118
|
+
buttons = []
|
119
|
+
if authorized_for(:permission => :view_foreman_tasks, :auth_object => task)
|
120
|
+
buttons << link_to(_("Task Details"), foreman_tasks_task_path(task),
|
121
|
+
:class => "btn btn-default",
|
122
|
+
:title => _('See the task details'))
|
123
|
+
end
|
124
|
+
if authorized_for(:permission => :edit_foreman_tasks, :auth_object => task)
|
125
|
+
buttons << link_to(_("Cancel Job"), cancel_foreman_tasks_task_path(task),
|
126
|
+
:class => "btn btn-danger",
|
127
|
+
:title => _('Try to cancel the job on a host'),
|
128
|
+
:disabled => !task.cancellable?,
|
129
|
+
:method => :post)
|
130
|
+
end
|
131
|
+
return buttons
|
83
132
|
end
|
84
133
|
|
85
134
|
def link_to_invocation_task_if_authorized(invocation)
|
86
|
-
if invocation.last_task.present?
|
135
|
+
if invocation.last_task.present? && invocation.last_task.state != 'scheduled'
|
87
136
|
link_to_if_authorized job_invocation_status(invocation),
|
88
137
|
hash_for_foreman_tasks_task_path(invocation.last_task).merge(:auth_object => invocation.last_task, :permission => :view_foreman_tasks)
|
89
138
|
else
|
@@ -93,6 +142,20 @@ module RemoteExecutionHelper
|
|
93
142
|
|
94
143
|
def invocation_count(invocation, options = {})
|
95
144
|
options = { :unknown_string => 'N/A' }.merge(options)
|
96
|
-
|
145
|
+
if invocation.last_task.nil? || invocation.last_task.state != 'scheduled'
|
146
|
+
(invocation.last_task.try(:output) || {}).fetch(options[:output_key], options[:unknown_string])
|
147
|
+
else
|
148
|
+
options[:unknown_string]
|
149
|
+
end
|
150
|
+
end
|
151
|
+
|
152
|
+
def preview_box(template_invocation, target)
|
153
|
+
renderer = InputTemplateRenderer.new(template_invocation.template, target, template_invocation)
|
154
|
+
if (preview = renderer.preview)
|
155
|
+
content_tag :pre, preview
|
156
|
+
else
|
157
|
+
alert :class => "alert-block alert-danger base in fade has-error",
|
158
|
+
:text => renderer.error_message.html_safe
|
159
|
+
end
|
97
160
|
end
|
98
161
|
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
module Actions
|
2
|
+
module Middleware
|
3
|
+
|
4
|
+
class BindJobInvocation < ::Dynflow::Middleware
|
5
|
+
|
6
|
+
def delay(*args)
|
7
|
+
_schedule_options, job_invocation = args
|
8
|
+
pass(*args).tap { bind(job_invocation) }
|
9
|
+
end
|
10
|
+
|
11
|
+
def plan(*args)
|
12
|
+
job_invocation = args.first
|
13
|
+
pass(*args).tap { bind(job_invocation) }
|
14
|
+
end
|
15
|
+
|
16
|
+
private
|
17
|
+
|
18
|
+
def task
|
19
|
+
@task ||= ForemanTasks::Task::DynflowTask.find_by_external_id!(action.execution_plan_id)
|
20
|
+
end
|
21
|
+
|
22
|
+
def bind(job_invocation)
|
23
|
+
job_invocation.update_attribute :last_task_id, task.id if job_invocation.last_task_id != task.id
|
24
|
+
end
|
25
|
+
|
26
|
+
end
|
27
|
+
|
28
|
+
end
|
29
|
+
end
|
@@ -8,12 +8,17 @@ module Actions
|
|
8
8
|
|
9
9
|
include ::Dynflow::Action::Cancellable
|
10
10
|
|
11
|
-
def plan(job_invocation, host)
|
11
|
+
def plan(job_invocation, host, template_invocation, proxy, connection_options = {})
|
12
12
|
action_subject(host, :job_name => job_invocation.job_name)
|
13
|
-
|
14
|
-
template_invocation = find_template_invocation(job_invocation, host)
|
15
13
|
hostname = find_ip_or_hostname(host)
|
16
|
-
|
14
|
+
|
15
|
+
raise _("Could not use any template used in the job invocation") if template_invocation.blank?
|
16
|
+
|
17
|
+
settings = { :global_proxy => 'remote_execution_global_proxy',
|
18
|
+
:fallback_proxy => 'remote_execution_fallback_proxy' }
|
19
|
+
|
20
|
+
raise _("Could not use any proxy. Consider configuring %{global_proxy} " +
|
21
|
+
"or %{fallback_proxy} in settings") % settings if proxy.blank?
|
17
22
|
|
18
23
|
renderer = InputTemplateRenderer.new(template_invocation.template, host, template_invocation)
|
19
24
|
script = renderer.render
|
@@ -22,71 +27,33 @@ module Actions
|
|
22
27
|
link!(job_invocation)
|
23
28
|
link!(template_invocation)
|
24
29
|
|
25
|
-
plan_action(RunProxyCommand, proxy, hostname, script)
|
30
|
+
plan_action(RunProxyCommand, proxy, hostname, script, { :connection_options => connection_options })
|
26
31
|
end
|
27
32
|
|
28
33
|
def humanized_output
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
output << proxy_output[:result].map { |o| o[:output] }.join("")
|
35
|
-
end
|
36
|
-
output << "Exit status: #{host_run_action.exit_status}" if host_run_action.exit_status
|
37
|
-
return output.join("\n")
|
34
|
+
live_output.map { |line| line['output'].chomp }.join("\n")
|
35
|
+
end
|
36
|
+
|
37
|
+
def live_output
|
38
|
+
planned_actions(RunProxyCommand).first.live_output
|
38
39
|
end
|
39
40
|
|
40
41
|
def humanized_name
|
41
42
|
_('Run %{job_name} on %{host}') % { :job_name => input[:job_name], :host => input[:host][:name] }
|
42
43
|
end
|
43
44
|
|
44
|
-
def
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
if template_invocation.template.provider_type == provider
|
49
|
-
return template_invocation
|
50
|
-
end
|
45
|
+
def find_ip_or_hostname(host)
|
46
|
+
%w(execution primary provision).each do |flag|
|
47
|
+
if host.send("#{flag}_interface") && host.send("#{flag}_interface").ip.present?
|
48
|
+
return host.execution_interface.ip
|
51
49
|
end
|
52
50
|
end
|
53
51
|
|
54
|
-
raise _("Could not use any template used in the job invocation")
|
55
|
-
end
|
56
|
-
|
57
|
-
def find_ip_or_hostname(host)
|
58
52
|
host.interfaces.each do |interface|
|
59
53
|
return interface.ip unless interface.ip.blank?
|
60
54
|
end
|
61
|
-
return host.name
|
62
|
-
end
|
63
|
-
|
64
|
-
def available_providers(job_invocation, host)
|
65
|
-
# TODO: determine from the host and job_invocation details
|
66
|
-
return ['Ssh']
|
67
|
-
end
|
68
|
-
|
69
|
-
def find_proxy(template_invocation, host)
|
70
|
-
provider = template_invocation.template.provider_type.to_s
|
71
|
-
all_host_proxies(host).each do |proxies|
|
72
|
-
if proxy = proxies.joins(:features).where("features.name = ?", provider).first
|
73
|
-
return proxy
|
74
|
-
end
|
75
|
-
end
|
76
|
-
raise _("Could not use any proxy: assign a proxy with provider '%{provider}' to the host or set '%{global_proxy_setting}' in settings") %\
|
77
|
-
{ :provider => provider, :global_proxy_setting => 'remote_execution_global_proxy' }
|
78
|
-
end
|
79
55
|
|
80
|
-
|
81
|
-
Enumerator.new do |e|
|
82
|
-
host.interfaces.each do |interface|
|
83
|
-
if interface.subnet
|
84
|
-
e << ::SmartProxy.where(:id => interface.subnet.proxies.map(&:id))
|
85
|
-
end
|
86
|
-
end
|
87
|
-
e << host.smart_proxies
|
88
|
-
e << ::SmartProxy.authorized if Setting[:remote_execution_global_proxy]
|
89
|
-
end
|
56
|
+
return host.fqdn
|
90
57
|
end
|
91
58
|
end
|
92
59
|
end
|