4

So I'm currently trying to get a script working but it's behaving differently when I run it manually than when I run it from crontab. Basically, I have a reverse ssh tunnel set up from one server to another, and in order to verify that my tunnel is up I:

  • SSH from server A to server B
  • Wget a test url from on server A from server B
  • if Wget succeeds, I disconnect and do nothing
  • if Wget fails, I disconnect and restart the tunnel

I know there are more elegant ways to verify ssh tunnels (like autossh and ServerKeepAlive), but for both policy and redundancy issues, I have to do things this way. Anyways, here's the script:

from __future__ import print_function
from __future__ import absolute_import

import os, sys, subprocess, logging, pexpect

COMMAND_PROMPT = '[#$] '
TERMINAL_PROMPT = '(?1)terminal type\?'
TERMINAL_TYPE = 'vt100'
SSH_NEWKEY = '(?i)are you sure you want to continue connecting'
SERVERS = [{address':'192.168.100.10', 'connString':'ssh user@192.168.100.10', 'testGet':'wget http://192.168.100.11/test.html -t 1 -T 10', 'tunnel':'start_tunnel'}, {address':'192.168.100.12', 'connString':'ssh user@192.168.100.12', 'testGet':'wget http://192.168.100.13/test.html -t 1 -T 10', 'tunnel':'start_tunnel2'}]

def main():

    global COMMAND_PROMPT, TERMINAL_PROMPT, TERMINAL_TYPE, SSH_NEWKEY, SERVERS

    #set up logging
    log = logging.getLogger(__name__)
    log.setLevel(logging.DEBUG)
    handler = logging.FileHandler('/home/user/tunnelTest.log')
    formatter = logging.Formatter('%(asctime)s - %(module)s.%(funcName)s: %(message)s')
    handler.setFormatter(formatter)
    log.addHandler(handler)


    for x in SERVERS:

        #connect to server
        child = pexpect.spawn(x['connString'])
        i = child.expect([pexpect.TIMEOUT, SSH_NEWKEY, COMMAND_PROMPT, '(?i)password'])
        if i == 0:   #Timeout
             log.debug('ERROR! Could not log in to ' + x['address'] + ' ...')
             sys.exit(1)
        if i = 1:    #No key cached
             child.sendline('yes')
             child.expect(COMMAND_PROMPT)
             log.debug('Connected to ' + x['address'] + '...')
        if i = 2:    #Good to go
             log.debug('Connected to ' + x['address'] + '...')
             pass

        #Housecleaning
        child.sendline('cd /tmp')
        child.expect(COMMAND_LINE)
        child.sendline('rm -r test.html')
        child.expect(COMMAND_LINE)

        log.debug('Testing service using ' + x['testGet'] + ' ...')
        child.sendline(x['testGet'])
        child.expect(COMMAND_PROMPT)
        if 'saved' in child.before.lower():
            log.debug('Tunnel working, nothing to do here!')
            log.debug('Disconnecting from remote host ' + x['address'] + '...')
            child.sendline('exit')
        else:
            log.error('Tunnel down!')
            log.debug('Disconnecting from remote host ' + x['address'] + ' and restarting tunnel')
            child.sendline('exit')
            subprocess.call(['start',x['tunnel']])
            log.debug('Autossh tunnel restarted')

if __name__ == "__main__":
    main()

My crontab entry is as follows:

0,30 * * * * python /home/user/tunnelTest.py

So yeah -- this script runs fine when I do it manually (sudo python tunnelTest.py) and also runs fine on crontab unless a tunnel is down. When a tunnel is down, I get the "Tunnel down!" and "Disconnecting from remote host 192.168.100.10 and restarting tunnel" messages in my log, but the script seems to die there. The tunnel doesn't restart, and I get no messages in my log until the start of the next scheduled run.

The start_tunnel script is in /etc/init, the testTunnel.py script is in /home/user, the testTunnel.log file is in /home/user/logs, and I ran crontab -e as root.

Any insight into this matter would be greatly appreciated.

Thanks!

  • So it's having issues calling an external script from Cron? Have you tried giving the complete path to the external script, or logging the return code from the call to the external script? – NickW Jul 31 '14 at 12:39
  • Cron calls the script, but the script is dying (by the looks of it, on the subprocess call). I added the full path to python as Shutupsquare suggested and I'm hoping that was my issue. – tparrott Jul 31 '14 at 12:46
  • Yeah, I should have been a bit more verbose, I was asking if the script had the full path of the subscript. Either way, it would be useful to get the return code from the subscript call, and do some logging int he subscript as well. – NickW Jul 31 '14 at 12:54
  • I'm pretty sure it's dying on either the child.sendline('exit') or subprocess.call(['start',x['tunnel']]) lines. Added more debugging there to see what's up. – tparrott Jul 31 '14 at 13:07
  • Figured it out! I had to give absolute paths to stop and start. Works fine now. – tparrott Jul 31 '14 at 13:26
5

You need to use the full path to python eg

/usr/bin/python

you can find out the path with which python

So your crontab entry would look like

0,30 * * * * /usr/bin/python /home/user/tunnelTest.py

  • 1
    Thanks for the reply! I made the changes and will wait and see. It seems strange to me that this would be the issue though, since crontab runs the script, but the script is failing at a certain point. – tparrott Jul 31 '14 at 12:40
  • 1
    @tparrott Sorry I read the title and seen the crontab entry and assumed that it wasn't running because in cron you usually have to use absolute paths unless you have setup some environmental variables. If your script is firing then yes adjusting the crontab entry would not help here. Although I would probably expect that you are having a environmental variable problem. – 0x7c0 Jul 31 '14 at 12:47
  • 2
    You alays have to keep in your head that the cronjobs are seeing diffenrent environment variables than an interactive prompt. – banyek Jul 31 '14 at 13:35
  • 1
    Yup, that turned out to be the issue. I had to give absolute paths to /sbin/start and /sbin/stop. – tparrott Jul 31 '14 at 13:49

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.