foreman-tasks 0.7.3 → 0.7.4
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 +8 -8
- data/app/lib/actions/bulk_action.rb +2 -2
- data/app/lib/actions/entry_action.rb +4 -0
- data/app/lib/actions/middleware/keep_current_user.rb +20 -1
- data/app/lib/actions/proxy_action.rb +106 -19
- data/app/lib/actions/serializers/active_record_serializer.rb +26 -0
- data/app/lib/proxy_api/foreman_dynflow/dynflow_proxy.rb +5 -1
- data/app/models/foreman_tasks/task.rb +3 -1
- data/app/models/foreman_tasks/task/dynflow_task.rb +9 -1
- data/app/models/foreman_tasks/task/summarizer.rb +2 -2
- data/app/models/foreman_tasks/task/task_cancelled_exception.rb +7 -0
- data/app/views/foreman_tasks/tasks/_details.html.erb +14 -2
- data/app/views/foreman_tasks/tasks/index.html.erb +3 -1
- data/db/migrate/20150817102538_add_delay_attributes.rb +6 -0
- data/db/seeds.d/61-foreman_tasks_bookmarks.rb +12 -0
- data/lib/foreman_tasks.rb +5 -0
- data/lib/foreman_tasks/dynflow/persistence.rb +15 -4
- data/lib/foreman_tasks/triggers.rb +4 -0
- data/lib/foreman_tasks/version.rb +1 -1
- data/test/controllers/api/tasks_controller_test.rb +2 -2
- data/test/unit/actions/proxy_action_test.rb +18 -0
- data/test/unit/cleaner_test.rb +1 -1
- data/test/unit/task_test.rb +2 -1
- metadata +8 -4
checksums.yaml
CHANGED
@@ -1,15 +1,15 @@
|
|
1
1
|
---
|
2
2
|
!binary "U0hBMQ==":
|
3
3
|
metadata.gz: !binary |-
|
4
|
-
|
4
|
+
NzAzZDZlZGRhYjg2OWM2ZGU3NTdkMGMzMmZmMTg4ZDJhODU3NjU3NA==
|
5
5
|
data.tar.gz: !binary |-
|
6
|
-
|
6
|
+
NzQ1ZDRmODAwYzg3ODhhNThjMGVmNmQyZDQwNDA3NDliNjVkYjYxNQ==
|
7
7
|
SHA512:
|
8
8
|
metadata.gz: !binary |-
|
9
|
-
|
10
|
-
|
11
|
-
|
9
|
+
N2U4ZmQ0ZTE4MTZkNDlmMWRmYmEzYThhODJiYWQwZTEyOTQyY2Q3MWZjMzM1
|
10
|
+
NDJlNjQ1YWNjNWU5ODgzZmE3NjVmN2Q0Y2YzMGI4Y2NlZjZkN2RmODcyYzRk
|
11
|
+
ODc5Y2FlNWQ5ZDE3YjlmODYyMWYzYTI3YTljOWIxMTdmOWYwMzE=
|
12
12
|
data.tar.gz: !binary |-
|
13
|
-
|
14
|
-
|
15
|
-
|
13
|
+
YTU2ZjFlNTY2ZjI3MzA5ZmMxMWQ2YzQzMDQxMTZjMjY3NDExMjNmNjVlZjkz
|
14
|
+
ZjJhOGRlODk5OTgxOGIyZDI0NzE0YjY3ZmFhZDQxNmE4NGFlYWQ4Y2Q3ZWMw
|
15
|
+
MTY5MWMwNjMzNDVlOWJiMzE2YWZjMTgwZjc0NDZkZjYyNmE2MWY=
|
@@ -54,10 +54,10 @@ module Actions
|
|
54
54
|
|
55
55
|
def check_targets!(targets)
|
56
56
|
if targets.empty?
|
57
|
-
fail
|
57
|
+
fail ::Foreman::Exception.new(N_("Empty bulk action"))
|
58
58
|
end
|
59
59
|
if targets.map(&:class).uniq.length > 1
|
60
|
-
fail
|
60
|
+
fail ::Foreman::Exception.new(N_("The targets are of different types"))
|
61
61
|
end
|
62
62
|
end
|
63
63
|
|
@@ -15,8 +15,15 @@ module Actions
|
|
15
15
|
module Middleware
|
16
16
|
|
17
17
|
class KeepCurrentUser < Dynflow::Middleware
|
18
|
+
|
19
|
+
def delay(*args)
|
20
|
+
pass(*args).tap { store_current_user }
|
21
|
+
end
|
22
|
+
|
18
23
|
def plan(*args)
|
19
|
-
|
24
|
+
with_current_user do
|
25
|
+
pass(*args).tap { store_current_user }
|
26
|
+
end
|
20
27
|
end
|
21
28
|
|
22
29
|
def run(*args)
|
@@ -29,6 +36,18 @@ module Actions
|
|
29
36
|
|
30
37
|
private
|
31
38
|
|
39
|
+
def with_current_user
|
40
|
+
if User.current || action.input[:current_user_id].nil?
|
41
|
+
yield
|
42
|
+
else
|
43
|
+
restore_curent_user { yield }
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
def store_current_user
|
48
|
+
action.input[:current_user_id] = User.current.try(:id)
|
49
|
+
end
|
50
|
+
|
32
51
|
def restore_curent_user
|
33
52
|
User.current = User.find(action.input[:current_user_id])
|
34
53
|
yield
|
@@ -2,6 +2,7 @@ module Actions
|
|
2
2
|
class ProxyAction < Base
|
3
3
|
|
4
4
|
include ::Dynflow::Action::Cancellable
|
5
|
+
include ::Dynflow::Action::Timeouts
|
5
6
|
|
6
7
|
class CallbackData
|
7
8
|
attr_reader :data
|
@@ -12,39 +13,65 @@ module Actions
|
|
12
13
|
end
|
13
14
|
|
14
15
|
def plan(proxy, options)
|
16
|
+
options[:connection_options] ||= {}
|
17
|
+
default_connection_options.each { |key, value| options[:connection_options][key] ||= value }
|
15
18
|
plan_self(options.merge(:proxy_url => proxy.url))
|
16
19
|
end
|
17
20
|
|
18
21
|
def run(event = nil)
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
22
|
+
with_connection_error_handling(event) do |event|
|
23
|
+
case event
|
24
|
+
when nil
|
25
|
+
if output[:proxy_task_id]
|
26
|
+
on_resume
|
27
|
+
else
|
28
|
+
trigger_proxy_task
|
29
|
+
end
|
30
|
+
suspend
|
31
|
+
when ::Dynflow::Action::Skip
|
32
|
+
# do nothing
|
33
|
+
when ::Dynflow::Action::Cancellable::Cancel
|
34
|
+
cancel_proxy_task
|
35
|
+
when CallbackData
|
36
|
+
on_data(event.data)
|
37
|
+
when ::Dynflow::Action::Timeouts::Timeout
|
38
|
+
check_task_status
|
23
39
|
else
|
24
|
-
|
40
|
+
raise "Unexpected event #{event.inspect}"
|
25
41
|
end
|
26
|
-
suspend
|
27
|
-
when ::Dynflow::Action::Skip
|
28
|
-
# do nothing
|
29
|
-
when ::Dynflow::Action::Cancellable::Cancel
|
30
|
-
cancel_proxy_task
|
31
|
-
when CallbackData
|
32
|
-
on_data(event.data)
|
33
|
-
else
|
34
|
-
raise "Unexpected event #{event.inspect}"
|
35
42
|
end
|
36
43
|
end
|
37
44
|
|
38
45
|
def trigger_proxy_task
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
46
|
+
suspend do |_suspended_action|
|
47
|
+
set_timeout! unless timeout_set?
|
48
|
+
response = proxy.trigger_task(proxy_action_name,
|
49
|
+
input.merge(:callback => { :task_id => task.id,
|
50
|
+
:step_id => run_step_id }))
|
51
|
+
output[:proxy_task_id] = response["task_id"]
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
def check_task_status
|
56
|
+
if output[:proxy_task_id]
|
57
|
+
response = proxy.status_of_task(output[:proxy_task_id])
|
58
|
+
if response['state'] == 'stopped'
|
59
|
+
if response['result'] == 'error'
|
60
|
+
raise ::Foreman::Exception, _("The smart proxy task '#{output[:proxy_task_id]}' failed.")
|
61
|
+
else
|
62
|
+
on_data(response['actions'].find { |block_action| block_action['class'] == proxy_action_name }['output'])
|
63
|
+
end
|
64
|
+
else
|
65
|
+
cancel_proxy_task
|
66
|
+
end
|
67
|
+
else
|
68
|
+
process_timeout
|
69
|
+
end
|
43
70
|
end
|
44
71
|
|
45
72
|
def cancel_proxy_task
|
46
73
|
if output[:cancel_sent]
|
47
|
-
error! _("Cancel enforced: the task might be still running on the proxy")
|
74
|
+
error! ForemanTasks::Task::TaskCancelledException.new(_("Cancel enforced: the task might be still running on the proxy"))
|
48
75
|
else
|
49
76
|
proxy.cancel_task(output[:proxy_task_id])
|
50
77
|
output[:cancel_sent] = true
|
@@ -78,5 +105,65 @@ module Actions
|
|
78
105
|
def proxy_output=(output)
|
79
106
|
output[:proxy_output] = output
|
80
107
|
end
|
108
|
+
|
109
|
+
def metadata
|
110
|
+
output[:metadata] ||= {}
|
111
|
+
output[:metadata]
|
112
|
+
end
|
113
|
+
|
114
|
+
def metadata=(thing)
|
115
|
+
output[:metadata] ||= {}
|
116
|
+
output[:metadata] = thing
|
117
|
+
end
|
118
|
+
|
119
|
+
def timeout_set?
|
120
|
+
!metadata[:timeout].nil?
|
121
|
+
end
|
122
|
+
|
123
|
+
def set_timeout!
|
124
|
+
time = Time.now + input[:connection_options][:timeout]
|
125
|
+
schedule_timeout(time)
|
126
|
+
metadata[:timeout] = time.to_s
|
127
|
+
end
|
128
|
+
|
129
|
+
def default_connection_options
|
130
|
+
# Fails if the plan is not finished within 60 seconds from the first task trigger attempt on the smart proxy
|
131
|
+
# If the triggering fails, it retries 3 more times with 15 second delays
|
132
|
+
{ :retry_interval => 15, :retry_count => 4, :timeout => 60 }
|
133
|
+
end
|
134
|
+
|
135
|
+
private
|
136
|
+
|
137
|
+
def with_connection_error_handling(event = nil)
|
138
|
+
yield event
|
139
|
+
rescue ::RestClient::Exception, Errno::ECONNREFUSED, Errno::EHOSTUNREACH, Errno::ETIMEDOUT => e
|
140
|
+
if event.class == CallbackData || event == ::Dynflow::Action::Timeouts::Timeout
|
141
|
+
raise e
|
142
|
+
else
|
143
|
+
handle_connection_exception(e, event)
|
144
|
+
end
|
145
|
+
end
|
146
|
+
|
147
|
+
def format_exception(exception)
|
148
|
+
{ output[:proxy_task_id] =>
|
149
|
+
{ :exception_class => exception.class.name,
|
150
|
+
:execption_message => exception.message } }
|
151
|
+
end
|
152
|
+
|
153
|
+
def handle_connection_exception(exception, event = nil)
|
154
|
+
metadata[:failed_proxy_tasks] ||= []
|
155
|
+
options = input[:connection_options]
|
156
|
+
metadata[:failed_proxy_tasks] << format_exception(exception)
|
157
|
+
output[:proxy_task_id] = nil
|
158
|
+
if metadata[:failed_proxy_tasks].count < options[:retry_count]
|
159
|
+
suspend do |suspended_action|
|
160
|
+
@world.clock.ping suspended_action,
|
161
|
+
Time.now + options[:retry_interval],
|
162
|
+
event
|
163
|
+
end
|
164
|
+
else
|
165
|
+
raise exception
|
166
|
+
end
|
167
|
+
end
|
81
168
|
end
|
82
169
|
end
|
@@ -0,0 +1,26 @@
|
|
1
|
+
module Actions
|
2
|
+
module Serializers
|
3
|
+
|
4
|
+
class ActiveRecordSerializer < ::Dynflow::Serializers::Noop
|
5
|
+
def serialize(arg)
|
6
|
+
if arg.is_a? ActiveRecord::Base
|
7
|
+
{ :active_record_object => true,
|
8
|
+
:class_name => arg.class.name,
|
9
|
+
:id => arg.id }
|
10
|
+
else
|
11
|
+
super arg
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
def deserialize(arg)
|
16
|
+
if arg.is_a?(Hash) && arg[:active_record_object]
|
17
|
+
arg[:class_name].constantize.find(arg[:id])
|
18
|
+
else
|
19
|
+
super arg
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
@@ -22,10 +22,14 @@ module ProxyAPI
|
|
22
22
|
MultiJson.load(Task.new(@args).send(:post, payload))
|
23
23
|
end
|
24
24
|
|
25
|
-
#
|
25
|
+
# Cancel the command
|
26
26
|
def cancel_task(proxy_task_id)
|
27
27
|
MultiJson.load(Task.new(@args).send(:post, "", "#{ proxy_task_id }/cancel"))
|
28
28
|
end
|
29
|
+
|
30
|
+
def status_of_task(proxy_task_id)
|
31
|
+
MultiJson.load(Task.new(@args).send(:get, "#{ proxy_task_id }/status"))
|
32
|
+
end
|
29
33
|
end
|
30
34
|
end
|
31
35
|
end
|
@@ -23,6 +23,7 @@ module ForemanTasks
|
|
23
23
|
scoped_search :on => :state, :complete_value => true
|
24
24
|
scoped_search :on => :result, :complete_value => true
|
25
25
|
scoped_search :on => :started_at, :complete_value => false
|
26
|
+
scoped_search :on => :ended_at, :complete_value => false
|
26
27
|
scoped_search :on => :parent_task_id, :complete_value => true
|
27
28
|
scoped_search :in => :locks, :on => :resource_type, :complete_value => true, :rename => "resource_type", :ext_method => :search_by_generic_resource
|
28
29
|
scoped_search :in => :locks, :on => :resource_id, :complete_value => false, :rename => "resource_id", :ext_method => :search_by_generic_resource
|
@@ -66,9 +67,10 @@ module ForemanTasks
|
|
66
67
|
end
|
67
68
|
|
68
69
|
# returns true if the task is running or waiting to be run
|
69
|
-
def pending
|
70
|
+
def pending?
|
70
71
|
self.state != 'stopped'
|
71
72
|
end
|
73
|
+
alias_method :pending, :pending?
|
72
74
|
|
73
75
|
def resumable?
|
74
76
|
false
|
@@ -11,6 +11,8 @@ module ForemanTasks
|
|
11
11
|
self.ended_at = data[:ended_at]
|
12
12
|
self.state = data[:state].to_s
|
13
13
|
self.result = data[:result].to_s
|
14
|
+
self.start_at = data[:start_at] if data[:start_at]
|
15
|
+
self.start_before = data[:start_before] if data[:start_before]
|
14
16
|
self.parent_task_id ||= begin
|
15
17
|
if main_action.caller_execution_plan_id
|
16
18
|
DynflowTask.find_by_external_id!(main_action.caller_execution_plan_id).id
|
@@ -102,10 +104,16 @@ module ForemanTasks
|
|
102
104
|
logger.warn("Task %s updated at consistency check: %s" % [task.id, changes.inspect])
|
103
105
|
end
|
104
106
|
rescue => e
|
105
|
-
Foreman::Logging.exception("Failed at consistency check for task #{task.id}", e, :logger =>
|
107
|
+
Foreman::Logging.exception("Failed at consistency check for task #{task.id}", e, :logger => 'foreman-tasks')
|
106
108
|
end
|
107
109
|
end
|
108
110
|
return fixed_count
|
109
111
|
end
|
112
|
+
|
113
|
+
def self.new_for_execution_plan(execution_plan_id, data)
|
114
|
+
self.new(:external_id => execution_plan_id,
|
115
|
+
:state => data[:state].to_s,
|
116
|
+
:result => data[:result].to_s)
|
117
|
+
end
|
110
118
|
end
|
111
119
|
end
|
@@ -1,8 +1,8 @@
|
|
1
1
|
module ForemanTasks
|
2
2
|
class Task::Summarizer
|
3
3
|
def summarize_by_status(since=nil)
|
4
|
-
result = ::ForemanTasks::Task.select('count(state), state, result').group(:state, :result).order(:state)
|
5
|
-
result.where('started_at > ?', since) if since
|
4
|
+
result = ::ForemanTasks::Task.select('count(state) AS count, state, result').group(:state, :result).order(:state)
|
5
|
+
result = result.where('started_at > ?', since) if since
|
6
6
|
result
|
7
7
|
end
|
8
8
|
|
@@ -95,13 +95,25 @@
|
|
95
95
|
<span class="param-name"><%= _("Owner") %>:</span>
|
96
96
|
<span class="param-value"><%= @task.username %></span>
|
97
97
|
</div>
|
98
|
+
<div>
|
99
|
+
<span class="param-name"><%= _("Execution type") %>:</span>
|
100
|
+
<span class="param-value"><%= @task.start_at.nil? ? _('Immediate') : _('Delayed') %></span>
|
101
|
+
</div>
|
102
|
+
<div>
|
103
|
+
<span class="param-name"><%= _("Start at") %>:</span>
|
104
|
+
<span class="param-value"><%= @task.start_at.nil? ? '-' : @task.start_at %></span>
|
105
|
+
</div>
|
106
|
+
<div>
|
107
|
+
<span class="param-name"><%= _("Start before") %>:</span>
|
108
|
+
<span class="param-value"><%= @task.start_before.nil? ? '-' : @task.start_before %></span>
|
109
|
+
</div>
|
98
110
|
<div>
|
99
111
|
<span class="param-name"><%= _("Started at") %>:</span>
|
100
|
-
<span class="param-value"><%= @task.started_at %></span>
|
112
|
+
<span class="param-value"><%= @task.started_at.try(:in_time_zone) %></span>
|
101
113
|
</div>
|
102
114
|
<div>
|
103
115
|
<span class="param-name"><%= _("Ended at") %>:</span>
|
104
|
-
<span class="param-value"><%= @task.ended_at %></span>
|
116
|
+
<span class="param-value"><%= @task.ended_at.try(:in_time_zone) %></span>
|
105
117
|
</div>
|
106
118
|
<div>
|
107
119
|
<span class="param-name"><%= _("State") %>:</span>
|
@@ -32,6 +32,7 @@ $(document).on('click', ".table-two-pane td.two-pane-link", function(e) {
|
|
32
32
|
<th><%= _("State") %></th>
|
33
33
|
<th><%= _("Result") %></th>
|
34
34
|
<th><%= sort :started_at, :as => _("Started at") %></th>
|
35
|
+
<th><%= sort :ended_at, :as => _("Ended at") %></th>
|
35
36
|
<th><%= _("User") %></th>
|
36
37
|
</tr>
|
37
38
|
<% for task in @tasks %>
|
@@ -42,7 +43,8 @@ $(document).on('click', ".table-two-pane td.two-pane-link", function(e) {
|
|
42
43
|
</td>
|
43
44
|
<td><%= task.state %></td>
|
44
45
|
<td><%= task.result %></td>
|
45
|
-
<td><%= task.started_at %></td>
|
46
|
+
<td><%= task.started_at.try(:in_time_zone) %></td>
|
47
|
+
<td><%= task.ended_at.try(:in_time_zone) %></td>
|
46
48
|
<td><%= task.username %></td>
|
47
49
|
</tr>
|
48
50
|
<% end %>
|
@@ -0,0 +1,12 @@
|
|
1
|
+
Bookmark.without_auditing do
|
2
|
+
[
|
3
|
+
{ :name => "running", :query => "state = running" },
|
4
|
+
{ :name => "failed", :query => "state = paused or result = error or result = warning" }
|
5
|
+
|
6
|
+
].each do |item|
|
7
|
+
next if Bookmark.find_by_name(item[:name])
|
8
|
+
next if audit_modified? Bookmark, item[:name]
|
9
|
+
b = Bookmark.create({:controller => "foreman_tasks_tasks", :public => true}.merge(item))
|
10
|
+
raise "Unable to create bookmark: #{format_errors b}" if b.nil? || b.errors.any?
|
11
|
+
end
|
12
|
+
end
|
data/lib/foreman_tasks.rb
CHANGED
@@ -40,4 +40,9 @@ module ForemanTasks
|
|
40
40
|
raise TaskError.new(task) if task.execution_plan.error?
|
41
41
|
end
|
42
42
|
end
|
43
|
+
|
44
|
+
def self.delay(action, delay_options, *args)
|
45
|
+
result = dynflow.world.delay action, delay_options, *args
|
46
|
+
ForemanTasks::Task::DynflowTask.find_by_external_id!(result.id)
|
47
|
+
end
|
43
48
|
end
|
@@ -13,7 +13,7 @@ module ForemanTasks
|
|
13
13
|
begin
|
14
14
|
on_execution_plan_save(execution_plan_id, value)
|
15
15
|
rescue => e
|
16
|
-
Foreman::Logging.exception("Error on on_execution_plan_save event", e, :logger =>
|
16
|
+
Foreman::Logging.exception("Error on on_execution_plan_save event", e, :logger => 'foreman-tasks/dynflow')
|
17
17
|
end
|
18
18
|
end
|
19
19
|
ensure
|
@@ -23,11 +23,22 @@ module ForemanTasks
|
|
23
23
|
def on_execution_plan_save(execution_plan_id, data)
|
24
24
|
# We can load the data unless the execution plan was properly planned and saved
|
25
25
|
# including its steps
|
26
|
-
|
27
|
-
|
26
|
+
case data[:state]
|
27
|
+
when :pending
|
28
|
+
ForemanTasks::Task::DynflowTask.new_for_execution_plan(execution_plan_id, data).save!
|
29
|
+
when :scheduled
|
30
|
+
delayed_plan = load_delayed_plan(execution_plan_id)
|
31
|
+
raise Foreman::Exception.new('Plan is delayed but the delay record is missing') if delayed_plan.nil?
|
32
|
+
# TODO: Rework this
|
33
|
+
delayed_plan = ::Dynflow::DelayedPlan.new_from_hash(ForemanTasks.dynflow.world, delayed_plan)
|
34
|
+
task = ::ForemanTasks::Task::DynflowTask.find_by_external_id(execution_plan_id)
|
35
|
+
task.update_from_dynflow(data.merge(:start_at => delayed_plan.start_at,
|
36
|
+
:start_before => delayed_plan.start_before))
|
37
|
+
when :planning
|
38
|
+
task = ::ForemanTasks::Task::DynflowTask.find_by_external_id(execution_plan_id)
|
28
39
|
task.update_from_dynflow(data)
|
29
40
|
Lock.owner!(::User.current, task.id) if ::User.current
|
30
|
-
|
41
|
+
else
|
31
42
|
if task = ::ForemanTasks::Task::DynflowTask.find_by_external_id(execution_plan_id)
|
32
43
|
unless task.state.to_s == data[:state].to_s
|
33
44
|
task.update_from_dynflow(data)
|
@@ -40,8 +40,8 @@ module ForemanTasks
|
|
40
40
|
task.reload
|
41
41
|
task.state.must_equal 'stopped'
|
42
42
|
task.result.must_equal 'success'
|
43
|
-
task.main_action.output.must_equal
|
44
|
-
|
43
|
+
task.main_action.output['proxy_task_id'].must_equal "123"
|
44
|
+
task.main_action.output['proxy_output'].must_equal({ 'result' => 'success' })
|
45
45
|
end
|
46
46
|
end
|
47
47
|
end
|
@@ -17,6 +17,7 @@ module ForemanTasks
|
|
17
17
|
proxy_call = Support::DummyProxyAction.proxy.log[:trigger_task].first
|
18
18
|
proxy_call.must_equal(["Proxy::DummyAction",
|
19
19
|
{ "foo" => "bar",
|
20
|
+
"connection_options" => { "retry_interval" => 15, "retry_count" => 4, "timeout" => 60 },
|
20
21
|
"proxy_url" => "proxy.example.com",
|
21
22
|
"callback" => { "task_id" => "123", "step_id" => @action.run_step_id }}])
|
22
23
|
end
|
@@ -61,6 +62,23 @@ module ForemanTasks
|
|
61
62
|
action = run_action(@action, ::Actions::ProxyAction::CallbackData.new('result' => 'success'))
|
62
63
|
action.output[:proxy_output].must_equal({'result' => 'success'})
|
63
64
|
end
|
65
|
+
|
66
|
+
it 'handles connection errors' do
|
67
|
+
action = create_and_plan_action(Support::DummyProxyAction, Support::DummyProxyAction.proxy, { :foo => 'bar' })
|
68
|
+
run_stubbed_action = lambda do |lambda_action|
|
69
|
+
run_action lambda_action do |block_action|
|
70
|
+
block_action.expects(:trigger_proxy_task).raises(Errno::ECONNREFUSED.new('Connection refused'))
|
71
|
+
end
|
72
|
+
end
|
73
|
+
action = run_stubbed_action.call action
|
74
|
+
action.state.must_equal :suspended
|
75
|
+
action.world.clock.pending_pings.length.must_equal 1
|
76
|
+
action.output[:metadata][:failed_proxy_tasks].length.must_equal 1
|
77
|
+
2.times { action.output[:metadata][:failed_proxy_tasks] << {} }
|
78
|
+
proc { action = run_stubbed_action.call action }.must_raise(Errno::ECONNREFUSED)
|
79
|
+
action.state.must_equal :error
|
80
|
+
end
|
81
|
+
|
64
82
|
end
|
65
83
|
|
66
84
|
end
|
data/test/unit/cleaner_test.rb
CHANGED
@@ -14,7 +14,7 @@ class TasksTest < ActiveSupport::TestCase
|
|
14
14
|
FactoryGirl.create(:dynflow_task, :product_create_task)]
|
15
15
|
cleaner.delete
|
16
16
|
ForemanTasks::Task.where(id: tasks_to_delete).must_be_empty
|
17
|
-
ForemanTasks::Task.where(id: tasks_to_keep).must_equal tasks_to_keep
|
17
|
+
ForemanTasks::Task.where(id: tasks_to_keep).order(:id).map(&:id).must_equal tasks_to_keep.map(&:id).sort
|
18
18
|
|
19
19
|
ForemanTasks.dynflow.world.persistence.
|
20
20
|
find_execution_plans(filters: {'uuid' => tasks_to_delete.map(&:external_id)}).size.must_equal 0
|
data/test/unit/task_test.rb
CHANGED
@@ -41,12 +41,13 @@ class TasksTest < ActiveSupport::TestCase
|
|
41
41
|
let(:inconsistent_task) { FactoryGirl.create(:dynflow_task, :inconsistent_dynflow_task) }
|
42
42
|
|
43
43
|
it 'ensures the tasks marked as running are really running in Dynflow' do
|
44
|
+
running_task_count = ForemanTasks::Task::DynflowTask.running.count
|
44
45
|
consistent_task.state.must_equal 'planned'
|
45
46
|
inconsistent_task.state.must_equal 'running'
|
46
47
|
|
47
48
|
fixed_count = ForemanTasks::Task::DynflowTask.consistency_check
|
48
49
|
|
49
|
-
fixed_count.must_equal 1
|
50
|
+
fixed_count.must_equal running_task_count + 1
|
50
51
|
consistent_task.reload.state.must_equal 'planned'
|
51
52
|
inconsistent_task.reload.state.must_equal 'planned'
|
52
53
|
end
|
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: 0.7.
|
4
|
+
version: 0.7.4
|
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: 2015-
|
11
|
+
date: 2015-09-17 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: dynflow
|
@@ -16,14 +16,14 @@ dependencies:
|
|
16
16
|
requirements:
|
17
17
|
- - ~>
|
18
18
|
- !ruby/object:Gem::Version
|
19
|
-
version: 0.8.
|
19
|
+
version: 0.8.6
|
20
20
|
type: :runtime
|
21
21
|
prerelease: false
|
22
22
|
version_requirements: !ruby/object:Gem::Requirement
|
23
23
|
requirements:
|
24
24
|
- - ~>
|
25
25
|
- !ruby/object:Gem::Version
|
26
|
-
version: 0.8.
|
26
|
+
version: 0.8.6
|
27
27
|
- !ruby/object:Gem::Dependency
|
28
28
|
name: sequel
|
29
29
|
requirement: !ruby/object:Gem::Requirement
|
@@ -105,6 +105,7 @@ files:
|
|
105
105
|
- app/lib/actions/helpers/lock.rb
|
106
106
|
- app/lib/actions/middleware/keep_current_user.rb
|
107
107
|
- app/lib/actions/proxy_action.rb
|
108
|
+
- app/lib/actions/serializers/active_record_serializer.rb
|
108
109
|
- app/lib/proxy_api/foreman_dynflow/dynflow_proxy.rb
|
109
110
|
- app/models/foreman_tasks/concerns/action_subject.rb
|
110
111
|
- app/models/foreman_tasks/concerns/action_triggering.rb
|
@@ -115,6 +116,7 @@ files:
|
|
115
116
|
- app/models/foreman_tasks/task/dynflow_task.rb
|
116
117
|
- app/models/foreman_tasks/task/status_explicator.rb
|
117
118
|
- app/models/foreman_tasks/task/summarizer.rb
|
119
|
+
- app/models/foreman_tasks/task/task_cancelled_exception.rb
|
118
120
|
- app/models/setting/foreman_tasks.rb
|
119
121
|
- app/views/foreman_tasks/api/tasks/show.json.rabl
|
120
122
|
- app/views/foreman_tasks/tasks/_details.html.erb
|
@@ -134,8 +136,10 @@ files:
|
|
134
136
|
- db/migrate/20131209122644_create_foreman_tasks_locks.rb
|
135
137
|
- db/migrate/20140324104010_remove_foreman_tasks_progress.rb
|
136
138
|
- db/migrate/20140813215942_add_parent_task_id.rb
|
139
|
+
- db/migrate/20150817102538_add_delay_attributes.rb
|
137
140
|
- db/seeds.d/20-foreman_tasks_permissions.rb
|
138
141
|
- db/seeds.d/60-dynflow_proxy_feature.rb
|
142
|
+
- db/seeds.d/61-foreman_tasks_bookmarks.rb
|
139
143
|
- deploy/foreman-tasks.init
|
140
144
|
- deploy/foreman-tasks.service
|
141
145
|
- deploy/foreman-tasks.sysconfig
|