Upstart Job HOWTO
From FrugalWiki
In Upstart, there aren't init scripts, there are job files. This page will show you how to write a simple job file for a service.
The most simple jobs for daemons will just want to start and monitor a daemon. At the top of our job file, we need a description and an author field. These aren't used by Upstart, they're just to show who made the job file and what it does.
description "Foobar management daemon" author "Alex Smith"
Next we want to define when we want this daemon to start and when we want it to stop.
start on started network stop on stopping network stop on starting shutdown
This means that it'll start once the network job has been started successfully, and stop when the network is stopping. Also it will stop when the machine is shutting down. The 'stop on starting shutdown' is correct because shutdown is a job which will be blocked from running until all the services are down
Now we should define where the output will go to. If this is not specified the output will be logged by logd, but right now logd is broken (will be fixed soon) so any message sent to it will disappear. So, for now, let's send the output to the console:
console output
Other possibilities here include 'console none', which just sends the output to /dev/null or 'console owner' which means that the job has full control over the console it is run from - this is useful for things like gettys.
Next we define what we want to run:
exec /usr/sbin/foobard --no-daemon respawn
The 'exec' part specifies what to run and with what arguments. This command should not fork into the background as then Upstart will think that it has exited and try to respawn it (at least, it will if you specify the respawn line). The respawn line will tell Upstart to restart the daemon if it exits.
So, our first Upstart job is here:
description "Foobar management daemon" author "Alex Smith" start on started network stop on stopping network stop on starting shutdown console output exec /usr/sbin/foobard --no-daemon respawn
Contents |
Scripts
Now lets say foobard version 2.0 was released, which requires some stuff to be run before the daemon can be started, and after it has been stopped. This is where the script stanza comes in handy. I can add in a pre-start script and a post-stop script to do the necessary stuff:
pre-start script if [ ! -d "/var/lib/foobard" ]; then mkdir -p /var/lib/foobard fi end script
post-stop script rm -f /var/lib/foobard/deleteme end script
States
Sometimes you'll need a job just to run something on startup and shutdown, not a daemon. You could just do this with 2 seperate job files with a script section, like this:
script /usr/bin/myprogram --set-up-blah /usr/sbin/foocleaner end script
But, however, if you did that, 'initctl list' would show both jobs to be stopped after they have been run. This can be made much cleaner by defining a state. If a job has no exec or script stanza, then it automatically becomes a state. Let's use the sound-settings job as an example
description "Save and restore the mixer settings" author "Alex Smith" start on stopped load-modules ok stop on starting shutdown console output service pre-start script # Here we don't want the script to fail. If it fails, we won't be in # the running state therefore when the user shuts down their mixer # settings won't be saved if [ -d /proc/asound -a -r /etc/asound.state ]; then alsactl restore || true else amixer set Master 35 unmute || true amixer set PCM 35 unmute || true fi end script post-stop script # Create the state file if it doesn't exist [ ! -r /etc/asound.state ] && touch /etc/asound.state # Only run if ALSA is available if [ -d /proc/asound ] ; then alsactl store fi end script
The pre-start script defines what to run when the job is being started. The post-stop script defines what to do when it is being stopped. Now, when this job is started, initctl list will actually show that it is started. You should always put the service stanza in a state because otherwise running 'start sound-settings' would block until it is stopped.
You can also use this state mechanism to run daemons that fork into the background. Just have the daemon started by the pre-start script and stopped by the post-stop script. This is not an ideal solution, but it will do until Upstart gains the functionality to find out the PID of a forked process and monitor it and/or patches are added to the daemon in question to give it a command line option to not fork.
When should my job start?
In most cases, this is sufficient:
start on stopped load-modules
However, if, say, your service needs DBUS, you should start it once DBUS is started:
start on started dbus
Or, in the case of a network service such as Apache, you need network to be available:
start on started network
Warnings
Scripts are run with /bin/sh -e. This means that any command that fails will cause the script to terminate. In most cases this is OK so you don't have to put || exit 1 everywhere, however if you wish to run commands in the scripts that may fail, and it's OK to carry on if they fail, you should put the command like this
pre-start script /usr/bin/programthatwillfail || true blah boo --fail || true end script