foreman-tasks 7.0.0 → 7.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (43) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/js_tests.yml +3 -1
  3. data/.github/workflows/ruby_tests.yml +1 -1
  4. data/app/lib/actions/foreman/host/import_facts.rb +1 -6
  5. data/app/lib/actions/helpers/with_delegated_action.rb +2 -2
  6. data/app/lib/actions/proxy_action.rb +19 -5
  7. data/app/lib/actions/trigger_proxy_batch.rb +4 -1
  8. data/app/models/foreman_tasks/remote_task.rb +3 -2
  9. data/app/models/foreman_tasks/task/dynflow_task.rb +10 -5
  10. data/app/views/foreman_tasks/recurring_logics/index.html.erb +11 -11
  11. data/app/views/foreman_tasks/task_groups/_common.html.erb +2 -2
  12. data/app/views/foreman_tasks/task_groups/recurring_logic_task_groups/_recurring_logic_task_group.html.erb +11 -11
  13. data/lib/foreman_tasks/cleaner.rb +1 -1
  14. data/lib/foreman_tasks/dynflow/configuration.rb +1 -1
  15. data/lib/foreman_tasks/engine.rb +4 -1
  16. data/lib/foreman_tasks/version.rb +1 -1
  17. data/lib/tasks/gettext.rake +1 -0
  18. data/locale/action_names.rb +2 -3
  19. data/locale/de/LC_MESSAGES/foreman_tasks.mo +0 -0
  20. data/locale/de/foreman_tasks.po +873 -0
  21. data/locale/en/LC_MESSAGES/foreman_tasks.mo +0 -0
  22. data/locale/en/foreman_tasks.po +4 -7
  23. data/locale/es/LC_MESSAGES/foreman_tasks.mo +0 -0
  24. data/locale/es/foreman_tasks.po +874 -0
  25. data/locale/foreman_tasks.pot +20 -25
  26. data/locale/fr/LC_MESSAGES/foreman_tasks.mo +0 -0
  27. data/locale/fr/foreman_tasks.po +71 -72
  28. data/locale/ja/LC_MESSAGES/foreman_tasks.mo +0 -0
  29. data/locale/ja/foreman_tasks.po +70 -74
  30. data/locale/ka/LC_MESSAGES/foreman_tasks.mo +0 -0
  31. data/locale/ka/foreman_tasks.po +871 -0
  32. data/locale/ko/LC_MESSAGES/foreman_tasks.mo +0 -0
  33. data/locale/ko/foreman_tasks.po +869 -0
  34. data/locale/pt_BR/LC_MESSAGES/foreman_tasks.mo +0 -0
  35. data/locale/pt_BR/foreman_tasks.po +874 -0
  36. data/locale/ru/LC_MESSAGES/foreman_tasks.mo +0 -0
  37. data/locale/ru/foreman_tasks.po +873 -0
  38. data/locale/zh_CN/LC_MESSAGES/foreman_tasks.mo +0 -0
  39. data/locale/zh_CN/foreman_tasks.po +157 -161
  40. data/locale/zh_TW/LC_MESSAGES/foreman_tasks.mo +0 -0
  41. data/locale/zh_TW/foreman_tasks.po +870 -0
  42. data/test/unit/task_test.rb +5 -8
  43. metadata +17 -3
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 1c6773ac47a0c5b8e3e28da1461a348510e8595da0bd2d08feafd78092394fb2
4
- data.tar.gz: 40d4c506cd3d31b72355e8c2d4255c854c703be6be49644b8d30a55032bd9b2b
3
+ metadata.gz: c5d611523d1262879b33177bf9c1f4c394142fee8433c2fda798cb4063b60f99
4
+ data.tar.gz: 1e7974c6fde725d0fe46dcffd6793c7f4b078c3c6e2e3429dce42180e61e4044
5
5
  SHA512:
6
- metadata.gz: 1d05cdb24aea11a647028a4b1c314cf5f0db3d95459bbcfa0c52aa8f53263b6deb3d27ee23bbb7ec2a227e1ebbead0a432c0ecf6701131b2f7921b39145085ab
7
- data.tar.gz: 777127d69a84b7c94780f78ad5a8aa5754ad246e6019a9f35c518e0b246d73b8f6f31acc84029b1b0648b8ff3ba8f167efc4fad7f4116cb4eb2f3fad7b850591
6
+ metadata.gz: 6f358b767cf2c8f2f6d31a43aa6c1fca27a6db053311d4540cea15d11c7c76758db192d5b39ecef17fcfc9d89e9e99a233c6b3d14fadd41efcca709aea37704b
7
+ data.tar.gz: 9c08bf19e2f8bdc05add76a9b8e9b783407b03ba99f0c47325454468a4654e44296f8dafd87e40a5d58ed771edb58900c0ac41738202efce5043193b5580a50c
@@ -12,7 +12,9 @@ jobs:
12
12
  strategy:
13
13
  fail-fast: false
14
14
  matrix:
15
- node-version: [10, 12]
15
+ node-version:
16
+ - 12
17
+ - 14
16
18
  steps:
17
19
  - uses: actions/checkout@v2
18
20
  - name: Setup Node
@@ -29,7 +29,7 @@ jobs:
29
29
  fail-fast: false
30
30
  matrix:
31
31
  foreman-core-branch: [develop]
32
- ruby-version: [2.5, 2.6, 2.7]
32
+ ruby-version: [2.7]
33
33
  node-version: [12]
34
34
  steps:
35
35
  - run: sudo apt-get update
@@ -8,12 +8,7 @@ module Actions
8
8
 
9
9
  def plan(_host_type, host_name, facts, certname, proxy_id)
10
10
  facts['domain'].try(:downcase!)
11
- host = if SETTINGS[:version].short > '1.16'
12
- ::Host::Managed.import_host(host_name, certname)
13
- else
14
- # backwards compatibility
15
- ::Host::Managed.import_host(host_name, facts['_type'], certname, proxy_id)
16
- end
11
+ host = ::Host::Managed.import_host(host_name, certname)
17
12
  host.save(:validate => false) if host.new_record?
18
13
  action_subject(host, :facts => facts.to_unsafe_h, :proxy_id => proxy_id)
19
14
  if host.build?
@@ -3,7 +3,7 @@ module Actions
3
3
  module WithDelegatedAction
4
4
  include ::Actions::Helpers::WithContinuousOutput
5
5
 
6
- def plan_delegated_action(proxy, klass, options)
6
+ def plan_delegated_action(proxy, klass, options, proxy_action_class: ::Actions::ProxyAction)
7
7
  case proxy
8
8
  when :not_defined
9
9
  if klass.is_a?(String)
@@ -14,7 +14,7 @@ module Actions
14
14
  when :not_available
15
15
  raise Foreman::Exception, _('All proxies with the required feature are unavailable at the moment')
16
16
  when ::SmartProxy
17
- delegated_action = plan_action(::Actions::ProxyAction, proxy, klass, options)
17
+ delegated_action = plan_action(proxy_action_class, proxy, klass, options)
18
18
  end
19
19
 
20
20
  input[:delegated_action_id] = delegated_action.id
@@ -22,7 +22,15 @@ module Actions
22
22
  end
23
23
  end
24
24
 
25
- class ProxyActionStopped; end
25
+ class ProxyActionStopped < RuntimeError
26
+ def backtrace
27
+ []
28
+ end
29
+ end
30
+
31
+ ProxyActionStoppedEvent = ::Algebrick.type do
32
+ fields! exception: type { variants NilClass, Exception }
33
+ end
26
34
 
27
35
  def plan(proxy, klass, options)
28
36
  options[:connection_options] ||= {}
@@ -52,8 +60,8 @@ module Actions
52
60
  on_data(event.data, event.meta)
53
61
  when ProxyActionMissing
54
62
  on_proxy_action_missing
55
- when ProxyActionStopped
56
- on_proxy_action_stopped
63
+ when ProxyActionStoppedEvent
64
+ on_proxy_action_stopped(event)
57
65
  else
58
66
  raise "Unexpected event #{event.inspect}"
59
67
  end
@@ -94,6 +102,8 @@ module Actions
94
102
  else
95
103
  suspend
96
104
  end
105
+ rescue RestClient::NotFound
106
+ on_proxy_action_missing
97
107
  end
98
108
 
99
109
  def cancel_proxy_task
@@ -133,8 +143,12 @@ module Actions
133
143
  error! ProxyActionMissing.new(_('Proxy task gone missing from the smart proxy'))
134
144
  end
135
145
 
136
- def on_proxy_action_stopped
137
- check_task_status
146
+ def on_proxy_action_stopped(event)
147
+ if event.exception
148
+ error! ProxyActionStopped.new(_('Failed to trigger task on the smart proxy: ') + event.exception.message)
149
+ else
150
+ check_task_status
151
+ end
138
152
  end
139
153
 
140
154
  # @override String name of an action to be triggered on server
@@ -42,7 +42,10 @@ module Actions
42
42
  rescue => e
43
43
  action_logger.warn "Could not trigger task on the smart proxy"
44
44
  action_logger.warn e
45
- batch.each { |remote_task| remote_task.update_from_batch_trigger({}) }
45
+ # The response contains non-serializable objects
46
+ # TypeError: no _dump_data is defined for class Monitor
47
+ e.response = nil
48
+ batch.each { |remote_task| remote_task.update_from_batch_trigger({ 'exception' => e }) }
46
49
  output[:failed_count] += batch.size
47
50
  end
48
51
 
@@ -7,7 +7,7 @@ module ForemanTasks
7
7
  :foreign_key => :execution_plan_id,
8
8
  :inverse_of => :remote_tasks
9
9
 
10
- scope :triggered, -> { where(:state => 'triggered') }
10
+ scope :triggered, -> { where(:state => ['triggered', 'parent-triggered']) }
11
11
  scope :pending, -> { where(:state => 'new') }
12
12
  scope :external, -> { where(:state => 'external') }
13
13
 
@@ -49,10 +49,11 @@ module ForemanTasks
49
49
  self.parent_task_id = parent['task_id']
50
50
  self.state = 'parent-triggered'
51
51
  else
52
+ exception = data['exception']
52
53
  # Tell the action the task on the smart proxy stopped
53
54
  ForemanTasks.dynflow.world.event execution_plan_id,
54
55
  step_id,
55
- ::Actions::ProxyAction::ProxyActionStopped.new,
56
+ ::Actions::ProxyAction::ProxyActionStoppedEvent[exception],
56
57
  optional: true
57
58
  end
58
59
  save!
@@ -219,19 +219,24 @@ module ForemanTasks
219
219
  def self.consistency_check
220
220
  fixed_count = 0
221
221
  logger = Foreman::Logging.logger('foreman-tasks')
222
- running.each do |task|
223
- changes = task.update_from_dynflow(task.execution_plan)
222
+
223
+ # Dynflow execution plans which are not stopped at this point should
224
+ # eventually get moving and their tasks should eventually get back in sync
225
+ # as the execution plans run
226
+ joins('LEFT JOIN dynflow_execution_plans ON foreman_tasks_tasks.external_id = dynflow_execution_plans.uuid::varchar')
227
+ .where('foreman_tasks_tasks.state_updated_at < dynflow_execution_plans.ended_at')
228
+ .find_each do |task|
229
+ changes = task.update_from_dynflow(task.execution_plan.to_hash)
224
230
  unless changes.empty?
225
231
  fixed_count += 1
226
232
  logger.warn('Task %s updated at consistency check: %s' % [task.id, changes.inspect])
227
233
  end
228
234
  rescue => e
229
- # if we fail updating the data from dynflow, it usually means there is something
230
- # odd with the data consistency and at this point it is not possible to resume, switching
231
- # the task to stopped/error
232
235
  task.update(:state => 'stopped', :result => 'error')
233
236
  Foreman::Logging.exception("Failed at consistency check for task #{task.id}", e, :logger => 'foreman-tasks')
234
237
  end
238
+ # Wipe tasks left behind by now stopped tasks
239
+ ForemanTasks::Lock.left_joins(:task).merge(where(:state => 'stopped')).destroy_all
235
240
  fixed_count
236
241
  end
237
242
 
@@ -1,5 +1,5 @@
1
1
  <% title _("Recurring logics") %>
2
- <% title_actions SETTINGS[:version].short <= '1.13' ? help_path : help_button %>
2
+ <% title_actions help_button %>
3
3
 
4
4
  <% if @errors %>
5
5
  <%= alert(:class => 'alert-info', :id => 'multiple-alert', :close => false, :header => '', :text => @errors) %>
@@ -38,16 +38,16 @@
38
38
  <table class="<%= table_css_classes('table-condensed table-fixed') %>">
39
39
  <thead>
40
40
  <th class="col-md-1"><%= N_("ID") %></th>
41
- <th><%= N_("Cron line") %></th>
42
- <th><%= N_("Task count") %></th>
43
- <th><%= N_("Action") %></th>
44
- <th><%= N_("Last occurrence") %></th>
45
- <th><%= N_("Next occurrence") %></th>
46
- <th><%= N_("Current iteration") %></th>
47
- <th><%= N_("Iteration limit") %></th>
48
- <th><%= N_("Repeat until") %></th>
49
- <th><%= N_("State") %></th>
50
- <th><%= N_("Purpose") %></th>
41
+ <th><%= _("Cron line") %></th>
42
+ <th><%= _("Task count") %></th>
43
+ <th><%= _("Action") %></th>
44
+ <th><%= _("Last occurrence") %></th>
45
+ <th><%= _("Next occurrence") %></th>
46
+ <th><%= _("Current iteration") %></th>
47
+ <th><%= _("Iteration limit") %></th>
48
+ <th><%= _("Repeat until") %></th>
49
+ <th><%= _("State") %></th>
50
+ <th><%= _("Purpose") %></th>
51
51
  <th/>
52
52
  </thead>
53
53
  <% @recurring_logics.each do |recurring_logic| %>
@@ -1,11 +1,11 @@
1
1
  <div>
2
2
  <table class='<%= table_css_classes('table-condensed') %>'>
3
3
  <tr>
4
- <th><%= N_('ID') %></th>
4
+ <th><%= _('ID') %></th>
5
5
  <td><%= link_to(task_group.id, foreman_tasks_task_group_url(task_group)) %></td>
6
6
  </tr>
7
7
  <tr>
8
- <th><%= N_('Task count') %></th>
8
+ <th><%= _('Task count') %></th>
9
9
  <td><%= link_to(task_group.tasks.count, foreman_tasks_tasks_url(:search => "task_group.id = #{task_group.id}")) %></td>
10
10
  </tr>
11
11
  </table>
@@ -1,47 +1,47 @@
1
1
  <% recurring_logic = task_group.recurring_logic -%>
2
2
  <table class='<%= table_css_classes('table-condensed') %>'>
3
3
  <tr>
4
- <th>ID</th>
4
+ <th><%= _('ID') %></th>
5
5
  <td><%= link_to(recurring_logic.id, recurring_logic) %></td>
6
6
  </tr>
7
7
  <tr>
8
- <th><%= N_("Cron line") %></th>
8
+ <th><%= _("Cron line") %></th>
9
9
  <td><%= recurring_logic.cron_line %></td>
10
10
  </tr>
11
11
  <tr>
12
- <th><%= N_("Action") %></th>
12
+ <th><%= _("Action") %></th>
13
13
  <td><%= format_task_input(recurring_logic.tasks.last) %></td>
14
14
  </tr>
15
15
  <tr>
16
- <th><%= N_("Last occurrence") %></th>
16
+ <th><%= _("Last occurrence") %></th>
17
17
  <td><%= recurring_logic.tasks.order(:started_at).where('started_at IS NOT NULL').last.try(:started_at) || '-' %></td>
18
18
  </tr>
19
19
  <tr>
20
- <th><%= N_("Next occurrence") %></th>
20
+ <th><%= _("Next occurrence") %></th>
21
21
  <td><%= recurring_logic_next_occurrence recurring_logic %></td>
22
22
  </tr>
23
23
  <tr>
24
- <th><%= N_("Current iteration") %></th>
24
+ <th><%= _("Current iteration") %></th>
25
25
  <td><%= recurring_logic.iteration %></td>
26
26
  </tr>
27
27
  <tr>
28
- <th><%= N_("Iteration limit") %></th>
28
+ <th><%= _("Iteration limit") %></th>
29
29
  <td><%= format_recurring_logic_limit recurring_logic.max_iteration %></td>
30
30
  </tr>
31
31
  <tr>
32
- <th><%= N_("Repeat until") %></th>
32
+ <th><%= _("Repeat until") %></th>
33
33
  <td><%= format_recurring_logic_limit recurring_logic.end_time.try(:in_time_zone) %></td>
34
34
  </tr>
35
35
  <tr>
36
- <th><%= N_("State") %></th>
36
+ <th><%= _("State") %></th>
37
37
  <td><%= recurring_logic_state(recurring_logic) %></td>
38
38
  </tr>
39
39
  <tr>
40
- <th><%= N_("Purpose") %></th>
40
+ <th><%= _("Purpose") %></th>
41
41
  <td><%= recurring_logic.purpose %></td>
42
42
  </tr>
43
43
  <tr>
44
- <th><%= N_("Task count") %></th>
44
+ <th><%= _("Task count") %></th>
45
45
  <td><%= link_to(task_group.tasks.count, foreman_tasks_tasks_url(:search => "task_group.id = #{task_group.id}")) %></td>
46
46
  </tr>
47
47
  </table>
@@ -84,7 +84,7 @@ module ForemanTasks
84
84
 
85
85
  def self.cleanup_settings
86
86
  return @cleanup_settings if @cleanup_settings
87
- @cleanup_settings = SETTINGS[:'foreman-tasks'] && SETTINGS[:'foreman-tasks'][:cleanup] || {}
87
+ @cleanup_settings = SETTINGS.dig(:'foreman-tasks', :cleanup) || {}
88
88
  end
89
89
 
90
90
  def self.actions_by_rules(action_rules)
@@ -16,7 +16,7 @@ module ForemanTasks
16
16
  :backup_deleted_plans => true,
17
17
  :backup_dir => default_backup_dir,
18
18
  }
19
- settings = SETTINGS[:'foreman-tasks'] && SETTINGS[:'foreman-tasks'][:backup]
19
+ settings = SETTINGS.dig(:'foreman-tasks', :backup)
20
20
  backup_options.merge!(settings) if settings
21
21
  @backup_settings = with_environment_override backup_options
22
22
  end
@@ -166,7 +166,10 @@ module ForemanTasks
166
166
  world.middleware.use Actions::Middleware::KeepCurrentUser, :before => ::Dynflow::Middleware::Common::Transaction
167
167
  world.middleware.use Actions::Middleware::KeepCurrentTimezone
168
168
  world.middleware.use Actions::Middleware::KeepCurrentRequestID
169
- world.middleware.use ::Actions::Middleware::LoadSettingValues if Gem::Version.new(::SETTINGS[:version]) >= Gem::Version.new('2.5')
169
+ world.middleware.use ::Actions::Middleware::LoadSettingValues
170
+ end
171
+ ::ForemanTasks.dynflow.config.on_init(true) do
172
+ ::ForemanTasks::Task::DynflowTask.consistency_check
170
173
  end
171
174
  end
172
175
 
@@ -1,3 +1,3 @@
1
1
  module ForemanTasks
2
- VERSION = '7.0.0'.freeze
2
+ VERSION = '7.2.0'.freeze
3
3
  end
@@ -16,6 +16,7 @@ if gettext_find_task
16
16
  .all_action_names
17
17
  .uniq
18
18
  .map { |n| %[_("#{n}")] }
19
+ .sort
19
20
  .join("\n")
20
21
  end
21
22
  end
@@ -1,5 +1,4 @@
1
1
  # Autogenerated!
2
- _("Import Puppet classes")
3
- _("Import facts")
4
2
  _("Action with sub plans")
5
- _("Remote action:")
3
+ _("Import Puppet classes")
4
+ _("Import facts")