Set of systemd services that require common initialization phase?

akavel asked:

In systemd, I need to setup some services, which depend on one common “initialization” service, that must finish before they are started. Also, I would like to ensure, that the worker services and the “initialization” service can never run simultaneously at any time:

                                    manual
    BOOT --.                     "restart svc" ---.
           V                                      V
svc-init   |-----|                                |---------|
svc-a            |--------------------------------|         |----- - - -
svc-b            |--------------------------------|         |----- - - -

I want to be sure that the services are “enabled” (run at system boot); also, I would like to be able to restart the whole thing manually at any time I need.

How can I do that?

I tried a setup with important fields like below:

/etc/systemd/system/svc-init.service:

[Service]
Type=oneshot
ExecStart=/opt/svc/init-svc.sh

[Install]
WantedBy=multi-user.target

…/svc-a.service, …/svc-b.service:

[Unit]
Wants=svc-init.service
After=svc-init.service
Conflicts=svc-init.service

[Service]
Restart=always
ExecStart=/opt/svc/svc.sh

[Install]
WantedBy=multi-user.target

But when I try to run them, it fails to do what I want:

  1. sudo systemctl start svc-init
    • it correctly stops svc-a & svc-b
    • but it doesn’t start svc-a & svc-b again after svc-init is done
  2. sudo systemctl start svc-a
    • it doesn’t force svc-init to run beforehand
  3. sudo systemctl start svc-a svc-b svc-init
    • the effect seems the same as in (1) above (that is, ... start svc-init)
  4. sudo systemctl start svc-init svc-a svc-b
    • doesn’t run svc-init
    • prints: Job for svc-init.service canceled.

What are the magic systemd incantations to make the system behave as I need it to? Or should I structure the units differently, somehow?

My answer:


Assuming you can’t get rid of the scripts and have systemd do all the setup itself (which you almost certainly can, but whoever wrote the scripts might not know how; yell at the vendor/developer until they learn) I think you should be using only one unit file for this.

In a single unit file, you will run the init script in an ExecStartPre= option. The unit will fail to start if the program called here fails to exit successfully. For example, in [email protected]:

[Service]
Restart=always
ExecStartPre=/opt/svc/init-svc.sh %I
ExecStart=/opt/svc/svc.sh %I

[Install]
WantedBy=multi-user.target

View the full question and any other answers on Server Fault.

Creative Commons License
This work is licensed under a Creative Commons Attribution-ShareAlike 3.0 Unported License.