openSUSE:Systemd packaging guidelines

Jump to: navigation, search
This article describe 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 (ie /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 (ie /usr/lib/systemd/user).

This command is an example of a legal install line where %{S:3} is a reference to your e.g. 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.

Since %suse_version > 1320 or %sle_version > 120100 %service_del_preun, %service_del_postun and %systemd_preun know the arguments -f and -n:

  1. -f forces a restart on update when called with %service_del_postun or stop on removal when called from %service_del_preunwhile
  2. -n will prevent active services from being touched on update (%service_del_postun) or uninstall (%service_del_preun).

On older versions or when nothing is specified, the default is that

  1. if the service should NOT be restarted when being updated, you should append in the %postun section, just before %service_del_postun call:
  1. if the service should NOT be stopped when being uninstalled, you should append in the %preun, just before the %service_del_preun call:

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-branding-openSUSE package, modifying default-openSUSE.preset file by adding e.g.:

enable your_service_name.service

Creating files / 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