foreman-tasks 1.0.0 → 1.1.3

Sign up to get free protection for your applications and to get access to all the features.
Files changed (165) hide show
  1. checksums.yaml +4 -4
  2. data/.eslintrc +2 -22
  3. data/.rubocop.yml +12 -12
  4. data/.rubocop_todo.yml +34 -116
  5. data/app/controllers/foreman_tasks/api/recurring_logics_controller.rb +20 -1
  6. data/app/controllers/foreman_tasks/api/tasks_controller.rb +38 -11
  7. data/app/controllers/foreman_tasks/concerns/hosts_controller_extension.rb +1 -1
  8. data/app/controllers/foreman_tasks/recurring_logics_controller.rb +19 -0
  9. data/app/helpers/foreman_tasks/foreman_tasks_helper.rb +1 -3
  10. data/app/lib/actions/helpers/humanizer.rb +1 -3
  11. data/app/lib/actions/proxy_action.rb +33 -12
  12. data/app/lib/foreman_tasks/concerns/polling_action_extensions.rb +12 -0
  13. data/app/models/foreman_tasks/concerns/action_triggering.rb +1 -1
  14. data/app/models/foreman_tasks/recurring_logic.rb +1 -0
  15. data/app/models/foreman_tasks/remote_task.rb +1 -0
  16. data/app/models/foreman_tasks/task.rb +4 -0
  17. data/app/models/foreman_tasks/task/dynflow_task.rb +1 -1
  18. data/app/models/foreman_tasks/task/search.rb +11 -1
  19. data/app/models/setting/foreman_tasks.rb +6 -1
  20. data/app/services/foreman_tasks/troubleshooting_help_generator.rb +0 -4
  21. data/app/services/ui_notifications/tasks/task_bulk_cancel.rb +36 -0
  22. data/app/services/ui_notifications/tasks/task_bulk_resume.rb +38 -0
  23. data/app/views/foreman_tasks/api/recurring_logics/base.json.rabl +2 -1
  24. data/app/views/foreman_tasks/api/tasks/details.json.rabl +1 -0
  25. data/app/views/foreman_tasks/api/tasks/show.json.rabl +1 -1
  26. data/app/views/foreman_tasks/recurring_logics/index.html.erb +30 -0
  27. data/app/views/foreman_tasks/tasks/show.html.erb +3 -0
  28. data/{.babelrc.js → babel.config.js} +0 -0
  29. data/config/routes.rb +7 -0
  30. data/db/migrate/20200611090846_add_task_lock_index_on_resource_type_and_task_id.rb +9 -0
  31. data/db/seeds.d/30-notification_blueprints.rb +14 -0
  32. data/foreman-tasks.gemspec +5 -6
  33. data/gemfile.d/foreman-tasks.rb +1 -0
  34. data/lib/foreman_tasks/dynflow/console_authorizer.rb +2 -2
  35. data/lib/foreman_tasks/engine.rb +17 -14
  36. data/lib/foreman_tasks/tasks/cleanup.rake +3 -3
  37. data/lib/foreman_tasks/tasks/dynflow.rake +6 -0
  38. data/lib/foreman_tasks/tasks/export_tasks.rake +3 -3
  39. data/lib/foreman_tasks/test_extensions.rb +1 -1
  40. data/lib/foreman_tasks/version.rb +1 -1
  41. data/locale/action_names.rb +1 -1
  42. data/package.json +18 -71
  43. data/script/rails +2 -2
  44. data/script/travis_run_js_tests.sh +2 -2
  45. data/test/controllers/api/tasks_controller_test.rb +9 -0
  46. data/test/factories/task_factory.rb +34 -2
  47. data/test/foreman_tasks_test_helper.rb +4 -0
  48. data/test/lib/concerns/polling_action_extensions_test.rb +34 -0
  49. data/test/unit/actions/action_with_sub_plans_test.rb +1 -1
  50. data/test/unit/task_test.rb +160 -74
  51. data/webpack/ForemanTasks/Components/TaskDetails/Components/Task.js +4 -0
  52. data/webpack/ForemanTasks/Components/TaskDetails/Components/TaskInfo.js +3 -12
  53. data/webpack/ForemanTasks/Components/TaskDetails/Components/__tests__/Errors.test.js +1 -1
  54. data/webpack/ForemanTasks/Components/TaskDetails/Components/__tests__/Locks.test.js +1 -1
  55. data/webpack/ForemanTasks/Components/TaskDetails/Components/__tests__/Raw.test.js +1 -1
  56. data/webpack/ForemanTasks/Components/TaskDetails/Components/__tests__/RunningSteps.test.js +1 -1
  57. data/webpack/ForemanTasks/Components/TaskDetails/Components/__tests__/Task.test.js +2 -1
  58. data/webpack/ForemanTasks/Components/TaskDetails/Components/__tests__/TaskInfo.test.js +1 -1
  59. data/webpack/ForemanTasks/Components/TaskDetails/Components/__tests__/__snapshots__/Task.test.js.snap +3 -1
  60. data/webpack/ForemanTasks/Components/TaskDetails/Components/__tests__/__snapshots__/TaskInfo.test.js.snap +3 -9
  61. data/webpack/ForemanTasks/Components/TaskDetails/TaskDetails.stories.js +6 -2
  62. data/webpack/ForemanTasks/Components/TaskDetails/TaskDetailsSelectors.js +4 -1
  63. data/webpack/ForemanTasks/Components/TaskDetails/__tests__/TaskDetails.test.js +1 -1
  64. data/webpack/ForemanTasks/Components/TaskDetails/__tests__/TaskDetailsActions.test.js +1 -1
  65. data/webpack/ForemanTasks/Components/TaskDetails/__tests__/TaskDetailsReducer.test.js +1 -1
  66. data/webpack/ForemanTasks/Components/TaskDetails/__tests__/__snapshots__/TaskDetails.test.js.snap +1 -0
  67. data/webpack/ForemanTasks/Components/TaskDetails/__tests__/integration.test.js +1 -1
  68. data/webpack/ForemanTasks/Components/TaskDetails/index.js +2 -0
  69. data/webpack/ForemanTasks/Components/TasksDashboard/Components/TasksCardsGrid/Components/PausedTasksCard/PausedTasksCard.stories.js +44 -40
  70. data/webpack/ForemanTasks/Components/TasksDashboard/Components/TasksCardsGrid/Components/PausedTasksCard/PausedTasksCard.test.js +1 -1
  71. data/webpack/ForemanTasks/Components/TasksDashboard/Components/TasksCardsGrid/Components/RunningTasksCard/RunningTasksCard.stories.js +45 -40
  72. data/webpack/ForemanTasks/Components/TasksDashboard/Components/TasksCardsGrid/Components/RunningTasksCard/RunningTasksCard.test.js +1 -1
  73. data/webpack/ForemanTasks/Components/TasksDashboard/Components/TasksCardsGrid/Components/ScheduledTasksCard/ScheduledTasksCard.stories.js +27 -22
  74. data/webpack/ForemanTasks/Components/TasksDashboard/Components/TasksCardsGrid/Components/ScheduledTasksCard/ScheduledTasksCard.test.js +1 -1
  75. data/webpack/ForemanTasks/Components/TasksDashboard/Components/TasksCardsGrid/Components/StoppedTasksCard/StoppedTasksCard.stories.js +61 -56
  76. data/webpack/ForemanTasks/Components/TasksDashboard/Components/TasksCardsGrid/Components/StoppedTasksCard/StoppedTasksCard.test.js +1 -1
  77. data/webpack/ForemanTasks/Components/TasksDashboard/Components/TasksCardsGrid/Components/TasksDonutCard/TasksDonutCard.stories.js +40 -35
  78. data/webpack/ForemanTasks/Components/TasksDashboard/Components/TasksCardsGrid/Components/TasksDonutCard/TasksDonutCard.test.js +1 -1
  79. data/webpack/ForemanTasks/Components/TasksDashboard/Components/TasksCardsGrid/Components/TasksDonutChart/TasksDonutChart.stories.js +21 -20
  80. data/webpack/ForemanTasks/Components/TasksDashboard/Components/TasksCardsGrid/Components/TasksDonutChart/TasksDonutChart.test.js +1 -1
  81. data/webpack/ForemanTasks/Components/TasksDashboard/Components/TasksCardsGrid/TasksCardsGrid.stories.js +40 -39
  82. data/webpack/ForemanTasks/Components/TasksDashboard/Components/TasksCardsGrid/TasksCardsGrid.test.js +1 -1
  83. data/webpack/ForemanTasks/Components/TasksDashboard/Components/TasksLabelsRow/TasksLabelsRow.stories.js +16 -17
  84. data/webpack/ForemanTasks/Components/TasksDashboard/Components/TasksLabelsRow/TasksLabelsRow.test.js +1 -2
  85. data/webpack/ForemanTasks/Components/TasksDashboard/Components/TasksTimeRow/Components/TimeDropDown/TimeDropDown.stories.mdx +57 -0
  86. data/webpack/ForemanTasks/Components/TasksDashboard/Components/TasksTimeRow/Components/TimeDropDown/TimeDropDown.test.js +1 -1
  87. data/webpack/ForemanTasks/Components/TasksDashboard/Components/TasksTimeRow/TasksTimeRow.stories.js +36 -18
  88. data/webpack/ForemanTasks/Components/TasksDashboard/Components/TasksTimeRow/TasksTimeRow.test.js +1 -1
  89. data/webpack/ForemanTasks/Components/TasksDashboard/TasksDashboardConstants.js +5 -0
  90. data/webpack/ForemanTasks/Components/TasksDashboard/TasksDashboardHelper.js +3 -2
  91. data/webpack/ForemanTasks/Components/TasksDashboard/__tests__/TasksDashboard.test.js +1 -1
  92. data/webpack/ForemanTasks/Components/TasksDashboard/__tests__/TasksDashboardActions.test.js +1 -1
  93. data/webpack/ForemanTasks/Components/TasksDashboard/__tests__/TasksDashboardReducer.test.js +1 -1
  94. data/webpack/ForemanTasks/Components/TasksDashboard/__tests__/TasksDashboardSelectors.test.js +1 -1
  95. data/webpack/ForemanTasks/Components/TasksTable/Components/CancelConfirm.js +53 -0
  96. data/webpack/ForemanTasks/Components/TasksTable/Components/ConfirmationModals.js +56 -0
  97. data/webpack/ForemanTasks/Components/TasksTable/Components/ResumeConfirm.js +52 -0
  98. data/webpack/ForemanTasks/Components/TasksTable/Components/SelectAllAlert.js +43 -0
  99. data/webpack/ForemanTasks/Components/TasksTable/Components/__test__/ActionSelectButton.test.js +1 -1
  100. data/webpack/ForemanTasks/Components/TasksTable/Components/__test__/CancelConfirm.test.js +26 -0
  101. data/webpack/ForemanTasks/Components/TasksTable/Components/__test__/ConfirmationModals.test.js +24 -0
  102. data/webpack/ForemanTasks/Components/TasksTable/Components/__test__/ResumeConfirm.test.js +26 -0
  103. data/webpack/ForemanTasks/Components/TasksTable/Components/__test__/SelectAllAlert.test.js +29 -0
  104. data/webpack/ForemanTasks/Components/TasksTable/Components/__test__/TableSelectionCell.test.js +1 -1
  105. data/webpack/ForemanTasks/Components/TasksTable/Components/__test__/TableSelectionHeaderCell.test.js +1 -1
  106. data/webpack/ForemanTasks/Components/TasksTable/Components/__test__/__snapshots__/CancelConfirm.test.js.snap +65 -0
  107. data/webpack/ForemanTasks/Components/TasksTable/Components/__test__/__snapshots__/ConfirmationModals.test.js.snap +30 -0
  108. data/webpack/ForemanTasks/Components/TasksTable/Components/__test__/__snapshots__/ResumeConfirm.test.js.snap +63 -0
  109. data/webpack/ForemanTasks/Components/TasksTable/Components/__test__/__snapshots__/SelectAllAlert.test.js.snap +75 -0
  110. data/webpack/ForemanTasks/Components/TasksTable/SubTasksPage.js +4 -1
  111. data/webpack/ForemanTasks/Components/TasksTable/TasksBulkActions.js +164 -0
  112. data/webpack/ForemanTasks/Components/TasksTable/TasksTable.js +46 -22
  113. data/webpack/ForemanTasks/Components/TasksTable/TasksTableActionHelpers.js +52 -0
  114. data/webpack/ForemanTasks/Components/TasksTable/TasksTableActions.js +88 -87
  115. data/webpack/ForemanTasks/Components/TasksTable/TasksTableConstants.js +23 -9
  116. data/webpack/ForemanTasks/Components/TasksTable/TasksTableHelpers.js +4 -3
  117. data/webpack/ForemanTasks/Components/TasksTable/TasksTablePage.js +128 -31
  118. data/webpack/ForemanTasks/Components/TasksTable/TasksTableReducer.js +26 -9
  119. data/webpack/ForemanTasks/Components/TasksTable/TasksTableSelectors.js +24 -16
  120. data/webpack/ForemanTasks/Components/TasksTable/__tests__/SubTasksPage.test.js +1 -1
  121. data/webpack/ForemanTasks/Components/TasksTable/__tests__/TasksBulkActions.test.js +112 -0
  122. data/webpack/ForemanTasks/Components/TasksTable/__tests__/TasksIndexPage.test.js +1 -1
  123. data/webpack/ForemanTasks/Components/TasksTable/__tests__/TasksTable.fixtures.js +12 -5
  124. data/webpack/ForemanTasks/Components/TasksTable/__tests__/TasksTable.test.js +1 -1
  125. data/webpack/ForemanTasks/Components/TasksTable/__tests__/TasksTableActionHelpers.test.js +46 -0
  126. data/webpack/ForemanTasks/Components/TasksTable/__tests__/TasksTableActions.test.js +28 -52
  127. data/webpack/ForemanTasks/Components/TasksTable/__tests__/TasksTableHelpers.test.js +17 -1
  128. data/webpack/ForemanTasks/Components/TasksTable/__tests__/TasksTablePage.test.js +10 -2
  129. data/webpack/ForemanTasks/Components/TasksTable/__tests__/TasksTableReducer.test.js +28 -8
  130. data/webpack/ForemanTasks/Components/TasksTable/__tests__/__snapshots__/SubTasksPage.test.js.snap +15 -5
  131. data/webpack/ForemanTasks/Components/TasksTable/__tests__/__snapshots__/TasksBulkActions.test.js.snap +229 -0
  132. data/webpack/ForemanTasks/Components/TasksTable/__tests__/__snapshots__/TasksIndexPage.test.js.snap +14 -5
  133. data/webpack/ForemanTasks/Components/TasksTable/__tests__/__snapshots__/TasksTableActions.test.js.snap +56 -85
  134. data/webpack/ForemanTasks/Components/TasksTable/__tests__/__snapshots__/TasksTablePage.test.js.snap +158 -32
  135. data/webpack/ForemanTasks/Components/TasksTable/__tests__/__snapshots__/TasksTableReducer.test.js.snap +43 -16
  136. data/webpack/ForemanTasks/Components/TasksTable/formatters/__test__/selectionHeaderCellFormatter.test.js +1 -1
  137. data/webpack/ForemanTasks/Components/TasksTable/formatters/selectionHeaderCellFormatter.js +2 -2
  138. data/webpack/ForemanTasks/Components/TasksTable/index.js +11 -4
  139. data/webpack/ForemanTasks/Components/common/ActionButtons/ActionButton.js +4 -4
  140. data/webpack/ForemanTasks/Components/common/ActionButtons/ActionButton.test.js +1 -1
  141. data/webpack/ForemanTasks/Components/common/ActionButtons/CancelButton.test.js +1 -2
  142. data/webpack/ForemanTasks/Components/common/ActionButtons/ResumeButton.test.js +2 -2
  143. data/webpack/ForemanTasks/Components/common/ActionButtons/__snapshots__/ActionButton.test.js.snap +3 -3
  144. data/webpack/ForemanTasks/Components/common/ToastTypesConstants.js +11 -0
  145. data/webpack/ForemanTasks/ForemanTasks.test.js +1 -1
  146. data/webpack/ForemanTasks/Routes/ForemanTasksRouter.test.js +1 -1
  147. data/webpack/ForemanTasks/Routes/ForemanTasksRoutes.test.js +2 -3
  148. data/webpack/ForemanTasks/Routes/ShowTask/__tests__/ShowTask.test.js +1 -1
  149. data/webpack/__mocks__/foremanReact/components/ForemanModal/ForemanModalActions.js +2 -0
  150. data/webpack/__mocks__/foremanReact/components/ForemanModal/ForemanModalHooks.js +10 -0
  151. data/webpack/__mocks__/foremanReact/components/ForemanModal/index.js +4 -0
  152. metadata +55 -24
  153. data/.storybook/addons.js +0 -2
  154. data/.storybook/config.js +0 -7
  155. data/.storybook/webpack.config.js +0 -84
  156. data/webpack/ForemanTasks/Components/TasksDashboard/Components/TasksTimeRow/Components/TimeDropDown/TimeDropDown.stories.js +0 -23
  157. data/webpack/ForemanTasks/Components/TasksTable/Components/ActionConfirmation.js +0 -49
  158. data/webpack/ForemanTasks/Components/TasksTable/Components/CancelResumeConfirm.js +0 -51
  159. data/webpack/ForemanTasks/Components/TasksTable/Components/__test__/ActionConfirmation.test.js +0 -18
  160. data/webpack/ForemanTasks/Components/TasksTable/Components/__test__/CancelResumeConfirm.test.js +0 -28
  161. data/webpack/ForemanTasks/Components/TasksTable/Components/__test__/__snapshots__/ActionConfirmation.test.js.snap +0 -89
  162. data/webpack/ForemanTasks/Components/TasksTable/Components/__test__/__snapshots__/CancelResumeConfirm.test.js.snap +0 -37
  163. data/webpack/stories/index.js +0 -10
  164. data/webpack/stories/index.scss +0 -7
  165. data/webpack/test_setup.js +0 -7
@@ -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.generate_text
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
@@ -78,9 +78,7 @@ module Actions
78
78
  else
79
79
  head, *tail = subkeys
80
80
  if data.is_a?(Hash) && data.key?(head)
81
- return fetch_data(data[head], *tail)
82
- else
83
- return nil
81
+ fetch_data(data[head], *tail)
84
82
  end
85
83
  end
86
84
  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
- if remote_task
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['actions'].find { |block_action| block_action['class'] == proxy_action_name }['output'])
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
- proxy_data = proxy.status_of_task(proxy_task_id)['actions'].detect do |action|
158
- action['class'] == proxy_action_name || action.fetch('input', {})['proxy_operation_name'] == proxy_operation_name
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
@@ -158,7 +158,7 @@ module ForemanTasks
158
158
  end
159
159
  end
160
160
  end
161
- return true
161
+ true
162
162
  ensure
163
163
  # to not execute the same execution plan twice in a row
164
164
  @execution_plan = nil
@@ -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
@@ -9,6 +9,7 @@ module ForemanTasks
9
9
 
10
10
  scope :triggered, -> { where(:state => 'triggered') }
11
11
  scope :pending, -> { where(:state => 'new') }
12
+ scope :external, -> { where(:state => 'external') }
12
13
 
13
14
  delegate :proxy_action_name, :to => :action
14
15
 
@@ -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
@@ -228,7 +228,7 @@ module ForemanTasks
228
228
  # if we fail updating the data from dynflow, it usually means there is something
229
229
  # odd with the data consistency and at this point it is not possible to resume, switching
230
230
  # the task to stopped/error
231
- task.update_attributes(:state => 'stopped', :result => 'error')
231
+ task.update(:state => 'stopped', :result => 'error')
232
232
  Foreman::Logging.exception("Failed at consistency check for task #{task.id}", e, :logger => 'foreman-tasks')
233
233
  end
234
234
  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
- condition = sanitize_sql_for_conditions(["foreman_tasks_locks.#{key_name} #{operator} ?", value])
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
@@ -13,7 +13,12 @@ class Setting::ForemanTasks < Setting
13
13
  N_('Url pointing to the task troubleshooting documentation. '\
14
14
  'It should contain %{label} placeholder, that will be replaced with normalized task label '\
15
15
  '(restricted to only alphanumeric characters)). %{version} placeholder is also available.'),
16
- nil)
16
+ nil),
17
+ set('foreman_tasks_polling_multiplier',
18
+ N_('Polling multiplier which is used to multiply the default polling intervals. '\
19
+ 'This can be used to prevent polling too frequently for long running tasks.'),
20
+ 1,
21
+ N_("Polling intervals multiplier"))
17
22
  ]
18
23
  end
19
24
 
@@ -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
@@ -1,3 +1,4 @@
1
1
  object @recurring_logic
2
2
 
3
- attributes :id, :cron_line, :end_time, :iteration, :task_group_id, :state
3
+ attributes :id, :cron_line, :end_time, :iteration, :task_group_id, :state,
4
+ :max_iteration
@@ -16,3 +16,4 @@ node(:locks) do
16
16
  end
17
17
  end
18
18
  node(:username_path) { username_link_task(@task.owner, @task.username) }
19
+ node(:dynflow_enable_console) { Setting['dynflow_enable_console'] }
@@ -2,5 +2,5 @@ object @task if @task
2
2
 
3
3
  attributes :id, :label, :pending, :action
4
4
  attributes :username, :started_at, :ended_at, :state, :result, :progress
5
- attributes :input, :output, :humanized, :cli_example
5
+ attributes :input, :output, :humanized, :cli_example, :start_at
6
6
  node(:available_actions) { |t| { cancellable: t.execution_plan&.cancellable?, resumable: t.resumable? } }
@@ -5,6 +5,36 @@
5
5
  <%= alert(:class => 'alert-info', :id => 'multiple-alert', :close => false, :header => '', :text => @errors) %>
6
6
  <% end %>
7
7
 
8
+ <% if authorized_for(:permission => :edit_recurring_logics, :auth_object => @recurring_logics) %>
9
+ <% title_actions link_to(_('Clear Cancelled'),
10
+ clear_cancelled_foreman_tasks_recurring_logics_path,
11
+ class: ['btn', 'btn-sm', 'btn-danger'],
12
+ :'data-toggle' => "modal",
13
+ :'data-target' => "#clear_modal")
14
+ %>
15
+
16
+ <div class="modal fade" id="clear_modal" tabindex="-1" role="dialog" aria-labelledby="Deploy" aria-hidden="true">
17
+ <div class="modal-dialog">
18
+ <div class="modal-content">
19
+ <div class="modal-header">
20
+ <button type="button" class="close" data-dismiss="modal" aria-hidden="true">&times;</button>
21
+ <h2 class="modal-title" id="deploy_modal_label">
22
+ <span class="glyphicon glyphicon-warning-sign"></span>
23
+ <%= _("Clear Cancelled") %>
24
+ </h2>
25
+ </div>
26
+ <div class="modal-body">
27
+ <%= _("This action will delete all cancelled recurring logics. Please note that this action can't be reversed.") %>
28
+ </div>
29
+ <div class="modal-footer">
30
+ <button type="button" class="btn btn-default" data-dismiss="modal"><%= _("Cancel") %></button>
31
+ <%= link_to(_('Clear Cancelled'), clear_cancelled_foreman_tasks_recurring_logics_path, method: :post, class: 'btn btn-danger modal-submit') %>
32
+ </div>
33
+ </div>
34
+ </div>
35
+ </div>
36
+ <% end %>
37
+
8
38
  <table class="<%= table_css_classes('table-condensed table-fixed') %>">
9
39
  <thead>
10
40
  <th><%= N_("Cron line") %></th>
@@ -5,6 +5,9 @@
5
5
  <% content_for(:stylesheets) do %>
6
6
  <%= webpacked_plugins_css_for :'foreman-tasks' %>
7
7
  <% end %>
8
+
9
+ <% title _("Details of %s task") % @task.to_s %>
10
+
8
11
  <%= breadcrumbs(
9
12
  items: breadcrumb_items,
10
13
  name_field: 'action',
File without changes
@@ -6,6 +6,9 @@ Foreman::Application.routes.draw do
6
6
  put :enable
7
7
  put :disable
8
8
  end
9
+ collection do
10
+ post :clear_cancelled
11
+ end
9
12
  end
10
13
 
11
14
  resources :tasks, :only => [:show] do
@@ -39,6 +42,9 @@ Foreman::Application.routes.draw do
39
42
  member do
40
43
  post :cancel
41
44
  end
45
+ collection do
46
+ post :bulk_destroy
47
+ end
42
48
  end
43
49
 
44
50
  resources :tasks, :only => [:show, :index] do
@@ -49,6 +55,7 @@ Foreman::Application.routes.draw do
49
55
  collection do
50
56
  post :bulk_search
51
57
  post :bulk_resume
58
+ post :bulk_cancel
52
59
  get :summary
53
60
  get '/summary/:id/sub_tasks/', action: 'summary_sub_tasks'
54
61
  post :callback
@@ -0,0 +1,9 @@
1
+ class AddTaskLockIndexOnResourceTypeAndTaskId < ActiveRecord::Migration[5.2]
2
+ def change
3
+ add_index :foreman_tasks_locks, [:task_id, :resource_type, :resource_id], name: 'index_tasks_locks_on_task_id_resource_type_and_resource_id'
4
+ # These indexes are not needed as they can be gained from partial index lookups
5
+ [:task_id, :name, :resource_type].each do |index|
6
+ remove_index :foreman_tasks_locks, index if index_exists?(:foreman_tasks_locks, index)
7
+ end
8
+ end
9
+ end
@@ -27,6 +27,20 @@ blueprints = [
27
27
  title: N_('Task Details')
28
28
  ]
29
29
  }
30
+ },
31
+
32
+ {
33
+ group: N_('Tasks'),
34
+ name: 'tasks_bulk_resume',
35
+ level: 'info',
36
+ message: "DYNAMIC",
37
+ },
38
+
39
+ {
40
+ group: N_('Tasks'),
41
+ name: 'tasks_bulk_cancel',
42
+ level: 'info',
43
+ message: "DYNAMIC",
30
44
  }
31
45
  ]
32
46
 
@@ -1,6 +1,4 @@
1
- # -*- coding: utf-8 -*-
2
-
3
- $LOAD_PATH.push File.expand_path("../lib", __FILE__)
1
+ $LOAD_PATH.push File.expand_path('lib', __dir__)
4
2
 
5
3
  # Maintain your gem's version:
6
4
  require "foreman_tasks/version"
@@ -29,11 +27,12 @@ same resource. It also optionally provides Dynflow infrastructure for using it f
29
27
  s.test_files = `git ls-files test`.split("\n")
30
28
  s.extra_rdoc_files = Dir['README*', 'LICENSE']
31
29
 
32
- s.add_dependency "foreman-tasks-core"
33
30
  s.add_dependency "dynflow", '>= 1.2.3'
34
- s.add_dependency "sinatra" # for Dynflow web console
35
- s.add_dependency "parse-cron", '~> 0.1.4'
31
+ s.add_dependency "foreman-tasks-core"
36
32
  s.add_dependency "get_process_mem" # for memory polling
33
+ s.add_dependency "parse-cron", '~> 0.1.4'
34
+ s.add_dependency "sinatra" # for Dynflow web console
37
35
 
38
36
  s.add_development_dependency 'factory_bot_rails', '~> 4.8.0'
37
+ s.add_development_dependency 'sqlite3'
39
38
  end