On our Ubuntu Xenial(16.04) station I host a bot written in Python that connects to our IRC server that's set to launch in /etc/network/if-up.d/

Our bot was connecting twice though the script is set to only run one instance and if its username is taken it must close the current connection and reconnect under the next username.

I used ps aux | grep$ to determine the issue was not at the script level, but for some reason two instances of the script were being run when Ubuntu connected to the internet.

I've created a workaround on the script level that checks how many instances of the script are running locally and if it's any number besides one, it will close the script.

What would be some reasons if-up.d/might launch two instances of a single script stored in its directory?

The script in if-up.d/ is a sh script that wraps the call to python so it waits past the timeout period for irc then connects:

sleep 269
sh -c "python /dir/to/ >> /dir/to/log" & disown

Additional Sources:
So far, I've seen the issue mirrored here in a different context where someone used a python script to send emails and the recipients received multiple emails due to multiple instances of their script launching.

I was also able to find this question for 16.04 on Server Fault where someone experienced a similar issue and the answer listed suggested it might be running twice because there's one instance launched for IPv4 and IPv6, though I'm not sure if this is actually the root cause or how to specify you'd only want to use IPv4 and forego the IPv6 call if that was the case.

Between our 3 cases, Ubuntu 16.04 seems to be the common thread which makes me wonder if this is a bug.

up vote 1 down vote accepted

Looking more into 16.04 if-up.d/, I found a similar question for someone running Debian 7.3 and found the answer. It is not a bug, and the issue I experienced is explained here in @Søren Løvborg's answer:

In general, ifup / ifdown does not guarantee that your script only runs once. Thus your script has to be idempotent; that is, contain its own logic not to establish a tunnel that already exists. The best way, of course, is to start the script by actually checking if the tunnel is already there:

# Exit if network device "tun0" exists.
ip link show dev tun0 >/dev/null 2>&1 && exit 0

Additionally, the scripts in if-up.d etc. run for every interface that is brought up. As Jeff correctly observes, the if-*.d scripts receive no arguments specifying e.g. which interface is coming up.
Instead, per the interfaces(5) man page:

   There  exists  for  each  of  the  above  mentioned options a directory
   /etc/network/if-<option>.d/ [...]

   All of these commands have access to the  following  environment  vari‐

   IFACE  physical name of the interface being processed

          logical name of the interface being processed

  [... and more ...]

The solution is to start the script with a check for the correct IFACE value, e.g.:

# Exit if we're not starting "eth0".
[ "$IFACE" = 'eth0' ] || exit 0

Otherwise, the script will run for every network device, including lo, at which point it may be too early to establish a tunnel.

That said, my issue was it was executing the script for the lo interface in addition to my eth0 connection. I took one of the steps which was to program your script with the logic to not run more than once, but to only run it once without adjusting the code just specify the interface to be used before execution.

If I wanted to go back and solve this on the sh level, I'd simply need to update my script with this line since the interface I want to use is my Ethernet connection

[ "$IFACE" = 'eth0' ] || exit 0
sleep 269 
sh -c "python /dir/to/ >> /dir/to/log" & disown

Your Answer

By clicking "Post Your Answer", you acknowledge that you have read our updated terms of service, privacy policy and cookie policy, and that your continued use of the website is subject to these policies.

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