foreman-tasks 6.0.3 → 7.0.0

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