Exploring Paramiko’s Errors

Contents:

Bad Hostname

What happens if you give it a bad host-name?

client = paramiko.SSHClient()
client.set_missing_host_key_policy(paramiko.AutoAddPolicy())
#client.load_system_host_keys()

try:
    client.connect('badhostname', username='fakeuser')
except IOError as error:
    print error
[Errno 2] No such file or directory

That is dissapointingly vague, but at least I know how to catch the exception (it’s actually raising a socket.error but that’s a child of IOError so you can catch either one). The error number is a system error number:

print "ENOENT: {0} '{1}'".format(errno.ENOENT, os.strerror(errno.ENOENT))
ENOENT: 2 'No such file or directory'
ENOENT int(x=0) -> int or long
strerror((code) -> string) Translate an error code to a message string.

Looking at the documentation, though, it looks like it might make more sense to catch gaierror, not IOError.

socket.gaierror

But, that doesn’t work, because the connect raises a socket.error instead.

Bad Username

What happens if the address is okay but the user-name is wrong (it doesn’t exist)?

try:
    client.connect('localhost', username='ummagumma')
except paramiko.PasswordRequiredException as error:
    print error
Private key file is encrypted

So, there’s three really bad things that happened here.

  • Ubuntu popped up a gui asking for the password for the private-key which will then block the code forever since there’s no way to tell gnome what to do in the code.
  • Even though I typed in my password it rejected it.
  • The error message indicates that the private key is encrypted, even though it clearly isn’t, given that I can ssh to real usernames. This seems like something that would be really hard to work around.

Note

By (re) moving /etc/xdg/autostart/gnome-keyring-ssh.desktop I was able to disable the pop-up and it now fails without user-interaction. I don’t know how reasonable it is to expect that all users will know to do this, but at least it works.

Bad Password

I assume that the bad username and the bad password errors will be the same, since it raised a PasswordRequiredException, but I guess it’s better to test it and see.

try:
    client.connect('localhost', username='fakeuser', password='badpassword')
except paramiko.AuthenticationException as error:
    print error

Ooops... okay so a bad password is an AuthenticationException but a bad username is a PasswordRequiredException.

Note

Once I killed the keyring the PasswordRequiredException popped up when I forgot to execute ssh-add so although the error string doesn’t seem to be meaningful, the exception is – it is raised if a password is needed and you didn’t give it one (the bad username is then kind of a red-herring, ssh interprets it as a bad password).

Socket Timeouts

The last thing to check is the socket timeouts. These will pop up if you give paramiko a timeout and it’s exceeded (surprised?).

client.connect('localhost', username='fakeuser', password=None)
i,o,e = client.exec_command('ps -e | grep iperf')
for line in o:
    pid = line.split()[0]
    client.exec_command('kill -9 {0}'.format(pid))
time.sleep(0.1)

stdin, stdout, stderr = client.exec_command('iperf -s', timeout=0.1)

try:
    for line in stdout:
        print line
    for line in stderr:
        print line
except socket.timeout as error:
    print "socket.timeout doesn't give an error message"
    print error
------------------------------------------------------------

Server listening on TCP port 5001

TCP window size: 85.3 KByte (default)

------------------------------------------------------------

socket.timeout doesn't give an error message

On StandardError

When I was working with the previous section I initially forgot to kill the iperf process between runs of this code and was not getting any output because I wasn’t checking stderr – an error from the command won’t raise an exception in paramiko, so to be safe you have to always check stderr. But also note that not all stderr output is an error:

stdin, stdout, stderr = client.exec_command('iperf -v')
for line in stderr:
    print line
iperf version 2.0.5 (08 Jul 2010) pthreads

So it seems there is no universal way to decide if there was an error in the execution of the command – you have to know what to expect and interpret it for each command.