Class: EventMachine::Ssh::Shell
- Inherits:
-
Object
- Object
- EventMachine::Ssh::Shell
- Defined in:
- lib/em-ssh/shell.rb
Overview
EM::Ssh::Shell encapsulates interaction with a user shell on an SSH server. Shells can be easily and quickly duplicated (#split) without the need to establish another connection. Shells provide :closed, :childless, and :split callbacks.
Constant Summary collapse
- TIMEOUT =
Global timeout for wait operations; can be overriden by :timeout option to new
15
Instance Attribute Summary collapse
-
#children ⇒ Array
readonly
All shells that have been split off from this one.
-
#connect_opts ⇒ Hash
readonly
The options to pass to connect automatically.
- #connection ⇒ EM::Ssh::Connection readonly
-
#host ⇒ String
readonly
The host to login to.
-
#options ⇒ Hash
readonly
The options passed to initialize.
-
#parent ⇒ Shell
readonly
The parent of this shell.
-
#pass ⇒ String
readonly
The password to authenticate with - can be nil.
- #session ⇒ EM::Ssh::Session readonly
-
#shell ⇒ Net::SSH::Connection::Channel
readonly
The shell to which we can send_data.
-
#user ⇒ String
readonly
The user to authenticate as.
Instance Method Summary collapse
-
#clear_buffer! ⇒ Object
Remove any data in the buffer.
-
#close ⇒ Object
Close this shell and all children.
-
#closed? ⇒ Boolean
Has this shell been closed.
-
#connect ⇒ Object
Connect to the server.
-
#connected? ⇒ Boolean
True if the session is still alive.
- #debug(msg = nil, &blk) ⇒ Object
-
#disconnect(timeout = nil) ⇒ Object
Close the connection to the server and all child shells.
- #disconnect! ⇒ Object
- #error(msg = nil, &blk) ⇒ Object
-
#expect(strregex, send_str = nil, opts = {}, &blk) ⇒ Shell, String
Wait for a number of seconds until a specified string or regexp is matched by the data returned from the ssh connection.
- #fatal(msg = nil, &blk) ⇒ Object
- #info(msg = nil, &blk) ⇒ Object
-
#initialize(address, user, pass, opts = {}) {|_self| ... } ⇒ Shell
constructor
Connect to an ssh server then start a user shell.
-
#line_terminator ⇒ String
A string (rn) to append to every command.
-
#line_terminator=(lt) ⇒ Object
@param lt a string (rn) to append to every command.
-
#open(&blk) ⇒ self, Exception
Open a shell on the server.
-
#open? ⇒ Boolean
Is the shell open?.
-
#reconnect? ⇒ Boolean
True if the connection should be automatically re-established; default: false.
-
#send_and_wait(send_str, wait_str = nil, opts = {}) ⇒ String
Send a string to the server and wait for a response containing a specified String or Regex.
-
#send_data(d, send_newline = true) ⇒ Object
Send data to the ssh server shell.
-
#split {|Shell| ... } ⇒ Shell
Create a new shell using the same ssh connection.
-
#wait_for(strregex, opts = { }) ⇒ String
Wait for the shell to send data containing the given string.
- #warn(msg = nil, &blk) ⇒ Object
Methods included from Callbacks
#callbacks, #callbacks=, #fire, #on, #on_next
Methods included from Log
Constructor Details
#initialize(address, user, pass, opts = {}) {|_self| ... } ⇒ Shell
Connect to an ssh server then start a user shell.
74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 |
# File 'lib/em-ssh/shell.rb', line 74 def initialize(address, user, pass, opts = {}, &blk) @timeout = opts[:timeout].is_a?(Fixnum) ? opts[:timeout] : TIMEOUT @host = address @user = user @pass = pass @options = opts @logger = opts[:logger] if opts[:logger] @connect_opts = { password: pass, port: opts[:port] || 22, auth_methods: ['publickey', 'password'], logger: log }.merge(opts[:net_ssh] || {}) @session = opts[:session] @parent = opts[:parent] @children = [] @reconnect = opts[:reconnect] # TODO make all methods other than #callback and #errback inaccessible until connected? == true yield self if block_given? Fiber.new { begin open succeed(self) if connected? && !closed? rescue => e fail(e) end }.resume end |
Instance Attribute Details
#children ⇒ Array (readonly)
Returns all shells that have been split off from this one.
51 52 53 |
# File 'lib/em-ssh/shell.rb', line 51 def children @children end |
#connect_opts ⇒ Hash (readonly)
Returns the options to pass to connect automatically. They will be extracted from the opptions on initialization.
42 43 44 |
# File 'lib/em-ssh/shell.rb', line 42 def connect_opts @connect_opts end |
#connection ⇒ EM::Ssh::Connection (readonly)
38 39 40 |
# File 'lib/em-ssh/shell.rb', line 38 def connection @connection end |
#host ⇒ String (readonly)
Returns the host to login to.
45 46 47 |
# File 'lib/em-ssh/shell.rb', line 45 def host @host end |
#options ⇒ Hash (readonly)
Returns the options passed to initialize.
40 41 42 |
# File 'lib/em-ssh/shell.rb', line 40 def @options end |
#parent ⇒ Shell (readonly)
Returns the parent of this shell.
53 54 55 |
# File 'lib/em-ssh/shell.rb', line 53 def parent @parent end |
#pass ⇒ String (readonly)
Returns the password to authenticate with - can be nil.
49 50 51 |
# File 'lib/em-ssh/shell.rb', line 49 def pass @pass end |
#session ⇒ EM::Ssh::Session (readonly)
36 37 38 |
# File 'lib/em-ssh/shell.rb', line 36 def session @session end |
#shell ⇒ Net::SSH::Connection::Channel (readonly)
Returns The shell to which we can send_data.
34 35 36 |
# File 'lib/em-ssh/shell.rb', line 34 def shell @shell end |
#user ⇒ String (readonly)
Returns The user to authenticate as.
47 48 49 |
# File 'lib/em-ssh/shell.rb', line 47 def user @user end |
Instance Method Details
#clear_buffer! ⇒ Object
Remove any data in the buffer.
351 352 353 |
# File 'lib/em-ssh/shell.rb', line 351 def clear_buffer! shell.clear_buffer! end |
#close ⇒ Object
Close this shell and all children. Even when a shell is closed it is still connected to the server. Fires :closed event.
139 140 141 142 143 144 |
# File 'lib/em-ssh/shell.rb', line 139 def close shell.close.tap{ debug("closing") } if shell && shell.active? @closed = true children.each { |c| c.close } fire(:closed) end |
#closed? ⇒ Boolean
Returns Has this shell been closed.
147 148 149 |
# File 'lib/em-ssh/shell.rb', line 147 def closed? @closed == true end |
#connect ⇒ Object
Connect to the server. Does not open the shell; use #open or #split You generally won’t need to call this on your own.
264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 |
# File 'lib/em-ssh/shell.rb', line 264 def connect return @session if connected? trace = caller f = Fiber.current ::EM::Ssh.start(host, user, connect_opts) do |connection| @connection = connection connection.callback do |ssh| f.resume(@session = ssh) if f.alive? end connection.errback do |e| e.set_backtrace(trace + Array(e.backtrace)) f.resume(e) if f.alive? end end return Fiber.yield.tap { |r| raise r if r.is_a?(Exception) } end |
#connected? ⇒ Boolean
Returns true if the session is still alive.
130 131 132 |
# File 'lib/em-ssh/shell.rb', line 130 def connected? session && !session.closed? end |
#debug(msg = nil, &blk) ⇒ Object
355 356 357 |
# File 'lib/em-ssh/shell.rb', line 355 def debug(msg = nil, &blk) super("#{host} #{msg}", &blk) end |
#disconnect(timeout = nil) ⇒ Object
Close the connection to the server and all child shells. Disconnected shells cannot be split.
111 112 113 114 115 116 117 118 119 |
# File 'lib/em-ssh/shell.rb', line 111 def disconnect(timeout = nil) if timeout EM::Timer.new(timeout) { disconnect! } end close @session && @session.close @shell = nil disconnect! end |
#disconnect! ⇒ Object
121 122 123 124 125 126 127 |
# File 'lib/em-ssh/shell.rb', line 121 def disconnect! @session = nil if @connection @connection.close_connection @connection = nil end end |
#error(msg = nil, &blk) ⇒ Object
371 372 373 |
# File 'lib/em-ssh/shell.rb', line 371 def error(msg = nil, &blk) super("#{host} #{msg}", &blk) end |
#expect(strregex, send_str = nil, opts = {}, &blk) ⇒ Shell, String
Wait for a number of seconds until a specified string or regexp is matched by the data returned from the ssh connection. Optionally send a given string first.
If a block is not provided the current Fiber will yield until strregex matches or :timeout # is reached.
If a block is provided expect will return immediately.
310 311 312 313 314 315 316 |
# File 'lib/em-ssh/shell.rb', line 310 def expect(strregex, send_str = nil, opts = {}, &blk) assert_channel! shell.expect(strregex, send_str, {:timeout => @timeout, :log => self }.merge(opts), &blk) end |
#fatal(msg = nil, &blk) ⇒ Object
363 364 365 |
# File 'lib/em-ssh/shell.rb', line 363 def fatal(msg = nil, &blk) super("#{host} #{msg}", &blk) end |
#info(msg = nil, &blk) ⇒ Object
359 360 361 |
# File 'lib/em-ssh/shell.rb', line 359 def info(msg = nil, &blk) super("#{host} #{msg}", &blk) end |
#line_terminator ⇒ String
Returns a string (rn) to append to every command.
56 57 58 |
# File 'lib/em-ssh/shell.rb', line 56 def line_terminator shell ? shell.line_terminator : "\n" end |
#line_terminator=(lt) ⇒ Object
@param lt a string (rn) to append to every command
61 62 63 64 |
# File 'lib/em-ssh/shell.rb', line 61 def line_terminator=(lt) @line_terminator = lt shell.line_terminator = lt if shell end |
#open(&blk) ⇒ self, Exception
Open a shell on the server. You generally don’t need to call this.
160 161 162 163 164 165 166 167 168 169 170 |
# File 'lib/em-ssh/shell.rb', line 160 def open(&blk) f = Fiber.current trace = caller on_open do |s| Fiber.new { yield(self) if block_given? }.resume f.resume(self) end @on_open_err = proc { |e| f.resume(e) } open! return Fiber.yield.tap { |r| raise r if r.is_a?(Exception) } end |
#open? ⇒ Boolean
Returns Is the shell open?.
153 154 155 |
# File 'lib/em-ssh/shell.rb', line 153 def open? !closed? && @shell end |
#reconnect? ⇒ Boolean
Returns true if the connection should be automatically re-established; default: false.
105 106 107 |
# File 'lib/em-ssh/shell.rb', line 105 def reconnect? @reconnect == true end |
#send_and_wait(send_str, wait_str = nil, opts = {}) ⇒ String
Send a string to the server and wait for a response containing a specified String or Regex.
321 322 323 324 325 326 |
# File 'lib/em-ssh/shell.rb', line 321 def send_and_wait(send_str, wait_str = nil, opts = {}) assert_channel! shell.send_and_wait(send_str, wait_str, {:timeout => @timeout, :log => self }.merge(opts)) end |
#send_data(d, send_newline = true) ⇒ Object
Send data to the ssh server shell. You generally don’t need to call this.
332 333 334 335 |
# File 'lib/em-ssh/shell.rb', line 332 def send_data(d, send_newline=true) assert_channel! shell.send_data(d, send_newline) end |
#split {|Shell| ... } ⇒ Shell
Create a new shell using the same ssh connection. A connection will be established if this shell is not connected.
If a block is provided the call to split must be inside of a Fiber. The child will be closed after yielding. The block will not be yielded until the remote PTY has been opened.
242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 |
# File 'lib/em-ssh/shell.rb', line 242 def split connect unless connected? child = self.class.new(host, user, pass, {:session => session, :parent => self}.merge()) child.line_terminator = line_terminator children.push(child) child.on(:closed) do children.delete(child) fire(:childless).tap{ info("fired :childless") } if children.empty? end fire(:split, child) if block_given? # requires that the caller be in a Fiber child.open yield(child).tap { child.close } else child end end |
#wait_for(strregex, opts = { }) ⇒ String
Wait for the shell to send data containing the given string.
345 346 347 348 |
# File 'lib/em-ssh/shell.rb', line 345 def wait_for(strregex, opts = { }) assert_channel! shell.wait_for(strregex, {:timeout => @timeout, :log => self }.merge(opts)) end |
#warn(msg = nil, &blk) ⇒ Object
367 368 369 |
# File 'lib/em-ssh/shell.rb', line 367 def warn(msg = nil, &blk) super("#{host} #{msg}", &blk) end |