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.
@@ -1,15 +1,9 @@
1
1
  module ForemanTasks
2
2
  module Concerns
3
- module ActionSubject # TODO slit to two modules: auto planning, acting as action subject
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
@@ -3,6 +3,7 @@ module ForemanTasks
3
3
  module ArchitectureActionSubject
4
4
  extend ActiveSupport::Concern
5
5
  include ForemanTasks::Concerns::ActionSubject
6
+ include ForemanTasks::Concerns::ActionTriggering
6
7
 
7
8
  def create_action
8
9
  ::Actions::Foreman::Architecture::Create
@@ -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
- <div class="bar" style="width: <%= 100 * @task.progress %>%;"></div>
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>
@@ -1,3 +1,3 @@
1
1
  module ForemanTasks
2
- VERSION = "0.3.6"
2
+ VERSION = "0.4.0"
3
3
  end
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.3.6
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-10 00:00:00.000000000 Z
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