Desperate help needed with SSH

Hi you Ruby Guru's

I have a small problem thats driving me crazy. I am trying to connect to
multiple ssh servers (1 at a time), run a number of commands and capture
the output to a unique file for each server.

My code looks like this :

-- snip --

require 'rubygems'
require 'net/ssh'
  
hosts = ['10.0.255.1' , '10.0.255.2' , '10.0.255.3']

instructions = [
  'sh version',
  'sh cdp ne'
  ]

hosts.each do |host|
  Net::SSH.start(host, 'user', :password => 'password') do |ssh|
  
    fn = File.open("output\/#{host}.txt", 'w')
    instructions.each do |command|
      fn.puts "|--------\[#{command}\]--------------------------"
      fn.puts ssh.exec!(command)
    end
    fn.close
  end
end

-- snip --

When I run this I get the following error :

Net::SSH::ChannelOpenFailed: (4)

If I remove the instructions.each loop and run only a single command. Life
is good and it all works. If I add a second ssh.exec! or the loop, the
error returns.

It appears that the ssh.exec! closes the connection. How do I keep it open
to allow me to run a second command?

Alan.

-- snip --

require 'rubygems'
require 'net/ssh'

hosts = ['10.0.255.1' , '10.0.255.2' , '10.0.255.3']

instructions = [
'sh version',
'sh cdp ne'
]

These instructions looks strange for me. Are you sure that these run
on all hosts?

Try to use other instructions that should work like
["echo foo", "sh -c 'echo bar'"]

Maybe your instructions kill the shell environment by calling exec
or something similar.

hosts.each do |host|
Net::SSH.start(host, 'user', :password => 'password') do |ssh|

     File.open("output/#{host}.txt", 'w') do |fn|

   instructions.each do |command|
     fn.puts "|--------\[#{command}\]--------------------------"
     fn.puts ssh.exec!(command)
   end

    end

end
end

-- snip --

This part should be ok, but you can improve your code and use a block
for File.open().

  File.open("output/#{host}.txt", 'w') do |fn|
   ..
  end # fn.close not needed, because the block end close the file already.

When I run this I get the following error :

Net::SSH::ChannelOpenFailed: (4)

If I remove the instructions.each loop and run only a single command. Life
is good and it all works. If I add a second ssh.exec! or the loop, the
error returns.

Calling ssh.exec!() twice in a session is not a problem.

Net::SSH.start(host, user, :password => passwd) do |ssh|
  ['sh -c "echo foo"', 'echo bar'].each do |command|
   puts ssh.exec!(command)
  end
end

foo
bar

hth. regards, Sandor Szücs

···

On 13.05.2009, at 11:05, alan@isdial.net wrote:
--

unknown wrote:

I have a small problem thats driving me crazy. I am trying to connect to
multiple ssh servers (1 at a time), run a number of commands and capture
the output to a unique file for each server.

Try using Net::SSH::Telnet (which is something I wrote to talk to
routers). It hides the Net::SSH API behind a simple Net::Telnet one, and
as a side benefit, you can write code which connects transparently using
either telnet or ssh.

Alternatively, looking at the Net::SSH::Telnet code may show you how to
drive Net::SSH successfully.

HTH,

Brian.

···

--
Posted via http://www.ruby-forum.com/\.

Hi Sandor

Thanks for the reply.

The host I am connecting to is a Cisco Router. The commands definitely work on a manual SSH session from my terminal

The first command always works.
I get the channel failure when trying to run the second command.
I tried swapping the two commands around, but I get the same failure.

I used the following code to talk to my mac:

require 'rubygems'
require 'net/ssh'

  Net::SSH.start('127.0.0.1', 'user', :password => 'password') do |ssh|
    ssh.exec "ls -al"
    ssh.exec "pwd"
    ssh.exec "ps -axe"
    ssh.loop
  end

Which worked great. I then changed the IP address and replaced the commands with router commands:

require 'rubygems'
require 'net/ssh'

  Net::SSH.start('10.0.255.1', 'name', :password => 'password') do |ssh|
    ssh.exec "sh ver"
    ssh.exec "cdp ne"
    ssh.loop
  end

And it fails at the second ssh.exec, so I'm guessing this is related to the Cisco SSH Server.

Alan.

···

On 17 May 2009, at 12:26 AM, Sandor Szücs wrote:

On 13.05.2009, at 11:05, alan@isdial.net wrote:

-- snip --

require 'rubygems'
require 'net/ssh'

hosts = ['10.0.255.1' , '10.0.255.2' , '10.0.255.3']

instructions = [
'sh version',
'sh cdp ne'
]

These instructions looks strange for me. Are you sure that these run
on all hosts?

Try to use other instructions that should work like
["echo foo", "sh -c 'echo bar'"]

Maybe your instructions kill the shell environment by calling exec
or something similar.

hosts.each do |host|
Net::SSH.start(host, 'user', :password => 'password') do |ssh|

   File.open("output/#{host}.txt", 'w') do |fn|

  instructions.each do |command|
    fn.puts "|--------\[#{command}\]--------------------------"
    fn.puts ssh.exec!(command)
  end

  end

end

-- snip --

This part should be ok, but you can improve your code and use a block
for File.open().

File.open("output/#{host}.txt", 'w') do |fn|
..
end # fn.close not needed, because the block end close the file already.

When I run this I get the following error :

Net::SSH::ChannelOpenFailed: (4)

If I remove the instructions.each loop and run only a single command. Life
is good and it all works. If I add a second ssh.exec! or the loop, the
error returns.

Calling ssh.exec!() twice in a session is not a problem.

> Net::SSH.start(host, user, :password => passwd) do |ssh|
> ['sh -c "echo foo"', 'echo bar'].each do |command|
> puts ssh.exec!(command)
> end
> end
foo
bar

hth. regards, Sandor Szücs
--

Ack.
Maybe there are options that you can set on the router to let the channel open?

regards, Sandor Szücs

···

On 18.05.2009, at 19:23, Alan Claughan wrote:

And it fails at the second ssh.exec, so I'm guessing this is related to the Cisco SSH Server.

--