class Proxy::RemoteExecution::Ssh::Runners::PollingScriptRunner

Constants

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

DEFAULT_REFRESH_INTERVAL
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

Public Class Methods

load_script(name) click to toggle source
# File lib/smart_proxy_remote_execution_ssh/runners/polling_script_runner.rb, line 7
def self.load_script(name)
  script_dir = File.expand_path('../async_scripts', __dir__)
  File.read(File.join(script_dir, name))
end
new(options, user_method, suspended_action: nil) click to toggle source
Calls superclass method
# File lib/smart_proxy_remote_execution_ssh/runners/polling_script_runner.rb, line 22
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 = Proxy::Dynflow::OtpManager.generate_otp(@task_id)
end

Public Instance Methods

close() click to toggle source
Calls superclass method
# File lib/smart_proxy_remote_execution_ssh/runners/polling_script_runner.rb, line 91
def close
  super
  Proxy::Dynflow::OtpManager.drop_otp(@task_id, @otp) if @otp
end
env_script() click to toggle source

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

# File lib/smart_proxy_remote_execution_ssh/runners/polling_script_runner.rb, line 106
    def env_script
      <<-SCRIPT.gsub(/^ +\| /, '')
      | CALLBACK_HOST="#{@callback_host}"
      | TASK_ID="#{@task_id}"
      | STEP_ID="#{@step_id}"
      | OTP="#{@otp}"
      SCRIPT
    end
external_event(event) click to toggle source
# File lib/smart_proxy_remote_execution_ssh/runners/polling_script_runner.rb, line 79
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_script() click to toggle source
# File lib/smart_proxy_remote_execution_ssh/runners/polling_script_runner.rb, line 36
    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_start() click to toggle source
Calls superclass method
# File lib/smart_proxy_remote_execution_ssh/runners/polling_script_runner.rb, line 30
def prepare_start
  super
  @base_dir = File.dirname @remote_script
  upload_control_scripts
end
process_retrieved_data(output, err) click to toggle source
# File lib/smart_proxy_remote_execution_ssh/runners/polling_script_runner.rb, line 65
def process_retrieved_data(output, err)
  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
end
refresh() click to toggle source
# File lib/smart_proxy_remote_execution_ssh/runners/polling_script_runner.rb, line 52
def refresh
  err = output = nil
  begin
    _, output, err = run_sync("#{@user_method.cli_command_prefix} #{@retrieval_script}")
  rescue StandardError => e
    @logger.info("Error while connecting to the remote host on refresh: #{e.message}")
  end

  process_retrieved_data(output, err)
ensure
  destroy_session
end
trigger(*args) click to toggle source
# File lib/smart_proxy_remote_execution_ssh/runners/polling_script_runner.rb, line 48
def trigger(*args)
  run_sync(*args)
end
upload_control_scripts() click to toggle source
# File lib/smart_proxy_remote_execution_ssh/runners/polling_script_runner.rb, line 96
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

Private Instance Methods

cleanup() click to toggle source
# File lib/smart_proxy_remote_execution_ssh/runners/polling_script_runner.rb, line 128
def cleanup
  run_sync("rm -rf \"#{remote_command_dir}\"") if @cleanup_working_dirs
end
destroy_session() click to toggle source
# File lib/smart_proxy_remote_execution_ssh/runners/polling_script_runner.rb, line 132
def destroy_session
  if @session
    @logger.debug("Closing session with #{@ssh_user}@#{@host}")
    close_session
  end
end
load_event_updates(event_data) click to toggle source

Generates updates based on the callback data from the manual mode

# File lib/smart_proxy_remote_execution_ssh/runners/polling_script_runner.rb, line 118
def load_event_updates(event_data)
  continuous_output = Proxy::Dynflow::ContinuousOutput.new
  if event_data.key?('output')
    lines = Base64.decode64(event_data['output']).sub(/\A(RUNNING|DONE).*\n/, '')
    continuous_output.add_output(lines, 'stdout')
  end
  cleanup if event_data['exit_code']
  new_update(continuous_output, event_data['exit_code'])
end