Experimenting with Busybox Runit
Refer to these posts yesterday:
http://bkhome.org/news/201802/busybox-1251-runit-applets.html
http://bkhome.org/news/201802/thinking-about-service-managers.html
I have been wondering more about why I find daemontools and
derivatives to be unsatisfactory. I think that the developers are system
adminstrators, and have a particular mindset. They are developing for
systems that have fairly fixed software and interfaces, not for generic
desktop systems.
Also, I have struggled with the documentation. Regarding Runit, one person commented:
"Runits documentation is so bad that I had to learn it by experimentation, even though I know its ancestor daemontools inside and out."
I was also hampered by the documentation of the Busybox
implementation of Runit. "sv --help" showed the commandline options,
which lead me to believe it was only a subset of the full 'sv' utility.
Options such as "check" and "start" were missing. Until I looked at the
Busybox 'sv.c' source, and saw that those options are supported.
Anyway, my simple requirement for some services to be dependent on a
network up. It was not explained in the official docs, found some info
after much hunting...
I created a service named "network", by creating a folder '/etc/sv/network'.
Inside, created two scripts, 'run' and 'check'. Contents of 'run':
#!/bin/ash
#sleep forever...
sleep 9999d
Contents of 'check':
#!/bin/ash
exec 2>&1
#exit with 0 if network is up (exclude 'lo')...
UP_IFS="$(grep -l '^0$' /sys/class/net/[^l]*/dormant | cut -f 5 -d '/')"
#...ex: /sys/class/net/eth0/dormant, cut 'eth0'
if [ "$UP_IFS" ];then
exit 0
else
exit 1
fi
Now, if another service specifies "network" as a dependency, the
'network/check' script will be run, and if returns "0" then yep it is
running.
So, I created '/etc/sv/test_net', with script 'run':
#!/bin/ash
exec 2>&1
sv -w10 check network
if [ $? -eq 0 ];then
echo 'up' >> /tmp/zz-net
sleep 99999d
else
echo 'down' >> /tmp/zz-net
exit 1
fi
...this is just a dummy script. A real service might be to start a daemon instead of that "sleep 99999d".
The key line in that script is "sv -w10 check network". This will run
the 'network/check' script. If 'check' returns non-0, the above 'run'
will exit with non-0. The Runit supervising utility 'runsvdir' will wait
one second, then try again, that is, rerun 'test_net/run', and will
keep at it until the network is up.
This is the official way to do it, and at this stage I was thinking "Oh
my goodness gracious me, surely not!" (or words to that effect). But
yep, that's it, a polling loop. Furthermore, if several services have
the same "network" dependency, they will all independently be calling
'network/check'.
Then I recalled something that I had read in the 's6' docs, at https://skarnet.org/software/s6/why.html:
"Neither System V init, daemontools, runit or perp provides any hooks to wait for a service to go up or down. runit provides a waiting mechanism, but it's based on polling, and the ./check script has to be manually written for every service."
It is a pity that I am not happy with Runit, as the Busybox
implementation is tiny. I reported yesterday that I recompiled Busybox
statically, adding the Runit applets and three extra network applets.
The size of the stripped binary grew from 933KB to only 965KB.