Class: ASAConsole::Terminal::SSH

Inherits:
Object
  • Object
show all
Defined in:
lib/asa_console/terminal/ssh.rb

Overview

An SSH terminal session.

Constant Summary collapse

DEFAULT_CONNECT_TIMEOUT =
5
DEFAULT_COMMAND_TIMEOUT =
5

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(opts) ⇒ SSH

Returns a new instance of SSH.

Parameters:

  • opts (Hash)

    a customizable set of options

Options Hash (opts):

  • :host (String)
  • :user (String)
  • :password (String)
  • :connect_timeout (Numeric)
  • :command_timeout (Numeric)

See Also:



44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
# File 'lib/asa_console/terminal/ssh.rb', line 44

def initialize(opts)
  fail Error::MissingOptionError, 'Option :host is missing' unless opts[:host]
  fail Error::MissingOptionError, 'Option :user is missing' unless opts[:user]

  @host = opts[:host]
  @user = opts[:user]
  @ssh_opts = {
    timeout: opts.fetch(:connect_timeout, DEFAULT_CONNECT_TIMEOUT),
    number_of_password_prompts: 0 # Avoid prompting for password on authentication failure
  }
  self.password = opts[:password]
  @command_timeout = opts.fetch(:command_timeout, DEFAULT_COMMAND_TIMEOUT)
  @prompt = nil

  @raw_buffer           = ''
  @raw_session_log      = ''
  @connected            = false
  @channel              = nil
  @session              = nil
  @last_output_received = nil
  @on_output_callbacks  = []
end

Instance Attribute Details

#command_timeoutNumeric

Maximum time to wait for a command to execute.

Returns:

  • (Numeric)

    the current value of command_timeout



27
28
29
# File 'lib/asa_console/terminal/ssh.rb', line 27

def command_timeout
  @command_timeout
end

#connect_timeoutNumeric

SSH connection timeout. (:timeout option passed to Net::SSH::start)

Returns:

  • (Numeric)

    the current value of connect_timeout



27
28
29
# File 'lib/asa_console/terminal/ssh.rb', line 27

def connect_timeout
  @connect_timeout
end

#hostString

Hostname or IP address.

Returns:

  • (String)

    the current value of host



27
28
29
# File 'lib/asa_console/terminal/ssh.rb', line 27

def host
  @host
end

#passwordString

SSH password.

Returns:

  • (String)

    the current value of password



27
28
29
# File 'lib/asa_console/terminal/ssh.rb', line 27

def password
  @password
end

#promptString? (readonly)

Prompt currently displayed on the terminal or nil if not connected.

Returns:

  • (String, nil)

    the current value of prompt



27
28
29
# File 'lib/asa_console/terminal/ssh.rb', line 27

def prompt
  @prompt
end

#ssh_optsHash

Option hash passed to Net::SSH::start.

Returns:

  • (Hash)

    the current value of ssh_opts



27
28
29
# File 'lib/asa_console/terminal/ssh.rb', line 27

def ssh_opts
  @ssh_opts
end

#userString

SSH username.

Returns:

  • (String)

    the current value of user



27
28
29
# File 'lib/asa_console/terminal/ssh.rb', line 27

def user
  @user
end

Instance Method Details

#connectvoid

This method returns an undefined value.

Start an SSH session and send a remote shell request. The method blocks until an EXEC prompt is received or a timeout is reached.

Raises:

See Also:



94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
# File 'lib/asa_console/terminal/ssh.rb', line 94

def connect
  Net::SSH.start(@host, @user, @ssh_opts) do |session|
    @session = session
    @session.open_channel do |channel|
      channel.send_channel_request('shell') do |ch, ch_success|
        fail Error::ConnectFailure, 'Failed to start remote shell' unless ch_success
        @connected = true
        @channel = ch
        @channel.on_data do |_ch, data|
          @last_output_received = Time.now.getlocal
          @raw_session_log << data
          @raw_buffer << data
        end
        @channel.on_close do
          @connected = false
        end
        expect(ANY_EXEC_PROMPT) do |success, output|
          @on_output_callbacks.each { |c| c.call(nil, nil, output) }
          fail Error::ConnectFailure, 'Failed to parse EXEC prompt', self unless success
        end
        return # Workaround for Net::SSH limitations borrowed from Puppet
      end
    end
  end
rescue Timeout::Error
  raise Error::ConnectionTimeoutError, "Timeout connecting to #{@host}"
rescue Net::SSH::AuthenticationFailed
  raise Error::AuthenticationFailure, "Authentication failed for #{@user}@#{@host}"
rescue SystemCallError, SocketError => e
  raise Error::ConnectFailure, "#{e.class}: #{e.message}"
end

#connected?Boolean

Returns:

  • (Boolean)


127
128
129
130
# File 'lib/asa_console/terminal/ssh.rb', line 127

def connected?
  @connected = false if @session.nil? || @session.closed?
  @connected
end

#disconnectvoid

This method returns an undefined value.



133
134
135
136
137
# File 'lib/asa_console/terminal/ssh.rb', line 133

def disconnect
  @session.close if connected?
rescue Net::SSH::Disconnect
  @session = nil
end

#on_output {|prompt, command, output| ... } ⇒ void

This method returns an undefined value.

Register a proc to be called whenever the #send method finishes processing a transaction (whether successful or not).

Examples:

@command_log = []
asa.terminal.on_output do |prompt, command, output|
  if prompt && prompt !~ ASAConsole::PASSWORD_PROMPT
    @command_log << command
  end
end

Yield Parameters:

  • prompt (String)
  • command (String)
  • output (String)


179
180
181
# File 'lib/asa_console/terminal/ssh.rb', line 179

def on_output(&block)
  @on_output_callbacks << block
end

#send(line, expect_regex, is_password = false) {|success, output| ... } ⇒ void

Note:

Special characters are not escaped by this method. Use the ASAConsole wrapper for unescaped text.

This method returns an undefined value.

Send a line of text to the console and block until the expected prompt is seen in the output or a timeout is reached.

Parameters:

  • line (String)
  • expect_regex (Regexp)
  • is_password (Boolean) (defaults to: false)

Yield Parameters:

  • success (Boolean)
  • output (String)

See Also:



153
154
155
156
157
158
159
160
161
162
# File 'lib/asa_console/terminal/ssh.rb', line 153

def send(line, expect_regex, is_password = false)
  last_prompt = @prompt
  @channel.send_data "#{line}\n" if connected?
  input = (is_password ? '*' * line.length : line) + "\n"
  expect(expect_regex) do |success, output|
    output = output.sub(/^[^\n]*\n/m, '') # Remove echoed input
    @on_output_callbacks.each { |c| c.call(last_prompt, input, output) }
    yield(success, output)
  end
end

#session_logString

Returns a complete log of the SSH session.

Returns:

  • (String)

    a complete log of the SSH session



184
185
186
# File 'lib/asa_console/terminal/ssh.rb', line 184

def session_log
  Util.apply_control_chars(@raw_session_log)
end