foreman-tasks 0.3.6 → 0.4.0
Sign up to get free protection for your applications and to get access to all the features.
- data/app/models/foreman_tasks/concerns/action_subject.rb +1 -116
- data/app/models/foreman_tasks/concerns/action_triggering.rb +129 -0
- data/app/models/foreman_tasks/concerns/architecture_action_subject.rb +1 -0
- data/app/views/foreman_tasks/tasks/show.html.erb +6 -1
- data/lib/foreman_tasks/version.rb +1 -1
- metadata +3 -2
@@ -1,15 +1,9 @@
|
|
1
1
|
module ForemanTasks
|
2
2
|
module Concerns
|
3
|
-
module ActionSubject
|
3
|
+
module ActionSubject
|
4
4
|
|
5
5
|
extend ActiveSupport::Concern
|
6
6
|
|
7
|
-
included do
|
8
|
-
after_create :plan_create_action
|
9
|
-
after_update :plan_update_action
|
10
|
-
after_destroy :plan_destroy_action
|
11
|
-
end
|
12
|
-
|
13
7
|
module ClassMethods
|
14
8
|
def available_locks
|
15
9
|
[:read, :write]
|
@@ -49,115 +43,6 @@ module ForemanTasks
|
|
49
43
|
mine + mine.reduce(Set.new) { |s, resource| s + get_all_related_resources.(resource) }
|
50
44
|
end
|
51
45
|
|
52
|
-
# to make the triggered action synchronous
|
53
|
-
def sync_action!
|
54
|
-
@dynflow_sync_action = true
|
55
|
-
end
|
56
|
-
|
57
|
-
def sync_action_flag_reset!
|
58
|
-
@dynflow_sync_action = false
|
59
|
-
end
|
60
|
-
|
61
|
-
def create_action
|
62
|
-
end
|
63
|
-
|
64
|
-
def update_action
|
65
|
-
end
|
66
|
-
|
67
|
-
def destroy_action
|
68
|
-
end
|
69
|
-
|
70
|
-
def plan_create_action
|
71
|
-
plan_action(create_action, self) if create_action
|
72
|
-
return true
|
73
|
-
end
|
74
|
-
|
75
|
-
def plan_update_action
|
76
|
-
plan_action(update_action, self) if update_action
|
77
|
-
return true
|
78
|
-
end
|
79
|
-
|
80
|
-
def plan_destroy_action
|
81
|
-
plan_action(destroy_action, self) if destroy_action
|
82
|
-
return true
|
83
|
-
end
|
84
|
-
|
85
|
-
# Perform planning phase of the action tied with the model event.
|
86
|
-
# We do it separately from the execution phase, because the transaction
|
87
|
-
# of planning phase is expected to be commited when execution occurs. Also
|
88
|
-
# we want to be able to rollback the whole db operation when planning fails.
|
89
|
-
def plan_action(action_class, *args)
|
90
|
-
@execution_plan = ::ForemanTasks.dynflow.world.plan(action_class, *args)
|
91
|
-
raise @execution_plan.errors.first if @execution_plan.error?
|
92
|
-
end
|
93
|
-
|
94
|
-
def save(*)
|
95
|
-
dynflow_task_wrap(:save) { super }
|
96
|
-
end
|
97
|
-
|
98
|
-
def save!(*)
|
99
|
-
dynflow_task_wrap(:save) { super }
|
100
|
-
end
|
101
|
-
|
102
|
-
def destroy
|
103
|
-
dynflow_task_wrap(:destroy) { super }
|
104
|
-
end
|
105
|
-
|
106
|
-
# Makes sure the execution plan is executed AFTER the transaction is commited.
|
107
|
-
# We can't user after_commit filters because they don't allow to raise
|
108
|
-
# exceptions in there, so we would not be able to report that something
|
109
|
-
# went wrong when running a sync_task.:
|
110
|
-
#
|
111
|
-
# http://guides.rubyonrails.org/v3.2.14/active_record_validations_callbacks.html#transaction-callbacks
|
112
|
-
#
|
113
|
-
# That's why we need to override save and destroy methods instead.
|
114
|
-
# Another reason why one should avoid callbacks for orchestration.
|
115
|
-
#
|
116
|
-
# Also, it makes sure the save is not run inside other transaction because
|
117
|
-
# we would start the execution phase inside this transaction which would lead
|
118
|
-
# to unexpected results.
|
119
|
-
def dynflow_task_wrap(method)
|
120
|
-
action = case method
|
121
|
-
when :save
|
122
|
-
self.new_record? ? create_action : update_action
|
123
|
-
when :destroy
|
124
|
-
destroy_action
|
125
|
-
else
|
126
|
-
raise 'unexpected method'
|
127
|
-
end
|
128
|
-
if action
|
129
|
-
ensure_not_in_transaction!
|
130
|
-
yield.tap do |result|
|
131
|
-
execute_planned_action if result
|
132
|
-
sync_action_flag_reset!
|
133
|
-
end
|
134
|
-
else
|
135
|
-
yield
|
136
|
-
end
|
137
|
-
end
|
138
|
-
|
139
|
-
# we don't want to start executing the task calling to external services
|
140
|
-
# when inside some other transaction. Might lead to unexpected results
|
141
|
-
def ensure_not_in_transaction!
|
142
|
-
if self.class.connection.open_transactions > 0
|
143
|
-
raise "Executing dynflow action inside a transaction is not a good idea"
|
144
|
-
end
|
145
|
-
end
|
146
|
-
|
147
|
-
# Execute the prepared execution plan after the db transaction was commited
|
148
|
-
def execute_planned_action
|
149
|
-
if @execution_plan
|
150
|
-
run = ::ForemanTasks.dynflow.world.execute(@execution_plan.id)
|
151
|
-
if @dynflow_sync_action
|
152
|
-
run.wait
|
153
|
-
if run.value.error?
|
154
|
-
task = ForemanTasks::Task::DynflowTask.find_by_external_id!(@execution_plan.id)
|
155
|
-
raise ForemanTasks::TaskError.new(task)
|
156
|
-
end
|
157
|
-
end
|
158
|
-
end
|
159
|
-
return true
|
160
|
-
end
|
161
46
|
end
|
162
47
|
end
|
163
48
|
end
|
@@ -0,0 +1,129 @@
|
|
1
|
+
module ForemanTasks
|
2
|
+
module Concerns
|
3
|
+
module ActionTriggering
|
4
|
+
|
5
|
+
extend ActiveSupport::Concern
|
6
|
+
|
7
|
+
included do
|
8
|
+
after_create :plan_create_action
|
9
|
+
after_update :plan_update_action
|
10
|
+
after_destroy :plan_destroy_action
|
11
|
+
end
|
12
|
+
|
13
|
+
# @override
|
14
|
+
def create_action
|
15
|
+
end
|
16
|
+
|
17
|
+
# @override
|
18
|
+
def update_action
|
19
|
+
end
|
20
|
+
|
21
|
+
# @override
|
22
|
+
def destroy_action
|
23
|
+
end
|
24
|
+
|
25
|
+
def save(*)
|
26
|
+
dynflow_task_wrap(:save) { super }
|
27
|
+
end
|
28
|
+
|
29
|
+
def save!(*)
|
30
|
+
dynflow_task_wrap(:save) { super }
|
31
|
+
end
|
32
|
+
|
33
|
+
def destroy
|
34
|
+
dynflow_task_wrap(:destroy) { super }
|
35
|
+
end
|
36
|
+
|
37
|
+
protected
|
38
|
+
|
39
|
+
def sync_action_flag_reset!
|
40
|
+
@dynflow_sync_action = false
|
41
|
+
end
|
42
|
+
|
43
|
+
# to make the triggered action synchronous
|
44
|
+
def sync_action!
|
45
|
+
@dynflow_sync_action = true
|
46
|
+
end
|
47
|
+
|
48
|
+
def plan_create_action
|
49
|
+
plan_action(create_action, self) if create_action
|
50
|
+
return true
|
51
|
+
end
|
52
|
+
|
53
|
+
def plan_update_action
|
54
|
+
plan_action(update_action, self) if update_action
|
55
|
+
return true
|
56
|
+
end
|
57
|
+
|
58
|
+
def plan_destroy_action
|
59
|
+
plan_action(destroy_action, self) if destroy_action
|
60
|
+
return true
|
61
|
+
end
|
62
|
+
|
63
|
+
# Perform planning phase of the action tied with the model event.
|
64
|
+
# We do it separately from the execution phase, because the transaction
|
65
|
+
# of planning phase is expected to be commited when execution occurs. Also
|
66
|
+
# we want to be able to rollback the whole db operation when planning fails.
|
67
|
+
def plan_action(action_class, *args)
|
68
|
+
@execution_plan = ::ForemanTasks.dynflow.world.plan(action_class, *args)
|
69
|
+
raise @execution_plan.errors.first if @execution_plan.error?
|
70
|
+
end
|
71
|
+
|
72
|
+
# Makes sure the execution plan is executed AFTER the transaction is commited.
|
73
|
+
# We can't user after_commit filters because they don't allow to raise
|
74
|
+
# exceptions in there, so we would not be able to report that something
|
75
|
+
# went wrong when running a sync_task.:
|
76
|
+
#
|
77
|
+
# http://guides.rubyonrails.org/v3.2.14/active_record_validations_callbacks.html#transaction-callbacks
|
78
|
+
#
|
79
|
+
# That's why we need to override save and destroy methods instead.
|
80
|
+
# Another reason why one should avoid callbacks for orchestration.
|
81
|
+
#
|
82
|
+
# Also, it makes sure the save is not run inside other transaction because
|
83
|
+
# we would start the execution phase inside this transaction which would lead
|
84
|
+
# to unexpected results.
|
85
|
+
def dynflow_task_wrap(method)
|
86
|
+
action = case method
|
87
|
+
when :save
|
88
|
+
self.new_record? ? create_action : update_action
|
89
|
+
when :destroy
|
90
|
+
destroy_action
|
91
|
+
else
|
92
|
+
raise 'unexpected method'
|
93
|
+
end
|
94
|
+
if action
|
95
|
+
ensure_not_in_transaction!
|
96
|
+
yield.tap do |result|
|
97
|
+
execute_planned_action if result
|
98
|
+
sync_action_flag_reset!
|
99
|
+
end
|
100
|
+
else
|
101
|
+
yield
|
102
|
+
end
|
103
|
+
end
|
104
|
+
|
105
|
+
# we don't want to start executing the task calling to external services
|
106
|
+
# when inside some other transaction. Might lead to unexpected results
|
107
|
+
def ensure_not_in_transaction!
|
108
|
+
if self.class.connection.open_transactions > 0
|
109
|
+
raise "Executing dynflow action inside a transaction is not a good idea"
|
110
|
+
end
|
111
|
+
end
|
112
|
+
|
113
|
+
# Execute the prepared execution plan after the db transaction was commited
|
114
|
+
def execute_planned_action
|
115
|
+
if @execution_plan
|
116
|
+
run = ::ForemanTasks.dynflow.world.execute(@execution_plan.id)
|
117
|
+
if @dynflow_sync_action
|
118
|
+
run.wait
|
119
|
+
if run.value.error?
|
120
|
+
task = ForemanTasks::Task::DynflowTask.find_by_external_id!(@execution_plan.id)
|
121
|
+
raise ForemanTasks::TaskError.new(task)
|
122
|
+
end
|
123
|
+
end
|
124
|
+
end
|
125
|
+
return true
|
126
|
+
end
|
127
|
+
end
|
128
|
+
end
|
129
|
+
end
|
@@ -40,8 +40,13 @@
|
|
40
40
|
<span class="param-name"><%= _("Progress") %>:</span>
|
41
41
|
<span class="param-value">
|
42
42
|
<div class="progress progress-striped">
|
43
|
-
|
43
|
+
<% progress = 100 * @task.progress %>
|
44
|
+
<div class="progress-bar" role="progressbar" aria-valuenow="<%= progress %>"
|
45
|
+
aria-valuemin="0" aria-valuemax="100" style="width: <%= progress %>%">
|
46
|
+
<span class="sr-only"><%= progress %>% Complete</span>
|
47
|
+
</div>
|
44
48
|
</div>
|
49
|
+
</span>
|
45
50
|
</div>
|
46
51
|
<% if @task.cli_example %>
|
47
52
|
<div>
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: foreman-tasks
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.4.0
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2014-03-
|
12
|
+
date: 2014-03-12 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: rails
|
@@ -143,6 +143,7 @@ files:
|
|
143
143
|
- app/controllers/foreman_tasks/tasks_controller.rb
|
144
144
|
- app/controllers/foreman_tasks/concerns/hosts_controller_extension.rb
|
145
145
|
- app/models/foreman_tasks/concerns/architecture_action_subject.rb
|
146
|
+
- app/models/foreman_tasks/concerns/action_triggering.rb
|
146
147
|
- app/models/foreman_tasks/concerns/host_action_subject.rb
|
147
148
|
- app/models/foreman_tasks/concerns/action_subject.rb
|
148
149
|
- app/models/foreman_tasks/task/dynflow_task.rb
|