foreman-tasks 0.8.6 → 0.9.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 (87) hide show
  1. checksums.yaml +4 -4
  2. data/.rubocop.yml +35 -0
  3. data/.rubocop_todo.yml +138 -0
  4. data/app/controllers/foreman_tasks/api/recurring_logics_controller.rb +3 -4
  5. data/app/controllers/foreman_tasks/api/tasks_controller.rb +56 -72
  6. data/app/controllers/foreman_tasks/concerns/hosts_controller_extension.rb +2 -4
  7. data/app/controllers/foreman_tasks/recurring_logics_controller.rb +2 -5
  8. data/app/controllers/foreman_tasks/tasks_controller.rb +7 -8
  9. data/app/helpers/foreman_tasks/foreman_tasks_helper.rb +44 -46
  10. data/app/helpers/foreman_tasks/tasks_helper.rb +1 -1
  11. data/app/lib/actions/action_with_sub_plans.rb +6 -8
  12. data/app/lib/actions/base.rb +6 -7
  13. data/app/lib/actions/bulk_action.rb +13 -9
  14. data/app/lib/actions/entry_action.rb +1 -3
  15. data/app/lib/actions/foreman/host/import_facts.rb +2 -5
  16. data/app/lib/actions/foreman/puppetclass/import.rb +1 -1
  17. data/app/lib/actions/helpers/args_serialization.rb +0 -1
  18. data/app/lib/actions/helpers/humanizer.rb +16 -21
  19. data/app/lib/actions/helpers/with_continuous_output.rb +0 -1
  20. data/app/lib/actions/helpers/with_delegated_action.rb +2 -2
  21. data/app/lib/actions/middleware/inherit_task_groups.rb +3 -5
  22. data/app/lib/actions/middleware/keep_current_user.rb +0 -3
  23. data/app/lib/actions/middleware/recurring_logic.rb +0 -1
  24. data/app/lib/actions/proxy_action.rb +8 -8
  25. data/app/lib/actions/serializers/active_record_serializer.rb +0 -3
  26. data/app/lib/proxy_api/foreman_dynflow/dynflow_proxy.rb +3 -3
  27. data/app/models/foreman_tasks/concerns/action_subject.rb +4 -6
  28. data/app/models/foreman_tasks/concerns/action_triggering.rb +20 -33
  29. data/app/models/foreman_tasks/concerns/host_action_subject.rb +5 -5
  30. data/app/models/foreman_tasks/lock.rb +29 -37
  31. data/app/models/foreman_tasks/recurring_logic.rb +23 -24
  32. data/app/models/foreman_tasks/task.rb +65 -39
  33. data/app/models/foreman_tasks/task/dynflow_task.rb +23 -24
  34. data/app/models/foreman_tasks/task/status_explicator.rb +3 -3
  35. data/app/models/foreman_tasks/task/summarizer.rb +3 -3
  36. data/app/models/foreman_tasks/task_group.rb +0 -2
  37. data/app/models/foreman_tasks/task_group_member.rb +0 -2
  38. data/app/models/foreman_tasks/task_groups/recurring_logic_task_group.rb +1 -4
  39. data/app/models/foreman_tasks/triggering.rb +19 -19
  40. data/app/models/setting/foreman_tasks.rb +8 -11
  41. data/app/services/foreman_tasks/proxy_selector.rb +4 -5
  42. data/app/views/foreman_tasks/tasks/_details.html.erb +1 -1
  43. data/bin/dynflow-executor +1 -1
  44. data/bin/foreman-tasks +1 -1
  45. data/config/routes.rb +1 -1
  46. data/db/migrate/20150814204140_add_task_type_value_index.rb +1 -1
  47. data/db/migrate/20160924213030_change_tasks_widget_names.rb +8 -8
  48. data/db/seeds.d/61-foreman_tasks_bookmarks.rb +3 -3
  49. data/deploy/foreman-tasks.sysconfig +6 -0
  50. data/extra/dynflow-debug.sh +12 -0
  51. data/foreman-tasks.gemspec +1 -1
  52. data/lib/foreman_tasks.rb +3 -3
  53. data/lib/foreman_tasks/authorizer_ext.rb +1 -1
  54. data/lib/foreman_tasks/cleaner.rb +14 -16
  55. data/lib/foreman_tasks/dynflow.rb +11 -9
  56. data/lib/foreman_tasks/dynflow/configuration.rb +8 -10
  57. data/lib/foreman_tasks/dynflow/console_authorizer.rb +4 -5
  58. data/lib/foreman_tasks/dynflow/daemon.rb +17 -19
  59. data/lib/foreman_tasks/dynflow/persistence.rb +5 -8
  60. data/lib/foreman_tasks/engine.rb +30 -31
  61. data/lib/foreman_tasks/task_error.rb +1 -3
  62. data/lib/foreman_tasks/tasks/cleanup.rake +7 -19
  63. data/lib/foreman_tasks/tasks/dynflow.rake +1 -1
  64. data/lib/foreman_tasks/tasks/export_tasks.rake +51 -59
  65. data/lib/foreman_tasks/test_extensions.rb +1 -1
  66. data/lib/foreman_tasks/version.rb +1 -1
  67. data/lib/tasks/gettext.rake +10 -7
  68. data/locale/action_names.rb +3 -6
  69. data/locale/en/foreman_tasks.po +189 -177
  70. data/locale/foreman_tasks.pot +177 -137
  71. data/test/controllers/api/recurring_logics_controller_test.rb +3 -5
  72. data/test/controllers/api/tasks_controller_test.rb +5 -7
  73. data/test/factories/task_factory.rb +8 -8
  74. data/test/factories/triggering_factory.rb +2 -3
  75. data/test/helpers/foreman_tasks/tasks_helper_test.rb +11 -11
  76. data/test/support/dummy_proxy_action.rb +3 -4
  77. data/test/unit/actions/action_with_sub_plans_test.rb +5 -6
  78. data/test/unit/actions/proxy_action_test.rb +5 -8
  79. data/test/unit/cleaner_test.rb +11 -12
  80. data/test/unit/dynflow_console_authorizer_test.rb +4 -4
  81. data/test/unit/proxy_selector_test.rb +3 -3
  82. data/test/unit/recurring_logic_test.rb +19 -17
  83. data/test/unit/task_groups_test.rb +3 -4
  84. data/test/unit/task_test.rb +72 -5
  85. data/test/unit/triggering_test.rb +0 -1
  86. metadata +7 -6
  87. data/app/controllers/foreman_tasks/concerns/environments_extension.rb +0 -24
@@ -15,7 +15,7 @@ module Actions
15
15
  end
16
16
 
17
17
  def humanized_name
18
- _("Import Puppet classes")
18
+ _('Import Puppet classes')
19
19
  end
20
20
 
21
21
  # default value for cleaning up the tasks, it can be overriden by settings
@@ -62,4 +62,3 @@ module Actions
62
62
  end
63
63
  end
64
64
  end
65
-
@@ -1,8 +1,6 @@
1
1
  module Actions
2
2
  module Helpers
3
-
4
3
  class Humanizer
5
-
6
4
  def initialize(action)
7
5
  @action = action
8
6
  @input = action.respond_to?(:task_input) ? action.task_input : action.input
@@ -20,7 +18,7 @@ module Actions
20
18
  end
21
19
 
22
20
  def self.default_parts
23
- self.resource_classes_order.map { |klass| klass.new.name }
21
+ resource_classes_order.map { |klass| klass.new.name }
24
22
  end
25
23
 
26
24
  # Registers the resource class to the humanizer. Usually, this
@@ -29,25 +27,23 @@ module Actions
29
27
  # The `register_resource` can be run more times for the same class,
30
28
  # effectively moving the resource to the end of the humanized form.
31
29
  def self.register_resource(resource_class)
32
- self.resource_classes_order.delete_if { |klass| klass.name == resource_class.name }
33
- self.resource_classes_order << resource_class
30
+ resource_classes_order.delete_if { |klass| klass.name == resource_class.name }
31
+ resource_classes_order << resource_class
34
32
  end
35
33
 
36
34
  def input(*parts)
37
- if parts.empty?
38
- parts = self.class.default_parts
39
- end
35
+ parts = self.class.default_parts if parts.empty?
40
36
  included_parts(parts, @input).map do |part|
41
37
  [part, humanize_resource(part, @input)]
42
38
  end
43
39
  end
44
40
 
45
41
  def included_parts(parts, data)
46
- parts.select { |part| data.has_key?(part) }
42
+ parts.select { |part| data.key?(part) }
47
43
  end
48
44
 
49
45
  def humanize_resource(name, data)
50
- if resource = self.class.resource(name)
46
+ if (resource = self.class.resource(name))
51
47
  { text: "#{resource.humanized_name} '#{resource.humanized_value(data)}'",
52
48
  link: resource.link(data) }
53
49
  end
@@ -62,13 +58,12 @@ module Actions
62
58
  name
63
59
  end
64
60
 
65
- def link(data)
66
- end
61
+ def link(data); end
67
62
 
68
63
  def humanized_value(data)
69
64
  fetch_data(data, name, :name) ||
70
- fetch_data(data, name, :label) ||
71
- fetch_data(data, name, :id)
65
+ fetch_data(data, name, :label) ||
66
+ fetch_data(data, name, :id)
72
67
  end
73
68
 
74
69
  def self.inherited(klass)
@@ -79,10 +74,10 @@ module Actions
79
74
 
80
75
  def fetch_data(data, *subkeys)
81
76
  if subkeys.empty?
82
- return data
77
+ data
83
78
  else
84
79
  head, *tail = subkeys
85
- if data.is_a?(Hash) && data.has_key?(head)
80
+ if data.is_a?(Hash) && data.key?(head)
86
81
  return fetch_data(data[head], *tail)
87
82
  else
88
83
  return nil
@@ -101,7 +96,7 @@ module Actions
101
96
  end
102
97
 
103
98
  def link(data)
104
- if ackey_id = fetch_data(data, :activation_key, :id)
99
+ if (ackey_id = fetch_data(data, :activation_key, :id))
105
100
  "/activation_keys/#{ackey_id}/info"
106
101
  end
107
102
  end
@@ -156,7 +151,7 @@ module Actions
156
151
  end
157
152
 
158
153
  def link(data)
159
- if content_view_id = fetch_data(data, :content_view, :id)
154
+ if (content_view_id = fetch_data(data, :content_view, :id))
160
155
  "#/content_views/#{content_view_id}/versions"
161
156
  end
162
157
  end
@@ -172,7 +167,7 @@ module Actions
172
167
  end
173
168
 
174
169
  def link(data)
175
- if product_id = fetch_data(data, :product, :id)
170
+ if (product_id = fetch_data(data, :product, :id))
176
171
  "#/products/#{product_id}/info"
177
172
  end
178
173
  end
@@ -188,7 +183,7 @@ module Actions
188
183
  end
189
184
 
190
185
  def link(data)
191
- if system_uuid = fetch_data(data, :system, :uuid)
186
+ if (system_uuid = fetch_data(data, :system, :uuid))
192
187
  "#/systems/#{system_uuid}/info"
193
188
  end
194
189
  end
@@ -204,7 +199,7 @@ module Actions
204
199
  end
205
200
 
206
201
  def link(data)
207
- if org_id = fetch_data(data, :organization, :id)
202
+ if (org_id = fetch_data(data, :organization, :id))
208
203
  "/organizations/#{org_id}/edit"
209
204
  end
210
205
  end
@@ -23,4 +23,3 @@ module Actions
23
23
  end
24
24
  end
25
25
  end
26
-
@@ -7,12 +7,12 @@ module Actions
7
7
  case proxy
8
8
  when :not_defined
9
9
  if klass.is_a?(String)
10
- raise ::Foreman::Exception.new(_('No proxy defined for execution'))
10
+ raise Foreman::Exception, _('No proxy defined for execution')
11
11
  else
12
12
  delegated_action = plan_action(klass, options)
13
13
  end
14
14
  when :not_available
15
- raise ::Foreman::Exception.new(_('All proxies with the required feature are unavailable at the moment'))
15
+ raise Foreman::Exception, _('All proxies with the required feature are unavailable at the moment')
16
16
  when ::SmartProxy
17
17
  delegated_action = plan_action(::Actions::ProxyAction, proxy, klass, options)
18
18
  end
@@ -1,18 +1,17 @@
1
1
  module Actions
2
2
  module Middleware
3
3
  class InheritTaskGroups < Dynflow::Middleware
4
-
5
4
  def delay(*args)
6
- pass *args
5
+ pass(*args)
7
6
  end
8
7
 
9
8
  def plan(*args)
10
9
  inherit_task_groups
11
- pass *args
10
+ pass(*args)
12
11
  end
13
12
 
14
13
  def run(*args)
15
- pass *args
14
+ pass(*args)
16
15
  collect_children_task_groups
17
16
  end
18
17
 
@@ -36,4 +35,3 @@ module Actions
36
35
  end
37
36
  end
38
37
  end
39
-
@@ -13,9 +13,7 @@
13
13
 
14
14
  module Actions
15
15
  module Middleware
16
-
17
16
  class KeepCurrentUser < Dynflow::Middleware
18
-
19
17
  def delay(*args)
20
18
  pass(*args).tap { store_current_user }
21
19
  end
@@ -54,7 +52,6 @@ module Actions
54
52
  ensure
55
53
  User.current = nil
56
54
  end
57
-
58
55
  end
59
56
  end
60
57
  end
@@ -1,7 +1,6 @@
1
1
  module Actions
2
2
  module Middleware
3
3
  class RecurringLogic < ::Dynflow::Middleware
4
-
5
4
  # ::Actions::Middleware::RecurringLogic
6
5
  #
7
6
  # A middleware designed to make action repeatable.
@@ -47,7 +47,7 @@ module Actions
47
47
  response = proxy.trigger_task(proxy_action_name,
48
48
  input.merge(:callback => { :task_id => task.id,
49
49
  :step_id => run_step_id }))
50
- output[:proxy_task_id] = response["task_id"]
50
+ output[:proxy_task_id] = response['task_id']
51
51
  end
52
52
  end
53
53
 
@@ -56,7 +56,7 @@ module Actions
56
56
  response = proxy.status_of_task(output[:proxy_task_id])
57
57
  if %w(stopped paused).include? response['state']
58
58
  if response['result'] == 'error'
59
- raise ::Foreman::Exception, _("The smart proxy task %s failed.") % (output[:proxy_task_id])
59
+ raise ::Foreman::Exception, _('The smart proxy task %s failed.') % output[:proxy_task_id]
60
60
  else
61
61
  on_data(response['actions'].find { |block_action| block_action['class'] == proxy_action_name }['output'])
62
62
  end
@@ -70,7 +70,7 @@ module Actions
70
70
 
71
71
  def cancel_proxy_task
72
72
  if output[:cancel_sent]
73
- error! ForemanTasks::Task::TaskCancelledException.new(_("Cancel enforced: the task might be still running on the proxy"))
73
+ error! ForemanTasks::Task::TaskCancelledException.new(_('Cancel enforced: the task might be still running on the proxy'))
74
74
  else
75
75
  proxy.cancel_task(output[:proxy_task_id])
76
76
  output[:cancel_sent] = true
@@ -112,7 +112,7 @@ module Actions
112
112
  def fill_continuous_output(continuous_output)
113
113
  failed_proxy_tasks.each do |failure_data|
114
114
  message = _('Initialization error: %s') %
115
- "#{failure_data[:exception_class]} - #{failure_data[:exception_message]}"
115
+ "#{failure_data[:exception_class]} - #{failure_data[:exception_message]}"
116
116
  continuous_output.add_output(message, 'debug', failure_data[:timestamp])
117
117
  end
118
118
  end
@@ -136,7 +136,7 @@ module Actions
136
136
  end
137
137
 
138
138
  def set_timeout!
139
- time = Time.now + input[:connection_options][:timeout]
139
+ time = Time.zone.now + input[:connection_options][:timeout]
140
140
  schedule_timeout(time)
141
141
  metadata[:timeout] = time.to_s
142
142
  end
@@ -145,8 +145,8 @@ module Actions
145
145
  # Fails if the plan is not finished within 60 seconds from the first task trigger attempt on the smart proxy
146
146
  # If the triggering fails, it retries 3 more times with 15 second delays
147
147
  { :retry_interval => Setting['foreman_tasks_proxy_action_retry_interval'] || 15,
148
- :retry_count => Setting['foreman_tasks_proxy_action_retry_count' ] || 4,
149
- :timeout => Setting['foreman_tasks_proxy_action_start_timeout'] || 60 }
148
+ :retry_count => Setting['foreman_tasks_proxy_action_retry_count'] || 4,
149
+ :timeout => Setting['foreman_tasks_proxy_action_start_timeout'] || 60 }
150
150
  end
151
151
 
152
152
  private
@@ -179,7 +179,7 @@ module Actions
179
179
  if failed_proxy_tasks.count < options[:retry_count]
180
180
  suspend do |suspended_action|
181
181
  @world.clock.ping suspended_action,
182
- Time.now + options[:retry_interval],
182
+ Time.zone.now + options[:retry_interval],
183
183
  event
184
184
  end
185
185
  else
@@ -1,6 +1,5 @@
1
1
  module Actions
2
2
  module Serializers
3
-
4
3
  class ActiveRecordSerializer < ::Dynflow::Serializers::Noop
5
4
  def serialize(arg)
6
5
  if arg.is_a? ActiveRecord::Base
@@ -20,7 +19,5 @@ module Actions
20
19
  end
21
20
  end
22
21
  end
23
-
24
22
  end
25
23
  end
26
-
@@ -1,7 +1,7 @@
1
1
  module ProxyAPI
2
2
  module ForemanDynflow
3
3
  class DynflowProxy
4
- PREFIX = 'dynflow'
4
+ PREFIX = 'dynflow'.freeze
5
5
 
6
6
  class Task < ProxyAPI::Resource
7
7
  def initialize(args)
@@ -24,11 +24,11 @@ module ProxyAPI
24
24
 
25
25
  # Cancel the command
26
26
  def cancel_task(proxy_task_id)
27
- MultiJson.load(Task.new(@args).send(:post, "", "#{ proxy_task_id }/cancel"))
27
+ MultiJson.load(Task.new(@args).send(:post, '', "#{proxy_task_id}/cancel"))
28
28
  end
29
29
 
30
30
  def status_of_task(proxy_task_id)
31
- MultiJson.load(Task.new(@args).send(:get, "#{ proxy_task_id }/status"))
31
+ MultiJson.load(Task.new(@args).send(:get, "#{proxy_task_id}/status"))
32
32
  end
33
33
 
34
34
  def tasks_count(state)
@@ -1,7 +1,6 @@
1
1
  module ForemanTasks
2
2
  module Concerns
3
3
  module ActionSubject
4
-
5
4
  extend ActiveSupport::Concern
6
5
 
7
6
  module ClassMethods
@@ -15,10 +14,10 @@ module ForemanTasks
15
14
  end
16
15
 
17
16
  def to_action_input
18
- raise 'The resource needs to be saved first' if self.new_record?
17
+ raise 'The resource needs to be saved first' if new_record?
19
18
 
20
19
  { id: id, name: name }.tap do |hash|
21
- hash.update(label: label) if self.respond_to? :label
20
+ hash.update(label: label) if respond_to? :label
22
21
  end
23
22
  end
24
23
 
@@ -36,13 +35,12 @@ module ForemanTasks
36
35
  def all_related_resources
37
36
  mine = Set.new Array(related_resources)
38
37
 
39
- get_all_related_resources = -> resource do
38
+ get_all_related_resources = lambda do |resource|
40
39
  resource.is_a?(ActionSubject) ? resource.all_related_resources : []
41
40
  end
42
41
 
43
- mine + mine.reduce(Set.new) { |s, resource| s + get_all_related_resources.(resource) }
42
+ mine + mine.reduce(Set.new) { |s, resource| s + get_all_related_resources.call(resource) }
44
43
  end
45
-
46
44
  end
47
45
  end
48
46
  end
@@ -1,29 +1,25 @@
1
1
  module ForemanTasks
2
2
  module Concerns
3
3
  module ActionTriggering
4
-
5
4
  extend ActiveSupport::Concern
6
5
 
7
6
  included do
8
- after_create :plan_create_action
9
- after_update :plan_update_action
10
- after_destroy :plan_destroy_action
7
+ after_create :plan_hook_action
8
+ after_update :plan_hook_action
9
+ after_destroy :plan_hook_action
11
10
 
12
11
  alias_method_chain :save, :dynflow_task_wrap
13
12
  end
14
13
 
14
+ # These three *_action methods are called before the save/destroy actually occurs
15
15
  # @override
16
- def create_action
17
- end
16
+ def create_action; end
18
17
 
19
18
  # @override
20
- def update_action
21
- end
19
+ def update_action; end
22
20
 
23
21
  # @override
24
- def destroy_action
25
- end
26
-
22
+ def destroy_action; end
27
23
 
28
24
  def save_with_dynflow_task_wrap(*args)
29
25
  dynflow_task_wrap(:save) { save_without_dynflow_task_wrap(*args) }
@@ -48,12 +44,12 @@ module ForemanTasks
48
44
  # this can be used when HostActionSubject is used for orchestration but you want to avoid
49
45
  # triggering more tasks by ActiveRecord callbacks within run/finalize phase of your task
50
46
  # e.g. host.disable_dynflow_hooks { |h| h.save }
51
- def disable_dynflow_hooks(&block)
47
+ def disable_dynflow_hooks
52
48
  @_disable_dynflow_hooks = true
53
49
 
54
50
  if block_given?
55
51
  begin
56
- block.call(self)
52
+ yield(self)
57
53
  ensure
58
54
  @_disable_dynflow_hooks = false
59
55
  end
@@ -75,19 +71,9 @@ module ForemanTasks
75
71
  @dynflow_sync_action = true
76
72
  end
77
73
 
78
- def plan_create_action
79
- plan_action(create_action, self) if create_action
80
- return true
81
- end
82
-
83
- def plan_update_action
84
- plan_action(update_action, self) if update_action
85
- return true
86
- end
87
-
88
- def plan_destroy_action
89
- plan_action(destroy_action, self) if destroy_action
90
- return true
74
+ def plan_hook_action
75
+ plan_action(@_dynflow_hook_action, self) if @_dynflow_hook_action
76
+ true
91
77
  end
92
78
 
93
79
  # Perform planning phase of the action tied with the model event.
@@ -115,26 +101,27 @@ module ForemanTasks
115
101
  # to unexpected results.
116
102
  def dynflow_task_wrap(method)
117
103
  if ForemanTasks.dynflow.config.disable_active_record_actions ||
118
- @_disable_dynflow_hooks ||
119
- @_dynflow_task_wrapped
104
+ @_disable_dynflow_hooks ||
105
+ @_dynflow_task_wrapped
120
106
  return yield
121
107
  end
122
108
  @_dynflow_task_wrapped = true
123
109
 
124
- action = case method
110
+ @_dynflow_hook_action = case method
125
111
  when :save
126
- self.new_record? ? create_action : update_action
112
+ new_record? ? create_action : update_action
127
113
  when :destroy
128
114
  destroy_action
129
115
  else
130
116
  raise 'unexpected method'
131
117
  end
132
- ensure_not_in_transaction! if action
118
+ ensure_not_in_transaction! if @_dynflow_hook_action
133
119
  yield.tap do |result|
134
120
  execute_planned_action if result
135
121
  sync_action_flag_reset!
136
122
  end
137
123
  ensure
124
+ @_dynflow_hook_action = nil
138
125
  @_dynflow_task_wrapped = false
139
126
  end
140
127
 
@@ -143,7 +130,7 @@ module ForemanTasks
143
130
  def ensure_not_in_transaction!
144
131
  # we don't care about transactions when using InThreadWorld
145
132
  if defined?(::Dynflow::Testing::InThreadWorld) &&
146
- ForemanTasks.dynflow.world.is_a?(::Dynflow::Testing::InThreadWorld)
133
+ ForemanTasks.dynflow.world.is_a?(::Dynflow::Testing::InThreadWorld)
147
134
  return
148
135
  end
149
136
  if self.class.connection.open_transactions > 0
@@ -159,7 +146,7 @@ module ForemanTasks
159
146
  run.wait
160
147
  if run.value.error?
161
148
  task = ForemanTasks::Task::DynflowTask.where(:external_id => @execution_plan.id).first!
162
- raise ForemanTasks::TaskError.new(task)
149
+ raise ForemanTasks::TaskError, task
163
150
  end
164
151
  end
165
152
  end