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, #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 |
# 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 = opts @logger = opts[:logger] if opts[:logger] @connect_opts = {:password => pass, :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 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.
344 345 346 |
# File 'lib/em-ssh/shell.rb', line 344 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.
134 135 136 137 138 139 |
# File 'lib/em-ssh/shell.rb', line 134 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.
142 143 144 |
# File 'lib/em-ssh/shell.rb', line 142 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.
257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 |
# File 'lib/em-ssh/shell.rb', line 257 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.
125 126 127 |
# File 'lib/em-ssh/shell.rb', line 125 def connected? session && !session.closed? end |
#debug(msg = nil, &blk) ⇒ Object
348 349 350 |
# File 'lib/em-ssh/shell.rb', line 348 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.
106 107 108 109 110 111 112 113 114 |
# File 'lib/em-ssh/shell.rb', line 106 def disconnect(timeout = nil) if timeout EM::Timer.new(timeout) { disconnect! } end close @session && @session.close @shell = nil disconnect! end |
#disconnect! ⇒ Object
116 117 118 119 120 121 122 |
# File 'lib/em-ssh/shell.rb', line 116 def disconnect! @session = nil if @connection @connection.close_connection @connection = nil end end |
#error(msg = nil, &blk) ⇒ Object
364 365 366 |
# File 'lib/em-ssh/shell.rb', line 364 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.
303 304 305 306 307 308 309 |
# File 'lib/em-ssh/shell.rb', line 303 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
356 357 358 |
# File 'lib/em-ssh/shell.rb', line 356 def fatal(msg = nil, &blk) super("#{host} #{msg}", &blk) end |
#info(msg = nil, &blk) ⇒ Object
352 353 354 |
# File 'lib/em-ssh/shell.rb', line 352 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.
155 156 157 158 159 160 161 162 163 164 165 |
# File 'lib/em-ssh/shell.rb', line 155 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?.
148 149 150 |
# File 'lib/em-ssh/shell.rb', line 148 def open? !closed? && @shell end |
#reconnect? ⇒ Boolean
Returns true if the connection should be automatically re-established; default: false.
100 101 102 |
# File 'lib/em-ssh/shell.rb', line 100 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.
314 315 316 317 318 319 |
# File 'lib/em-ssh/shell.rb', line 314 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.
325 326 327 328 |
# File 'lib/em-ssh/shell.rb', line 325 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.
235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 |
# File 'lib/em-ssh/shell.rb', line 235 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.
338 339 340 341 |
# File 'lib/em-ssh/shell.rb', line 338 def wait_for(strregex, opts = { }) assert_channel! shell.wait_for(strregex, {:timeout => @timeout, :log => self }.merge(opts)) end |
#warn(msg = nil, &blk) ⇒ Object
360 361 362 |
# File 'lib/em-ssh/shell.rb', line 360 def warn(msg = nil, &blk) super("#{host} #{msg}", &blk) end |