Is it possible to specify a systemd dependency on any one of multiple units?
Currently, I have a unit Z that depends on at least one of unit A or unit B.
Configuring unit A to be WantedBy
unit Z and unit B to be WantedBy
unit Z mostly works.
However, if only one of units A or B is able to start, the boot process waits for the other unit to timeout before starting unit Z. I want to eliminate this timeout.
Units A and B require a timeout in order to function properly, however, once once of them has started, there is no need to wait for the other unit to timeout before starting unit Z.
Is there a way to specify that unit Z depends on either unit A or unit B, but does not need to wait for both unit A and unit B before starting unit Z?
In the Debian world, the packaging system uses Provides
to specify something similar to what I'm hoping to accomplish here.
What I'm Trying To Accomplish
Debian used to support a keyscript
option in crypttab
but did not reimplement that option when upstream rewrote the startup scripts for the move to systemd
. Previously, I used a keyscript
to read my key from a USB drive. Currently, I am using a systemd
unit file to take the place of the keyscript
option (unit A). That works perfectly. However, USB drives are prone to failure, so for redundancy, I want to carry a second copy of my key on a second USB drive. And I want to add a second systemd
unit file for that second USB drive (unit B), so that whichever USB drive is inserted, systemd
is able to use that USB drive and continue without a timeout.
Other Things I've Tried
Using Conflicts
to specify that A conflicts with B, and B conflicts with A. Unfortunately, systemd processes the conflict before attempting to start either of units A or B, and removes one of these units from the scheduler before trying to start the remaining unit. So Z sometimes fails, for example, if A fails, but B would have succeeded, if B was already eliminated from consideration due to the conflict with A.
Using JobTimeoutSec
to shorten the timeout. Unfortunately, this can result in Z failing, if A and B timeout.
Michael Hampton's suggestions. As he mentions, the NTP example creates a weak dependency between each client and the target. Each NTP client wants the target, but the target does not depend on each of the NTP clients, so this works. However, as best I can tell, a weak dependency does not pull in the unit unless the unit also has an [Install]
section specifying an additional dependency. So when I pull in my units A and B, the WantedBy
in the [Install]
section creates the blocking timeout. If I remove the [Install]
section, units A and B are ignored.
This is a job for a systemd target unit.
Rather than give a contrived example, I'll give a real world example which is already present on your system.
Consider NTP. Most computers sync via NTP, but there are three (and maybe more) NTP clients that you might choose from: systemd-timesyncd, chronyd or (the classic) ntpd.
Each of the service units for these NTP clients is part of a target called
time-sync.target
, and weakly requires it as such.Thus, when you start any of the NTP clients,
time-sync.target
is started up after the NTP client starts. Note thattime-sync.target
itself is empty and doesn't actually do anything on its own.So, if you run a service which requires that the system time has been synchronized, and would fail otherwise, you can require it to start only after
time-sync.target
has started.You should easily be able to adapt this to your own service.
I think if this feature existed, it would be in the
systemd.unit
man page, and I don't see it there.A solution could be use a small
bash
script that succeeds as soon as either A or B starts, or fails if both A & B fail to start.