Class: Actions::RemoteExecution::RunHostJob

Inherits:
EntryAction
  • Object
show all
Extended by:
ApipieDSL::Class
Includes:
Helpers::WithContinuousOutput, Helpers::WithDelegatedAction, ObservableAction
Defined in:
app/lib/actions/remote_execution/run_host_job.rb

Defined Under Namespace

Classes: Jail

Class Method Summary collapse

Instance Method Summary collapse

Class Method Details

.feature_job_event_name(label, suffix = :success) ⇒ Object



75
76
77
# File 'app/lib/actions/remote_execution/run_host_job.rb', line 75

def self.feature_job_event_name(label, suffix = :success)
  ::Foreman::Observable.event_name_for("#{::Actions::RemoteExecution::RunHostJob.event_name_base}_#{label}_#{::Actions::RemoteExecution::RunHostJob.event_name_suffix(suffix)}")
end

Instance Method Details

#check_exit_statusObject



99
100
101
102
# File 'app/lib/actions/remote_execution/run_host_job.rb', line 99

def check_exit_status
  error! ForemanTasks::Task::TaskCancelledException.new(_('Task cancelled')) if delegated_action && delegated_action.output[:cancel_sent]
  error! _('Job execution failed') if exit_status.to_s != '0'
end

#continuous_output_providersObject



126
127
128
# File 'app/lib/actions/remote_execution/run_host_job.rb', line 126

def continuous_output_providers
  super << self
end

#emit_feature_event(execution_plan, hook = :success) ⇒ Object



79
80
81
82
83
84
85
86
87
88
89
# File 'app/lib/actions/remote_execution/run_host_job.rb', line 79

def emit_feature_event(execution_plan, hook = :success)
  return unless root_action?

  payload = event_payload(execution_plan)
  if input["job_features"]&.any?
    input['job_features'].each do |feature|
      name = "#{self.class.event_name_base}_#{feature}_#{self.class.event_name_suffix(hook)}"
      trigger_hook name, payload: payload
    end
  end
end

#exit_statusObject



151
152
153
# File 'app/lib/actions/remote_execution/run_host_job.rb', line 151

def exit_status
  delegated_output[:exit_status]
end

#fill_continuous_output(continuous_output) ⇒ Object



130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
# File 'app/lib/actions/remote_execution/run_host_job.rb', line 130

def fill_continuous_output(continuous_output)
  delegated_output.fetch('result', []).each do |raw_output|
    continuous_output.add_raw_output(raw_output)
  end

  final_timestamp = (continuous_output.last_timestamp || task.ended_at).to_f + 1

  if task.state == 'stopped' && task.result == 'cancelled'
    continuous_output.add_output(_('Job cancelled by user'), 'debug', final_timestamp)
  else
    fill_planning_errors_to_continuous_output(continuous_output) unless exit_status
  end
  if exit_status
    continuous_output.add_output(_('Exit status: %s') % exit_status, 'stdout', final_timestamp)
  elsif run_step&.error
    continuous_output.add_output(_('Job finished with error') + ": #{run_step.error.exception_class} - #{run_step.error.message}", 'debug', final_timestamp)
  end
rescue => e
  continuous_output.add_exception(_('Error loading data from proxy'), e)
end

#finalize(*args) ⇒ Object



70
71
72
73
# File 'app/lib/actions/remote_execution/run_host_job.rb', line 70

def finalize(*args)
  update_host_status
  check_exit_status
end

#hostObject



171
172
173
# File 'app/lib/actions/remote_execution/run_host_job.rb', line 171

def host
  @host ||= ::Host.authorized.find(host_id)
end

#host_idObject



155
156
157
# File 'app/lib/actions/remote_execution/run_host_job.rb', line 155

def host_id
  input['host']['id']
end

#host_nameObject



159
160
161
# File 'app/lib/actions/remote_execution/run_host_job.rb', line 159

def host_name
  input['host']['name']
end

#humanized_inputObject



109
110
111
112
# File 'app/lib/actions/remote_execution/run_host_job.rb', line 109

def humanized_input
  N_('%{description} on %{host}') % { :host => input[:host].try(:[], :name),
    :description => input[:description].try(:capitalize) || input[:job_category] }
end

#humanized_nameObject



114
115
116
# File 'app/lib/actions/remote_execution/run_host_job.rb', line 114

def humanized_name
  N_('Remote action:')
end

#humanized_outputObject



122
123
124
# File 'app/lib/actions/remote_execution/run_host_job.rb', line 122

def humanized_output
  continuous_output.humanize
end

#job_invocationObject



167
168
169
# File 'app/lib/actions/remote_execution/run_host_job.rb', line 167

def job_invocation
  @job_invocation ||= ::JobInvocation.authorized.find(job_invocation_id)
end

#job_invocation_idObject



163
164
165
# File 'app/lib/actions/remote_execution/run_host_job.rb', line 163

def job_invocation_id
  input['job_invocation_id']
end

#live_outputObject



104
105
106
107
# File 'app/lib/actions/remote_execution/run_host_job.rb', line 104

def live_output
  continuous_output.sort!
  continuous_output.raw_outputs
end

#plan(job_invocation, host, template_invocation, proxy_selector = ::RemoteExecutionProxySelector.new, options = {}) ⇒ Object



21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
# File 'app/lib/actions/remote_execution/run_host_job.rb', line 21

def plan(job_invocation, host, template_invocation, proxy_selector = ::RemoteExecutionProxySelector.new, options = {})
  features = template_invocation.template.remote_execution_features.pluck(:label).uniq
  action_subject(host,
    :job_category => job_invocation.job_category,
    :description => job_invocation.description,
    :job_invocation_id => job_invocation.id,
    :job_features => features)

  template_invocation.host_id = host.id
  template_invocation.run_host_job_task_id = task.id
  template_invocation.save!

  link!(job_invocation)
  link!(template_invocation)

  verify_permissions(host, template_invocation)

  raise _('Could not use any template used in the job invocation') if template_invocation.blank?

  provider = template_invocation.template.provider
  proxy_selector = provider.required_proxy_selector_for(template_invocation.template) || proxy_selector

  provider_type = template_invocation.template.provider_type.to_s
  proxy = determine_proxy!(proxy_selector, provider_type, host)
  link!(proxy)
  input[:proxy_id] = proxy.id

  renderer = InputTemplateRenderer.new(template_invocation.template, host, template_invocation)
  script = renderer.render
  raise _('Failed rendering template: %s') % renderer.error_message unless script

  first_execution = host.executed_through_proxies.where(:id => proxy.id).none?
  host.executed_through_proxies << proxy if first_execution

  additional_options = { :hostname => provider.find_ip_or_hostname(host),
                         :script => script,
                         :execution_timeout_interval => job_invocation.execution_timeout_interval,
                         :secrets => secrets(host, job_invocation, provider),
                         :use_batch_triggering => true,
                         :use_concurrency_control => options[:use_concurrency_control],
                         :first_execution => first_execution,
                         :alternative_names => provider.alternative_names(host) }
  action_options = provider.proxy_command_options(template_invocation, host)
                           .merge(additional_options)

  plan_delegated_action(proxy, provider.proxy_action_class, action_options)
  plan_self
end

#queueObject



13
14
15
# File 'app/lib/actions/remote_execution/run_host_job.rb', line 13

def queue
  ForemanRemoteExecution::DYNFLOW_QUEUE
end

#rescue_strategyObject



118
119
120
# File 'app/lib/actions/remote_execution/run_host_job.rb', line 118

def rescue_strategy
  ::Dynflow::Action::Rescue::Fail
end

#resource_locksObject



17
18
19
# File 'app/lib/actions/remote_execution/run_host_job.rb', line 17

def resource_locks
  :link
end

#secrets(host, job_invocation, provider) ⇒ Object



91
92
93
94
95
96
97
# File 'app/lib/actions/remote_execution/run_host_job.rb', line 91

def secrets(host, job_invocation, provider)
  job_secrets = { :ssh_password => job_invocation.password,
                  :key_passphrase => job_invocation.key_passphrase,
                  :effective_user_password => job_invocation.effective_user_password }

  job_secrets.merge(provider.secrets(host)) { |_key, job_secret, provider_secret| job_secret || provider_secret }
end