Class: ForemanTasks::Task::DynflowTask
Constant Summary
Constants included
from Search
Search::SUPPORTED_DURATION_FORMAT
Class Method Summary
collapse
Instance Method Summary
collapse
#action, #action_continuous_output, #add_missing_task_groups, authorized_resource_name, #build_notifications, #check_permissions_after_save, #delayed?, #execution_type, latest_tasks_by_resource_ids, #notification_recipients_ids, #owner, #paused?, #pending?, #recurring?, #scheduled?, #self_and_parents, #sub_tasks_counts, #to_label, #username
Methods included from Search
#search_by_duration, #search_by_generic_resource, #search_by_taxonomy
Class Method Details
.consistency_check ⇒ Object
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
|
# File 'app/models/foreman_tasks/task/dynflow_task.rb', line 219
def self.consistency_check
fixed_count = 0
logger = Foreman::Logging.logger('foreman-tasks')
joins('LEFT JOIN dynflow_execution_plans ON foreman_tasks_tasks.external_id = dynflow_execution_plans.uuid::varchar')
.where('foreman_tasks_tasks.state_updated_at < dynflow_execution_plans.ended_at')
.find_each do |task|
changes = task.update_from_dynflow(task.execution_plan.to_hash)
unless changes.empty?
fixed_count += 1
logger.warn('Task %s updated at consistency check: %s' % [task.id, changes.inspect])
end
rescue => e
task.update(:state => 'stopped', :result => 'error')
Foreman::Logging.exception("Failed at consistency check for task #{task.id}", e, :logger => 'foreman-tasks')
end
ForemanTasks::Lock.left_joins(:task).merge(where(:state => 'stopped')).destroy_all
fixed_count
end
|
.model_name ⇒ Object
250
251
252
|
# File 'app/models/foreman_tasks/task/dynflow_task.rb', line 250
def self.model_name
superclass.model_name
end
|
.new_for_execution_plan(execution_plan) ⇒ Object
243
244
245
246
247
248
|
# File 'app/models/foreman_tasks/task/dynflow_task.rb', line 243
def self.new_for_execution_plan(execution_plan)
new(:external_id => execution_plan.id,
:state => execution_plan.state.to_s,
:result => execution_plan.result.to_s,
:user_id => User.current.try(:id))
end
|
Instance Method Details
#abort ⇒ Object
35
36
37
|
# File 'app/models/foreman_tasks/task/dynflow_task.rb', line 35
def abort
execution_plan!.cancel(true).any?
end
|
#active_job? ⇒ Boolean
165
166
167
168
169
|
# File 'app/models/foreman_tasks/task/dynflow_task.rb', line 165
def active_job?
return false unless execution_plan.present? &&
execution_plan.root_plan_step.present?
execution_plan_action.class == ::Dynflow::ActiveJob::QueueAdapters::JobWrapper
end
|
#active_job_action(klass, args) ⇒ Object
The class for ActiveJob jobs in Dynflow, JobWrapper is not expected to implement any humanized actions. Individual jobs are expected to implement humanized_* methods for foreman-tasks integration.
158
159
160
161
162
163
|
# File 'app/models/foreman_tasks/task/dynflow_task.rb', line 158
def active_job_action(klass, args)
return if klass.blank?
if (active_job_class = klass.safe_constantize)
active_job_class.new(*args)
end
end
|
#active_job_data ⇒ Object
171
172
173
174
175
176
177
178
179
180
|
# File 'app/models/foreman_tasks/task/dynflow_task.rb', line 171
def active_job_data
args = if execution_plan.delay_record
execution_plan.delay_record.args.first
else
execution_plan_action.input
end
return args['job_data'] if args.key?('job_data')
{ 'job_class' => args['job_class'], 'arguments' => args['job_arguments'] }
end
|
#cancel ⇒ Object
31
32
33
|
# File 'app/models/foreman_tasks/task/dynflow_task.rb', line 31
def cancel
execution_plan!.cancel.any?
end
|
#cancellable? ⇒ Boolean
27
28
29
|
# File 'app/models/foreman_tasks/task/dynflow_task.rb', line 27
def cancellable?
execution_plan.try(:cancellable?)
end
|
#cancellable_action?(action) ⇒ Boolean
43
44
45
|
# File 'app/models/foreman_tasks/task/dynflow_task.rb', line 43
def cancellable_action?(action)
action.is_a?(::Dynflow::Action::Cancellable)
end
|
#cli_example ⇒ Object
136
137
138
|
# File 'app/models/foreman_tasks/task/dynflow_task.rb', line 136
def cli_example
main_action.cli_example if main_action.respond_to?(:cli_example)
end
|
#delayed_plan ⇒ Object
72
73
74
|
# File 'app/models/foreman_tasks/task/dynflow_task.rb', line 72
def delayed_plan
ForemanTasks.dynflow.world.persistence.load_delayed_plan(external_id) if state == :scheduled
end
|
#execution_plan(silence_exception = true) ⇒ Object
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
|
# File 'app/models/foreman_tasks/task/dynflow_task.rb', line 52
def execution_plan(silence_exception = true)
return @execution_plan if defined?(@execution_plan)
execution_plan = ForemanTasks.dynflow.world.persistence.load_execution_plan(external_id)
if execution_plan.respond_to?(:valid?) && !execution_plan.valid?
raise execution_plan.exception
else
@execution_plan = execution_plan
end
@execution_plan
rescue => e
Foreman::Logging.exception("Could not load execution plan #{external_id} for task #{id}", e, :logger => 'foreman-tasks')
raise e unless silence_exception
nil
end
|
#execution_plan! ⇒ Object
76
77
78
|
# File 'app/models/foreman_tasks/task/dynflow_task.rb', line 76
def execution_plan!
execution_plan(false)
end
|
#execution_plan_action ⇒ Object
182
183
184
|
# File 'app/models/foreman_tasks/task/dynflow_task.rb', line 182
def execution_plan_action
execution_plan.root_plan_step.action(execution_plan)
end
|
#execution_scheduled? ⇒ Boolean
186
187
188
189
190
|
# File 'app/models/foreman_tasks/task/dynflow_task.rb', line 186
def execution_scheduled?
main_action.nil? || main_action.respond_to?(:execution_plan) &&
main_action.execution_plan.state == :scheduled ||
execution_plan.state == :scheduled
end
|
#failed_steps ⇒ Object
94
95
96
|
# File 'app/models/foreman_tasks/task/dynflow_task.rb', line 94
def failed_steps
execution_plan.try(:steps_in_state, :skipped, :skipping, :error) || []
end
|
#find_humanize_method_kind(method) ⇒ Object
212
213
214
215
216
217
|
# File 'app/models/foreman_tasks/task/dynflow_task.rb', line 212
def find_humanize_method_kind(method)
return method if /humanized_.*/ =~ method
if [:name, :input, :output, :error].include?(method)
"humanized_#{method}".to_sym
end
end
|
#frozen ⇒ Object
68
69
70
|
# File 'app/models/foreman_tasks/task/dynflow_task.rb', line 68
def frozen
delayed_plan.try(:frozen)
end
|
#get_humanized(method) ⇒ Object
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
|
# File 'app/models/foreman_tasks/task/dynflow_task.rb', line 192
def get_humanized(method)
@humanized_cache ||= {}
method = find_humanize_method_kind(method)
Match! method, :humanized_name, :humanized_input, :humanized_output, :humanized_errors
if method != :humanized_name && execution_scheduled?
return
elsif method == :humanized_name && main_action.nil?
return N_(label)
end
@humanized_cache[method] ||= begin
if main_action.respond_to? method
begin
main_action.send method
rescue Exception => error "#{error.message} (#{error.class})\n#{error.backtrace.join "\n"}"
end
end
end
end
|
#halt ⇒ Object
254
255
256
|
# File 'app/models/foreman_tasks/task/dynflow_task.rb', line 254
def halt
::ForemanTasks.dynflow.world.halt(external_id)
end
|
#humanized ⇒ Object
129
130
131
132
133
134
|
# File 'app/models/foreman_tasks/task/dynflow_task.rb', line 129
def humanized
{ action: get_humanized(:humanized_name),
input: get_humanized(:humanized_input),
output: get_humanized(:humanized_output),
errors: get_humanized(:humanized_errors) }
end
|
85
86
87
88
|
# File 'app/models/foreman_tasks/task/dynflow_task.rb', line 85
def input
return active_job_data['arguments'] if active_job?
main_action.task_input if main_action.respond_to?(:task_input)
end
|
102
103
104
105
106
107
108
109
110
111
112
113
|
# File 'app/models/foreman_tasks/task/dynflow_task.rb', line 102
def input_output_failed_steps
failed_steps.map do |f|
f_action = f.action(execution_plan)
{
error: ({ exception_class: f.error.exception_class, message: f.error.message, backtrace: f.error.backtrace } if f.error),
action_class: f.action_class.name,
state: f.state,
input: f_action.input.pretty_inspect,
output: f_action.output.pretty_inspect,
}
end
end
|
115
116
117
118
119
120
121
122
123
124
125
126
127
|
# File 'app/models/foreman_tasks/task/dynflow_task.rb', line 115
def input_output_running_steps
running_steps.map do |f|
f_action = f.action(execution_plan)
{
id: f_action.id,
action_class: f.action_class.name,
state: f.state,
input: f_action.input.pretty_inspect,
output: f_action.output.pretty_inspect,
cancellable: cancellable_action?(f_action),
}
end
end
|
#label ⇒ Object
80
81
82
83
|
# File 'app/models/foreman_tasks/task/dynflow_task.rb', line 80
def label
return main_action.class.name if main_action.present?
self[:label]
end
|
#main_action ⇒ Object
140
141
142
143
144
145
146
147
148
149
150
151
152
153
|
# File 'app/models/foreman_tasks/task/dynflow_task.rb', line 140
def main_action
return @main_action if defined?(@main_action)
@main_action = execution_plan && execution_plan.root_plan_step.try(:action, execution_plan)
if active_job?
job_data = active_job_data
begin
@main_action = active_job_action(job_data['job_class'], job_data['arguments'])
rescue => e
Foreman::Logging.exception("Failed to load ActiveJob for task #{id}", e, :logger => 'foreman-tasks')
end
end
@main_action
end
|
#output ⇒ Object
90
91
92
|
# File 'app/models/foreman_tasks/task/dynflow_task.rb', line 90
def output
main_action.task_output if main_action.respond_to?(:task_output)
end
|
#progress ⇒ Object
47
48
49
50
|
# File 'app/models/foreman_tasks/task/dynflow_task.rb', line 47
def progress
progress_raw = execution_plan.try(:progress) || 0
progress_raw.round(2)
end
|
#resumable? ⇒ Boolean
39
40
41
|
# File 'app/models/foreman_tasks/task/dynflow_task.rb', line 39
def resumable?
execution_plan.try(:state) == :paused
end
|
#running_steps ⇒ Object
98
99
100
|
# File 'app/models/foreman_tasks/task/dynflow_task.rb', line 98
def running_steps
execution_plan.try(:steps_in_state, :running, :suspended) || []
end
|
#update_from_dynflow(plan, delayed_plan = nil) ⇒ Object
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
|
# File 'app/models/foreman_tasks/task/dynflow_task.rb', line 8
def update_from_dynflow(plan, delayed_plan = nil)
self.external_id = plan.id
self.result = map_result(plan).to_s
self.state = plan.state.to_s
self.started_at = plan.started_at unless plan.started_at.nil?
self.ended_at = plan.ended_at unless plan.ended_at.nil?
self.start_at = delayed_plan.start_at if delayed_plan
self.start_before = delayed_plan.start_before if delayed_plan
self.parent_task_id ||= begin
if main_action.try(:caller_execution_plan_id)
DynflowTask.where(:external_id => main_action.caller_execution_plan_id).first!.id
end
end
self[:label] ||= label
changes = self.changes
save!
changes
end
|