4

I'm using Net::SSH to connect to another server. It works fine, but I want to be able to deal with situations where it can't connect. Documentation for the method mentions nothing about exceptions, and as far as I can see it doesn't raise any. In the following example, passing a host and user that don't exist and no keys doesn't raise an exception.

The only way I can check if it failed is to look at @session, which will be nil, but this doesn't tell me anything about why it failed.

begin
  @session = Net::SSH.start('no-host', 'no-user', keys: [])
rescue SocketError => e
  connection_failed = true
  logger.error "SOCKET ERROR: "+e.message
rescue Net::SSH::AuthenticationFailed
  connection_failed = true
  logger.error "AUTH ERROR: "+e.message
rescue Exception => e
  logger.error "EXCEPTION: "+e.message
end

[Update] Running the following in irb raises a SocketError:

> require 'net/ssh'
> Net::SSH.start('no-host', 'no-user', keys: [])
= SocketError: getaddrinfo: nodename nor servname provided, or not known

Why doesn't this raise an exception in my app?

Undistraction
  • 42,754
  • 56
  • 195
  • 331
  • What version of ruby are you using? Just trying in irb ruby-1.9.3p327 the second line of SSH.start, i get the exception 'SocketError: initialize: name or service not known'. Works in rails console just fine as well. – agmcleod Jan 28 '13 at 16:25
  • @agmcleod I'm on 1.9.3-p194 and yes you're correct. In irb I get an exception, however in the app I don't. – Undistraction Jan 28 '13 at 17:08
  • I have the same issue. If I use an incorrect password then it raises an exception, but when my credentials are correct it's creating a connection that is immediately closed but I have no way of finding out why it's getting closed immediately. – tigris Feb 21 '13 at 23:23

2 Answers2

3

I was dealing with trying to rescue some exceptions, here is what worked for me:

def mydef
  begin
    Net::SSH.start("host", "user", :password => "password", :timeout => 10) do |ssh|
      #stuff
    end 
  rescue Timeout::Error
    @error = "  Timed out"
  rescue Errno::EHOSTUNREACH
    @error = "  Host unreachable"
  rescue Errno::ECONNREFUSED
    @error = "  Connection refused"
  rescue Net::SSH::AuthenticationFailed
    @error = "  Authentication failure"
  end
end

then probably use the @error in the view

Brian Joseph Spinos
  • 2,144
  • 2
  • 18
  • 18
2

the start() method sets up the connection and yields it to an inner block. When you don't pass it a block, like in your example it may not even connect. You should try doing a simple loop or some other activity:

begin
  Net::SSH.start('no-host', 'no-user', keys: []) do |ssh|
    ssh.loop { true }
  end
rescue SocketError => e
  connection_failed = true
  logger.error "SOCKET ERROR: "+e.message
rescue Net::SSH::AuthenticationFailed
  connection_failed = true
  logger.error "AUTH ERROR: "+e.message
rescue Exception => e
  logger.error "EXCEPTION: "+e.message
end

Additionally, if you're worried about error handling and failures, you should specify a connection timeout via the :timeout parameter.

Winfield
  • 18,985
  • 3
  • 52
  • 65
  • There are two ways to use Net::SSH.start, either with or block or without. Both are supported and as I mention in my question it works for me. You are correct about timeout though, that would be a good idea. – Undistraction Jan 28 '13 at 17:16