20

I need a Python program I'm using to poll a remote server for SSH connectivity and notify when it is available. I am currently doing this using paramiko; attempt to connect, if failure, wait and retry until success or max retries. This works, but it's a bit clunky. Also paramiko seems to either connect or throw an error, so the only way I could see to do this was with a try/except block which is bad, bad, bad. Here is the method:

def check_ssh(self, ip, user, key_file, initial_wait=0, interval=0, retries=1):
    ssh = paramiko.SSHClient()
    ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())

    sleep(initial_wait)

    for x in range(retries):
        try:
            ssh.connect(ip, username=user, key_filename=key_file)
            return True
        except Exception, e:
            print e
            sleep(interval)
    return False

There must be a more elegant solution than this. Paramiko is my SSH library of choice but am open to any suggestions here.

To clarify, I want to avoid using try / except as a means to control the normal flow of code execution - it should be used for catching actual errors such as bad host key, invalid user etc.

tshepang
  • 12,111
  • 21
  • 91
  • 136
nightowl
  • 375
  • 1
  • 4
  • 10
  • 10
    `the only way I could see to do this was with a try/except block which is bad, bad, bad` why is it bad? – David Robinson Jan 09 '13 at 13:31
  • 15
    You're definitely right that catching `Exception` is bad. Catching the specific exception thrown by paramiko, however, is not bad at all. – Fredrick Brennan Jan 09 '13 at 13:36
  • Indeed, but using exception handling as a means of program flow is generally bad, as per: http://google-styleguide.googlecode.com/svn/trunk/pyguide.html#Exceptions – nightowl Jan 09 '13 at 14:04
  • I didn't bother putting the actual exceptions in because this was intended to be a temporary hack, and plus I'm lazy! The point of my question is that I don't want to use try/except to control the normal flow of my program - only to catch an actual error – nightowl Jan 09 '13 at 14:13

1 Answers1

26

As mentioned in the comment by frb, a try ... except block is a good approach to test availability of a specific service. You shouldn't use a "catch-all" except block though, but limit it to the specific exceptions that occur if the service is unavailable.

According to documentation, paramiko.SSHClient.connect may throw different exceptions, depending on the problem that occured while connecting. If you want to catch all those, your try ... except block would look like this:

try:
    ssh.connect(ip, username=user, key_filename=key_file)
    return True
except (BadHostKeyException, AuthenticationException, 
        SSHException, socket.error) as e:
    print e
    sleep(interval)

If just a subset of these exceptions is relevant to your case, put only those into the tuple after except.

trss
  • 915
  • 1
  • 19
  • 35
silvado
  • 17,202
  • 2
  • 30
  • 46
  • 1
    Fair point on my lax code specifying only a generic exception :p I do need a try / catch I guess for things like a bad host key as these are actual errors not "the server isn't up yet" - the point is I do not want the try / except block to control the wait loop (i.e. the normal flow of the code). – nightowl Jan 09 '13 at 14:16
  • Can you include imports in your example script? It's unclear where most of these variables are coming from – Preethi Vaidyanathan Sep 08 '20 at 17:38
  • @P.V. It's not a standalone example, just a suggested replacement for the `try` ... `except` block in the OP's code. – silvado Sep 23 '20 at 14:42