Class: ForemanRemoteExecutionCore::PollingScriptRunner

Inherits:
ScriptRunner
  • Object
show all
Defined in:
lib/foreman_remote_execution_core/polling_script_runner.rb

Constant Summary collapse

DEFAULT_REFRESH_INTERVAL =
60
CONTROL_SCRIPT =

The script that controls the flow of the job, able to initiate update or finish on the task, or take over the control over script lifecycle

load_script('control.sh')
RETRIEVE_SCRIPT =

The script always outputs at least one line First line of the output either has to begin with “RUNNING” or “DONE $EXITCODE” The following lines are treated as regular output

load_script('retrieve.sh')

Constants inherited from ScriptRunner

ScriptRunner::EXPECTED_POWER_ACTION_MESSAGES, ScriptRunner::MAX_PROCESS_RETRIES

Instance Attribute Summary

Attributes inherited from ScriptRunner

#execution_timeout_interval

Class Method Summary collapse

Instance Method Summary collapse

Methods inherited from ScriptRunner

build, #kill, #publish_data, #start, #timeout, #timeout_interval, #with_disconnect_handling, #with_retries

Constructor Details

#initialize(options, user_method, suspended_action: nil) ⇒ PollingScriptRunner

Returns a new instance of PollingScriptRunner.



23
24
25
26
27
28
29
# File 'lib/foreman_remote_execution_core/polling_script_runner.rb', line 23

def initialize(options, user_method, suspended_action: nil)
  super(options, user_method, suspended_action: suspended_action)
  @callback_host = options[:callback_host]
  @task_id = options[:uuid]
  @step_id = options[:step_id]
  @otp = ForemanTasksCore::OtpManager.generate_otp(@task_id)
end

Class Method Details

.load_script(name) ⇒ Object



8
9
10
11
# File 'lib/foreman_remote_execution_core/polling_script_runner.rb', line 8

def self.load_script(name)
  script_dir = File.expand_path('../async_scripts', __FILE__)
  File.read(File.join(script_dir, name))
end

Instance Method Details

#closeObject



87
88
89
90
# File 'lib/foreman_remote_execution_core/polling_script_runner.rb', line 87

def close
  super
  ForemanTasksCore::OtpManager.drop_otp(@task_id, @otp) if @otp
end

#env_scriptObject

Script setting the dynamic values to env variables: it’s sourced from other control scripts



102
103
104
105
106
107
108
109
# File 'lib/foreman_remote_execution_core/polling_script_runner.rb', line 102

def env_script
  <<-SCRIPT.gsub(/^ +\| /, '')
  | CALLBACK_HOST="#{@callback_host}"
  | TASK_ID="#{@task_id}"
  | STEP_ID="#{@step_id}"
  | OTP="#{@otp}"
  SCRIPT
end

#external_event(event) ⇒ Object



75
76
77
78
79
80
81
82
83
84
85
# File 'lib/foreman_remote_execution_core/polling_script_runner.rb', line 75

def external_event(event)
  data = event.data
  if data['manual_mode']
    load_event_updates(data)
  else
    # getting the update from automatic mode - reaching to the host to get the latest update
    return run_refresh
  end
ensure
  destroy_session
end

#initialization_scriptObject



37
38
39
40
41
42
43
44
45
46
47
# File 'lib/foreman_remote_execution_core/polling_script_runner.rb', line 37

def initialization_script
  close_stdin = '</dev/null'
  close_fds = close_stdin + ' >/dev/null 2>/dev/null'
  main_script = "(#{@remote_script} #{close_stdin} 2>&1; echo $?>#{@base_dir}/init_exit_code) >#{@base_dir}/output"
  control_script_finish = "#{@control_script_path} init-script-finish"
  <<-SCRIPT.gsub(/^ +\| /, '')
  | export CONTROL_SCRIPT="#{@control_script_path}"
  | sh -c '#{main_script}; #{control_script_finish}' #{close_fds} &
  | echo $! > '#{@base_dir}/pid'
  SCRIPT
end

#prepare_startObject



31
32
33
34
35
# File 'lib/foreman_remote_execution_core/polling_script_runner.rb', line 31

def prepare_start
  super
  @base_dir = File.dirname @remote_script
  upload_control_scripts
end

#refreshObject



53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
# File 'lib/foreman_remote_execution_core/polling_script_runner.rb', line 53

def refresh
  err = output = nil
  begin
    _, output, err = run_sync("#{@user_method.cli_command_prefix} #{@retrieval_script}")
  rescue => e
    @logger.info("Error while connecting to the remote host on refresh: #{e.message}")
  end
  return if output.nil? || output.empty?

  lines = output.lines
  result = lines.shift.match(/^DONE (\d+)?/)
  publish_data(lines.join, 'stdout') unless lines.empty?
  publish_data(err, 'stderr') unless err.empty?
  if result
    exitcode = result[1] || 0
    publish_exit_status(exitcode.to_i)
    cleanup
  end
ensure
  destroy_session
end

#trigger(*args) ⇒ Object



49
50
51
# File 'lib/foreman_remote_execution_core/polling_script_runner.rb', line 49

def trigger(*args)
  run_sync(*args)
end

#upload_control_scriptsObject



92
93
94
95
96
97
98
99
# File 'lib/foreman_remote_execution_core/polling_script_runner.rb', line 92

def upload_control_scripts
  return if @control_scripts_uploaded

  cp_script_to_remote(env_script, 'env.sh')
  @control_script_path = cp_script_to_remote(CONTROL_SCRIPT, 'control.sh')
  @retrieval_script = cp_script_to_remote(RETRIEVE_SCRIPT, 'retrieve.sh')
  @control_scripts_uploaded = true
end