foreman-tasks 5.2.2 → 6.0.1

Sign up to get free protection for your applications and to get access to all the features.
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:")