foreman-tasks 6.0.3 → 7.0.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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: a5c1faf969670adf42567f2dd46b7b78dc2199561bb96b483516fe4169b7558d
4
- data.tar.gz: 9aad850fd8decb284e1ccfc1869e5220da554e53286d31ccb3abb6da492a3ca3
3
+ metadata.gz: 1c6773ac47a0c5b8e3e28da1461a348510e8595da0bd2d08feafd78092394fb2
4
+ data.tar.gz: 40d4c506cd3d31b72355e8c2d4255c854c703be6be49644b8d30a55032bd9b2b
5
5
  SHA512:
6
- metadata.gz: 9f76c37ad5faccedfee63f80b35b9bb1a3b65974fbef664c49baac53f6991846ed215c76cef6452bd966ea9da219d1adbae82edba3b3e783c7619ce832d51e96
7
- data.tar.gz: d32b7d573c6809bba7bc28a4568513544752657461a9877c4f3824e8f5b0eca0b674fa9161f97cd8c72204b6edcc52f3e86480e19636538c53c8a4f473304e4f
6
+ metadata.gz: 1d05cdb24aea11a647028a4b1c314cf5f0db3d95459bbcfa0c52aa8f53263b6deb3d27ee23bbb7ec2a227e1ebbead0a432c0ecf6701131b2f7921b39145085ab
7
+ data.tar.gz: 777127d69a84b7c94780f78ad5a8aa5754ad246e6019a9f35c518e0b246d73b8f6f31acc84029b1b0648b8ff3ba8f167efc4fad7f4116cb4eb2f3fad7b850591
@@ -22,15 +22,7 @@ module Actions
22
22
  end
23
23
  end
24
24
 
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
25
+ class ProxyActionStopped; end
34
26
 
35
27
  def plan(proxy, klass, options)
36
28
  options[:connection_options] ||= {}
@@ -60,8 +52,8 @@ module Actions
60
52
  on_data(event.data, event.meta)
61
53
  when ProxyActionMissing
62
54
  on_proxy_action_missing
63
- when ProxyActionStoppedEvent
64
- on_proxy_action_stopped(event)
55
+ when ProxyActionStopped
56
+ on_proxy_action_stopped
65
57
  else
66
58
  raise "Unexpected event #{event.inspect}"
67
59
  end
@@ -102,8 +94,6 @@ module Actions
102
94
  else
103
95
  suspend
104
96
  end
105
- rescue RestClient::NotFound
106
- on_proxy_action_missing
107
97
  end
108
98
 
109
99
  def cancel_proxy_task
@@ -143,12 +133,8 @@ module Actions
143
133
  error! ProxyActionMissing.new(_('Proxy task gone missing from the smart proxy'))
144
134
  end
145
135
 
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
136
+ def on_proxy_action_stopped
137
+ check_task_status
152
138
  end
153
139
 
154
140
  # @override String name of an action to be triggered on server
@@ -42,10 +42,7 @@ 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
- # 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 }) }
45
+ batch.each { |remote_task| remote_task.update_from_batch_trigger({}) }
49
46
  output[:failed_count] += batch.size
50
47
  end
51
48
 
@@ -49,11 +49,10 @@ module ForemanTasks
49
49
  self.parent_task_id = parent['task_id']
50
50
  self.state = 'parent-triggered'
51
51
  else
52
- exception = data['exception']
53
52
  # Tell the action the task on the smart proxy stopped
54
53
  ForemanTasks.dynflow.world.event execution_plan_id,
55
54
  step_id,
56
- ::Actions::ProxyAction::ProxyActionStoppedEvent[exception],
55
+ ::Actions::ProxyAction::ProxyActionStopped.new,
57
56
  optional: true
58
57
  end
59
58
  save!
@@ -10,4 +10,4 @@
10
10
  <div id="user-id" data-id="<%= User.current.id if User.current %>" ></div>
11
11
  <%= react_component('ForemanTasks') %>
12
12
  <% end %>
13
- <%= render file: "layouts/base" %>
13
+ <%= render template: "layouts/base" %>
@@ -27,16 +27,23 @@
27
27
  #
28
28
  :cleanup:
29
29
  #
30
- # the period after which to delete all the tasks (by default all tasks are not being deleted after some period)
31
- # will be deprecated in Foreman 1.18 and the use of rules is recommended.
32
- #
33
- # :after: 30d
34
- #
35
30
  # per action settings to override the default defined in the actions (self.cleanup_after method)
36
31
  #
37
32
  # :actions:
38
33
  # - :name: Actions::Foreman::Host::ImportFacts
39
34
  # :after: 10d
35
+ # # Actions name can also be a list of names
36
+ # - :name:
37
+ # - Actions::Katello::Host::Erratum::Install
38
+ # - Actions::Katello::Host::Erratum::ApplicableErrataInstall
39
+ # :after: 90d
40
+ # # Actions can also define a condition
41
+ # - :name:
42
+ # - Actions::RemoteExecution::RunHostJob
43
+ # - Actions::RemoteExecution::RunHostsJob
44
+ # :filter: remote_execution_feature.label = katello_errata_install
45
+ # :after: 90d
46
+
40
47
  #
41
48
  # Rules defined in this section by default don't operate
42
49
  # on tasks specified in the actions section. This behavior
@@ -2,6 +2,50 @@ require 'csv'
2
2
 
3
3
  module ForemanTasks
4
4
  # Represents the cleanup mechanism for tasks
5
+ class ActionRule
6
+ attr_reader :klass, :after, :condition
7
+ def initialize(klass, after, condition = nil)
8
+ @klass = klass
9
+ @after = after
10
+ @condition = condition
11
+ end
12
+
13
+ def exclude_search
14
+ "NOT (#{include_search})"
15
+ end
16
+
17
+ def include_search
18
+ parts = if klass.is_a? Array
19
+ ["label ^ (#{klass.join(', ')})"]
20
+ else
21
+ ["label = \"#{klass}\""]
22
+ end
23
+ parts << "(#{@condition})" if @condition
24
+ '(' + parts.join(' AND ') + ')'
25
+ end
26
+
27
+ def self.compose_include_rules(rules)
28
+ rules.group_by { |rule| [rule.after, rule.condition] }
29
+ .map do |(after, condition), rules|
30
+ ActionRule.new(rules.map(&:klass), after, condition)
31
+ end
32
+ end
33
+ end
34
+
35
+ class CompositeActionRule
36
+ def initialize(*rules)
37
+ @rules = rules
38
+ end
39
+
40
+ def exclude_search
41
+ partial_condition = @rules.group_by(&:condition)
42
+ .map do |condition, rules|
43
+ ActionRule.new(rules.map(&:klass), nil, condition).include_search
44
+ end.join(' OR ')
45
+ "NOT (#{partial_condition})"
46
+ end
47
+ end
48
+
5
49
  class Cleaner
6
50
  def self.run(options)
7
51
  if options.key?(:filter)
@@ -12,36 +56,30 @@ module ForemanTasks
12
56
  raise "The option #{invalid_option} is not valid unless the filter specified"
13
57
  end
14
58
  end
15
- if cleanup_settings[:after]
16
- Foreman::Deprecation.deprecation_warning('1.18', _(':after setting in tasks cleanup section is deprecated, use :after in :rules section to set the value. to cleanup rules'))
17
- new(options.merge(:filter => '', :after => cleanup_settings[:after])).delete
18
- end
19
59
  with_periods = actions_with_default_cleanup
20
- with_periods.each do |action_class, period|
21
- new(options.merge(:filter => "label = #{action_class.name}", :after => period)).delete
60
+ ActionRule.compose_include_rules(with_periods).each do |rule|
61
+ new(options.merge(:filter => rule.include_search, :after => rule.after)).delete
22
62
  end
23
- actions_by_rules(with_periods).each do |hash|
63
+ actions_by_rules(CompositeActionRule.new(*with_periods)).each do |hash|
24
64
  new(options.merge(hash)).delete
25
65
  end
26
66
  end
27
67
  end
28
68
 
29
69
  def self.actions_with_default_cleanup
30
- actions_with_periods = {}
31
- if cleanup_settings[:actions]
32
- cleanup_settings[:actions].each do |action|
33
- action_class = action[:name].constantize
34
- actions_with_periods[action_class] = action[:after]
35
- rescue => e
36
- Foreman::Logging.exception("Error handling #{action} cleanup settings", e)
37
- end
38
- end
39
- (ForemanTasks.dynflow.world.action_classes - actions_with_periods.keys).each do |action_class|
40
- if action_class.respond_to?(:cleanup_after)
41
- actions_with_periods[action_class] = action_class.cleanup_after
70
+ actions = cleanup_settings.fetch(:actions, [])
71
+ .flat_map do |action|
72
+ Array(action[:name]).map do |klass|
73
+ ActionRule.new(klass.safe_constantize || klass, action[:after], action[:filter])
42
74
  end
43
- end
44
- actions_with_periods
75
+ rescue => e
76
+ Foreman::Logging.exception("Error handling #{action} cleanup settings", e)
77
+ nil
78
+ end.compact
79
+ hardcoded = (ForemanTasks.dynflow.world.action_classes - actions.map(&:klass))
80
+ .select { |klass| klass.respond_to?(:cleanup_after) || klass.respond_to?(:cleanup_rules) }
81
+ .flat_map { |klass| klass.respond_to?(:cleanup_rules) ? klass.cleanup_rules : ActionRule.new(klass, klass.cleanup_after) }
82
+ actions + hardcoded
45
83
  end
46
84
 
47
85
  def self.cleanup_settings
@@ -49,8 +87,8 @@ module ForemanTasks
49
87
  @cleanup_settings = SETTINGS[:'foreman-tasks'] && SETTINGS[:'foreman-tasks'][:cleanup] || {}
50
88
  end
51
89
 
52
- def self.actions_by_rules(actions_with_periods)
53
- disable_actions_with_periods = "label !^ (#{actions_with_periods.keys.join(', ')})"
90
+ def self.actions_by_rules(action_rules)
91
+ disable_actions_with_periods = action_rules.exclude_search
54
92
  cleanup_settings.fetch(:rules, []).map do |hash|
55
93
  next if hash[:after].nil?
56
94
  conditions = []
@@ -25,7 +25,7 @@ module ForemanTasks
25
25
 
26
26
  initializer 'foreman_tasks.register_plugin', :before => :finisher_hook do |_app|
27
27
  Foreman::Plugin.register :"foreman-tasks" do
28
- requires_foreman '>= 3.2.0'
28
+ requires_foreman '>= 3.3.0'
29
29
  divider :top_menu, :parent => :monitor_menu, :last => true, :caption => N_('Foreman Tasks')
30
30
  menu :top_menu, :tasks,
31
31
  :url_hash => { :controller => 'foreman_tasks/tasks', :action => :index },
@@ -39,23 +39,18 @@ namespace :foreman_tasks do
39
39
 
40
40
  desc 'Show the current configuration for auto-cleanup'
41
41
  task :config => ['environment', 'dynflow:client'] do
42
- if ForemanTasks::Cleaner.cleanup_settings[:after]
43
- puts _('The tasks will be deleted after %{after}') % { :after => ForemanTasks::Cleaner.cleanup_settings[:after] }
44
- else
45
- puts _('Global period for cleaning up tasks is not set')
46
- end
47
-
48
42
  if ForemanTasks::Cleaner.actions_with_default_cleanup.empty?
49
43
  puts _('No actions are configured to be cleaned automatically')
50
44
  else
51
45
  puts _('The following actions are configured to be deleted automatically after some time:')
52
- printf("%-50s %s\n", _('name'), _('delete after'))
53
- ForemanTasks::Cleaner.actions_with_default_cleanup.each do |action, after|
54
- printf("%-50s %s\n", action.name, after)
46
+ printf("%-75s %-20s %-50s\n", _('name'), _('delete after'), _('filter'))
47
+ ForemanTasks::Cleaner.actions_with_default_cleanup.each do |action, _after|
48
+ klass = action.klass
49
+ printf("%-75s %-20s %-50s\n", klass.try(:name) || klass, action.after, action.condition)
55
50
  end
56
51
  end
57
52
  puts
58
- by_rules = ForemanTasks::Cleaner.actions_by_rules(ForemanTasks::Cleaner.actions_with_default_cleanup)
53
+ by_rules = ForemanTasks::Cleaner.actions_by_rules(ForemanTasks::CompositeActionRule.new(*ForemanTasks::Cleaner.actions_with_default_cleanup))
59
54
  if by_rules.empty?
60
55
  puts _('No cleanup rules are configured')
61
56
  else
@@ -1,3 +1,3 @@
1
1
  module ForemanTasks
2
- VERSION = '6.0.3'.freeze
2
+ VERSION = '7.0.0'.freeze
3
3
  end
data/package.json CHANGED
@@ -23,18 +23,18 @@
23
23
  "url": "http://projects.theforeman.org/projects/foreman-tasks/issues"
24
24
  },
25
25
  "peerDependencies": {
26
- "@theforeman/vendor": "^8.15.0"
26
+ "@theforeman/vendor": "^10.1.0"
27
27
  },
28
28
  "dependencies": {
29
29
  "c3": "^0.4.11"
30
30
  },
31
31
  "devDependencies": {
32
32
  "@babel/core": "^7.7.0",
33
- "@theforeman/builder": "^8.15.0",
34
- "@theforeman/eslint-plugin-foreman": "^8.15.0",
35
- "@theforeman/stories": "^8.15.0",
36
- "@theforeman/test": "^8.15.0",
37
- "@theforeman/vendor-dev": "^8.15.0",
33
+ "@theforeman/builder": "^10.1.0",
34
+ "@theforeman/eslint-plugin-foreman": "^10.1.0",
35
+ "@theforeman/stories": "^10.1.0",
36
+ "@theforeman/test": "^10.1.0",
37
+ "@theforeman/vendor-dev": "^10.1.0",
38
38
  "babel-eslint": "^10.0.3",
39
39
  "eslint": "^6.7.2",
40
40
  "jed": "^1.1.1",
@@ -108,7 +108,7 @@ module ForemanTasks
108
108
  get :show, params: { id: task.id }, session: set_session_user
109
109
  assert_response :success
110
110
  data = JSON.parse(response.body)
111
- _(data['duration']).must_equal task.duration
111
+ _(data['duration']).must_equal task.duration.in_seconds.to_s
112
112
  end
113
113
  end
114
114
 
@@ -118,7 +118,7 @@ module ForemanTasks
118
118
  get :index, session: set_session_user
119
119
  assert_response :success
120
120
  data = JSON.parse(response.body)
121
- _(data['results'][0]['duration']).must_equal task.duration
121
+ _(data['results'][0]['duration']).must_equal task.duration.in_seconds.to_s
122
122
  end
123
123
  end
124
124
 
@@ -96,7 +96,8 @@ module ForemanTasks
96
96
  task = ForemanTasks::Task.with_duration.find(FactoryBot.create(:some_task).id)
97
97
  get(:index, params: {}, session: set_session_user)
98
98
  assert_response :success
99
- assert_include response.body.lines[1], task.duration
99
+ row = CSV.parse(response.body, headers: true).first
100
+ assert_include row['Duration'], task.duration.in_seconds.to_s
100
101
  end
101
102
  end
102
103
 
@@ -126,7 +127,8 @@ module ForemanTasks
126
127
  child.save!
127
128
  get(:sub_tasks, params: { id: parent.id }, session: set_session_user)
128
129
  assert_response :success
129
- assert_include response.body.lines[1], child.duration
130
+ row = CSV.parse(response.body, headers: true).first
131
+ assert_include row['Duration'], child.duration.in_seconds.to_s
130
132
  end
131
133
  end
132
134
 
@@ -133,33 +133,31 @@ class TasksTest < ActiveSupport::TestCase
133
133
  describe 'default behaviour' do
134
134
  it 'searches for the actions that have the cleanup_after defined' do
135
135
  ForemanTasks::Cleaner.stubs(:cleanup_settings => {})
136
- _(ForemanTasks::Cleaner.actions_with_default_cleanup[ActionWithCleanup]).must_equal '15d'
136
+ actions = ForemanTasks::Cleaner.actions_with_default_cleanup
137
+ example = actions.find { |rule| rule.klass == ActionWithCleanup }
138
+ _(example.after).must_equal '15d'
137
139
  end
138
140
 
139
141
  it 'searches for the actions that have the cleanup_after defined' do
140
142
  ForemanTasks::Cleaner.stubs(:cleanup_settings =>
141
143
  { :actions => [{ :name => ActionWithCleanup.name, :after => '5d' }] })
142
- _(ForemanTasks::Cleaner.actions_with_default_cleanup[ActionWithCleanup]).must_equal '5d'
143
- end
144
-
145
- it 'deprecates the usage of :after' do
146
- Foreman::Deprecation.expects(:deprecation_warning)
147
- ForemanTasks::Cleaner.any_instance.expects(:delete)
148
- ForemanTasks::Cleaner.stubs(:cleanup_settings =>
149
- { :after => '1d' })
150
- ForemanTasks::Cleaner.stubs(:actions_with_default_cleanup).returns({})
151
- ForemanTasks::Cleaner.run({})
144
+ actions = ForemanTasks::Cleaner.actions_with_default_cleanup
145
+ example = actions.find { |rule| rule.klass == ActionWithCleanup }
146
+ _(example.after).must_equal '5d'
152
147
  end
153
148
 
154
149
  it 'generates filters from rules properly' do
155
- actions_with_default = { 'action1' => nil, 'action2' => nil }
150
+ actions_with_default = ForemanTasks::CompositeActionRule.new(
151
+ ForemanTasks::ActionRule.new('action1', nil),
152
+ ForemanTasks::ActionRule.new('action2', nil)
153
+ )
156
154
  rules = [{ :after => nil },
157
155
  { :after => '10d', :filter => 'label = something', :states => %w[stopped paused] },
158
156
  { :after => '15d', :filter => 'label = something_else',
159
157
  :override_actions => true, :states => 'all' }]
160
158
  ForemanTasks::Cleaner.stubs(:cleanup_settings).returns(:rules => rules)
161
159
  r1, r2 = ForemanTasks::Cleaner.actions_by_rules actions_with_default
162
- _(r1[:filter]).must_equal '(label !^ (action1, action2)) AND (label = something)'
160
+ _(r1[:filter]).must_equal '(NOT ((label ^ (action1, action2)))) AND (label = something)'
163
161
  _(r1[:states]).must_equal %w[stopped paused]
164
162
  _(r2[:filter]).must_equal '(label = something_else)'
165
163
  _(r2[:states]).must_equal []
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: foreman-tasks
3
3
  version: !ruby/object:Gem::Version
4
- version: 6.0.3
4
+ version: 7.0.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Ivan Nečas
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2022-09-06 00:00:00.000000000 Z
11
+ date: 1980-01-01 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: dynflow
@@ -608,7 +608,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
608
608
  - !ruby/object:Gem::Version
609
609
  version: '0'
610
610
  requirements: []
611
- rubygems_version: 3.3.20
611
+ rubygems_version: 3.2.26
612
612
  signing_key:
613
613
  specification_version: 4
614
614
  summary: Foreman plugin for showing tasks information for resources and users