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 +4 -4
- data/app/lib/actions/proxy_action.rb +5 -19
- data/app/lib/actions/trigger_proxy_batch.rb +1 -4
- data/app/models/foreman_tasks/remote_task.rb +1 -2
- data/app/views/foreman_tasks/layouts/react.html.erb +1 -1
- data/config/foreman-tasks.yaml.example +12 -5
- data/lib/foreman_tasks/cleaner.rb +61 -23
- data/lib/foreman_tasks/engine.rb +1 -1
- data/lib/foreman_tasks/tasks/cleanup.rake +5 -10
- data/lib/foreman_tasks/version.rb +1 -1
- data/package.json +6 -6
- data/test/controllers/api/tasks_controller_test.rb +2 -2
- data/test/controllers/tasks_controller_test.rb +4 -2
- data/test/unit/cleaner_test.rb +11 -13
- metadata +3 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 1c6773ac47a0c5b8e3e28da1461a348510e8595da0bd2d08feafd78092394fb2
|
4
|
+
data.tar.gz: 40d4c506cd3d31b72355e8c2d4255c854c703be6be49644b8d30a55032bd9b2b
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
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
|
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
|
64
|
-
on_proxy_action_stopped
|
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
|
147
|
-
|
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
|
-
|
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::
|
55
|
+
::Actions::ProxyAction::ProxyActionStopped.new,
|
57
56
|
optional: true
|
58
57
|
end
|
59
58
|
save!
|
@@ -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 |
|
21
|
-
new(options.merge(:filter =>
|
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
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
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
|
-
|
44
|
-
|
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(
|
53
|
-
disable_actions_with_periods =
|
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 = []
|
data/lib/foreman_tasks/engine.rb
CHANGED
@@ -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.
|
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
|
53
|
-
ForemanTasks::Cleaner.actions_with_default_cleanup.each do |action,
|
54
|
-
|
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
|
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": "^
|
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": "^
|
34
|
-
"@theforeman/eslint-plugin-foreman": "^
|
35
|
-
"@theforeman/stories": "^
|
36
|
-
"@theforeman/test": "^
|
37
|
-
"@theforeman/vendor-dev": "^
|
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
|
-
|
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
|
-
|
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
|
|
data/test/unit/cleaner_test.rb
CHANGED
@@ -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
|
-
|
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
|
-
|
143
|
-
|
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 =
|
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
|
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:
|
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:
|
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.
|
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
|