openSUSE:Systemd packaging guidelines

Jump to: navigation, search
This article describes packaging guidelines for systemd services.

RPM macros

Starting with openSUSE 12.1, several RPM macros must be used to package systemd services files.

(Build) Requirements

You should add :

%if 0%{?suse_version} >= 1210
%bcond_without systemd
%bcond_with systemd
%if %{with systemd}
BuildRequires: systemd-rpm-macros

You need both the build requirement and the %{?systemd_requires}.

Systemd unit files

Systemd unit files like service, socket, and path files should always be installed in %_unitdir (i.e. /usr/lib/systemd/system) and never in /etc/systemd/system (so they can be overridden by users without conflicting with packaging). An exception are user unit files which must be installed in %{_prefix}/lib/systemd/user (i.e. /usr/lib/systemd/user).

This command is an example of a legal install line where %{S:3} is a reference e.g. to your service file:

install -D -m 644 %{S:3} %{buildroot}%{_unitdir}/foo.service

Systemd unit files should be considered not to be edited by system administrators. For this the directory /etc/systemd/system exists. A service file named foo.service might be overriden by the system administrator creating a file /etc/systemd/system/foo.service.d/my.conf.

Instantiated Service files

If an instantiated service (compare with manual page systemd.unit(5)) is needed then the service file packaged with the RPM should be installed to foo@.service. Thus this command is a legal install line:

install -D -m 644 %{S:3} %{buildroot}%{_unitdir}/foo@.service

The user should instantiate the service via a command like:

sytemctl enable autossh@${my-instance}.service

and override the service file by the system administrator creating a file /etc/systemd/system/foo@${my-instance}.service.d/my.conf

Thus each instance must be individually instantiated and overridden by the system administrator or the appropriate systemd generator (compare with manual page systemd.generator(7)) as specified in .

Register systemd unit files in install scripts

Add the following macros to your scripts:

if foo.service, bar.socket, and elsewhere.path are three systemd units you are installing :

%service_add_pre foo.service bar.socket elsewhere.path

%service_add_post foo.service bar.socket elsewhere.path

%service_del_preun foo.service bar.socket elsewhere.path

%service_del_postun foo.service bar.socket elsewhere.path

Compare with the manual pages systemd.service(5), systemd.socket(5), and systemd.path(5) as well as the overview systemd.exec(5) and systemd.unit(5).

If your package is also providing sysv initscripts, those macros will handle sysv initscripts migration transparently (as long as initscripts and systemd services have similar names).

If your package is supposed to build for openSUSE older than 12.1, you should use condition test for those macros.

During package update, %service_del_postun restarts units. If the units should not be restarted while the package is updated then %service_del_postun_without_restart should be called instead.

Enabling systemd unit files

By default, services are not enabled when package is installed. If you want your service to be enabled by default, you should do a submit request (with OBS) on systemd-presets-common-SUSE or systemd-presets-branding-openSUSE package, modifying default-openSUSE.preset file by adding e.g.:

enable your_service_name.service

Such an automatically enabled service shouldn't require any manual configuration before it can start properly.

Recent openSUSE and SUSE products contain two important preset files in two preset packages. systemd-presets-common-SUSE with 95-default-SUSE.preset (or 90-default-SUSE.preset up to Leap 15.0) and systemd-presets-branding-openSUSE (or generally systemd-presets-branding-brand) with 90-default-openSUSE.preset (or 90-default-brand.preset).

Both are technically equivalent. Depending on a purpose of your service, pick a proper one:

systemd-presets-common-SUSE is intended for services that are mandatory for a proper function of the system or the package. Placing preset into this file means: All systems should use this value as a default. This package is a common base for both open and enterprise products and it is part of all base installations.

systemd-presets-branding-openSUSE is indented for vendor customization. Placing a preset here means: It is a wise default for openSUSE, but not enabling this service in other product makes perfect sense. The package structure makes possible to create a custom brand with a custom systemd-presets-branding-brand as a part of custom branding. Generic rules for branding packages are explained in openSUSE:Packaging_Branding.

Note: Third party packages can install a custom preset file, but it is not allowed for packages in the openSUSE distribution.

Preset change and upgrade

When you change preset of a service, upgrade scripts calls one-time customization reset. It means, that if you add enable, then it will force-enable the service on all systems during the upgrade. And vice versa, if you delete an enable or add disable, it will force-disable the service during the upgrade.

Systemd timers

Systemd timer is a systemd feature that helps to define time activated services or events. It's an alternative to cron.

Since 2018-11-09, a process of migration from cron to systemd timers (fate#323635) is in progress. See boo#1115430 (openSUSE) and bsc#1115399 (SLE, internal) trackerbugs that track all packages that should be migrated for openSUSE and SLE.

Timer and service units

Timer unit is a unit configuration file that ends with .timer suffix and it activates the matching service file (foo.timer activates foo.service). Systemd automatically pair timer and service with the same name but it can be also specified via Unit=.

Timers need to include [Timer] section that defines when the timer is activated. For the whole description of the time format used for timer configuration please see systemd.timer(5). For time and date specification see systemd.time(7).

Timer units can be either provided by upstream or a packager needs to write it himself/herself (e.g. during migration from cron to systemd timers).


Example logrotate.timer

Description=Daily rotation of log files
Documentation=man:logrotate(8) man:logrotate.conf(5)



Example logrotate.service

Description=Rotate log files
Documentation=man:logrotate(8) man:logrotate.conf(5)

ExecStart=/usr/sbin/logrotate /etc/logrotate.conf

Packaging of the systemd timers

Packaging of the systemd timers is very similar to the packaging of any other systemd unit.

# Pack service and timer files
Source5:      %{name}.service
Source6:      %{name}.timer

# Standard systemd requirements
BuildRequires:  pkgconfig(systemd)

# Install service and timer file
install -D -m 0644 %{SOURCE5} %{buildroot}%{_unitdir}/%{name}.service
install -D -m 0644 %{SOURCE6} %{buildroot}%{_unitdir}/%{name}.timer

# Use systemd macros in %pre, %post, %preun, %postun sections
%service_add_pre %{name}.timer

%service_add_post %{name}.timer

%service_del_preun %{name}.timer

%service_del_postun %{name}.timer

# List them in the %files section

Enabling and starting

Please note that by default, timers are not enabled when the package is installed. See Enabling systemd unit files for more information.


Systemd currently doesn't support equivalent to crons's MAILTO function for sending emails on job failure. See Arch Linux wiki for a workaround.

Creating files and subdirectories in /var/run and /run

Since openSUSE 12.2, /var/run (which is either bind mounted or symlinked to /run) are mounted as tmpfs, so packages should not contain any directories (or files) under /var/run (or /run), since they will disappear at the next reboot.

If new files / directories need to be created there, you should package a tmpfiles.d file (see man tmpfiles.d for the syntax), installed in %_tmpfilesdir(/usr/lib/tmpfiles.d/). One example of such a file:

# create a directory with permissions 0770 owned by user foo and group bar
d /var/run/my_new_directory 0770 foo bar

You should install them in %install section like this:

install -d -m 0755 %{buildroot}/usr/lib/tmpfiles.d/
install -m 0644 %{SOURCE4} %{buildroot}/usr/lib/tmpfiles.d/%{name}.conf

If you expect this file or directory to be available after package installation (and before reboot), remember to add in your package %post section:

%tmpfiles_create %_tmpfilesdir/<file_name>

Backward compatibility

rc symlink

It's still possible to keep the /usr/sbin/rcname symlink. In order to make it work with systemd, link to /usr/sbin/service for each unit (service and target types are supported):

ln -s /usr/sbin/service %{buildroot}%{_sbindir}/rcname

Extra actions

Init scripts sometimes implemented additional actions besides the usual start/stop/status etc. For systemd service files that extra feature doesn't exist. It's still convenient to have for some services though. Therefore /usr/sbin/service implements "legacy actions" like Fedora.

Suppose your previous init script "foo" had an action "frob". Now the service file is called "foo.service" and you want to still support the "frob" action. In Factory since 2014-03-11 (post 13.1) you can create a script


that implements the feature you need. Obviously the action is only available when calling the service via /usr/sbin/service, ie

 # service foo frob


 # rcfoo frob