foreman_remote_execution 18.0.1 → 18.1.0
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/assets/javascripts/foreman_remote_execution/locale/fr/foreman_remote_execution.js +28 -28
- data/app/assets/javascripts/foreman_remote_execution/locale/ja/foreman_remote_execution.js +48 -48
- data/app/assets/javascripts/foreman_remote_execution/locale/ko/foreman_remote_execution.js +29 -29
- data/app/assets/javascripts/foreman_remote_execution/locale/zh_CN/foreman_remote_execution.js +22 -22
- data/app/assets/javascripts/foreman_remote_execution/template_invocation.js +0 -170
- data/app/assets/stylesheets/foreman_remote_execution/job_invocations.scss +0 -6
- data/app/controllers/job_invocations_controller.rb +1 -98
- data/app/helpers/job_invocations_helper.rb +0 -49
- data/app/helpers/remote_execution_helper.rb +23 -123
- data/config/routes.rb +0 -6
- data/lib/foreman_remote_execution/plugin.rb +2 -2
- data/lib/foreman_remote_execution/version.rb +1 -1
- data/locale/foreman_remote_execution.pot +2 -2
- data/locale/fr/LC_MESSAGES/foreman_remote_execution.mo +0 -0
- data/locale/fr/foreman_remote_execution.po +28 -28
- data/locale/ja/LC_MESSAGES/foreman_remote_execution.mo +0 -0
- data/locale/ja/foreman_remote_execution.po +48 -48
- data/locale/ko/LC_MESSAGES/foreman_remote_execution.mo +0 -0
- data/locale/ko/foreman_remote_execution.po +29 -29
- data/locale/zh_CN/LC_MESSAGES/foreman_remote_execution.mo +0 -0
- data/locale/zh_CN/foreman_remote_execution.po +22 -22
- data/package.json +1 -14
- data/test/functional/job_invocations_controller_test.rb +0 -77
- data/webpack/JobInvocationDetail/JobInvocationConstants.js +5 -0
- data/webpack/JobInvocationDetail/JobInvocationToolbarButtons.js +0 -10
- data/webpack/JobInvocationDetail/TemplateInvocation.js +12 -69
- data/webpack/JobInvocationDetail/TemplateInvocationComponents/OutputCodeBlock.js +94 -72
- data/webpack/JobInvocationDetail/TemplateInvocationHelpers.js +33 -0
- data/webpack/JobInvocationDetail/__tests__/JobInvocationDetailEmptyState.test.js +1 -1
- data/webpack/JobInvocationDetail/__tests__/MainInformation.test.js +0 -6
- data/webpack/JobInvocationDetail/__tests__/OutputCodeBlock.test.js +1 -1
- data/webpack/JobInvocationDetail/__tests__/TableToolbarActions.test.js +1 -1
- data/webpack/JobInvocationDetail/__tests__/TemplateInvocation.test.js +5 -1
- data/webpack/JobInvocationDetail/__tests__/TemplateInvocationHelpers.test.js +94 -0
- data/webpack/JobInvocationDetail/__tests__/TemplateInvocationPolling.test.js +338 -139
- data/webpack/JobInvocationDetail/useTemplateInvocationOutputPolling.js +185 -0
- data/webpack/JobWizard/JobWizardPageRerun.js +0 -10
- data/webpack/JobWizard/__tests__/autofill.test.js +23 -0
- data/webpack/JobWizard/__tests__/integration.test.js +1 -1
- data/webpack/JobWizard/autofill.js +18 -4
- data/webpack/JobWizard/index.js +1 -18
- data/webpack/JobWizard/steps/HostsAndInputs/__tests__/HostsAndInputs.test.js +49 -1
- data/webpack/global_index.js +0 -2
- data/webpack/index.js +0 -15
- data/webpack/react_app/components/RegistrationExtension/__tests__/RexInterface.test.js +1 -1
- metadata +6 -53
- data/app/assets/stylesheets/foreman_remote_execution/modal_window.scss +0 -4
- data/app/helpers/job_invocations_chart_helper.rb +0 -80
- data/app/views/job_invocations/_card_results.html.erb +0 -12
- data/app/views/job_invocations/_card_schedule.html.erb +0 -33
- data/app/views/job_invocations/_card_target_hosts.html.erb +0 -57
- data/app/views/job_invocations/_card_user_input.html.erb +0 -16
- data/app/views/job_invocations/_description_fields.html.erb +0 -4
- data/app/views/job_invocations/_form.html.erb +0 -144
- data/app/views/job_invocations/_preview_hosts_modal.html.erb +0 -15
- data/app/views/job_invocations/_rerun_taxonomies.html.erb +0 -22
- data/app/views/job_invocations/_tab_hosts.html.erb +0 -11
- data/app/views/job_invocations/_tab_overview.html.erb +0 -41
- data/app/views/job_invocations/_tab_preview_templates.html.erb +0 -20
- data/app/views/job_invocations/_user_input.html.erb +0 -21
- data/app/views/job_invocations/new.html.erb +0 -9
- data/app/views/job_invocations/refresh.js.erb +0 -4
- data/app/views/job_invocations/show.html.erb +0 -59
- data/app/views/job_invocations/show.js.erb +0 -12
- data/app/views/job_invocations/show.json.erb +0 -5
- data/test/support/remote_execution_helper.rb +0 -5
- data/webpack/react_app/components/TargetingHosts/TargetingHosts.js +0 -62
- data/webpack/react_app/components/TargetingHosts/TargetingHostsConsts.js +0 -2
- data/webpack/react_app/components/TargetingHosts/TargetingHostsHelpers.js +0 -10
- data/webpack/react_app/components/TargetingHosts/TargetingHostsLabelsRow.js +0 -45
- data/webpack/react_app/components/TargetingHosts/TargetingHostsLabelsRow.scss +0 -30
- data/webpack/react_app/components/TargetingHosts/TargetingHostsPage.js +0 -78
- data/webpack/react_app/components/TargetingHosts/TargetingHostsPage.scss +0 -3
- data/webpack/react_app/components/TargetingHosts/TargetingHostsSelectors.js +0 -25
- data/webpack/react_app/components/TargetingHosts/__tests__/HostItem.test.js +0 -76
- data/webpack/react_app/components/TargetingHosts/__tests__/HostStatus.test.js +0 -6
- data/webpack/react_app/components/TargetingHosts/__tests__/TargetingHosts.test.js +0 -6
- data/webpack/react_app/components/TargetingHosts/__tests__/TargetingHostsPage.test.js +0 -9
- data/webpack/react_app/components/TargetingHosts/__tests__/TargetingHostsSelectors.test.js +0 -31
- data/webpack/react_app/components/TargetingHosts/__tests__/__snapshots__/HostStatus.test.js.snap +0 -12
- data/webpack/react_app/components/TargetingHosts/__tests__/__snapshots__/TargetingHosts.test.js.snap +0 -96
- data/webpack/react_app/components/TargetingHosts/__tests__/__snapshots__/TargetingHostsPage.test.js.snap +0 -75
- data/webpack/react_app/components/TargetingHosts/__tests__/__snapshots__/TargetingHostsSelectors.test.js.snap +0 -16
- data/webpack/react_app/components/TargetingHosts/__tests__/fixtures.js +0 -56
- data/webpack/react_app/components/TargetingHosts/components/HostItem.js +0 -39
- data/webpack/react_app/components/TargetingHosts/components/HostStatus.js +0 -54
- data/webpack/react_app/components/TargetingHosts/index.js +0 -150
- data/webpack/react_app/components/jobInvocations/AggregateStatus/index.js +0 -60
- data/webpack/react_app/components/jobInvocations/AggregateStatus/index.test.js +0 -76
- data/webpack/react_app/components/jobInvocations/index.js +0 -94
- data/webpack/react_app/extend/reducers.js +0 -5
- data/webpack/react_app/redux/actions/jobInvocations/index.js +0 -87
- data/webpack/react_app/redux/consts.js +0 -5
- data/webpack/react_app/redux/reducers/index.js +0 -6
- data/webpack/react_app/redux/reducers/jobInvocations/index.fixtures.js +0 -46
- data/webpack/react_app/redux/reducers/jobInvocations/index.js +0 -34
- data/webpack/react_app/redux/reducers/jobInvocations/index.test.js +0 -43
|
@@ -1,56 +1,8 @@
|
|
|
1
1
|
class JobInvocationsController < ApplicationController
|
|
2
2
|
include ::Foreman::Controller::AutoCompleteSearch
|
|
3
3
|
include ::ForemanTasks::Concerns::Parameters::Triggering
|
|
4
|
-
include ::JobInvocationsChartHelper
|
|
5
4
|
include RemoteExecutionHelper
|
|
6
5
|
|
|
7
|
-
def new
|
|
8
|
-
return @composer = prepare_composer if params[:feature].present?
|
|
9
|
-
|
|
10
|
-
ui_params = {
|
|
11
|
-
:host_ids => params[:host_ids],
|
|
12
|
-
:targeting => {
|
|
13
|
-
:targeting_type => Targeting::STATIC_TYPE,
|
|
14
|
-
:bookmark_id => params[:bookmark_id],
|
|
15
|
-
},
|
|
16
|
-
}
|
|
17
|
-
# replace an empty string search with a dummy search query to match all hosts
|
|
18
|
-
# but only if search query was entered (based on presence of :search parameter)
|
|
19
|
-
if params.key?(:search)
|
|
20
|
-
query = params[:search].empty? ? "name != ''" : params[:search]
|
|
21
|
-
ui_params[:targeting].update(:search_query => query)
|
|
22
|
-
end
|
|
23
|
-
|
|
24
|
-
if (template = JobTemplate.find_by(id: params[:template_id]))
|
|
25
|
-
ui_params[:job_invocation] = {
|
|
26
|
-
:job_category => template.job_category,
|
|
27
|
-
:providers => {
|
|
28
|
-
template.provider_type => {:job_template_id => template.id},
|
|
29
|
-
},
|
|
30
|
-
}
|
|
31
|
-
end
|
|
32
|
-
|
|
33
|
-
@composer = JobInvocationComposer.from_ui_params(ui_params)
|
|
34
|
-
end
|
|
35
|
-
|
|
36
|
-
def rerun
|
|
37
|
-
job_invocation = resource_base.find(params[:id])
|
|
38
|
-
@composer = JobInvocationComposer.from_job_invocation(job_invocation, params)
|
|
39
|
-
@job_organization = Taxonomy.find_by(id: job_invocation.task.input[:current_organization_id])
|
|
40
|
-
@job_location = Taxonomy.find_by(id: job_invocation.task.input[:current_location_id])
|
|
41
|
-
render :action => 'new'
|
|
42
|
-
end
|
|
43
|
-
|
|
44
|
-
def legacy_create
|
|
45
|
-
@composer = prepare_composer
|
|
46
|
-
if @composer.trigger
|
|
47
|
-
redirect_to job_invocation_path(@composer.job_invocation)
|
|
48
|
-
else
|
|
49
|
-
@composer.job_invocation.description_format = nil if params.fetch(:job_invocation, {}).key?(:description_override)
|
|
50
|
-
render :action => 'new'
|
|
51
|
-
end
|
|
52
|
-
end
|
|
53
|
-
|
|
54
6
|
def create
|
|
55
7
|
@composer = prepare_composer
|
|
56
8
|
if @composer.trigger
|
|
@@ -60,46 +12,10 @@ class JobInvocationsController < ApplicationController
|
|
|
60
12
|
end
|
|
61
13
|
end
|
|
62
14
|
|
|
63
|
-
def show
|
|
64
|
-
@job_invocation = resource_base.includes(:template_invocations => :run_host_job_task).find(params[:id])
|
|
65
|
-
@job_organization = Taxonomy.find_by(id: @job_invocation.task.input[:current_organization_id])
|
|
66
|
-
@job_location = Taxonomy.find_by(id: @job_invocation.task.input[:current_location_id])
|
|
67
|
-
@auto_refresh = @job_invocation.task.try(:pending?)
|
|
68
|
-
|
|
69
|
-
respond_to do |format|
|
|
70
|
-
format.json do
|
|
71
|
-
targeting_hosts_resources
|
|
72
|
-
end
|
|
73
|
-
|
|
74
|
-
format.html
|
|
75
|
-
format.js
|
|
76
|
-
end
|
|
77
|
-
end
|
|
78
|
-
|
|
79
15
|
def index
|
|
80
16
|
@job_invocations = resource_base_search_and_page.preload(:task, :targeting).order('job_invocations.id DESC')
|
|
81
17
|
end
|
|
82
18
|
|
|
83
|
-
# refreshes the form
|
|
84
|
-
def refresh
|
|
85
|
-
params[:job_invocation].delete :description_format if params[:job_invocation].key?(:description_override)
|
|
86
|
-
@composer = prepare_composer
|
|
87
|
-
end
|
|
88
|
-
|
|
89
|
-
def chart
|
|
90
|
-
find_resource
|
|
91
|
-
render :json => {
|
|
92
|
-
:finished => @job_invocation.finished?,
|
|
93
|
-
:job_invocations => job_invocation_data(@job_invocation)[:columns],
|
|
94
|
-
:statuses => {
|
|
95
|
-
:success => @job_invocation.progress_report[:success],
|
|
96
|
-
:cancelled => @job_invocation.progress_report[:cancelled],
|
|
97
|
-
:failed => @job_invocation.progress_report[:error],
|
|
98
|
-
:pending => @job_invocation.progress_report[:pending],
|
|
99
|
-
},
|
|
100
|
-
}
|
|
101
|
-
end
|
|
102
|
-
|
|
103
19
|
def preview_hosts
|
|
104
20
|
composer = prepare_composer
|
|
105
21
|
|
|
@@ -168,13 +84,11 @@ class JobInvocationsController < ApplicationController
|
|
|
168
84
|
|
|
169
85
|
def action_permission
|
|
170
86
|
case params[:action]
|
|
171
|
-
when 'rerun'
|
|
172
|
-
'create'
|
|
173
87
|
when 'preview_hosts'
|
|
174
88
|
'create'
|
|
175
89
|
when 'cancel'
|
|
176
90
|
'cancel'
|
|
177
|
-
when '
|
|
91
|
+
when 'preview_job_invocations_per_host', 'report'
|
|
178
92
|
'view'
|
|
179
93
|
else
|
|
180
94
|
super
|
|
@@ -199,15 +113,4 @@ class JobInvocationsController < ApplicationController
|
|
|
199
113
|
end
|
|
200
114
|
end
|
|
201
115
|
|
|
202
|
-
def targeting_hosts_resources
|
|
203
|
-
@auto_refresh = @job_invocation.task.try(:pending?)
|
|
204
|
-
@resource_base = @job_invocation.targeting.hosts.authorized(:view_hosts, Host)
|
|
205
|
-
|
|
206
|
-
unless params[:search].nil?
|
|
207
|
-
@resource_base = @resource_base.joins(:template_invocations)
|
|
208
|
-
.where(:template_invocations => { :job_invocation_id => @job_invocation.id})
|
|
209
|
-
end
|
|
210
|
-
@hosts = resource_base_search_and_page
|
|
211
|
-
@total_hosts = resource_base_with_search.size
|
|
212
|
-
end
|
|
213
116
|
end
|
|
@@ -1,55 +1,6 @@
|
|
|
1
1
|
# frozen_string_literal:true
|
|
2
2
|
|
|
3
3
|
module JobInvocationsHelper
|
|
4
|
-
def minicard(icon, number, text, tooltip: nil)
|
|
5
|
-
tooltip_options = tooltip ? { :'data-original-title' => tooltip, :rel => 'twipsy' } : {}
|
|
6
|
-
content_tag(:div, :class => 'card-pf card-pf-accented
|
|
7
|
-
card-pf-aggregate-status card-pf-aggregate-status-mini') do
|
|
8
|
-
content_tag(:h2, { :class => 'card-pf-title', :style => 'line-height: 1.1' }.merge(tooltip_options)) do
|
|
9
|
-
icon_text(icon, '', :kind => 'pficon') +
|
|
10
|
-
content_tag(:span, number, :class =>'card-pf-aggregate-status-count') +
|
|
11
|
-
text
|
|
12
|
-
end
|
|
13
|
-
end
|
|
14
|
-
end
|
|
15
|
-
|
|
16
|
-
def template_name_and_provider_link(template)
|
|
17
|
-
template_name = content_tag(:strong, template.name)
|
|
18
|
-
provider = template.provider.humanized_name
|
|
19
|
-
link_content = template_name + ' - ' + provider + ' ' +
|
|
20
|
-
icon_text('edit', '', :kind => 'pficon')
|
|
21
|
-
link_to_if_authorized(link_content,
|
|
22
|
-
hash_for_edit_job_template_path(:id => template.id))
|
|
23
|
-
end
|
|
24
|
-
|
|
25
|
-
def preview_hosts(template_invocation)
|
|
26
|
-
hosts = template_invocation.targeting.hosts.authorized(:view_hosts, Host).take(20)
|
|
27
|
-
hosts.map do |host|
|
|
28
|
-
collapsed_preview(host) +
|
|
29
|
-
render(:partial => 'job_invocations/user_input',
|
|
30
|
-
:locals => { :template_invocation => template_invocation,
|
|
31
|
-
:target => host })
|
|
32
|
-
end.reduce(:+)
|
|
33
|
-
end
|
|
34
|
-
|
|
35
|
-
def collapsed_preview(target)
|
|
36
|
-
title = (target || 'N/A').to_s
|
|
37
|
-
content_tag(:h5,
|
|
38
|
-
:class => "expander collapsed out",
|
|
39
|
-
:data => { :toggle => 'collapse',
|
|
40
|
-
:target => "#preview_#{target.id}" }) do
|
|
41
|
-
content_tag(:span, '', :class => 'caret') + title
|
|
42
|
-
end
|
|
43
|
-
end
|
|
44
|
-
|
|
45
|
-
def show_job_organization(organization)
|
|
46
|
-
organization.presence || _('Any Organization')
|
|
47
|
-
end
|
|
48
|
-
|
|
49
|
-
def show_job_location(location)
|
|
50
|
-
location.presence || _('Any Location')
|
|
51
|
-
end
|
|
52
|
-
|
|
53
4
|
def input_safe_value(input)
|
|
54
5
|
template_input = input.template_input
|
|
55
6
|
template_input.respond_to?(:hidden_value) && template_input.hidden_value ? '*' * 5 : input.value
|
|
@@ -3,20 +3,6 @@ module RemoteExecutionHelper
|
|
|
3
3
|
RemoteExecutionProvider.providers.reject { |key, _provider| key == 'SSH' }.map { |key, provider| [ key, _(provider.humanized_name) ] }
|
|
4
4
|
end
|
|
5
5
|
|
|
6
|
-
def job_hosts_authorizer
|
|
7
|
-
@job_hosts_authorizer ||= Authorizer.new(User.current, :collection => @hosts)
|
|
8
|
-
end
|
|
9
|
-
|
|
10
|
-
def host_tasks_authorizer
|
|
11
|
-
@host_tasks_authorizer ||= Authorizer.new(User.current, :collection => @job_invocation.sub_tasks)
|
|
12
|
-
end
|
|
13
|
-
|
|
14
|
-
def host_counter(label, count)
|
|
15
|
-
content_tag(:div, :class => 'host_counter') do
|
|
16
|
-
content_tag(:div, label, :class => 'header') + content_tag(:div, count.to_s, :class => 'count')
|
|
17
|
-
end
|
|
18
|
-
end
|
|
19
|
-
|
|
20
6
|
def template_invocation_status(task, parent_task)
|
|
21
7
|
return(parent_task.result == 'cancelled' ? 'cancelled' : 'N/A') if task.nil?
|
|
22
8
|
return task.state if task.state == 'running' || task.state == 'planned'
|
|
@@ -25,33 +11,6 @@ module RemoteExecutionHelper
|
|
|
25
11
|
task.result
|
|
26
12
|
end
|
|
27
13
|
|
|
28
|
-
def template_invocation_actions(task, host, job_invocation, template_invocation)
|
|
29
|
-
links = []
|
|
30
|
-
host_task = template_invocation.try(:run_host_job_task)
|
|
31
|
-
|
|
32
|
-
if authorized_for(hash_for_host_path(host).merge(auth_object: host, permission: :view_hosts, authorizer: job_hosts_authorizer))
|
|
33
|
-
links << { title: _('Host detail'),
|
|
34
|
-
action: { href: current_host_details_path(host), 'data-method': 'get', id: "#{host.name}-actions-detail" } }
|
|
35
|
-
end
|
|
36
|
-
if authorized_for(controller: :job_invocations, action: :create) && (!host.infrastructure_host? || User.current.can?(:execute_jobs_on_infrastructure_hosts))
|
|
37
|
-
links << { title: (_('Rerun on %s') % host),
|
|
38
|
-
action: { href: rerun_job_invocation_path(job_invocation, host_ids: [ host.id ]),
|
|
39
|
-
'data-method': 'get', id: "#{host.name}-actions-rerun" } }
|
|
40
|
-
end
|
|
41
|
-
|
|
42
|
-
if host_task.present? && authorized_for(hash_for_foreman_tasks_task_path(host_task).merge(auth_object: host_task, permission: :view_foreman_tasks, authorizer: host_tasks_authorizer))
|
|
43
|
-
links << { title: _('Host task'),
|
|
44
|
-
action: { href: foreman_tasks_task_path(host_task),
|
|
45
|
-
'data-method': 'get', id: "#{host.name}-actions-task" } }
|
|
46
|
-
end
|
|
47
|
-
|
|
48
|
-
links
|
|
49
|
-
end
|
|
50
|
-
|
|
51
|
-
def remote_execution_provider_for(template_invocation)
|
|
52
|
-
template_invocation.nil? ? _('N/A') : template_invocation.template.provider.humanized_name
|
|
53
|
-
end
|
|
54
|
-
|
|
55
14
|
def job_invocations_buttons
|
|
56
15
|
[
|
|
57
16
|
documentation_button('Managing_Hosts', type: 'docs', chapter: 'executing-a-remote-job_managing-hosts'),
|
|
@@ -59,53 +18,6 @@ module RemoteExecutionHelper
|
|
|
59
18
|
]
|
|
60
19
|
end
|
|
61
20
|
|
|
62
|
-
def job_invocation_task_buttons(task)
|
|
63
|
-
job_invocation = task.task_groups.find { |group| group.class == JobInvocationTaskGroup }.job_invocation
|
|
64
|
-
task_authorizer = Authorizer.new(User.current, :collection => [task])
|
|
65
|
-
buttons = []
|
|
66
|
-
if (template = job_report_template) && authorized_for(controller: :report_templates, action: :generate)
|
|
67
|
-
buttons << link_to(_('Create Report'), generate_report_template_path(template, job_report_template_parameters(job_invocation, template)),
|
|
68
|
-
class: 'btn btn-default',
|
|
69
|
-
title: _('Create report for this job'),
|
|
70
|
-
disabled: task.pending?)
|
|
71
|
-
end
|
|
72
|
-
if authorized_for(controller: :job_invocations, action: :create)
|
|
73
|
-
buttons << link_to(_('Rerun'), rerun_job_invocation_path(:id => job_invocation.id),
|
|
74
|
-
:class => 'btn btn-default',
|
|
75
|
-
:title => _('Rerun the job'))
|
|
76
|
-
buttons << link_to(_('Rerun failed'), rerun_job_invocation_path(:id => job_invocation.id, :failed_only => 1),
|
|
77
|
-
:class => 'btn btn-default',
|
|
78
|
-
:disabled => job_invocation.failed_hosts.none?,
|
|
79
|
-
:title => _('Rerun on failed hosts'))
|
|
80
|
-
buttons << link_to(_('Rerun succeeded'), rerun_job_invocation_path(:id => job_invocation.id, :succeeded_only => 1),
|
|
81
|
-
:class => 'btn btn-default',
|
|
82
|
-
:disabled => job_invocation.succeeded_hosts.none?,
|
|
83
|
-
:title => _('Rerun on succeeded hosts'))
|
|
84
|
-
end
|
|
85
|
-
if authorized_for(:permission => :view_foreman_tasks, :auth_object => task, :authorizer => task_authorizer)
|
|
86
|
-
buttons << link_to(_('Job Task'), foreman_tasks_task_path(task),
|
|
87
|
-
:class => 'btn btn-default',
|
|
88
|
-
:title => _('See the last task details'))
|
|
89
|
-
end
|
|
90
|
-
if authorized_for(:permission => :cancel_job_invocations, :auth_object => job_invocation)
|
|
91
|
-
buttons << button_to(_('Cancel Job'), cancel_job_invocation_path(job_invocation),
|
|
92
|
-
:class => 'btn btn-danger',
|
|
93
|
-
:title => _('Try to cancel the job'),
|
|
94
|
-
:disabled => !task.cancellable?,
|
|
95
|
-
:method => :post)
|
|
96
|
-
buttons << button_to(_('Abort Job'), cancel_job_invocation_path(job_invocation, :force => true),
|
|
97
|
-
:class => 'btn btn-danger',
|
|
98
|
-
:title => _('Try to abort the job without waiting for the results from the remote hosts'),
|
|
99
|
-
:disabled => !task.cancellable?,
|
|
100
|
-
:method => :post)
|
|
101
|
-
end
|
|
102
|
-
buttons << link_to(_('New UI'), job_invocation_path(:id => job_invocation.id),
|
|
103
|
-
class: 'btn btn-default',
|
|
104
|
-
title: _('Switch to the new job invocation detail UI'))
|
|
105
|
-
|
|
106
|
-
buttons
|
|
107
|
-
end
|
|
108
|
-
|
|
109
21
|
def template_invocation_task_buttons(task, invocation)
|
|
110
22
|
buttons = []
|
|
111
23
|
if authorized_for(:permission => :view_foreman_tasks, :auth_object => task)
|
|
@@ -130,8 +42,30 @@ module RemoteExecutionHelper
|
|
|
130
42
|
buttons
|
|
131
43
|
end
|
|
132
44
|
|
|
45
|
+
def job_invocation_status(invocation, percent = nil, verbose: true)
|
|
46
|
+
case invocation.status
|
|
47
|
+
when HostStatus::ExecutionStatus::QUEUED
|
|
48
|
+
if verbose && invocation.task
|
|
49
|
+
_('queued to start executing in %{time}') % {:time => time_ago_in_words(invocation.task.start_at) }
|
|
50
|
+
else
|
|
51
|
+
_('queued')
|
|
52
|
+
end
|
|
53
|
+
when HostStatus::ExecutionStatus::RUNNING
|
|
54
|
+
percent ||= invocation.progress_report[:progress]
|
|
55
|
+
_('running %{percent}%%') % {:percent => percent}
|
|
56
|
+
when HostStatus::ExecutionStatus::OK
|
|
57
|
+
_('succeeded')
|
|
58
|
+
when HostStatus::ExecutionStatus::CANCELLED
|
|
59
|
+
_('cancelled')
|
|
60
|
+
when HostStatus::ExecutionStatus::ERROR
|
|
61
|
+
_('failed')
|
|
62
|
+
else
|
|
63
|
+
_('unknown status')
|
|
64
|
+
end
|
|
65
|
+
end
|
|
66
|
+
|
|
133
67
|
def link_to_invocation_task_if_authorized(invocation)
|
|
134
|
-
status = job_invocation_status(invocation, nil, false)
|
|
68
|
+
status = job_invocation_status(invocation, nil, verbose: false)
|
|
135
69
|
if invocation.queued?
|
|
136
70
|
status
|
|
137
71
|
else
|
|
@@ -207,27 +141,6 @@ module RemoteExecutionHelper
|
|
|
207
141
|
end
|
|
208
142
|
end
|
|
209
143
|
|
|
210
|
-
def description_checkbox_f(f, job_template, disabled)
|
|
211
|
-
check_box_tag('description_format_override',
|
|
212
|
-
job_template.generate_description_format,
|
|
213
|
-
f.object.description_format.nil?,
|
|
214
|
-
:class => 'description_format_override',
|
|
215
|
-
:name => f.object_name + '[description_override]',
|
|
216
|
-
:disabled => disabled,
|
|
217
|
-
:onchange => 'description_override(this);') + ' ' + _('Use default description template')
|
|
218
|
-
end
|
|
219
|
-
|
|
220
|
-
def description_format_textarea_f(f, job_template, disabled)
|
|
221
|
-
textarea_f f, 'description_format',
|
|
222
|
-
:label => _('Description template'),
|
|
223
|
-
:value => f.object.description_format || job_template.generate_description_format,
|
|
224
|
-
:rows => 2,
|
|
225
|
-
:onchange => 'regenerate_description(this);',
|
|
226
|
-
:class => 'description_format advanced',
|
|
227
|
-
:disabled => disabled,
|
|
228
|
-
:label_help => description_format_help
|
|
229
|
-
end
|
|
230
|
-
|
|
231
144
|
def description_format_help
|
|
232
145
|
_('This template is used to generate the description.<br/>' +
|
|
233
146
|
'Input values can be used using the syntax %{package}.<br/>' +
|
|
@@ -262,17 +175,4 @@ module RemoteExecutionHelper
|
|
|
262
175
|
},
|
|
263
176
|
}
|
|
264
177
|
end
|
|
265
|
-
|
|
266
|
-
def targeting_hosts(job_invocation, hosts)
|
|
267
|
-
hosts.map do |host|
|
|
268
|
-
template_invocation = job_invocation.template_invocations.find { |template_inv| template_inv.host_id == host.id }
|
|
269
|
-
task = template_invocation.try(:run_host_job_task)
|
|
270
|
-
link_authorized = !task.nil? && authorized_for(hash_for_template_invocation_path(:id => template_invocation).merge(:auth_object => host, :permission => :view_hosts, :authorizer => job_hosts_authorizer))
|
|
271
|
-
|
|
272
|
-
{ name: host.to_label,
|
|
273
|
-
link: link_authorized ? template_invocation_path(:id => template_invocation) : '',
|
|
274
|
-
status: template_invocation_status(task, job_invocation.task),
|
|
275
|
-
actions: template_invocation_actions(task, host, job_invocation, template_invocation) }
|
|
276
|
-
end
|
|
277
|
-
end
|
|
278
178
|
end
|
data/config/routes.rb
CHANGED
|
@@ -18,19 +18,13 @@ Rails.application.routes.draw do
|
|
|
18
18
|
|
|
19
19
|
match 'job_invocations/new', to: 'react#index', :via => [:get], as: 'new_job_invocation'
|
|
20
20
|
match 'job_invocations/new', to: 'job_invocations#create', via: [:post], as: 'create_job_invocation'
|
|
21
|
-
match 'job_invocations/', to: 'job_invocations#legacy_create', via: [:post], as: 'legacy_create_job_invocation'
|
|
22
21
|
match 'job_invocations/:id/rerun', to: 'react#index', :via => [:get], as: 'rerun_job_invocation'
|
|
23
|
-
match 'old/job_invocations/new', to: 'job_invocations#new', via: [:get], as: 'form_new_job_invocation'
|
|
24
|
-
match 'old/job_invocations/:id/rerun', to: 'job_invocations#rerun', via: [:get, :post], as: 'form_rerun_job_invocation'
|
|
25
|
-
get 'legacy/job_invocations/:id', to: 'job_invocations#show', as: 'legacy_job_invocation'
|
|
26
22
|
match 'job_invocations_detail/:id/host_invocation/:host_id', to: 'react#index', :via => [:get], as: 'new_job_invocation_detail_by_host'
|
|
27
23
|
get 'show_template_invocation_by_host/:host_id/job_invocation/:id', to: 'template_invocations#show_template_invocation_by_host'
|
|
28
24
|
|
|
29
25
|
resources :job_invocations, :only => [:create, :index] do
|
|
30
26
|
collection do
|
|
31
27
|
get 'preview_job_invocations_per_host'
|
|
32
|
-
post 'refresh'
|
|
33
|
-
get 'chart'
|
|
34
28
|
get 'preview_hosts'
|
|
35
29
|
get 'auto_complete_search'
|
|
36
30
|
end
|
|
@@ -141,9 +141,9 @@ Foreman::Plugin.register :foreman_remote_execution do
|
|
|
141
141
|
permission :destroy_job_templates, { :job_templates => [:destroy],
|
|
142
142
|
:'api/v2/job_templates' => [:destroy] }, :resource_type => 'JobTemplate'
|
|
143
143
|
permission :lock_job_templates, { :job_templates => [:lock, :unlock] }, :resource_type => 'JobTemplate'
|
|
144
|
-
permission :create_job_invocations, { :job_invocations => [:
|
|
144
|
+
permission :create_job_invocations, { :job_invocations => [:create, :preview_hosts],
|
|
145
145
|
'api/v2/job_invocations' => [:create, :rerun] }, :resource_type => 'JobInvocation'
|
|
146
|
-
permission :view_job_invocations, { :job_invocations => [:index, :
|
|
146
|
+
permission :view_job_invocations, { :job_invocations => [:index, :auto_complete_search, :preview_job_invocations_per_host, :report], :template_invocations => [:show, :show_template_invocation_by_host],
|
|
147
147
|
'api/v2/job_invocations' => [:index, :show, :output, :raw_output, :outputs, :hosts] }, :resource_type => 'JobInvocation'
|
|
148
148
|
permission :view_template_invocations, { :template_invocations => [:show, :template_invocation_preview, :show_template_invocation_by_host],
|
|
149
149
|
'api/v2/template_invocations' => [:template_invocations], :ui_job_wizard => [:job_invocation] }, :resource_type => 'TemplateInvocation'
|
|
@@ -8,8 +8,8 @@ msgid ""
|
|
|
8
8
|
msgstr ""
|
|
9
9
|
"Project-Id-Version: foreman_remote_execution 1.0.0\n"
|
|
10
10
|
"Report-Msgid-Bugs-To: \n"
|
|
11
|
-
"POT-Creation-Date: 2026-09-
|
|
12
|
-
"PO-Revision-Date: 2026-09-
|
|
11
|
+
"POT-Creation-Date: 2026-09-29 10:56+0000\n"
|
|
12
|
+
"PO-Revision-Date: 2026-09-29 10:56+0000\n"
|
|
13
13
|
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
|
|
14
14
|
"Language-Team: LANGUAGE <LL@li.org>\n"
|
|
15
15
|
"Language: \n"
|
|
Binary file
|
|
@@ -139,7 +139,7 @@ msgid "Alphabetical"
|
|
|
139
139
|
msgstr "Alphabétique"
|
|
140
140
|
|
|
141
141
|
msgid "Already on the review step"
|
|
142
|
-
msgstr ""
|
|
142
|
+
msgstr "Déjà à l'étape de révision"
|
|
143
143
|
|
|
144
144
|
msgid "An error occurred while fetching the template invocation details."
|
|
145
145
|
msgstr "Une erreur s'est produite lors de la récupération des détails d'invocation du modèle."
|
|
@@ -271,28 +271,28 @@ msgid "Copy to clipboard"
|
|
|
271
271
|
msgstr "Copier dans le presse-papiers"
|
|
272
272
|
|
|
273
273
|
msgid "Could not abort the job %s: %s"
|
|
274
|
-
msgstr ""
|
|
274
|
+
msgstr "Impossible d'annuler le job %s: %s"
|
|
275
275
|
|
|
276
276
|
msgid "Could not abort the task"
|
|
277
277
|
msgstr "Impossible d'annuler la tâche"
|
|
278
278
|
|
|
279
279
|
msgid "Could not cancel recurring logic %s: %s"
|
|
280
|
-
msgstr ""
|
|
280
|
+
msgstr "Impossible d'annuler la logique récurrente %s :%s"
|
|
281
281
|
|
|
282
282
|
msgid "Could not cancel the job %s: %s"
|
|
283
|
-
msgstr ""
|
|
283
|
+
msgstr "Impossible d'annuler le job %s: %s"
|
|
284
284
|
|
|
285
285
|
msgid "Could not cancel the task"
|
|
286
286
|
msgstr "Impossible d'annuler la tâche"
|
|
287
287
|
|
|
288
288
|
msgid "Could not disable recurring logic %s: %s"
|
|
289
|
-
msgstr ""
|
|
289
|
+
msgstr "Impossible de désactiver la logique récurrente %s :%s"
|
|
290
290
|
|
|
291
291
|
msgid "Could not display data for job invocation."
|
|
292
292
|
msgstr "Impossible d'afficher les données pour le lancement du job."
|
|
293
293
|
|
|
294
294
|
msgid "Could not enable recurring logic %s: %s"
|
|
295
|
-
msgstr ""
|
|
295
|
+
msgstr "Impossible d’activer la logique récurrente %s :%s"
|
|
296
296
|
|
|
297
297
|
msgid "Could not find any suitable interface for execution"
|
|
298
298
|
msgstr "Impossible de trouver une interface qui convient pour l'exécution"
|
|
@@ -325,7 +325,7 @@ msgid "Create a job template"
|
|
|
325
325
|
msgstr "Créer un modèle de job"
|
|
326
326
|
|
|
327
327
|
msgid "Create a new job invocation"
|
|
328
|
-
msgstr ""
|
|
328
|
+
msgstr "Créer une nouvelle invocation de tâche"
|
|
329
329
|
|
|
330
330
|
msgid "Create a recurring job"
|
|
331
331
|
msgstr "Créer un job récurrent"
|
|
@@ -418,7 +418,7 @@ msgid "Designation of a special purpose"
|
|
|
418
418
|
msgstr "Désignation d’un objectif spécial"
|
|
419
419
|
|
|
420
420
|
msgid "Directory on the host where remote execution jobs in push mode place and run their scripts. You can override this setting per host with the `remote_execution_remote_working_dir` host parameter."
|
|
421
|
-
msgstr ""
|
|
421
|
+
msgstr "Répertoire sur l'hôte où les tâches d'exécution à distance en mode push placent et exécutent leurs scripts. Vous pouvez modifier ce paramètre pour chaque hôte à l'aide du paramètre `remote_execution_remote_working_dir`."
|
|
422
422
|
|
|
423
423
|
msgid "Disable recurring"
|
|
424
424
|
msgstr "Désactiver les récurrents"
|
|
@@ -556,7 +556,7 @@ msgid "Failed rendering template: %s"
|
|
|
556
556
|
msgstr "Echec de rendu du modèle : %s"
|
|
557
557
|
|
|
558
558
|
msgid "Failed to load host invocation data"
|
|
559
|
-
msgstr ""
|
|
559
|
+
msgstr "Échec du chargement des données d'invocation de l'hôte"
|
|
560
560
|
|
|
561
561
|
msgid "Failed:"
|
|
562
562
|
msgstr "Échec :"
|
|
@@ -613,7 +613,7 @@ msgid "Get raw output for a host"
|
|
|
613
613
|
msgstr "Récupérer la sortie brut d'un hôte"
|
|
614
614
|
|
|
615
615
|
msgid "Go to job invocations"
|
|
616
|
-
msgstr ""
|
|
616
|
+
msgstr "Aller aux invocations de travail"
|
|
617
617
|
|
|
618
618
|
msgid "Has to be a positive number"
|
|
619
619
|
msgstr "Doit correspondre à un nombre positif"
|
|
@@ -682,10 +682,10 @@ msgid "Include all inputs from the foreign template"
|
|
|
682
682
|
msgstr "Inclut toutes les entrées du modèle étranger"
|
|
683
683
|
|
|
684
684
|
msgid "Include hosts and template invocations in the response. Defaults to true for backwards compatibility. Pass false to skip serializing all hosts."
|
|
685
|
-
msgstr ""
|
|
685
|
+
msgstr "Inclure les hôtes et les appels de modèles dans la réponse. Par défaut, la valeur est « true » pour assurer la compatibilité avec les versions précédentes. Indiquez « false » pour ne pas sérialiser les hôtes."
|
|
686
686
|
|
|
687
687
|
msgid "Include per-host task and permission data in the response"
|
|
688
|
-
msgstr ""
|
|
688
|
+
msgstr "Inclure les données de tâche et d'autorisation par hôte dans la réponse"
|
|
689
689
|
|
|
690
690
|
msgid "Indicates that the action should be cancelled if it cannot be started before this time."
|
|
691
691
|
msgstr "Indique si l'action doit être annulée si elle ne peut commencer à ce moment là."
|
|
@@ -856,7 +856,7 @@ msgid "Minute can only be a number between 0-59"
|
|
|
856
856
|
msgstr "La minute doit être un nombre compris entre 0 et 59"
|
|
857
857
|
|
|
858
858
|
msgid "Missing permissions to generate report templates"
|
|
859
|
-
msgstr ""
|
|
859
|
+
msgstr "Autorisations manquantes pour générer des modèles de rapports"
|
|
860
860
|
|
|
861
861
|
msgid "Missing the required permissions: ${missingPermissions.join( ', ' )}"
|
|
862
862
|
msgstr "Il manque les autorisations requises : ${missingPermissions.join( ', ' )}"
|
|
@@ -910,7 +910,7 @@ msgid "No output for the selected filters"
|
|
|
910
910
|
msgstr "Aucune sortie pour les filtres sélectionnés"
|
|
911
911
|
|
|
912
912
|
msgid "No results found"
|
|
913
|
-
msgstr "Aucun résultat"
|
|
913
|
+
msgstr "Aucun résultat trouvé"
|
|
914
914
|
|
|
915
915
|
msgid "No template mapped to feature %{feature_name}"
|
|
916
916
|
msgstr "Aucun modèle n'est en relation avec la fonction %{feature_name}"
|
|
@@ -1102,13 +1102,13 @@ msgid "Recurring logic"
|
|
|
1102
1102
|
msgstr "Logique récurrente"
|
|
1103
1103
|
|
|
1104
1104
|
msgid "Recurring logic %s cancelled successfully."
|
|
1105
|
-
msgstr "Logique récurrente%s activée avec succès."
|
|
1105
|
+
msgstr "Logique récurrente %s activée avec succès."
|
|
1106
1106
|
|
|
1107
1107
|
msgid "Recurring logic %s disabled successfully."
|
|
1108
|
-
msgstr "Logique récurrente%s désactivé avec succès."
|
|
1108
|
+
msgstr "Logique récurrente %s désactivé avec succès."
|
|
1109
1109
|
|
|
1110
1110
|
msgid "Recurring logic %s enabled successfully."
|
|
1111
|
-
msgstr "Logique récurrente%s activée avec succès."
|
|
1111
|
+
msgstr "Logique récurrente %s activée avec succès."
|
|
1112
1112
|
|
|
1113
1113
|
msgid "Recursive rendering of templates detected"
|
|
1114
1114
|
msgstr "Détection de récursion dans le rendu des modèles"
|
|
@@ -1138,10 +1138,10 @@ msgid "Remote execution job"
|
|
|
1138
1138
|
msgstr "Job à exécution distante"
|
|
1139
1139
|
|
|
1140
1140
|
msgid "Remote working directory"
|
|
1141
|
-
msgstr ""
|
|
1141
|
+
msgstr "Répertoire de travail à distance"
|
|
1142
1142
|
|
|
1143
1143
|
msgid "Remote working directory \"%{current_value}\" is not an absolute path"
|
|
1144
|
-
msgstr ""
|
|
1144
|
+
msgstr "Répertoire de travail distant \"%{current_value} \" n'est pas un chemin absolu"
|
|
1145
1145
|
|
|
1146
1146
|
msgid "Repeat a maximum of N times"
|
|
1147
1147
|
msgstr "Répéter un maximum de N fois"
|
|
@@ -1156,7 +1156,7 @@ msgid "Repeats"
|
|
|
1156
1156
|
msgstr "Répétitions"
|
|
1157
1157
|
|
|
1158
1158
|
msgid "Report template not found or not configured properly"
|
|
1159
|
-
msgstr ""
|
|
1159
|
+
msgstr "Modèle de rapport introuvable ou mal configuré"
|
|
1160
1160
|
|
|
1161
1161
|
msgid "Rerun"
|
|
1162
1162
|
msgstr "Relancer"
|
|
@@ -1363,7 +1363,7 @@ msgid "Show job invocation"
|
|
|
1363
1363
|
msgstr "Voir le lancement du job"
|
|
1364
1364
|
|
|
1365
1365
|
msgid "Show job status for each host, only applicable when include_hosts is true"
|
|
1366
|
-
msgstr ""
|
|
1366
|
+
msgstr "Afficher l'état des tâches pour chaque hôte, applicable uniquement si include_hosts est vrai"
|
|
1367
1367
|
|
|
1368
1368
|
msgid "Show job template details"
|
|
1369
1369
|
msgstr "Voir les détails d'un modèle de job"
|
|
@@ -1522,7 +1522,7 @@ msgid "The dynamic query '%{query}' was not resolved yet. The list of hosts to w
|
|
|
1522
1522
|
msgstr "La requête dynamique '%{query}' n'a pas encore été résolue. La liste des hôtes actuelle avec lesquels ils pourraient être résolus peut être vue ici %{here}."
|
|
1523
1523
|
|
|
1524
1524
|
msgid "The dynamic query is still being processed. You can {viewTheHosts} targeted by the query."
|
|
1525
|
-
msgstr "La requête dynamique est toujours en cours de traitement. Vous pouvez{viewTheHosts} ciblé par la requête."
|
|
1525
|
+
msgstr "La requête dynamique est toujours en cours de traitement. Vous pouvez {viewTheHosts} ciblé par la requête."
|
|
1526
1526
|
|
|
1527
1527
|
msgid "The execution interface is used for remote execution"
|
|
1528
1528
|
msgstr "L'interface d'exécution est celle utilisée pour l'exécution distante"
|
|
@@ -1627,7 +1627,7 @@ msgid "Trying to abort the job"
|
|
|
1627
1627
|
msgstr "Tentative d'abandon du job"
|
|
1628
1628
|
|
|
1629
1629
|
msgid "Trying to abort the job %s."
|
|
1630
|
-
msgstr "J’essaie d'abandonner le job %s
|
|
1630
|
+
msgstr "J’essaie d'abandonner le job %s."
|
|
1631
1631
|
|
|
1632
1632
|
msgid "Trying to abort the task for the host"
|
|
1633
1633
|
msgstr "Tentative d'annulation de la tâche pour l'hôte"
|
|
@@ -1636,7 +1636,7 @@ msgid "Trying to cancel the job"
|
|
|
1636
1636
|
msgstr "Tentative d'annulation du job"
|
|
1637
1637
|
|
|
1638
1638
|
msgid "Trying to cancel the job %s."
|
|
1639
|
-
msgstr "J'essaie d'annuler le travail%s
|
|
1639
|
+
msgstr "J'essaie d'annuler le travail%s."
|
|
1640
1640
|
|
|
1641
1641
|
msgid "Trying to cancel the task for the host"
|
|
1642
1642
|
msgstr "Tentative d'annulation de la tâche pour l'hôte"
|
|
@@ -1681,7 +1681,7 @@ msgid "Unknown"
|
|
|
1681
1681
|
msgstr "Inconnu"
|
|
1682
1682
|
|
|
1683
1683
|
msgid "Unknown error."
|
|
1684
|
-
msgstr ""
|
|
1684
|
+
msgstr "Erreur inconnue"
|
|
1685
1685
|
|
|
1686
1686
|
msgid "Unknown execution status"
|
|
1687
1687
|
msgstr "État d'exécution inconnu"
|
|
@@ -1831,7 +1831,7 @@ msgid "host already has an execution interface"
|
|
|
1831
1831
|
msgstr "L'hôte possède déjà une interface d'exécution"
|
|
1832
1832
|
|
|
1833
1833
|
msgid "host method"
|
|
1834
|
-
msgstr ""
|
|
1834
|
+
msgstr "méthode hôte"
|
|
1835
1835
|
|
|
1836
1836
|
msgid "hosts"
|
|
1837
1837
|
msgstr "hôtes"
|
|
@@ -1861,10 +1861,10 @@ msgid "is month (range: 1-12)"
|
|
|
1861
1861
|
msgstr "est mois (Plage: 1-12)"
|
|
1862
1862
|
|
|
1863
1863
|
msgid "job invocation"
|
|
1864
|
-
msgstr ""
|
|
1864
|
+
msgstr "Invocation de job"
|
|
1865
1865
|
|
|
1866
1866
|
msgid "must be an absolute path"
|
|
1867
|
-
msgstr ""
|
|
1867
|
+
msgstr "doit être un chemin absolu"
|
|
1868
1868
|
|
|
1869
1869
|
msgid "no"
|
|
1870
1870
|
msgstr "non"
|
|
Binary file
|