Undistraction
Undistraction

Reputation: 43589

Net/SSH.start doesn't raise an exception if it fails

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?

Upvotes: 4

Views: 5302

Answers (2)

Brian Joseph Spinos
Brian Joseph Spinos

Reputation: 2244

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

Upvotes: 3

Winfield
Winfield

Reputation: 19145

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.

Upvotes: 2

Related Questions