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 +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
|