Brian Candler
9/24/2007 10:56:00 AM
On Thu, Apr 26, 2007 at 05:56:34PM +0900, Manish Sapariya wrote:
> I have been looking for expect like interface for Net::SSH lib,
> but apparently there is none.
This is something I've been wanting for a long time too, ideally to use ssh
as a drop-in replacement for Net::Telnet.
I've made a first step by monkey-patching Net::SSH so that the
process.popen3 interface is also available for shell sessions, just by
passing in nil as the command name (see attached). Once you've done this,
you can drive Net::SSH like this:
------------------------------------------------------------------------
require 'rubygems'
require 'net/ssh'
class ShellSession
def initialize(*args)
@session = Net::SSH.start(*args)
@inp, @out, @err = @session.process.popen3 # nil means shell
end
def cmd(command, prompt = /[>\#\$?] ?\z/)
puts "(#{command})"
@inp.puts command
res = ""
while true
@out.channel.connection.process # block for incoming data
res << @out.read if @out.data_available?
res << @err.read if @err.data_available?
break if res =~ prompt
end
res
end
end
s = ShellSession.new("x.x.x.x", "cisco", "cisco")
puts s.cmd("term len 0")
puts s.cmd("show ver")
puts s.cmd("show run")
puts s.cmd("enable", /assword:/)
puts s.cmd("cisco")
puts s.cmd("show run")
------------------------------------------------------------------------
However this is only part of the story. Both IO#expect and Net::Telnet
expect a real IO object that you can use as an argument to Kernel#select.
One solution may be to make a Socketpair:
s1, s2 = Socket.pair(Socket::AF_LOCAL, Socket::SOCK_STREAM, 0)
However, then the code which copies the other end of the pair to/from the
ssh session needs to run as a thread. It's probably also not portable to
Windows.
Alternatively, a modified version of Net::Telnet can be made. And in that
case, it could use the ssh channel interface directly and so not rely on a
patched Net::SSH.
Regards,
Brian.