foreman-tasks 5.2.2 → 6.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (62) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/ruby_tests.yml +7 -18
  3. data/.rubocop.yml +1 -0
  4. data/app/lib/actions/base.rb +1 -0
  5. data/app/lib/actions/foreman/host/import_facts.rb +1 -1
  6. data/app/lib/actions/helpers/lifecycle_logging.rb +1 -1
  7. data/app/lib/actions/middleware/rails_executor_wrap.rb +2 -2
  8. data/app/lib/actions/middleware/watch_delegated_proxy_sub_tasks.rb +18 -11
  9. data/app/lib/actions/proxy_action.rb +2 -2
  10. data/app/lib/actions/task_synchronization.rb +65 -0
  11. data/app/lib/actions/trigger_proxy_batch.rb +1 -1
  12. data/app/models/foreman_tasks/lock.rb +1 -1
  13. data/app/models/foreman_tasks/remote_task.rb +10 -3
  14. data/app/models/foreman_tasks/task/dynflow_task.rb +20 -21
  15. data/app/views/foreman_tasks/api/locks/show.json.rabl +4 -0
  16. data/config/routes.rb +1 -1
  17. data/db/migrate/20210708123832_add_parent_task_id_to_remote_tasks.foreman_tasks.rb +5 -0
  18. data/db/migrate/20211123170430_tasks_settings_to_dsl_category.rb +5 -0
  19. data/foreman-tasks.gemspec +1 -1
  20. data/lib/foreman_tasks/dynflow/configuration.rb +1 -6
  21. data/lib/foreman_tasks/dynflow.rb +1 -1
  22. data/lib/foreman_tasks/engine.rb +56 -9
  23. data/lib/foreman_tasks/test_helpers.rb +1 -1
  24. data/lib/foreman_tasks/version.rb +1 -1
  25. data/locale/action_names.rb +2 -3
  26. data/locale/en/foreman_tasks.po +27 -3
  27. data/locale/foreman_tasks.pot +230 -176
  28. data/locale/fr/foreman_tasks.po +27 -3
  29. data/locale/ja/foreman_tasks.po +27 -3
  30. data/locale/zh_CN/foreman_tasks.po +27 -3
  31. data/test/controllers/api/tasks_controller_test.rb +1 -2
  32. data/test/factories/task_factory.rb +1 -1
  33. data/test/lib/actions/middleware/keep_current_taxonomies_test.rb +9 -1
  34. data/test/support/dummy_dynflow_action.rb +1 -1
  35. data/test/support/dummy_proxy_action.rb +1 -1
  36. data/test/unit/actions/proxy_action_test.rb +19 -13
  37. data/test/unit/actions/trigger_proxy_batch_test.rb +0 -1
  38. data/test/unit/troubleshooting_help_generator_test.rb +0 -1
  39. data/test/unit/ui_notifications_test.rb +0 -1
  40. data/webpack/ForemanTasks/Components/TaskActions/TaskActionHelpers.js +1 -1
  41. data/webpack/ForemanTasks/Components/TaskActions/index.js +1 -1
  42. data/webpack/ForemanTasks/Components/TaskDetails/Components/Locks.js +28 -14
  43. data/webpack/ForemanTasks/Components/TaskDetails/Components/__tests__/__snapshots__/Locks.test.js.snap +50 -42
  44. data/webpack/ForemanTasks/Components/TaskDetails/TaskDetailsActions.js +1 -1
  45. data/webpack/ForemanTasks/Components/TasksTable/TasksBulkActions.js +1 -1
  46. data/webpack/ForemanTasks/Components/TasksTable/TasksTable.js +2 -28
  47. data/webpack/ForemanTasks/Components/TasksTable/TasksTablePage.js +5 -9
  48. data/webpack/ForemanTasks/Components/TasksTable/TasksTableReducer.js +1 -5
  49. data/webpack/ForemanTasks/Components/TasksTable/TasksTableSelectors.js +2 -2
  50. data/webpack/ForemanTasks/Components/TasksTable/__tests__/TasksTable.fixtures.js +1 -4
  51. data/webpack/ForemanTasks/Components/TasksTable/__tests__/__snapshots__/SubTasksPage.test.js.snap +1 -6
  52. data/webpack/ForemanTasks/Components/TasksTable/__tests__/__snapshots__/TasksIndexPage.test.js.snap +1 -6
  53. data/webpack/ForemanTasks/Components/TasksTable/__tests__/__snapshots__/TasksTable.test.js.snap +2 -22
  54. data/webpack/ForemanTasks/Components/TasksTable/__tests__/__snapshots__/TasksTablePage.test.js.snap +2 -12
  55. data/webpack/ForemanTasks/Components/TasksTable/__tests__/__snapshots__/TasksTableReducer.test.js.snap +1 -4
  56. data/webpack/ForemanTasks/Components/TasksTable/index.js +2 -2
  57. data/webpack/__mocks__/foremanReact/components/Pagination/index.js +2 -0
  58. data/webpack/__mocks__/foremanReact/{redux/actions/toasts.js → components/ToastsList/index.js} +0 -0
  59. metadata +8 -7
  60. data/app/models/setting/foreman_tasks.rb +0 -29
  61. data/lib/foreman_tasks/dynflow/persistence.rb +0 -46
  62. data/webpack/__mocks__/foremanReact/components/Pagination/PaginationWrapper.js +0 -2
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 882587333f9ebd555b6bd0ca6adf6c9e75789fce2e84cbbc2e3af0943cdf0051
4
- data.tar.gz: 1db069d66971fed8af95856a2d582b1320c02c48fddec68f9f9a1061abc6965c
3
+ metadata.gz: 7fe4afd0fbe9eaa5cb5587310ddddd1538453e733b48b6f927e6bc14fa4ad42e
4
+ data.tar.gz: 27591131ac0329e66625a15c4b512fa7a24b23b3623abdc1eaef40fee7bdea9a
5
5
  SHA512:
6
- metadata.gz: b204e43fe719216b44377fa0eb69654a404dfc7d53fbd5ed803efca3f5dd649d2dc901abd1b29b4048c1f99f7a37bd1b94c5c349ae9844e08ae95bd86a942b35
7
- data.tar.gz: 90c69b77188a55d8d993a6e098945448dce1ff720697def8ea1914ba2c03fe2ed7efec30b4a7e33224afa9b32d3b9f1c8eb4fd37cdee37566321e69d67d78b1a
6
+ metadata.gz: 042c221e1f3c01b2d38b2011165479282165846d9b46923b5ef7cc4fc8f91c3ab6ff5921bd229a4a26dbf661dccff3a9d0f0d474e11eb18b074880fc8fc25870
7
+ data.tar.gz: 4fdf7dfc1836bd8b4ea0490f8c7a894569c7ccf9eca811945b517f7aedface6b04c0c6bbe9c7f34a7b7bbea77328edaadd27ebb624bc29c4acae2eb86bc25624
@@ -4,6 +4,7 @@ env:
4
4
  RAILS_ENV: test
5
5
  DATABASE_URL: postgresql://postgres:@localhost/test
6
6
  DATABASE_CLEANER_ALLOW_REMOTE_DATABASE_URL: true
7
+ BUNDLE_WITHOUT: "journald:development:console:mysql2:sqlite:libvirt"
7
8
  jobs:
8
9
  rubocop:
9
10
  runs-on: ubuntu-latest
@@ -13,10 +14,7 @@ jobs:
13
14
  uses: ruby/setup-ruby@v1
14
15
  with:
15
16
  ruby-version: 2.7
16
- - name: Setup
17
- run: |
18
- gem install bundler
19
- bundle install --jobs=3 --retry=3
17
+ bundler-cache: true
20
18
  - name: Run rubocop
21
19
  run: bundle exec rubocop
22
20
  test_ruby:
@@ -43,30 +41,21 @@ jobs:
43
41
  - uses: actions/checkout@v2
44
42
  with:
45
43
  path: foreman-tasks
44
+ - name: Setup Plugin in Foreman
45
+ run: |
46
+ echo "gem 'foreman-tasks', path: './foreman-tasks'" > bundler.d/foreman-tasks.local.rb
47
+ echo "gem 'sqlite3'" >> bundler.d/foreman-tasks.local.rb
46
48
  - name: Setup Ruby
47
49
  uses: ruby/setup-ruby@v1
48
50
  with:
49
51
  ruby-version: ${{ matrix.ruby-version }}
52
+ bundler-cache: true
50
53
  - name: Setup Node
51
54
  uses: actions/setup-node@v1
52
55
  with:
53
56
  node-version: ${{ matrix.node-version }}
54
- - uses: actions/cache@v2
55
- with:
56
- path: vendor/bundle
57
- key: ${{ runner.os }}-fgems-${{ matrix.ruby-version }}-${{ hashFiles('Gemfile.lock') }}
58
- restore-keys: |
59
- ${{ runner.os }}-fgems-${{ matrix.ruby-version }}-
60
- - name: Setup Bundler
61
- run: |
62
- echo "gem 'foreman-tasks', path: './foreman-tasks'" > bundler.d/foreman-tasks.local.rb
63
- echo "gem 'sqlite3'" >> bundler.d/foreman-tasks.local.rb
64
- gem install bundler
65
- bundle config set without journald development console libvirt
66
- bundle config set path vendor/bundle
67
57
  - name: Prepare test env
68
58
  run: |
69
- bundle install --jobs=3 --retry=3
70
59
  bundle exec rake db:create
71
60
  bundle exec rake db:migrate
72
61
  - name: Run plugin tests
data/.rubocop.yml CHANGED
@@ -9,6 +9,7 @@ AllCops:
9
9
  Exclude:
10
10
  - 'node_modules/**/*'
11
11
  - 'locale/*'
12
+ - 'vendor/**/*'
12
13
  TargetRubyVersion: 2.5
13
14
 
14
15
  Lint/ShadowingOuterLocalVariable:
@@ -2,6 +2,7 @@ module Actions
2
2
  class Base < Dynflow::Action
3
3
  middleware.use ::Actions::Middleware::RailsExecutorWrap
4
4
  include Actions::Helpers::LifecycleLogging
5
+ include Actions::TaskSynchronization
5
6
 
6
7
  execution_plan_hooks.use :notify_paused, :on => [:paused]
7
8
 
@@ -26,7 +26,7 @@ module Actions
26
26
  def run
27
27
  ::User.as :admin do
28
28
  host = ::Host.find(input[:host][:id])
29
- state = host.import_facts(input[:facts], proxy)
29
+ state = ::HostFactImporter.new(host).import_facts(input[:facts], proxy)
30
30
  output[:state] = state
31
31
  end
32
32
  rescue ::Foreman::Exception => e
@@ -7,7 +7,7 @@ module Actions
7
7
 
8
8
  def log_task_state_change(execution_plan)
9
9
  return unless root_action?
10
- logger = Rails.application.dynflow.world.action_logger
10
+ logger = ::Rails.application.dynflow.world.action_logger
11
11
  task_id = ForemanTasks::Task::DynflowTask.where(external_id: execution_plan.id).pluck(:id).first
12
12
 
13
13
  task_id_parts = []
@@ -10,13 +10,13 @@ module Actions
10
10
  # for more details.
11
11
  class RailsExecutorWrap < Dynflow::Middleware
12
12
  def run(*args)
13
- Rails.application.executor.wrap do
13
+ ::Rails.application.executor.wrap do
14
14
  pass(*args)
15
15
  end
16
16
  end
17
17
 
18
18
  def finalize
19
- Rails.application.executor.wrap do
19
+ ::Rails.application.executor.wrap do
20
20
  pass
21
21
  end
22
22
  end
@@ -26,17 +26,26 @@ module Actions
26
26
  def check_triggered
27
27
  in_remote_task_batches(remote_tasks.triggered) do |batch|
28
28
  batch.group_by(&:proxy_url).each do |(url, tasks)|
29
- tasks = poll_proxy_tasks(url, tasks).flatten
30
- process_task_results tasks
29
+ results = poll_proxy_tasks(url, tasks)
30
+ process_task_results tasks, results
31
31
  end
32
32
  end
33
33
  end
34
34
 
35
- def process_task_results(tasks)
36
- missing, present = tasks.partition { |task| task.result.nil? }
35
+ def process_task_results(tasks, results)
36
+ possibly_missing, present = tasks.partition { |task| !results.key?(task.remote_task_id) }
37
+ missing = possibly_missing.select do |task|
38
+ # Really missing are tasks which are missing and:
39
+ # don't have a remote parent
40
+ # had a remote parent but the proxy doesn't have the remote parent anymore
41
+ # has a remote parent, proxy has the remote parent but it is stopped or paused
42
+ task.parent_task_id.nil? ||
43
+ !results.key?(task.parent_task_id) ||
44
+ %(stopped paused).include?(results[task.parent_task_id]['state'])
45
+ end
37
46
  notify ::Actions::ProxyAction::ProxyActionMissing.new, missing if missing.any?
38
47
 
39
- stopped = present.select { |task| %w[stopped paused].include? task.result['state'] }
48
+ stopped = present.select { |task| %w[stopped paused].include? results.dig(task.remote_task_id, 'state') }
40
49
  notify ::Actions::ProxyAction::ProxyActionStopped.new, stopped if stopped.any?
41
50
  end
42
51
 
@@ -52,15 +61,13 @@ module Actions
52
61
 
53
62
  def poll_proxy_tasks(url, tasks)
54
63
  proxy = ProxyAPI::ForemanDynflow::DynflowProxy.new(:url => url)
55
- results = proxy.task_states(tasks.map(&:remote_task_id))
56
- tasks.map do |task|
57
- task.result = results[task.remote_task_id]
58
- task
59
- end
64
+ # Get statuses of tasks and their optional parent tasks
65
+ ids = (tasks.map(&:remote_task_id) + tasks.map(&:parent_task_id)).uniq
66
+ proxy.task_states(ids)
60
67
  rescue => e
61
68
  # We could not reach the remote task, we'll try again next time
62
69
  action.action_logger.warn(_('Failed to check on tasks on proxy at %{url}: %{exception}') % { :url => url, :exception => e.message })
63
- []
70
+ {}
64
71
  end
65
72
 
66
73
  def in_remote_task_batches(scope)
@@ -67,7 +67,7 @@ module Actions
67
67
  def trigger_proxy_task
68
68
  suspend do |_suspended_action|
69
69
  remote_task = prepare_remote_task
70
- remote_task.trigger(proxy_action_name, proxy_input)
70
+ ForemanTasks::RemoteTask.batch_trigger(remote_task.operation, [remote_task])
71
71
  output[:proxy_task_id] = remote_task.remote_task_id
72
72
  end
73
73
  end
@@ -263,7 +263,7 @@ module Actions
263
263
  end
264
264
 
265
265
  def proxy_task_id
266
- output[:proxy_task_id] ||= remote_task.try(:remote_task_id)
266
+ output[:proxy_task_id] || remote_task.try(:remote_task_id) || @execution_plan_id
267
267
  end
268
268
  end
269
269
  end
@@ -0,0 +1,65 @@
1
+ module Actions
2
+ # Examples:
3
+
4
+ # # Action A which emits an event when it successfully finishes.
5
+ # class A
6
+ # include ::Actions::ObservableAction
7
+ # # ... rest ...
8
+ # end
9
+
10
+ # # Action B which emits an event when it successfully finishes or fails.
11
+ # class B
12
+ # include ::Actions::ObservableAction
13
+ #
14
+ # execution_plan_hooks.use :emit_event_failure, :on => [:failure]
15
+ #
16
+ # def self.event_names
17
+ # super + [event_name_base + '_' + event_name_suffix(:failure)]
18
+ # end
19
+ #
20
+ # def emit_event_failure(plan)
21
+ # emit_event(plan, :failure)
22
+ # end
23
+ # # ... rest ...
24
+ # end
25
+ module TaskSynchronization
26
+ def self.included(base)
27
+ base.execution_plan_hooks.use :sync_execution_plan_to_task, on: ::Dynflow::ExecutionPlan.states
28
+ end
29
+
30
+ def sync_execution_plan_to_task(plan)
31
+ return unless root_action?
32
+ on_execution_plan_save(plan)
33
+ rescue => e
34
+ ::Foreman::Logging.exception('Error on on_execution_plan_save event', e,
35
+ :logger => 'dynflow')
36
+ end
37
+
38
+ private
39
+
40
+ def on_execution_plan_save(execution_plan)
41
+ # We can load the data unless the execution plan was properly planned and saved
42
+ # including its steps
43
+ case execution_plan.state
44
+ when :pending
45
+ task = ForemanTasks::Task::DynflowTask.new_for_execution_plan(execution_plan)
46
+ task.start_at ||= Time.zone.now
47
+ task.save!
48
+ when :scheduled
49
+ delayed_plan = world.persistence.load_delayed_plan(execution_plan.id)
50
+ raise ::Foreman::Exception, 'Plan is delayed but the delay record is missing' if delayed_plan.nil?
51
+ task = ::ForemanTasks::Task::DynflowTask.find_by!(:external_id => execution_plan.id)
52
+ task.update_from_dynflow(execution_plan, delayed_plan)
53
+ when :planning
54
+ task = ::ForemanTasks::Task::DynflowTask.where(:external_id => execution_plan.id).first
55
+ task.update_from_dynflow(execution_plan)
56
+ else
57
+ if (task = ::ForemanTasks::Task::DynflowTask.where(:external_id => execution_plan.id).first)
58
+ unless task.state.to_s == execution_plan.state.to_s
59
+ task.update_from_dynflow(execution_plan)
60
+ end
61
+ end
62
+ end
63
+ end
64
+ end
65
+ end
@@ -37,8 +37,8 @@ module Actions
37
37
  # Group the tasks by operation, in theory there should be only one operation
38
38
  batch.group_by(&:operation).each do |operation, group|
39
39
  ForemanTasks::RemoteTask.batch_trigger(operation, group)
40
+ output[:planned_count] += group.size
40
41
  end
41
- output[:planned_count] += batch.size
42
42
  rescue => e
43
43
  action_logger.warn "Could not trigger task on the smart proxy"
44
44
  action_logger.warn e
@@ -9,7 +9,7 @@ module ForemanTasks
9
9
  |
10
10
  | #{_('Conflicts with tasks:')}
11
11
  HEADER
12
- url_helpers = Rails.application.routes.url_helpers
12
+ url_helpers = ::Rails.application.routes.url_helpers
13
13
  conflicting_tasks = conflicting_locks
14
14
  .map(&:task)
15
15
  .uniq
@@ -33,20 +33,27 @@ module ForemanTasks
33
33
  :action_class => remote_task.proxy_action_name })
34
34
  end
35
35
  results = group.first.proxy.launch_tasks(operation, input_hash)
36
- group.each { |remote_task| remote_task.update_from_batch_trigger results[remote_task.execution_plan_id] }
36
+ group.each do |remote_task|
37
+ remote_task.update_from_batch_trigger results.fetch(remote_task.execution_plan_id, {}),
38
+ results.fetch('parent', {})
39
+ end
37
40
  end
38
41
  remote_tasks
39
42
  end
40
43
 
41
- def update_from_batch_trigger(data)
44
+ def update_from_batch_trigger(data, parent = {})
42
45
  if data['result'] == 'success'
43
46
  self.remote_task_id = data['task_id']
44
47
  self.state = 'triggered'
48
+ elsif !parent.empty?
49
+ self.parent_task_id = parent['task_id']
50
+ self.state = 'parent-triggered'
45
51
  else
46
52
  # Tell the action the task on the smart proxy stopped
47
53
  ForemanTasks.dynflow.world.event execution_plan_id,
48
54
  step_id,
49
- ::Actions::ProxyAction::ProxyActionStopped.new
55
+ ::Actions::ProxyAction::ProxyActionStopped.new,
56
+ optional: true
50
57
  end
51
58
  save!
52
59
  end
@@ -5,15 +5,14 @@ module ForemanTasks
5
5
  scope :for_action, ->(action_class) { where(label: action_class.name) }
6
6
  after_validation :set_action_field
7
7
 
8
- def update_from_dynflow(data)
9
- utc_zone = ActiveSupport::TimeZone.new('UTC')
10
- self.external_id = data[:id]
11
- self.result = map_result(data).to_s
12
- self.state = data[:state].to_s
13
- self.started_at = string_to_time(utc_zone, data[:started_at]) unless data[:started_at].nil?
14
- self.ended_at = string_to_time(utc_zone, data[:ended_at]) unless data[:ended_at].nil?
15
- self.start_at = string_to_time(utc_zone, data[:start_at]) if data[:start_at]
16
- self.start_before = string_to_time(utc_zone, data[:start_before]) if data[:start_before]
8
+ def update_from_dynflow(plan, delayed_plan = nil)
9
+ self.external_id = plan.id
10
+ self.result = map_result(plan).to_s
11
+ self.state = plan.state.to_s
12
+ self.started_at = plan.started_at unless plan.started_at.nil?
13
+ self.ended_at = plan.ended_at unless plan.ended_at.nil?
14
+ self.start_at = delayed_plan.start_at if delayed_plan
15
+ self.start_before = delayed_plan.start_before if delayed_plan
17
16
  self.parent_task_id ||= begin
18
17
  if main_action.try(:caller_execution_plan_id)
19
18
  DynflowTask.where(:external_id => main_action.caller_execution_plan_id).first!.id
@@ -221,7 +220,7 @@ module ForemanTasks
221
220
  fixed_count = 0
222
221
  logger = Foreman::Logging.logger('foreman-tasks')
223
222
  running.each do |task|
224
- changes = task.update_from_dynflow(task.execution_plan.to_hash)
223
+ changes = task.update_from_dynflow(task.execution_plan)
225
224
  unless changes.empty?
226
225
  fixed_count += 1
227
226
  logger.warn('Task %s updated at consistency check: %s' % [task.id, changes.inspect])
@@ -236,10 +235,10 @@ module ForemanTasks
236
235
  fixed_count
237
236
  end
238
237
 
239
- def self.new_for_execution_plan(execution_plan_id, data)
240
- new(:external_id => execution_plan_id,
241
- :state => data[:state].to_s,
242
- :result => data[:result].to_s,
238
+ def self.new_for_execution_plan(execution_plan)
239
+ new(:external_id => execution_plan.id,
240
+ :state => execution_plan.state.to_s,
241
+ :result => execution_plan.result.to_s,
243
242
  :user_id => User.current.try(:id))
244
243
  end
245
244
 
@@ -258,20 +257,20 @@ module ForemanTasks
258
257
  self.action = to_label
259
258
  end
260
259
 
261
- def map_result(data)
262
- if state_result_transitioned?(%w[planned pending], %w[stopped error], data) ||
263
- (data[:result] == :error && cancelled?)
260
+ def map_result(plan)
261
+ if state_result_transitioned?(%w[planned pending], %w[stopped error], plan) ||
262
+ (plan.result == :error && cancelled?)
264
263
  :cancelled
265
264
  else
266
- data[:result]
265
+ plan.result
267
266
  end
268
267
  end
269
268
 
270
- def state_result_transitioned?(from, to, data)
269
+ def state_result_transitioned?(from, to, plan)
271
270
  oldstate, oldresult = from
272
271
  newstate, newresult = to
273
- state == oldstate && data[:state].to_s == newstate &&
274
- result == oldresult && data[:result].to_s == newresult
272
+ state == oldstate && plan.state.to_s == newstate &&
273
+ result == oldresult && plan.result.to_s == newresult
275
274
  end
276
275
 
277
276
  def cancelled?
@@ -2,3 +2,7 @@ object @lock
2
2
 
3
3
  attributes :name, :resource_type, :resource_id
4
4
  node(:exclusive) { !locals[:link] }
5
+ node(:link) do
6
+ method = "#{@object.resource_type.underscore.split('/').first}_path".to_sym
7
+ public_send(method, @object.resource_id) if defined?(method)
8
+ end
data/config/routes.rb CHANGED
@@ -70,7 +70,7 @@ Foreman::Application.routes.draw do
70
70
  mount ForemanTasks.dynflow.web_console => '/dynflow'
71
71
  if defined? ::Sidekiq
72
72
  require 'sidekiq/web'
73
- redis_url = SETTINGS.dig(:dynflow, :redis_url)
73
+ redis_url = ENV['DYNFLOW_REDIS_URL'] || SETTINGS.dig(:dynflow, :redis_url)
74
74
  Sidekiq.redis = { url: redis_url }
75
75
  Sidekiq::Web.set :sessions, false
76
76
  mount Sidekiq::Web => '/sidekiq', :constraints => ForemanTasks::Dynflow::SidekiqConsoleConstraint.new
@@ -0,0 +1,5 @@
1
+ class AddParentTaskIdToRemoteTasks < ActiveRecord::Migration[5.0]
2
+ def change
3
+ add_column :foreman_tasks_remote_tasks, :parent_task_id, :string
4
+ end
5
+ end
@@ -0,0 +1,5 @@
1
+ class TasksSettingsToDslCategory < ActiveRecord::Migration[6.0]
2
+ def up
3
+ Setting.where(category: 'Setting::ForemanTasks').update_all(category: 'Setting')
4
+ end
5
+ end
@@ -26,7 +26,7 @@ same resource. It also optionally provides Dynflow infrastructure for using it f
26
26
  s.test_files = `git ls-files test`.split("\n")
27
27
  s.extra_rdoc_files = Dir['README*', 'LICENSE']
28
28
 
29
- s.add_dependency "dynflow", '>= 1.2.3'
29
+ s.add_dependency "dynflow", '>= 1.6.0'
30
30
  s.add_dependency "get_process_mem" # for memory polling
31
31
  s.add_dependency "parse-cron", '~> 0.1.4'
32
32
  s.add_dependency "sinatra" # for Dynflow web console
@@ -1,5 +1,4 @@
1
- require File.expand_path('lib/foreman/dynflow/configuration', Rails.root)
2
- require 'foreman_tasks/dynflow/persistence'
1
+ require File.expand_path('lib/foreman/dynflow/configuration', ::Rails.root)
3
2
 
4
3
  module ForemanTasks
5
4
  # Import all Dynflow configuration from Foreman, and add our own for Tasks
@@ -34,9 +33,5 @@ module ForemanTasks
34
33
  end
35
34
  options
36
35
  end
37
-
38
- def persistence_class
39
- ForemanTasks::Dynflow::Persistence
40
- end
41
36
  end
42
37
  end
@@ -17,7 +17,7 @@ module ForemanTasks
17
17
  set(:custom_navigation) do
18
18
  { _('Back to tasks') => "/#{ForemanTasks::TasksController.controller_path}" }
19
19
  end
20
- set(:world) { Rails.application.dynflow.world }
20
+ set(:world) { ::Rails.application.dynflow.world }
21
21
  end
22
22
  end
23
23
  end
@@ -5,14 +5,6 @@ module ForemanTasks
5
5
  class Engine < ::Rails::Engine
6
6
  engine_name 'foreman_tasks'
7
7
 
8
- initializer 'foreman_tasks.load_default_settings', :before => :load_config_initializers do
9
- require_dependency File.expand_path('../../app/models/setting/foreman_tasks.rb', __dir__) if begin
10
- Setting.table_exists?
11
- rescue
12
- false
13
- end
14
- end
15
-
16
8
  assets_to_precompile = %w[foreman_tasks/foreman_tasks.css
17
9
  foreman_tasks/foreman_tasks.js]
18
10
 
@@ -33,7 +25,7 @@ module ForemanTasks
33
25
 
34
26
  initializer 'foreman_tasks.register_plugin', :before => :finisher_hook do |_app|
35
27
  Foreman::Plugin.register :"foreman-tasks" do
36
- requires_foreman '>= 2.6.0'
28
+ requires_foreman '>= 3.2.0'
37
29
  divider :top_menu, :parent => :monitor_menu, :last => true, :caption => N_('Foreman Tasks')
38
30
  menu :top_menu, :tasks,
39
31
  :url_hash => { :controller => 'foreman_tasks/tasks', :action => :index },
@@ -65,6 +57,60 @@ module ForemanTasks
65
57
 
66
58
  add_all_permissions_to_default_roles
67
59
 
60
+ settings do
61
+ category(:tasks, N_('Tasks')) do
62
+ setting('foreman_tasks_sync_task_timeout',
63
+ type: :integer,
64
+ description: N_('Number of seconds to wait for synchronous task to finish.'),
65
+ default: 120,
66
+ full_name: N_('Sync task timeout'))
67
+ setting('dynflow_enable_console',
68
+ type: :boolean,
69
+ description: N_('Enable the dynflow console (/foreman_tasks/dynflow) for debugging'),
70
+ default: true,
71
+ full_name: N_('Enable dynflow console'))
72
+ setting('dynflow_console_require_auth',
73
+ type: :boolean,
74
+ description: N_('Require user to be authenticated as user with admin rights when accessing dynflow console'),
75
+ default: true,
76
+ full_name: N_('Require auth for dynflow console'))
77
+ setting('foreman_tasks_proxy_action_retry_count',
78
+ type: :integer,
79
+ description: N_('Number of attempts to start a task on the smart proxy before failing'),
80
+ default: 4,
81
+ full_name: N_('Proxy action retry count'))
82
+ setting('foreman_tasks_proxy_action_retry_interval',
83
+ type: :integer,
84
+ description: N_('Time in seconds between retries'),
85
+ default: 15,
86
+ full_name: N_('Proxy action retry interval'))
87
+ setting('foreman_tasks_proxy_batch_trigger',
88
+ type: :boolean,
89
+ description: N_('Allow triggering tasks on the smart proxy in batches'),
90
+ default: true,
91
+ full_name: N_('Allow proxy batch tasks'))
92
+ setting('foreman_tasks_proxy_batch_size',
93
+ type: :integer,
94
+ description: N_('Number of tasks which should be sent to the smart proxy in one request, if foreman_tasks_proxy_batch_trigger is enabled'),
95
+ default: 100,
96
+ full_name: N_('Proxy tasks batch size'))
97
+ setting('foreman_tasks_troubleshooting_url',
98
+ type: :string,
99
+ description: N_('Url pointing to the task troubleshooting documentation. '\
100
+ 'It should contain %{label} placeholder, that will be replaced with normalized task label '\
101
+ '(restricted to only alphanumeric characters)). %{version} placeholder is also available.'),
102
+ default: nil,
103
+ full_name: N_('Tasks troubleshooting URL'))
104
+ setting('foreman_tasks_polling_multiplier',
105
+ type: :integer,
106
+ description: N_('Polling multiplier which is used to multiply the default polling intervals. '\
107
+ 'This can be used to prevent polling too frequently for long running tasks.'),
108
+ default: 1,
109
+ full_name: N_("Polling intervals multiplier"),
110
+ validate: { numericality: { greater_than: 0 } })
111
+ end
112
+ end
113
+
68
114
  register_graphql_query_field :task, '::Types::Task', :record_field
69
115
  register_graphql_query_field :tasks, '::Types::Task', :collection_field
70
116
  register_graphql_query_field :recurring_logic, '::Types::RecurringLogic', :record_field
@@ -138,6 +184,7 @@ module ForemanTasks
138
184
  Authorizer.prepend AuthorizerExt
139
185
  User.include ForemanTasks::Concerns::UserExtensions
140
186
  ::Dynflow::Action::Polling.prepend ForemanTasks::Concerns::PollingActionExtensions
187
+ ::Dynflow::ActiveJob::QueueAdapters::JobWrapper.include Actions::TaskSynchronization
141
188
  end
142
189
 
143
190
  rake_tasks do
@@ -11,7 +11,7 @@ module ForemanTasks
11
11
  world_config = ForemanTasks.dynflow.config.world_config
12
12
  if @use_in_memory_sqlite
13
13
  world_config.persistence_adapter = lambda do |*_args|
14
- ::ForemanTasks::Dynflow::Persistence.new('adapter' => 'sqlite', 'database' => ':memory:')
14
+ ::Dynflow::PersistenceAdapters::Sequel.new('adapter' => 'sqlite', 'database' => ':memory:')
15
15
  end
16
16
  end
17
17
  @test_in_thread_world = ::Dynflow::Testing::InThreadWorld.new(world_config)
@@ -1,3 +1,3 @@
1
1
  module ForemanTasks
2
- VERSION = '5.2.2'.freeze
2
+ VERSION = '6.0.1'.freeze
3
3
  end
@@ -1,6 +1,5 @@
1
1
  # Autogenerated!
2
- _("Preupgrade job")
3
- _("Remote action:")
4
2
  _("Import Puppet classes")
5
3
  _("Import facts")
6
- _("Action with sub plans")
4
+ _("Action with sub plans")
5
+ _("Remote action:")