7

I am trying to run a very small python script AFTER internet has been established. I am currently editing /etc/network/if-up.d/upstart by adding the following code directly under all_interfaces_up():

all_interfaces_up() {
    python /path/to/script.py
    # return true if all interfaces listed in /etc/network/interfaces as 'auto'
    # are up.  if no interfaces are found there, then "all [given] were up"
    local prefix="$1" iface=""
    for iface in $(get_auto_interfaces); do
        # if cur interface does is not up, then all have not been brought up
        [ -f "${prefix}${iface}" ] || return 1
    done

    return 0
}

I know that the program "script.py" works, because I have tested it numerous times. I just need it to run AFTER internet connection has been established.

I have tried the above code with and without the "python" preceding the path to script.

I have also made sure that #!path/to/python was at the top of my .py file.

Furthermore, I did chmod + x to make it executable.

What am I missing? I have rebooted my Pi everytime I have tried something new and have run the code service networking restart to make sure the networking is restarted. Why isn't my script running after Internet connection has been established?

Ingo
  • 42,107
  • 20
  • 85
  • 197
user8951490
  • 215
  • 2
  • 3
  • 5
  • 2
    It is unclear what Raspbian you are running, or how your networking is configured. While this file is present, current Raspbian DO NOT use Debian networking. You should try a systemd service. – Milliways Feb 08 '18 at 23:00

3 Answers3

27

As @Milliways commented here is where the power of systemd comes to play. There is no need to wait that sequential processed commands are finished. systemd is working parallel (that is what it makes a bit unfamiliar). It can start services after other services are started. Because this "network-up thing" is a very common problem, we have a nice service for it named network-online.target. Now it is very simple to start your_script.py after network-online.target.

Let's do it with my_script.sh as template. You can replace it with your_script.py. I use Raspbian Lite from debian stretch.

Create my_script.sh and test it:

pi ~$ cd
pi ~$ cat > my_script.sh <<EOF
#!/bin/bash
echo "hello world" >>/tmp/my_script.out
EOF

pi ~$ chmod u+x my_script.sh
pi ~$ ./my_script.sh
pi ~$ cat /tmp/my_script.out
hello world
pi ~$

Now create a new service for my_script.sh:

pi ~$ sudo systemctl edit --force --full my_script.service

Insert this statements with your settings, save them and quit the editor:

[Unit]
Description=My Script Service
Wants=network-online.target
After=network-online.target

[Service]
Type=simple
User=pi
WorkingDirectory=/home/pi
ExecStart=/home/pi/my_script.sh

[Install]
WantedBy=multi-user.target

Check the new service:

pi ~$ systemctl status my_script.service
● my_script.service - My Script Service
   Loaded: loaded (/etc/systemd/system/my_script.service; disabled; vendor preset: enabled)
   Active: inactive (dead)

Now we can enable and test our service:

pi ~$ sudo systemctl enable my_script.service
pi ~$ sudo systemctl start my_script.service
pi ~$ sudo systemctl start my_script.service
pi ~$ cat /tmp/my_script.out
hello world
hello world
hello world

pi ~$ sudo systemctl reboot

Login and check. /tmp directory was cleaned up on boot.

pi ~$ cat /tmp/my_script.out
hello world
pi ~$

You can edit the unit-file and show it. After editing you must restart the service to take effect.

pi ~$ sudo systemctl edit --full my_script.service
pi ~$ sudo systemctl restart my_script.service
pi ~$ systemctl cat my_script.service

To check that all network devices are really up modify my_script.sh like this, reboot and look at /tmp/my_script.out:

pi ~$ cat > my_script.sh <<EOF
#!/bin/bash
/bin/ip addr >/tmp/my_script.out
EOF

pi ~$ sudo systemctl reboot


reference:
[1] man systemd.unit

Ingo
  • 42,107
  • 20
  • 85
  • 197
  • Wow, thank you for the detailed write-up! I can see that my script works when I do sudo systemctl start my-script.sh but not otherwise. This leads me to believe that either the service is not automatically starting up when I reboot, or the script is running before internet connection has been established. – user8951490 Feb 12 '18 at 09:47
  • I omitted the "Wants" line, and it seems to be working now. Thanks again for the detailed answer. – user8951490 Feb 12 '18 at 10:30
  • Yes, Wants=network-online.target means "I want it now". Otherwise it is only loaded when other services it want. That is while it works with sudo systemctl start my-script.sh. At boot-time it was loaded to late for your script by another service. – Ingo Feb 12 '18 at 18:03
  • I had to insert WantedBy=network-online.service to [Install] section, to make it work. – Mattia72 Jan 28 '20 at 18:36
  • I had trouble with this one as I was counting on a Wi-Fi connection to be established. My version of my_script.py was to simply log the Essid. The script captured a null value I think because it ran before dns services had stabilized. – leeprevost Jul 09 '22 at 14:51
1

@Ingo's answer got me most of the way, but my script's curl request was exiting with code 6 because it couldn't resolve the url's host yet--even though a network connection was established.

A fix shared by @richardeigenmann:

Before execution of the service, wait until a ping loop confirms it can resolve google.com:

[Service]
ExecStartPre=/bin/sh -c 'until ping -c1 google.com; do sleep 1; done;'

There are also a few other good solutions at the above link.

If you are expecting a case where there isn't WiFi around your pi, you might want to set up logic to limit the number of retry attempts.

Brian Chan
  • 11
  • 2
0

You are running the script at the beginning of the function all_interfaces_up()

This function is going to run even if they are not up, notice the two return values

You could have your script check for connection and wait until it has one, then execute rest of code

def Connected():
    check here if network is up

if not Connected():
    time.sleep(5)
restofcode....

then it does not matter if the connection comes up right away or not, your code will wait till it does, then execute the main body of the code

Chad G
  • 1,043
  • 1
  • 7
  • 14