Hooking up instantiated services with RPM

Posted on May 14, 2018

We already mentioned Instantiated Services a few times. However, there is one question we did not yet cover:

How to hook up those instances with our package manager

For a normal service file this is pretty easy. Such a service can be handled as follow in the spec file:

%pre
%service_add_pre superduper.service

%post
%service_add_post superduper.service

%preun
%service_del_preun superduper.service

%postun
%service_del_postun superduper.service

That is it. It will do all the things we want.

But our instantiated services are launched with a parameter like in the following example:

systemctl start superduper@bar

We could parse the output of systemctl status, find all instances and then restart them in a loop. But there is a better way.

Painting a target

Assuming the base superduper@.service file looks like following:

[Unit]
Description=Super Duper Daemon
Wants=network-online.target
After=network-online.target

[Service]
Type=simple
ExecStart=/usr/sbin/superduper --config /etc/superduper/%i.conf

[Install]
WantedBy=multi-user.target

The %i part in the ExecStart= line holds the parameter passed to the unit file.

With the PartOf= statement in the [Unit] section of the service file we declare that this unit file sees itself as part of the group.

The superduper@.service file now looks like this.

[Unit]
Description=Super Duper Daemon
Wants=network-online.target
After=network-online.target
PartOf=superduper.target

[Service]
Type=simple
ExecStart=/usr/sbin/superduper --config /etc/superduper/%i.conf

[Install]
WantedBy=multi-user.target

The corresponding target file is really simple:

[Unit]
Description=All instances of Super Duper Daemon

Now we can manually do the following actions:

systemctl stop superduper.target
systemctl restart superduper.target

You can not start all services with a target. This has to be done manually again. Restart and stop are the only working actions. Now our RPM integration becomes:

%preun
%service_del_preun superduper.target

%postun
%service_del_postun superduper.target

We can’t really handle that the macros for %pre and %post do with target files.

Targetting other things

It is worth mentioning that you can use the whole mechanism also with non instantiated services. We use it for example with our discourse package to restart the puma app server and sidekiq after an update.

Disable services

Until we get a clean solution to disable services via the following snippet, we need a temporary solution.

%preun
%service_del_preun superduper.target

We learned that systemctl disable superduper@.service works.

%preun
%service_del_preun superduper.target superduper@.service

The target will take care that the service gets shutdown, and the 2nd service reference will work for disabling the service. Of course this is a little ugly has 2 “noops” in it … the stop call will not work with the service part and the disable part will not work with the target.

But still some progress.

TODO

  1. check if foo@.target as seen in brltty makes sense