Class: JobInvocation

Inherits:
ApplicationRecord
  • Object
show all
Includes:
Authorizable, Encryptable, ForemanRemoteExecution::ErrorsFlattener, ForemanTasks::Concerns::ActionSubject
Defined in:
app/models/job_invocation.rb

Defined Under Namespace

Classes: Jail

Constant Summary collapse

CACHE_PREFIX =
"job_invocation".freeze
FLATTENED_ERRORS_MAPPING =
{
  :pattern_template_invocations => lambda do |template_invocation|
    _('template') + " #{template_invocation.template.name}"
  end,
}.freeze

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Methods included from ForemanRemoteExecution::ErrorsFlattener

#flattened_errors, #flattened_validation_exception

Instance Attribute Details

#description_formatObject

Returns the value of attribute description_format.



91
92
93
# File 'app/models/job_invocation.rb', line 91

def description_format
  @description_format
end

#start_at=(value) ⇒ Object (writeonly)

Sets the attribute start_at

Parameters:

  • value

    the value to set the attribute start_at to.



92
93
94
# File 'app/models/job_invocation.rb', line 92

def start_at=(value)
  @start_at = value
end

#start_beforeObject

Returns the value of attribute start_before.



91
92
93
# File 'app/models/job_invocation.rb', line 91

def start_before
  @start_before
end

Class Method Details

.search_by_pattern_template(key, operator, value) ⇒ Object



106
107
108
# File 'app/models/job_invocation.rb', line 106

def self.search_by_pattern_template(key, operator, value)
  { :conditions => sanitize_sql_for_conditions(["templates.name = ?", value]), :joins => :pattern_templates }
end

.search_by_recurring_logic(key, operator, value) ⇒ Object



116
117
118
119
120
121
122
# File 'app/models/job_invocation.rb', line 116

def self.search_by_recurring_logic(key, operator, value)
  reucurring = value == 'true'
  reucurring = !reucurring if operator == '<>'
  not_operator = reucurring ? 'NOT' : ''

  { :conditions => sanitize_sql_for_conditions(["foreman_tasks_recurring_logics.id IS #{not_operator} NULL"]), :joins => :recurring_logic }
end

.search_by_status(key, operator, value) ⇒ Object



110
111
112
113
114
# File 'app/models/job_invocation.rb', line 110

def self.search_by_status(key, operator, value)
  conditions = HostStatus::ExecutionStatus::ExecutionTaskStatusMapper.sql_conditions_for(value)
  conditions[0] = "NOT (#{conditions[0]})" if operator == '<>'
  { :conditions => sanitize_sql_for_conditions(conditions), :joins => :task }
end

.search_by_targeted_host(key, operator, value) ⇒ Object



102
103
104
# File 'app/models/job_invocation.rb', line 102

def self.search_by_targeted_host(key, operator, value)
  { :conditions => sanitize_sql_for_conditions(["hosts.id = ?", value]), :joins => :targeted_hosts }
end

Instance Method Details

#available_providers(host) ⇒ Object

TODO: determine from the host and job_invocation details



238
239
240
# File 'app/models/job_invocation.rb', line 238

def available_providers(host)
  return RemoteExecutionProvider.provider_names
end

#build_notificationObject



128
129
130
131
132
133
134
135
136
137
138
139
# File 'app/models/job_invocation.rb', line 128

def build_notification
  klass = nil
  if self.remote_execution_feature && self.remote_execution_feature.notification_builder.present?
    begin
      klass = remote_execution_feature.notification_builder.constantize
    rescue NameError => e
      logger.exception "REX feature defines unknown notification builder class", e
    end
  end
  klass ||= UINotifications::RemoteExecutionJobs::BaseJobFinish
  klass.new(self)
end

#cancel(force = false) ⇒ Object



282
283
284
285
# File 'app/models/job_invocation.rb', line 282

def cancel(force = false)
  method = force ? :abort : :cancel
  task.send(method)
end

#deep_cloneObject



168
169
170
171
172
173
174
175
176
177
178
179
# File 'app/models/job_invocation.rb', line 168

def deep_clone
  JobInvocationComposer.from_job_invocation(self).job_invocation.tap do |invocation|
    invocation.task_group = JobInvocationTaskGroup.new
    invocation.triggering = self.triggering
    invocation.description_format = self.description_format
    invocation.description = self.description
    invocation.pattern_template_invocations = self.pattern_template_invocations.map(&:deep_clone)
    invocation.password = self.password
    invocation.key_passphrase = self.key_passphrase
    invocation.effective_user_password = self.effective_user_password
  end
end

#deep_clone!Object



181
182
183
# File 'app/models/job_invocation.rb', line 181

def deep_clone!
  deep_clone.tap(&:save!)
end

#failed_host_idsObject



193
194
195
# File 'app/models/job_invocation.rb', line 193

def failed_host_ids
  failed_hosts.pluck(:id)
end

#failed_hostsObject



201
202
203
204
205
206
207
208
# File 'app/models/job_invocation.rb', line 201

def failed_hosts
  base = targeting.hosts
  if finished?
    base.where.not(:id => not_failed_template_invocations.select(:host_id))
  else
    base.where(:id => failed_template_invocations.select(:host_id))
  end
end

#failed_template_invocation_tasksObject



189
190
191
# File 'app/models/job_invocation.rb', line 189

def failed_template_invocation_tasks
  template_invocation_tasks.where(:result => TemplateInvocation::TaskResultMap.status_to_task_result(:failed))
end

#finished?Boolean

Returns:

  • (Boolean)


287
288
289
# File 'app/models/job_invocation.rb', line 287

def finished?
  !(task.nil? || task.pending?)
end

#generate_descriptionObject



252
253
254
255
256
257
258
259
260
261
262
263
264
# File 'app/models/job_invocation.rb', line 252

def generate_description
  template_invocation = pattern_template_invocations.first
  input_hash = template_invocation.input_values.reduce({}) do |h, v|
    value = v.value
    value = '*' * 3 if v.template_input.respond_to?(:hidden_value) && v.template_input.hidden_value?
    h.update("%{#{v.template_input.name}}" => value)
  end
  input_hash.update("%{job_category}" => job_category)
  input_hash.update("%{template_name}" => template_invocation.template.name)
  input_hash.default = "''"
  self.description = description_format.gsub(/%{[^}]+}/) { |key| input_hash[key] }
  self.description = self.description[0..(JobInvocation.columns_hash['description'].limit - 1)]
end

#missing_hosts_countObject



291
292
293
# File 'app/models/job_invocation.rb', line 291

def missing_hosts_count
  targeting.resolved? ? total_hosts_count - targeting.hosts.count : 0
end

#notification_recipients_idsObject



124
125
126
# File 'app/models/job_invocation.rb', line 124

def notification_recipients_ids
  [ self.targeting.user_id ]
end

#output(host) ⇒ Object



246
247
248
249
250
# File 'app/models/job_invocation.rb', line 246

def output(host)
  return unless (task = sub_task_for_host(host)) && task.main_action && task.main_action.live_output.any?

  task.main_action.live_output.first['output']
end

#pattern_template_invocation_for_host(host) ⇒ Object



232
233
234
235
# File 'app/models/job_invocation.rb', line 232

def pattern_template_invocation_for_host(host)
  providers = available_providers(host)
  pattern_template_invocations.find { |pti| providers.include? pti.template.provider_type }
end

#progress(total = nil, done = nil) ⇒ Object

returns progress in percents



154
155
156
157
158
159
160
161
162
# File 'app/models/job_invocation.rb', line 154

def progress(total = nil, done = nil)
  if queued? || !targeting.resolved? || done == 0
    0
  else
    total ||= targeting.hosts.count
    done  ||= sub_tasks.where(:result => %w(success warning error)).count
    ((done.to_f / total) * 100).round
  end
end

#progress_reportObject



266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
# File 'app/models/job_invocation.rb', line 266

def progress_report
  map = TemplateInvocation::TaskResultMap
  all_keys = (map.results | map.statuses | [:progress, :total])
  if queued? || (task && task.started_at.nil?) || !targeting.resolved?
    all_keys.reduce({}) do |acc, key|
      acc.merge(key => 0)
    end
  else
    counts = task.sub_tasks_counts
    counts.default = 0
    done = counts.values_at(*map.results).reduce(:+)
    percent = progress(counts[:total], done)
    counts.merge(:progress => percent, :failed => counts.values_at(*map.status_to_task_result(:failed)).reduce(:+))
  end
end

#queued?Boolean

Returns:

  • (Boolean)


164
165
166
# File 'app/models/job_invocation.rb', line 164

def queued?
  status == HostStatus::ExecutionStatus::QUEUED
end

#statusObject



141
142
143
# File 'app/models/job_invocation.rb', line 141

def status
  HostStatus::ExecutionStatus::ExecutionTaskStatusMapper.new(task).status
end

#status_labelObject



145
146
147
# File 'app/models/job_invocation.rb', line 145

def status_label
  HostStatus::ExecutionStatus::ExecutionTaskStatusMapper.new(task).status_label
end

#sub_task_for_host(host) ⇒ Object



242
243
244
# File 'app/models/job_invocation.rb', line 242

def sub_task_for_host(host)
  template_invocations.find_by(:host => host.id).try(:run_host_job_task)
end

#succeeded_host_idsObject



197
198
199
# File 'app/models/job_invocation.rb', line 197

def succeeded_host_ids
  succeeded_hosts.pluck(:id)
end

#succeeded_hostsObject



210
211
212
213
214
215
216
217
# File 'app/models/job_invocation.rb', line 210

def succeeded_hosts
  base = targeting.hosts
  if finished?
    base.where.not(:id => not_succeeded_template_invocations.select(:host_id))
  else
    base.where(:id => succeeded_template_invocations.select(:host_id))
  end
end

#to_action_inputObject



185
186
187
# File 'app/models/job_invocation.rb', line 185

def to_action_input
  { :id => id, :name => job_category, :description => description }
end

#to_labelObject



149
150
151
# File 'app/models/job_invocation.rb', line 149

def to_label
  description
end

#total_hosts_countObject



219
220
221
222
223
224
225
226
227
228
229
230
# File 'app/models/job_invocation.rb', line 219

def total_hosts_count
  count = _('N/A')

  if targeting.resolved?
    count = if task&.main_action.respond_to?(:total_count)
              task.main_action.total_count
            else
              targeting.hosts.count
            end
  end
  count
end