3

With SystemD, how can I make certain services dependent on certain network interfaces being up?

For example, let's say I have an 802.1ad bond interface I need to wait on for access to my SAN/NAS before I bring up libvirtd, even though I may have network access available via a different interface. Or let's say I have an sshfs mount I want to come up automatically (and be torn down automatically) dependent on a VPN connection?

What's the idiomatic way to handle fine-grained dependencies on network interfaces?

At present, I'm using NetworkManager on Ubuntu and CentOS7, but I'm open to other platform-appropriate mechanisms for managing network state.

Michael Mol
  • 917
  • 7
  • 15

1 Answers1

1

There isn't really a standard built in way I don't think, but there are a few things you can leverage in systemd.

ExecStartPre=

Additional commands that are executed before [...] the command in ExecStart=, respectively. Syntax is the same as for ExecStart=, except that multiple command lines are allowed and the commands are executed one after the other, serially.

If any of those commands (not prefixed with "-") fail, the rest are not executed and the unit is considered failed.

Restart=on-failure

Configures whether the service shall be restarted when the service process exits, is killed, or a timeout is reached.

If set to on-failure, the service will be restarted when the process exits with a non-zero exit code, is terminated by a signal (including on core dump, but excluding the aforementioned four signals), when an operation (such as service reload) times out, and when the configured watchdog timeout is triggered.


Commands are considered to have failed if they return non-zero exit codes, so by setting the ExecStartPre to something that proves your interface is up you can be sure your service will require it.

Some examples:

ExecStartPre=/usr/bin/ping -c 1 ${SAN_IP}

ExecStartPre=/usr/sbin/iscsiadm -m session

I personally like the iscsiadm variant for your use case. If there are iscsi connections the return value is 0, otherwise it returns 21 (which would cause the service to fail). The ping variant can work for a larger variety of uses, but I would say in most cases you may want to find a more suitable command to check network status. You could even try using ssh if you have keys setup to check things on another host.

The point is that ExecStartPre can let you make your service fail based on any commands. Just check to make sure that any command you use will return non-zero exit codes when you want it to (for example cating an empty file returns 0, whereas cating a non-existent file returns 1)


After some consideration and the asker's comment, I would say the best way to define a complex condition for a service is to create another service for it to depend on.

Create a new service that uses the command to check status as the ExecStart. Give it the Restart=on-failure. Then make your original service Require and After it.

The ExecStartPre example I used above is sort of twisting its original purpose, which was to set things up for the service to run properly. It can still apply and the knowledge is still useful so I'm leaving it intact.

Centimane
  • 4,420
  • 2
  • 21
  • 45
  • This sounds like it's about as close to a right answer as is possible for now; I have to define my "up" condition as a script and set it up as a `systemd` unit. – Michael Mol Apr 28 '17 at 18:25
  • That's probably the most correct way. This is simply a method for defining it within the service. It has the main drawback of causing the service itself to restart on failure, which may not be desired. – Centimane Apr 29 '17 at 01:52