Coordinate Scripts With systemd
Coordinate Scripts With systemd
- author
-
akeil
- date
-
2013-12-14
- version
-
1
Use systemd to execute scripts, controlling the order of execution.
- Assuming we have:
a single preparation unit -
prep.service
multiple "task" units -
task-N.service
a single cleanup script -
done.service
We want to run the prep unit once, then run all our task units and finally the done unit once.
Defining dependencies between tasks is relatively simple when each task
is represented by a systemd unit 1.
Dependencies are defined using Requires=
or Wants=
and order of execution is defined with After=
and Before=
.
The only thing left is to make sure that the "preparation" and "finish" steps are executed only once, even if multiple tasks are run (and not once for each task).
To achieve this a .target
is created
and all tasks are associated to that target.
Note
- Steps:
Create
.service
files for the commands that must be executed beforeCreate
.service
for commands that should be executed afterCreate as single
.target
for all tasksCreate a
.service
for each task, make itWantedBy=
the target.
Target Unit
A systemd target 2 is used to group several units together.
The target file goes into /etc/systemd/system
and looks like this:
# tasks.target --------------------------------------- [Unit] Description = Tasks Target
The target can be started manually with:
# systemctl start tasks.target
The task units are associated with the target using WantedBy=
.
This means, if we enable one or more task units with
# systemctl enable task-1.service task-2.service
... starting the tasks.target
will start all of the associated
units.
This allows us to start all tasks with a single invocation which in turn means that we execute any number of tasks and the prep and done units only once.
Task Units
Each task unit specifies the prep.service
as a
precondition using Requires=
and After=
.
It also specifies the done.service
using Wants=
and Before=
to have it run after the tasks.
# task.service --------------------------------------- [Unit] Description = A task unit Requires = prep.service After = prep.service Wants = done.service Before = done.service [Service] User = someuser Group = somegroup Type = oneshot ExecStart = /usr/local/bin/script.sh [Install] WantedBy = tasks.target
The Requires=prep.service
directive means that the task is not started
if the prep.service
failed.
Using Wants=prep.service
would try to start the prep unit first
but continue with the tasks regardless of whether preparation was
successful or not.
The User=
and Group=
properties can be used to run the command
under a different user than root.
Not all tasks have to specify the same dependencies. It is also possible that tasks depend on each other.
Prep and Done Units
The prep.service
and the done.service
are plain units
and do not define any dependencies.
the prep unit should be configured with Type=oneshot
to have it complete before the first task can be started.
Service Type
By default, Before=
and After=
only control the order in which
services are started.
To make sure that the prep unit completes before the tasks are started,
use Type=oneshot
in the [Service]
definition.
From the systemd service 3 documentation:
Behavior of oneshot is similar to simple; however, it is expected that the process has to exit before systemd starts follow-up units.
The same goes for the task units if the done unit should only be executed after the tasks are complete.
Locations
- Custom unit files go into:
/etc/systemd/system
for system-wide scope~/.config/systemd/user
for user-specific scope