foreman-tasks 1.0.1 → 2.0.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.rubocop.yml +12 -12
- data/.rubocop_todo.yml +34 -116
- data/README.md +2 -0
- data/app/controllers/foreman_tasks/api/recurring_logics_controller.rb +20 -1
- data/app/controllers/foreman_tasks/api/tasks_controller.rb +65 -10
- data/app/controllers/foreman_tasks/concerns/hosts_controller_extension.rb +1 -1
- data/app/controllers/foreman_tasks/recurring_logics_controller.rb +19 -0
- data/app/controllers/foreman_tasks/tasks_controller.rb +9 -14
- data/app/helpers/foreman_tasks/foreman_tasks_helper.rb +1 -3
- data/app/lib/actions/helpers/humanizer.rb +1 -3
- data/app/lib/actions/proxy_action.rb +33 -12
- data/app/lib/foreman_tasks/concerns/polling_action_extensions.rb +12 -0
- data/app/models/foreman_tasks/concerns/action_triggering.rb +1 -1
- data/app/models/foreman_tasks/recurring_logic.rb +1 -0
- data/app/models/foreman_tasks/remote_task.rb +1 -0
- data/app/models/foreman_tasks/task.rb +8 -0
- data/app/models/foreman_tasks/task/dynflow_task.rb +2 -1
- data/app/models/foreman_tasks/task/search.rb +11 -1
- data/app/models/setting/foreman_tasks.rb +7 -2
- data/app/services/foreman_tasks/troubleshooting_help_generator.rb +0 -4
- data/app/services/ui_notifications/tasks/task_bulk_cancel.rb +36 -0
- data/app/services/ui_notifications/tasks/task_bulk_resume.rb +38 -0
- data/app/services/ui_notifications/tasks/task_bulk_stop.rb +36 -0
- data/app/views/foreman_tasks/api/recurring_logics/base.json.rabl +2 -1
- data/app/views/foreman_tasks/api/tasks/details.json.rabl +1 -1
- data/app/views/foreman_tasks/api/tasks/show.json.rabl +1 -1
- data/app/views/foreman_tasks/recurring_logics/index.html.erb +30 -0
- data/app/views/foreman_tasks/tasks/show.html.erb +3 -0
- data/config/routes.rb +8 -0
- data/db/migrate/20200517215015_rename_bookmarks_controller.rb +35 -0
- data/db/migrate/20200519093217_drop_dynflow_allow_dangerous_actions_setting.foreman_tasks.rb +5 -0
- data/db/migrate/20200611090846_add_task_lock_index_on_resource_type_and_task_id.rb +9 -0
- data/db/seeds.d/30-notification_blueprints.rb +21 -0
- data/foreman-tasks.gemspec +5 -6
- data/gemfile.d/foreman-tasks.rb +1 -0
- data/lib/foreman_tasks/dynflow/console_authorizer.rb +2 -2
- data/lib/foreman_tasks/engine.rb +17 -19
- data/lib/foreman_tasks/tasks/cleanup.rake +1 -1
- data/lib/foreman_tasks/tasks/export_tasks.rake +2 -2
- data/lib/foreman_tasks/test_extensions.rb +1 -1
- data/lib/foreman_tasks/version.rb +1 -1
- data/locale/action_names.rb +2 -2
- data/locale/en/LC_MESSAGES/foreman_tasks.mo +0 -0
- data/locale/en/foreman_tasks.po +270 -54
- data/locale/foreman_tasks.pot +630 -292
- data/locale/fr/LC_MESSAGES/foreman_tasks.mo +0 -0
- data/locale/fr/foreman_tasks.po +817 -0
- data/locale/ja/LC_MESSAGES/foreman_tasks.mo +0 -0
- data/locale/ja/foreman_tasks.po +817 -0
- data/locale/zh_CN/LC_MESSAGES/foreman_tasks.mo +0 -0
- data/locale/zh_CN/foreman_tasks.po +816 -0
- data/package.json +1 -2
- data/script/rails +2 -2
- data/script/travis_run_js_tests.sh +2 -2
- data/test/factories/task_factory.rb +34 -2
- data/test/foreman_tasks_test_helper.rb +4 -0
- data/test/lib/concerns/polling_action_extensions_test.rb +34 -0
- data/test/unit/actions/action_with_sub_plans_test.rb +1 -1
- data/test/unit/task_test.rb +160 -74
- data/webpack/ForemanTasks/Components/TaskActions/TaskAction.test.js +60 -0
- data/webpack/ForemanTasks/Components/TaskActions/TaskActionHelpers.js +67 -0
- data/webpack/ForemanTasks/Components/TaskActions/TaskActionHelpers.test.js +46 -0
- data/webpack/ForemanTasks/Components/TaskActions/TaskActionsConstants.js +16 -0
- data/webpack/ForemanTasks/Components/TaskActions/UnlockModals.js +60 -0
- data/webpack/ForemanTasks/Components/TaskActions/UnlockModals.test.js +14 -0
- data/webpack/ForemanTasks/Components/TaskActions/__snapshots__/TaskAction.test.js.snap +233 -0
- data/webpack/ForemanTasks/Components/TaskActions/__snapshots__/UnlockModals.test.js.snap +25 -0
- data/webpack/ForemanTasks/Components/TaskActions/index.js +115 -0
- data/webpack/ForemanTasks/Components/TaskDetails/Components/RunningSteps.js +17 -3
- data/webpack/ForemanTasks/Components/TaskDetails/Components/Task.js +132 -165
- data/webpack/ForemanTasks/Components/TaskDetails/Components/TaskInfo.js +3 -12
- data/webpack/ForemanTasks/Components/TaskDetails/Components/__tests__/RunningSteps.test.js +8 -1
- data/webpack/ForemanTasks/Components/TaskDetails/Components/__tests__/Task.test.js +68 -3
- data/webpack/ForemanTasks/Components/TaskDetails/Components/__tests__/TaskInfo.test.js +0 -1
- data/webpack/ForemanTasks/Components/TaskDetails/Components/__tests__/__snapshots__/RunningSteps.test.js.snap +1 -1
- data/webpack/ForemanTasks/Components/TaskDetails/Components/__tests__/__snapshots__/Task.test.js.snap +108 -75
- data/webpack/ForemanTasks/Components/TaskDetails/Components/__tests__/__snapshots__/TaskInfo.test.js.snap +3 -9
- data/webpack/ForemanTasks/Components/TaskDetails/TaskDetails.js +35 -5
- data/webpack/ForemanTasks/Components/TaskDetails/TaskDetailsActions.js +34 -14
- data/webpack/ForemanTasks/Components/TaskDetails/TaskDetailsConstants.js +3 -4
- data/webpack/ForemanTasks/Components/TaskDetails/TaskDetailsReducer.js +0 -6
- data/webpack/ForemanTasks/Components/TaskDetails/TaskDetailsSelectors.js +4 -10
- data/webpack/ForemanTasks/Components/TaskDetails/TasksDetailsHelper.js +6 -1
- data/webpack/ForemanTasks/Components/TaskDetails/__tests__/TaskDetails.fixtures.js +8 -0
- data/webpack/ForemanTasks/Components/TaskDetails/__tests__/TaskDetails.test.js +7 -1
- data/webpack/ForemanTasks/Components/TaskDetails/__tests__/TaskDetailsActions.test.js +18 -2
- data/webpack/ForemanTasks/Components/TaskDetails/__tests__/__snapshots__/TaskDetails.test.js.snap +30 -13
- data/webpack/ForemanTasks/Components/TaskDetails/__tests__/__snapshots__/TaskDetailsActions.test.js.snap +91 -0
- data/webpack/ForemanTasks/Components/TaskDetails/__tests__/integration.test.js +13 -4
- data/webpack/ForemanTasks/Components/TaskDetails/index.js +6 -8
- data/webpack/ForemanTasks/Components/TasksDashboard/TasksDashboardActions.js +1 -1
- data/webpack/ForemanTasks/Components/TasksDashboard/TasksDashboardConstants.js +5 -0
- data/webpack/ForemanTasks/Components/TasksDashboard/TasksDashboardHelper.js +3 -2
- data/webpack/ForemanTasks/Components/TasksDashboard/__tests__/TasksDashboardActions.test.js +2 -2
- data/webpack/ForemanTasks/Components/TasksTable/Components/ActionSelectButton.js +14 -1
- data/webpack/ForemanTasks/Components/TasksTable/Components/ConfirmModal/ConfirmModal.js +83 -0
- data/webpack/ForemanTasks/Components/TasksTable/Components/ConfirmModal/ConfirmModalActions.js +106 -0
- data/webpack/ForemanTasks/Components/TasksTable/Components/ConfirmModal/ConfirmModalReducer.js +38 -0
- data/webpack/ForemanTasks/Components/TasksTable/Components/ConfirmModal/ConfirmModalSelectors.js +45 -0
- data/webpack/ForemanTasks/Components/TasksTable/Components/ConfirmModal/__test__/ConfirmModal.test.js +36 -0
- data/webpack/ForemanTasks/Components/TasksTable/Components/ConfirmModal/__test__/ConfirmModalActions.test.js +205 -0
- data/webpack/ForemanTasks/Components/TasksTable/Components/ConfirmModal/__test__/ConfirmModalReducer.test.js +27 -0
- data/webpack/ForemanTasks/Components/TasksTable/Components/ConfirmModal/__test__/ConfirmModalSelectors.test.js +54 -0
- data/webpack/ForemanTasks/Components/TasksTable/Components/ConfirmModal/__test__/__snapshots__/ConfirmModal.test.js.snap +41 -0
- data/webpack/ForemanTasks/Components/TasksTable/Components/ConfirmModal/__test__/__snapshots__/ConfirmModalReducer.test.js.snap +19 -0
- data/webpack/ForemanTasks/Components/TasksTable/Components/ConfirmModal/__test__/__snapshots__/ConfirmModalSelectors.test.js.snap +30 -0
- data/webpack/ForemanTasks/Components/TasksTable/Components/ConfirmModal/index.js +29 -0
- data/webpack/ForemanTasks/Components/TasksTable/Components/SelectAllAlert.js +43 -0
- data/webpack/ForemanTasks/Components/TasksTable/Components/__test__/ActionSelectButton.test.js +1 -0
- data/webpack/ForemanTasks/Components/TasksTable/Components/__test__/SelectAllAlert.test.js +29 -0
- data/webpack/ForemanTasks/Components/TasksTable/Components/__test__/__snapshots__/ActionSelectButton.test.js.snap +11 -0
- data/webpack/ForemanTasks/Components/TasksTable/Components/__test__/__snapshots__/SelectAllAlert.test.js.snap +75 -0
- data/webpack/ForemanTasks/Components/TasksTable/SubTasksPage.js +4 -1
- data/webpack/ForemanTasks/Components/TasksTable/TasksBulkActions.js +247 -0
- data/webpack/ForemanTasks/Components/TasksTable/TasksTable.js +37 -19
- data/webpack/ForemanTasks/Components/TasksTable/TasksTableActions.js +56 -92
- data/webpack/ForemanTasks/Components/TasksTable/TasksTableConstants.js +19 -11
- data/webpack/ForemanTasks/Components/TasksTable/TasksTableHelpers.js +4 -3
- data/webpack/ForemanTasks/Components/TasksTable/TasksTablePage.js +64 -73
- data/webpack/ForemanTasks/Components/TasksTable/TasksTableReducer.js +21 -2
- data/webpack/ForemanTasks/Components/TasksTable/TasksTableSchema.js +2 -2
- data/webpack/ForemanTasks/Components/TasksTable/TasksTableSelectors.js +13 -4
- data/webpack/ForemanTasks/Components/TasksTable/__tests__/TasksBulkActions.test.js +147 -0
- data/webpack/ForemanTasks/Components/TasksTable/__tests__/TasksTable.fixtures.js +3 -10
- data/webpack/ForemanTasks/Components/TasksTable/__tests__/TasksTableActions.test.js +46 -74
- data/webpack/ForemanTasks/Components/TasksTable/__tests__/TasksTableHelpers.test.js +17 -1
- data/webpack/ForemanTasks/Components/TasksTable/__tests__/TasksTablePage.test.js +9 -1
- data/webpack/ForemanTasks/Components/TasksTable/__tests__/TasksTableReducer.test.js +22 -1
- data/webpack/ForemanTasks/Components/TasksTable/__tests__/__snapshots__/SubTasksPage.test.js.snap +4 -12
- data/webpack/ForemanTasks/Components/TasksTable/__tests__/__snapshots__/TasksBulkActions.test.js.snap +336 -0
- data/webpack/ForemanTasks/Components/TasksTable/__tests__/__snapshots__/TasksIndexPage.test.js.snap +3 -12
- data/webpack/ForemanTasks/Components/TasksTable/__tests__/__snapshots__/TasksTableActions.test.js.snap +22 -158
- data/webpack/ForemanTasks/Components/TasksTable/__tests__/__snapshots__/TasksTablePage.test.js.snap +56 -132
- data/webpack/ForemanTasks/Components/TasksTable/__tests__/__snapshots__/TasksTableReducer.test.js.snap +34 -0
- data/webpack/ForemanTasks/Components/TasksTable/formatters/__test__/selectionHeaderCellFormatter.test.js +1 -1
- data/webpack/ForemanTasks/Components/TasksTable/formatters/selectionHeaderCellFormatter.js +2 -2
- data/webpack/ForemanTasks/Components/TasksTable/index.js +10 -4
- data/webpack/ForemanTasks/Components/common/ActionButtons/ActionButton.js +47 -19
- data/webpack/ForemanTasks/Components/common/ActionButtons/ActionButton.test.js +61 -14
- data/webpack/ForemanTasks/Components/common/ActionButtons/__snapshots__/ActionButton.test.js.snap +80 -21
- data/webpack/ForemanTasks/Components/common/ClickConfirmation/ClickConfirmation.scss +9 -0
- data/webpack/ForemanTasks/Components/common/ClickConfirmation/ClickConfirmation.test.js +44 -0
- data/webpack/ForemanTasks/Components/common/ClickConfirmation/__snapshots__/ClickConfirmation.test.js.snap +52 -0
- data/webpack/ForemanTasks/Components/common/ClickConfirmation/index.js +59 -66
- data/webpack/ForemanTasks/Components/common/ToastsHelpers/ToastTypesConstants.js +11 -0
- data/webpack/ForemanTasks/Components/common/ToastsHelpers/index.js +15 -0
- data/webpack/ForemanTasks/ForemanTasksReducers.js +2 -0
- data/webpack/ForemanTasks/Routes/ForemanTasksRoutes.test.js +2 -1
- data/webpack/__mocks__/foremanReact/components/ForemanModal/ForemanModalHooks.js +2 -2
- data/webpack/__mocks__/foremanReact/components/ForemanModal/index.js +17 -3
- data/webpack/__mocks__/foremanReact/components/common/ActionButtons/ActionButtons.js +3 -0
- data/webpack/__mocks__/foremanReact/{API.js → redux/API.js} +1 -1
- metadata +76 -27
- data/webpack/ForemanTasks/Components/TasksTable/Components/CancelConfirm.js +0 -53
- data/webpack/ForemanTasks/Components/TasksTable/Components/ConfirmationModals.js +0 -56
- data/webpack/ForemanTasks/Components/TasksTable/Components/ResumeConfirm.js +0 -52
- data/webpack/ForemanTasks/Components/TasksTable/Components/__test__/CancelConfirm.test.js +0 -26
- data/webpack/ForemanTasks/Components/TasksTable/Components/__test__/ConfirmationModals.test.js +0 -24
- data/webpack/ForemanTasks/Components/TasksTable/Components/__test__/ResumeConfirm.test.js +0 -26
- data/webpack/ForemanTasks/Components/TasksTable/Components/__test__/__snapshots__/CancelConfirm.test.js.snap +0 -65
- data/webpack/ForemanTasks/Components/TasksTable/Components/__test__/__snapshots__/ConfirmationModals.test.js.snap +0 -30
- data/webpack/ForemanTasks/Components/TasksTable/Components/__test__/__snapshots__/ResumeConfirm.test.js.snap +0 -63
- data/webpack/ForemanTasks/Components/common/ActionButtons/CancelButton.js +0 -23
- data/webpack/ForemanTasks/Components/common/ActionButtons/CancelButton.test.js +0 -26
- data/webpack/ForemanTasks/Components/common/ActionButtons/ResumeButton.js +0 -23
- data/webpack/ForemanTasks/Components/common/ActionButtons/ResumeButton.test.js +0 -27
- data/webpack/ForemanTasks/Components/common/ActionButtons/__snapshots__/CancelButton.test.js.snap +0 -15
- data/webpack/ForemanTasks/Components/common/ActionButtons/__snapshots__/ResumeButton.test.js.snap +0 -15
@@ -3,8 +3,6 @@ module ForemanTasks
|
|
3
3
|
include Foreman::Controller::AutoCompleteSearch
|
4
4
|
include Foreman::Controller::CsvResponder
|
5
5
|
|
6
|
-
before_action :restrict_dangerous_actions, :only => [:unlock, :force_unlock]
|
7
|
-
|
8
6
|
def show
|
9
7
|
@task = resource_base.find(params[:id])
|
10
8
|
render :layout => !request.xhr?
|
@@ -33,9 +31,12 @@ module ForemanTasks
|
|
33
31
|
|
34
32
|
def cancel_step
|
35
33
|
task = find_dynflow_task
|
36
|
-
|
37
|
-
|
38
|
-
|
34
|
+
result = ForemanTasks.dynflow.world.event(task.external_id, params[:step_id].to_i, ::Dynflow::Action::Cancellable::Cancel).wait
|
35
|
+
if result.rejected?
|
36
|
+
render json: { error: result.reason }, status: :bad_request
|
37
|
+
else
|
38
|
+
render json: { statusText: 'OK' }
|
39
|
+
end
|
39
40
|
end
|
40
41
|
|
41
42
|
def cancel
|
@@ -72,19 +73,17 @@ module ForemanTasks
|
|
72
73
|
if task.paused?
|
73
74
|
task.state = :stopped
|
74
75
|
task.save!
|
75
|
-
|
76
|
+
render json: { statusText: 'OK' }
|
76
77
|
else
|
77
|
-
|
78
|
+
render json: {}, status: :bad_request
|
78
79
|
end
|
79
|
-
redirect_back(:fallback_location => foreman_tasks_task_path(task))
|
80
80
|
end
|
81
81
|
|
82
82
|
def force_unlock
|
83
83
|
task = find_dynflow_task
|
84
84
|
task.state = :stopped
|
85
85
|
task.save!
|
86
|
-
|
87
|
-
redirect_back(:fallback_location => foreman_tasks_task_path(task))
|
86
|
+
render json: { statusText: 'OK' }
|
88
87
|
end
|
89
88
|
|
90
89
|
# we need do this to make the Foreman helpers working properly
|
@@ -103,10 +102,6 @@ module ForemanTasks
|
|
103
102
|
csv_response(@tasks, [:id, :action, :state, :result, 'started_at.in_time_zone', 'ended_at.in_time_zone', :username], ['Id', 'Action', 'State', 'Result', 'Started At', 'Ended At', 'User'])
|
104
103
|
end
|
105
104
|
|
106
|
-
def restrict_dangerous_actions
|
107
|
-
render_403 unless Setting['dynflow_allow_dangerous_actions']
|
108
|
-
end
|
109
|
-
|
110
105
|
def controller_permission
|
111
106
|
'foreman_tasks'
|
112
107
|
end
|
@@ -1,5 +1,4 @@
|
|
1
1
|
module ForemanTasks
|
2
|
-
# rubocop:disable Metrics/ModuleLength
|
3
2
|
module ForemanTasksHelper
|
4
3
|
def recurring_logic_state(recurring_logic)
|
5
4
|
icon, status = case recurring_logic.state
|
@@ -28,7 +27,7 @@ module ForemanTasks
|
|
28
27
|
def troubleshooting_info_text
|
29
28
|
return if @task.state != 'paused' || @task.main_action.nil?
|
30
29
|
helper = TroubleshootingHelpGenerator.new(@task.main_action)
|
31
|
-
helper.
|
30
|
+
helper.generate_html
|
32
31
|
end
|
33
32
|
|
34
33
|
def username_link_task(owner, username)
|
@@ -209,5 +208,4 @@ module ForemanTasks
|
|
209
208
|
tags.join.html_safe
|
210
209
|
end
|
211
210
|
end
|
212
|
-
# rubocop:enable Metrics/ModuleLength
|
213
211
|
end
|
@@ -41,12 +41,7 @@ module Actions
|
|
41
41
|
with_connection_error_handling(event) do |event|
|
42
42
|
case event
|
43
43
|
when nil
|
44
|
-
|
45
|
-
on_resume
|
46
|
-
else
|
47
|
-
trigger_proxy_task
|
48
|
-
end
|
49
|
-
suspend
|
44
|
+
start_or_resume
|
50
45
|
when ::Dynflow::Action::Skip
|
51
46
|
# do nothing
|
52
47
|
when ::Dynflow::Action::Cancellable::Cancel
|
@@ -77,6 +72,12 @@ module Actions
|
|
77
72
|
end
|
78
73
|
end
|
79
74
|
|
75
|
+
def trigger_remote_task
|
76
|
+
suspend do |_suspended_action|
|
77
|
+
ForemanTasks::RemoteTask.batch_trigger(remote_task.operation, [remote_task])
|
78
|
+
end
|
79
|
+
end
|
80
|
+
|
80
81
|
def proxy_input(task_id = task.id)
|
81
82
|
input.merge(:callback => { :task_id => task_id,
|
82
83
|
:step_id => run_step_id })
|
@@ -88,7 +89,7 @@ module Actions
|
|
88
89
|
if response['result'] == 'error'
|
89
90
|
raise ::Foreman::Exception, _('The smart proxy task %s failed.') % proxy_task_id
|
90
91
|
else
|
91
|
-
on_data(response
|
92
|
+
on_data(get_proxy_data(response))
|
92
93
|
end
|
93
94
|
else
|
94
95
|
suspend
|
@@ -154,10 +155,8 @@ module Actions
|
|
154
155
|
if output.key?(:proxy_output) || state == :error
|
155
156
|
output.fetch(:proxy_output, {})
|
156
157
|
elsif live && proxy_task_id
|
157
|
-
|
158
|
-
|
159
|
-
end
|
160
|
-
proxy_data.fetch('output', {})
|
158
|
+
response = proxy.status_of_task(proxy_task_id)
|
159
|
+
get_proxy_data(response)
|
161
160
|
else
|
162
161
|
{}
|
163
162
|
end
|
@@ -205,6 +204,26 @@ module Actions
|
|
205
204
|
|
206
205
|
private
|
207
206
|
|
207
|
+
def start_or_resume
|
208
|
+
if remote_task
|
209
|
+
if remote_task.state == 'external'
|
210
|
+
trigger_remote_task
|
211
|
+
else
|
212
|
+
on_resume
|
213
|
+
end
|
214
|
+
else
|
215
|
+
trigger_proxy_task
|
216
|
+
end
|
217
|
+
suspend
|
218
|
+
end
|
219
|
+
|
220
|
+
def get_proxy_data(response)
|
221
|
+
proxy_data = response['actions'].detect do |action|
|
222
|
+
action['class'] == proxy_action_name || action.fetch('input', {})['proxy_operation_name'] == proxy_operation_name
|
223
|
+
end
|
224
|
+
proxy_data.fetch('output', {})
|
225
|
+
end
|
226
|
+
|
208
227
|
def proxy_version(proxy)
|
209
228
|
match = proxy.statuses[:version].version['version'].match(/(\d+)\.(\d+)\.(\d+)/)
|
210
229
|
{ :major => match[1].to_i, :minor => match[2].to_i, :patch => match[3].to_i }
|
@@ -247,10 +266,12 @@ module Actions
|
|
247
266
|
end
|
248
267
|
|
249
268
|
def prepare_remote_task
|
269
|
+
state = input[:use_concurrency_control] ? 'external' : 'new'
|
250
270
|
::ForemanTasks::RemoteTask.new(:execution_plan_id => execution_plan_id,
|
251
271
|
:proxy_url => input[:proxy_url],
|
252
272
|
:step_id => run_step_id,
|
253
|
-
:operation => proxy_operation_name
|
273
|
+
:operation => proxy_operation_name,
|
274
|
+
:state => state)
|
254
275
|
end
|
255
276
|
|
256
277
|
def proxy_task_id
|
@@ -0,0 +1,12 @@
|
|
1
|
+
module ForemanTasks
|
2
|
+
module Concerns
|
3
|
+
module PollingActionExtensions
|
4
|
+
def poll_intervals
|
5
|
+
multiplier = Setting[:foreman_tasks_polling_multiplier] || 1
|
6
|
+
|
7
|
+
# Prevent the intervals from going below 0.5 seconds
|
8
|
+
super.map { |interval| [interval * multiplier, 0.5].max }
|
9
|
+
end
|
10
|
+
end
|
11
|
+
end
|
12
|
+
end
|
@@ -14,6 +14,7 @@ module ForemanTasks
|
|
14
14
|
scoped_search :on => :max_iteration, :complete_value => false, :rename => :iteration_limit
|
15
15
|
scoped_search :on => :iteration, :complete_value => false
|
16
16
|
scoped_search :on => :cron_line, :complete_value => true
|
17
|
+
scoped_search :on => :state, :complete_value => true
|
17
18
|
|
18
19
|
before_create do
|
19
20
|
task_group.save
|
@@ -42,6 +42,10 @@ module ForemanTasks
|
|
42
42
|
scoped_search :on => :start_at, :complete_value => false
|
43
43
|
scoped_search :on => :ended_at, :complete_value => false
|
44
44
|
scoped_search :on => :parent_task_id, :complete_value => true
|
45
|
+
scoped_search :on => :duration, :complete_value => false, :ext_method => :search_by_duration, :operators => %w[> >= = <= <], :only_explicit => true
|
46
|
+
|
47
|
+
# Note: the following searches may return duplicates, this is due to
|
48
|
+
# one task maybe having multiple locks (e.g. read/write) for the same resource_id
|
45
49
|
scoped_search :relation => :locks, :on => :resource_id, :complete_value => false, :rename => 'location_id', :ext_method => :search_by_taxonomy, :only_explicit => true
|
46
50
|
scoped_search :relation => :locks, :on => :resource_id, :complete_value => false, :rename => 'organization_id', :ext_method => :search_by_taxonomy, :only_explicit => true
|
47
51
|
scoped_search :relation => :locks, :on => :resource_type, :complete_value => true, :rename => 'resource_type', :ext_method => :search_by_generic_resource, :only_explicit => true
|
@@ -66,6 +70,10 @@ module ForemanTasks
|
|
66
70
|
end)
|
67
71
|
scope :for_action_types, (->(action_types) { where('foreman_tasks_tasks.label IN (?)', Array(action_types)) })
|
68
72
|
|
73
|
+
class Jail < Safemode::Jail
|
74
|
+
allow :started_at, :ended_at, :result, :state, :label, :main_action
|
75
|
+
end
|
76
|
+
|
69
77
|
def input
|
70
78
|
{}
|
71
79
|
end
|
@@ -119,6 +119,7 @@ module ForemanTasks
|
|
119
119
|
begin
|
120
120
|
f_action = f.action(execution_plan)
|
121
121
|
{
|
122
|
+
id: f_action.id,
|
122
123
|
action_class: f.action_class.name,
|
123
124
|
state: f.state,
|
124
125
|
input: f_action.input.pretty_inspect,
|
@@ -228,7 +229,7 @@ module ForemanTasks
|
|
228
229
|
# if we fail updating the data from dynflow, it usually means there is something
|
229
230
|
# odd with the data consistency and at this point it is not possible to resume, switching
|
230
231
|
# the task to stopped/error
|
231
|
-
task.
|
232
|
+
task.update(:state => 'stopped', :result => 'error')
|
232
233
|
Foreman::Logging.exception("Failed at consistency check for task #{task.id}", e, :logger => 'foreman-tasks')
|
233
234
|
end
|
234
235
|
end
|
@@ -4,7 +4,8 @@ module ForemanTasks
|
|
4
4
|
def search_by_generic_resource(key, operator, value)
|
5
5
|
key = 'resource_type' if key.blank?
|
6
6
|
key_name = connection.quote_column_name(key.sub(/^.*\./, ''))
|
7
|
-
|
7
|
+
value = value.split(',') if operator.index(/IN/i)
|
8
|
+
condition = sanitize_sql_for_conditions(["foreman_tasks_locks.#{key_name} #{operator} (?)", value])
|
8
9
|
|
9
10
|
{ :conditions => condition, :joins => :locks }
|
10
11
|
end
|
@@ -22,6 +23,15 @@ module ForemanTasks
|
|
22
23
|
sql = "foreman_tasks_locks_taxonomy#{uniq_suffix}.resource_id #{operator} ? OR foreman_tasks_locks_taxonomy#{uniq_suffix}.resource_id IS NULL"
|
23
24
|
{ :conditions => sanitize_sql_for_conditions([sql, value]), :joins => joins }
|
24
25
|
end
|
26
|
+
|
27
|
+
# Expects the time in the format "\d+ (seconds|minutes|hours|days|months|years)"
|
28
|
+
SUPPORTED_DURATION_FORMAT = /\A\s*(\d+(\s+\b(seconds?|minutes?|hours?|days?|months?|years?)\b)?)\b\s*\z/i.freeze
|
29
|
+
def search_by_duration(_key, operator, value)
|
30
|
+
raise "Unsupported duration '#{value}' specified for searching" unless value =~ SUPPORTED_DURATION_FORMAT
|
31
|
+
value = value.strip
|
32
|
+
{ :conditions => "coalesce(ended_at, current_timestamp) - coalesce(coalesce(started_at, ended_at), current_timestamp) #{operator} ?::interval",
|
33
|
+
:parameter => [value] }
|
34
|
+
end
|
25
35
|
end
|
26
36
|
end
|
27
37
|
end
|
@@ -2,7 +2,6 @@ class Setting::ForemanTasks < Setting
|
|
2
2
|
def self.default_settings
|
3
3
|
[
|
4
4
|
set('foreman_tasks_sync_task_timeout', N_('Number of seconds to wait for synchronous task to finish.'), 120),
|
5
|
-
set('dynflow_allow_dangerous_actions', N_('Allow unlocking actions which can have dangerous consequences.'), false),
|
6
5
|
set('dynflow_enable_console', N_('Enable the dynflow console (/foreman_tasks/dynflow) for debugging'), true),
|
7
6
|
set('dynflow_console_require_auth', N_('Require user to be authenticated as user with admin rights when accessing dynflow console'), true),
|
8
7
|
set('foreman_tasks_proxy_action_retry_count', N_('Number of attempts to start a task on the smart proxy before failing'), 4),
|
@@ -13,12 +12,18 @@ class Setting::ForemanTasks < Setting
|
|
13
12
|
N_('Url pointing to the task troubleshooting documentation. '\
|
14
13
|
'It should contain %{label} placeholder, that will be replaced with normalized task label '\
|
15
14
|
'(restricted to only alphanumeric characters)). %{version} placeholder is also available.'),
|
16
|
-
nil)
|
15
|
+
nil),
|
16
|
+
set('foreman_tasks_polling_multiplier',
|
17
|
+
N_('Polling multiplier which is used to multiply the default polling intervals. '\
|
18
|
+
'This can be used to prevent polling too frequently for long running tasks.'),
|
19
|
+
1,
|
20
|
+
N_("Polling intervals multiplier"))
|
17
21
|
]
|
18
22
|
end
|
19
23
|
|
20
24
|
def self.load_defaults
|
21
25
|
Setting::BLANK_ATTRS.push('foreman_tasks_troubleshooting_url')
|
26
|
+
Setting::NONZERO_ATTRS.push('foreman_tasks_polling_multiplier')
|
22
27
|
super
|
23
28
|
end
|
24
29
|
end
|
@@ -44,10 +44,6 @@ module ForemanTasks
|
|
44
44
|
# rubocop:enable Rails/OutputSafety
|
45
45
|
end
|
46
46
|
|
47
|
-
def generate_text
|
48
|
-
(description + link_descriptions_html).join("\n")
|
49
|
-
end
|
50
|
-
|
51
47
|
def link_descriptions_html
|
52
48
|
links.map do |link|
|
53
49
|
link.description % { link: %(<a href="%{href}">%{title}</a>) % link.to_h }
|
@@ -0,0 +1,36 @@
|
|
1
|
+
module UINotifications
|
2
|
+
module Tasks
|
3
|
+
class TaskBulkCancel < ::UINotifications::Base
|
4
|
+
def initialize(task, cancelled_length, skipped_length)
|
5
|
+
@subject = task
|
6
|
+
@cancelled_length = cancelled_length
|
7
|
+
@skipped_length = skipped_length
|
8
|
+
end
|
9
|
+
|
10
|
+
def create
|
11
|
+
Notification.create!(
|
12
|
+
initiator: initiator,
|
13
|
+
audience: audience,
|
14
|
+
subject: subject,
|
15
|
+
notification_blueprint: blueprint,
|
16
|
+
message: message,
|
17
|
+
notification_recipients: [NotificationRecipient.create({ :user => User.current })]
|
18
|
+
)
|
19
|
+
end
|
20
|
+
|
21
|
+
def audience
|
22
|
+
Notification::AUDIENCE_GLOBAL
|
23
|
+
end
|
24
|
+
|
25
|
+
def message
|
26
|
+
('%{cancelled} Tasks were cancelled. %{skipped} Tasks were skipped. ' %
|
27
|
+
{ cancelled: @cancelled_length,
|
28
|
+
skipped: @skipped_length })
|
29
|
+
end
|
30
|
+
|
31
|
+
def blueprint
|
32
|
+
@blueprint ||= NotificationBlueprint.find_by(name: 'tasks_bulk_cancel')
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
@@ -0,0 +1,38 @@
|
|
1
|
+
module UINotifications
|
2
|
+
module Tasks
|
3
|
+
class TaskBulkResume < ::UINotifications::Base
|
4
|
+
def initialize(task, resumed_length, failed_length, skipped_length)
|
5
|
+
@subject = task
|
6
|
+
@resumed_length = resumed_length
|
7
|
+
@failed_length = failed_length
|
8
|
+
@skipped_length = skipped_length
|
9
|
+
end
|
10
|
+
|
11
|
+
def create
|
12
|
+
Notification.create!(
|
13
|
+
initiator: initiator,
|
14
|
+
audience: audience,
|
15
|
+
subject: subject,
|
16
|
+
notification_blueprint: blueprint,
|
17
|
+
message: message,
|
18
|
+
notification_recipients: [NotificationRecipient.create({ :user => User.current })]
|
19
|
+
)
|
20
|
+
end
|
21
|
+
|
22
|
+
def audience
|
23
|
+
Notification::AUDIENCE_USER
|
24
|
+
end
|
25
|
+
|
26
|
+
def message
|
27
|
+
('%{resumed} Tasks were resumed. %{failed} Tasks failed to resume. %{skipped} Tasks were skipped. ' %
|
28
|
+
{ resumed: @resumed_length,
|
29
|
+
failed: @failed_length,
|
30
|
+
skipped: @skipped_length })
|
31
|
+
end
|
32
|
+
|
33
|
+
def blueprint
|
34
|
+
@blueprint ||= NotificationBlueprint.find_by(name: 'tasks_bulk_resume')
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
@@ -0,0 +1,36 @@
|
|
1
|
+
module UINotifications
|
2
|
+
module Tasks
|
3
|
+
class TaskBulkStop < ::UINotifications::Base
|
4
|
+
def initialize(task, stopped_length, skipped_length)
|
5
|
+
@subject = task
|
6
|
+
@stopped_length = stopped_length
|
7
|
+
@skipped_length = skipped_length
|
8
|
+
end
|
9
|
+
|
10
|
+
def create
|
11
|
+
Notification.create!(
|
12
|
+
initiator: initiator,
|
13
|
+
audience: audience,
|
14
|
+
subject: subject,
|
15
|
+
notification_blueprint: blueprint,
|
16
|
+
message: message,
|
17
|
+
notification_recipients: [NotificationRecipient.create(:user => User.current)]
|
18
|
+
)
|
19
|
+
end
|
20
|
+
|
21
|
+
def audience
|
22
|
+
Notification::AUDIENCE_GLOBAL
|
23
|
+
end
|
24
|
+
|
25
|
+
def message
|
26
|
+
('%{stopped} Tasks were stopped. %{skipped} Tasks were already stopped. ' %
|
27
|
+
{ stopped: @stopped_length,
|
28
|
+
skipped: @skipped_length })
|
29
|
+
end
|
30
|
+
|
31
|
+
def blueprint
|
32
|
+
@blueprint ||= NotificationBlueprint.find_by(name: 'tasks_bulk_stop')
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
@@ -9,10 +9,10 @@ node(:failed_steps) { @task.input_output_failed_steps }
|
|
9
9
|
node(:running_steps) { @task.input_output_running_steps }
|
10
10
|
node(:help) { troubleshooting_info_text }
|
11
11
|
node(:has_sub_tasks) { @task.sub_tasks.any? }
|
12
|
-
node(:allowDangerousActions) { Setting['dynflow_allow_dangerous_actions'] }
|
13
12
|
node(:locks) do
|
14
13
|
@task.locks.map do |lock|
|
15
14
|
{ name: lock.name, exclusive: lock.exclusive, resource_type: lock.resource_type, resource_id: lock.resource_id }
|
16
15
|
end
|
17
16
|
end
|
18
17
|
node(:username_path) { username_link_task(@task.owner, @task.username) }
|
18
|
+
node(:dynflow_enable_console) { Setting['dynflow_enable_console'] }
|