module SshExec

Constants

VERSION

Public Class Methods

ensure_exec(ssh, command, options = {}) click to toggle source

Runs the given command in the given SSH shell, and raises {ExecutionError} in case of failure (nonzero exit status). Logs the command in all cases. Logs the command, exit status, standard output and standard error in case of failure. @param ssh the {Net::SSH} shell to run the command in @param options [Hash] optional settings:

`echo_stdout` - whether to echo stdout from the subcommand,
`echo_stderr` - whether to echo stderr from the subcommand,
`quiet` - to suppress logging the command and the error in case of non-zero exit status

@return [OpenStruct] a struct containing `stdout`, `stderr`, `exit_status`, and `exit_signal`

# File lib/ssh-exec.rb, line 82
def self.ensure_exec(ssh, command, options = {})
  result = ssh_exec!(ssh, command, options)

  options = options.clone
  quiet = options.delete(:quiet)

  @@log.info("Running on #{ssh.host}: #{command}") unless quiet

  if result.exit_status  != 0
    @@log.error(
      ("Failed running command #{command}: exit status #{result.exit_status}. " +
      (result.stdout.empty? ? "" : "Standard output:\n#{result.stdout}\n") +
      (result.stderr.empty? ? "" : "Standard error:\n#{result.stderr}")).strip
    ) unless quiet
    raise ExecutionError.new(
      "Failed running command #{command}: exit status #{result.exit_status}"
    )
  end
  result
end
ssh_exec!(ssh, command, options = {}) click to toggle source

Execute the given command using the given ssh object and capture its standard output, standard error, and exit status. The implementation is based on this {stackoverflow.com/questions/3386233/how-to-get-exit-status-with-rubys-netssh-library/3386375#3386375 StackOveflow answer}. @param ssh the {Net::SSH} shell to run the command in @param options [Hash] optional settings:

`echo_stdout` - whether to echo standard output from the subcommand,
`echo_stderr` - whether to echo standard error from the subcommand

@return [OpenStruct] a struct containing `stdout`, `stderr`, `exit_status`, and `exit_signal`

# File lib/ssh-exec.rb, line 30
def self.ssh_exec!(ssh, command, options = {})
  options = options.clone
  echo_stdout = options[:echo_stdout]
  echo_stderr = options[:echo_stderr]
  raise "Invalid options: #{options}" unless options.empty?

  stdout_data = ""
  stderr_data = ""
  exit_code = nil
  exit_signal = nil
  ssh.open_channel do |channel|
    channel.exec(command) do |ch, success|
      unless success
        raise "FAILED: couldn't execute command #{command}"
      end
      channel.on_data do |ch, data|
        stdout_data += data
        $stdout.write(data) if echo_stdout
      end

      channel.on_extended_data do |ch, type, data|
        stderr_data += data
        $stderr.write(data) if echo_stderr
      end

      channel.on_request("exit-status") do |ch, data|
        exit_code = data.read_long
      end

      channel.on_request("exit-signal") do |ch, data|
        exit_signal = data.read_long
      end
    end
  end
  ssh.loop
  OpenStruct.new(
    :stdout => stdout_data,
    :stderr => stderr_data,
    :exit_status => exit_code,
    :exit_signal => exit_signal
  )
end