openSUSE:Systemd packaging guidelines
tagline: From openSUSE
Contents
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
%else
%bcond_with systemd
%endif
[...]
%if %{with systemd}
BuildRequires: systemd-rpm-macros
%{?systemd_requires}
%endif
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 http://www.freedesktop.org/wiki/Software/systemd/Generators .
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 :
%pre %service_add_pre foo.service bar.socket elsewhere.path %post %service_add_post foo.service bar.socket elsewhere.path %preun %service_del_preun foo.service bar.socket elsewhere.path %postun %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:
- -f forces a restart on update when called with
%service_del_postunor stop on removal when called from%service_del_preunwhile - -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
- if the service should NOT be restarted when being updated, you should append in the
%postunsection, just before%service_del_postuncall:
export DISABLE_RESTART_ON_UPDATE=yes
- if the service should NOT be stopped when being uninstalled, you should append in the
%preun, just before the%service_del_preuncall:
export DISALBLE_STOP_ON_REMOVAL=yes
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 /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:
%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
/usr/lib/initscripts/legacy-actions/foo/frob
that implements the feature you need. Obviously the action is only available when calling the service via /usr/sbin/service, ie
# service foo frob
or
# rcfoo frob
