How to run cron job when network is up?

I have some anacron jobs which run daily. The scripts update local bzr and git repositories. Naturally these scripts need working network connections. I'm on a laptop and often wired and wireless internet do not come up fast enough. This causes my cron job to time out when pulling the repositories =(

So:

How to make sure the internet is up before running specific cron jobs? Or how to fail a job if there is no network, such that it is retried by anacron later again?


Solution 1:

I think you can use Upstart to help you there. Mind you, I haven't tested that code below works but something very similar should.

# /etc/init/update-repositories.conf - Update local repos
#

description     "Update local repos"

# this will run the script section every time network is up
start on (net-device-up IFACE!=lo)

task

script
    svn up && git fetch
#   do some other useful stuff
end script

That pretty much it. You might want to add some code to check that it does not run very often. You might also want to add start update-repositories to your crontab, it'll make sure your update will happen if you are on the net constantly for a prolonged period of time.

Solution 2:

I made a cron that did a ping test on a DNS server to ensure networking. Something like this:

ping 8.8.8.8 -c 1 -i .2 -t 60 > /dev/null 2>&1
ONLINE=$?

if [ ONLINE -eq 0 ]; then
    #We're offline
else
    #We're online
fi

Recently I've used something like this:

#!/bin/bash

function check_online
{
    netcat -z -w 5 8.8.8.8 53 && echo 1 || echo 0
}

# Initial check to see if we are online
IS_ONLINE=check_online
# How many times we should check if we're online - this prevents infinite looping
MAX_CHECKS=5
# Initial starting value for checks
CHECKS=0

# Loop while we're not online.
while [ $IS_ONLINE -eq 0 ]; do
    # We're offline. Sleep for a bit, then check again

    sleep 10;
    IS_ONLINE=check_online

    CHECKS=$[ $CHECKS + 1 ]
    if [ $CHECKS -gt $MAX_CHECKS ]; then
        break
    fi
done

if [ $IS_ONLINE -eq 0 ]; then
    # We never were able to get online. Kill script.
    exit 1
fi

# Now we enter our normal code here. The above was just for online checking

This isn't the MOST elegant - I'm not sure how else to check via a simple command or file on the system, but this has worked for me when needed.

Solution 3:

You can talk to NetworkManager to see whether you are connected or not:

$state = $(dbus-send --system --print-reply \
    --dest=org.freedesktop.NetworkManager \
    /org/freedesktop/NetworkManager \
    org.freedesktop.NetworkManager.state 2>/dev/null \
| awk '/uint32/{print $2}')
if [ $state = 3 ]; then
    echo "Connected!"
else
    echo "Not connected!"
fi

Solution 4:

Just to wrap up a couple of the options here into a single script:

#! /bin/bash
# This script checks that the interface is up, and that an internet connection is available
# It is based on code from http://askubuntu.com/questions/3299/how-to-run-cron-job-when-network-is-up
#
# Then it sleeps for a random number of seconds between 30 and 600.
# This is based on code from http://tldp.org/LDP/abs/html/randomvar.html
#
# Collated by @JonTheNiceGuy on 2015-10-15

function check_ipaddr
{
  # Here we look for an IP(v4|v6) address when doing ip addr
  # Note we're filtering out 127.0.0.1 and ::1/128 which are the "localhost" ip addresses
  # I'm also removing fe80: which is the "link local" prefix

  ip addr | \
  grep -v 127.0.0.1 | \
  grep -v '::1/128' | \
  grep -v 'inet6 fe80:' | \
  grep -E "inet [[:digit:]]+\.[[:digit:]]+\.[[:digit:]]+\.[[:digit:]]+|inet6" | \
  wc -l
}

function check_google
{
  netcat -z -w 5 8.8.8.8 53 && echo 1 || echo 0
}

until [ `check_ipaddr` -gt 1 ]; do
  sleep 2
done

until [ `check_google` -eq 1 ]; do
  sleep 2
done

sleep $((RANDOM%570+30))

I plan to maintain this script at https://gist.github.com/JonTheNiceGuy/5cf4a23c8f2f755a9ca4