module ShellStrike::Ssh

Public Class Methods

check_host_reachable(host) click to toggle source
# File lib/shell_strike/ssh.rb, line 6
def check_host_reachable(host)
  reachable = false
  explanation = nil

  begin
    establish_connection(host, 'fake_username', 'fake_password')
    reachable = true
  rescue Net::SSH::AuthenticationFailed
    reachable = true
  rescue Net::SSH::ConnectionTimeout
    explanation = :timeout
  rescue Errno::EHOSTUNREACH
    explanation = :unreachable
  rescue Net::SSH::Exception
    explanation = :unexpected_error
  end
  
  [reachable, explanation]
end
execute_command(host, username, password, command) click to toggle source

Executes the specified command against the specified host. @param host [ShellStrike::Host] The host to execute the command against. @param username [String] The username to use to establish the connection. @param password [String] The password to use to establish the connection. @param command [String] The command to run against the remote host. @raise [HostUnreachableError] If a connection to the host could not be established. @raise [InvalidCredentialsError] If the credentials supplied are invalid. @return [CommandResult] The result of the command's execution.

# File lib/shell_strike/ssh.rb, line 45
def execute_command(host, username, password, command)
  raise HostUnreachableError unless check_host_reachable(host)[0]
  raise InvalidCredentialsError unless valid_credentials?(host, username, password)

  exit_code = 1
  stdout_text = ''
  stderr_text = ''


  establish_connection(host, username, password) do |ssh|
    ssh.open_channel do |channel|
      channel.exec(command) do |ch, success|
        raise CommandExecutionFailureError unless success

        # Process the stdout stream
        ch.on_data do |_, stdout_buf|
          stdout_text << stdout_buf.read
        end

        # Process the stderr stream
        ch.on_extended_data do |_, stderr_buf|
          stderr_text << stderr_buf.read
        end

        ch.on_request('exit-status') do |_, status|
          exit_code = status.read_long
        end
      end

      channel.wait # Make sure we don't close the channel until the command has completed
    end
  end

  # Split the output streams at each linefeed
  stdout_arr = stdout_text.split("\n")
  stderr_arr = stderr_text.split("\n")

  CommandResult.new(command: command, exit_code: exit_code, stdout: stdout_arr, stderr: stderr_arr)
end
valid_credentials?(host, username, password) click to toggle source
# File lib/shell_strike/ssh.rb, line 26
def valid_credentials?(host, username, password)
  return false unless check_host_reachable(host)[0]

  begin
    establish_connection(host, username, password)
    true
  rescue Net::SSH::Exception, Errno::EHOSTUNREACH
    false
  end
end

Private Class Methods

establish_connection(host, username, password, &block) click to toggle source

Establishes a connection to the specified host. @param host [ShellStrike::Host] The host to connect to. @param username [String] The username to connect using. @param password [String] The password to connect using. @yieldparam [Net::SSH::Connection::Session] block The block to execute against the established SSH connection.

# File lib/shell_strike/ssh.rb, line 93
def self.establish_connection(host, username, password, &block)
  Net::SSH::start(host.host, username, password: password, port: host.port, non_interactive: true, timeout: host.connection_timeout, &block)
end