Class: SshHelper::TmcSsh

Inherits:
Object show all
Defined in:
lib/helpers/tmc_helpers/ssh_helper/ssh_helper.rb

Instance Method Summary collapse

Constructor Details

#initialize(test_case) ⇒ TmcSsh

Returns a new instance of TmcSsh.



24
25
26
27
28
29
30
31
32
33
34
# File 'lib/helpers/tmc_helpers/ssh_helper/ssh_helper.rb', line 24

def initialize(test_case)
  @debug = false
  @test_case = test_case
  @host = nil
  @user = nil
  @ssh = nil
  @buffer = ''
  @buffer_lock = Mutex.new
  @last_sent_data = ''
  reset_pty
end

Instance Method Details

#expect(data, timeout: 10.sec) ⇒ Object

Public: Waits for some output in the active PTY.

data - String or Regexp output to expect. timeout - Integer timeout in milliseconds (default: 10.sec).

Returns a String data buffered before the expected output.



128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
# File 'lib/helpers/tmc_helpers/ssh_helper/ssh_helper.rb', line 128

def expect(data, timeout: 10.sec)
  raise 'No active pty.' if @pty.nil? && !@pty_starting
  data ||= @pty_prompt
  logdebug("Expecting: #{data.inspect}")
  reason = nil
  begin
    Timeout.timeout(timeout / 1000.0) do
      @ssh.loop(0.1) do
        ready = false
        if @pty.nil?
          unless @pty_starting
            reason = 'no pty'
            ready = true
          end
        elsif @pty.eof?
          reason = 'pty is eof'
          ready = true
        elsif search_buffer(data)
          reason = 'pty is ready'
          ready = true
        end
        !ready
      end
    end
  rescue TimeoutError
    @buffer_lock.synchronize do
      raise "#{session_info} Timed out waiting for expected output in buffer:\n#{@buffer}"
    end
  end
  puts "*ready (#{reason})" if @debug
  if @pty.nil?
    @buffer_lock.synchronize do
      puts "*buffer: #{@buffer.inspect}" if @debug
      raw_output = @buffer
    end
  else
    puts "*before: #{@before.inspect}" if @debug
    puts "*match: #{@match.inspect}" if @debug
    raw_output = @before
  end
  raw_output ||= ''
  logdebug("Output:\n#{@last_match || ''}#{raw_output.rstrip}")
  re = /^#{@last_sent_data.gsub(/\r?\n/, '\r?\n')}/
  puts "*trimming start: #{re.inspect}" if @debug
  raw_output.sub(re, '')
end

#send_command(cmd, prompt: nil, expect: nil, timeout: 10.sec) ⇒ Object

Public: Sends a command to the session and waits for output.

cmd - String command to send. prompt - String or Regexp prompt to set for the current program (default: nil). expect - String or Regexp output to expect, if not the prompt (default: nil). timeout - Integer timeout in milliseconds (default: 10.sec).

Returns a String data buffered before the prompt or expected output.



88
89
90
91
92
93
94
95
96
97
98
99
100
101
# File 'lib/helpers/tmc_helpers/ssh_helper/ssh_helper.rb', line 88

def send_command(cmd, prompt: nil, expect: nil, timeout: 10.sec)
  if @pty.nil?
    # no active pty, just execute the command the normal way
    loginfo("Sending command: #{cmd}")
    output = @ssh.exec!(cmd)
    logdebug("Output:\n#{output.rstrip}")
    output
  else
    # send to active pty and wait
    send_raw(cmd + "\n")
    @pty_prompt = prompt unless prompt.nil?
    expect(expect, timeout: timeout)
  end
end

#send_raw(data, expect: nil, timeout: 10.sec) ⇒ Object

Public: Sends some data to the active PTY.

data - String data to send. expect - String or Regexp output to expect (default: nil). timeout - Integer timeout in milliseconds (default: 10.sec).

Returns nothing, or a String data buffered before the expected output.



110
111
112
113
114
115
116
117
118
119
120
# File 'lib/helpers/tmc_helpers/ssh_helper/ssh_helper.rb', line 110

def send_raw(data, expect: nil, timeout: 10.sec)
  raise 'No active pty.' if @pty.nil?
  loginfo("Sending: #{data}".strip)
  @last_sent_data = data
  @pty.send_data(data)
  if expect.nil?
    nil
  else
    expect(expect, timeout: timeout)
  end
end

#sessionObject

Public: Gets the underlying session, for advanced usage.

Returns the Net::SSH session.



39
40
41
# File 'lib/helpers/tmc_helpers/ssh_helper/ssh_helper.rb', line 39

def session
  @ssh
end

#start(host, username, password: nil) ⇒ Object

Public: Starts a new SSH session.

host - String host name or IP. username - String username to use. password - String password to use (default: nil).

Returns nothing.



182
183
184
185
186
187
188
189
# File 'lib/helpers/tmc_helpers/ssh_helper/ssh_helper.rb', line 182

def start(host, username, password: nil)
  @test_case.logger.info("Starting new SSH session: #{username}@#{host}")
  @ssh = Net::SSH.start(host, username, :password => password)
  @host = host
  @user = username
  @test_case.add_teardown("#{session_info} Shutting down") { stop }
  puts '*ssh connected' if @debug
end

#start_program(program, prompt, expect: nil, timeout: 10.sec) ⇒ Object

Public: Starts a program in the session and waits for output. This should be used for running any interactive

programs like telnet, sudo, vim. Note that this will end any active program with possible loss of of data.

program - String name of program to start. prompt - String or Regexp prompt to use for the program. expect - String or Regexp output to expect, if not the prompt (default: nil). timeout - Integer timeout in milliseconds (default: 10.sec).

Returns a String data buffered before the prompt or expected output.



52
53
54
55
56
57
# File 'lib/helpers/tmc_helpers/ssh_helper/ssh_helper.rb', line 52

def start_program(program, prompt, expect: nil, timeout: 10.sec)
  loginfo("Starting program: #{program}")
  stop_pty unless @pty.nil?
  start_pty(program, prompt)
  expect(expect, timeout: timeout)
end

#start_ssh(host, username, prompt, password: nil, timeout: 30.sec) ⇒ Object

Public: Starts a new SSH session in the current session.

Note that this will end any active program with possible loss of of data.

host - String host name or IP. username - String username to use. prompt - String or Regexp prompt to use for the program. password - String password to use (default: nil). timeout - Integer timeout in milliseconds (default: 30.sec).

Returns a String data buffered before the prompt or expected output.



69
70
71
72
73
74
75
76
77
78
# File 'lib/helpers/tmc_helpers/ssh_helper/ssh_helper.rb', line 69

def start_ssh(host, username, prompt, password: nil, timeout: 30.sec)
  loginfo("Starting SSH to #{username}@#{host}")
  cmd = "ssh -o UserKnownHostsFile=/dev/null -o StrictHostKeyChecking=no #{username}@#{host}"
  start = Time.now
  start_program(cmd, prompt, timeout: timeout, expect: password.nil? ? nil : /(?i)password:/)
  unless password.nil?
    time_left = timeout - ((Time.now - start) * 1000)
    send_command(password, timeout: time_left)
  end
end

#stopObject

Public: Stops the SSH session.

Returns nothing.



194
195
196
197
198
199
200
201
202
# File 'lib/helpers/tmc_helpers/ssh_helper/ssh_helper.rb', line 194

def stop
  loginfo('Stopping')
  stop_pty unless @pty.nil?
  unless @ssh.nil?
    @ssh.close
    @ssh = nil
    @ssh_channel = nil
  end
end