From Fedora Project Wiki

(Created page with '= NOTE = Work in progress, not even close to useful or complete. == Fedora systemd Services == This document describes the guidelines for systemd services, for use and inclusion...')
 
No edit summary
Line 1: Line 1:
= NOTE =
= Fedora systemd Services =
Work in progress, not even close to useful or complete.
This document describes the guidelines for systemd services, for use and inclusion in Fedora packages.  


== Fedora systemd Services ==
= Unit Files =
This document describes the guidelines for systemd services, for use and inclusion in Fedora packages.  
The systemd equivalent for an SysV initscript is called a Unit file. Each package that contains software that wants/needs to start a service at boot must have a systemd unit file.


== Unit Files ==
{{admon/note|SysV Initscripts|Packages may also provide a SysV initscript file, but are not required to do so. This format is considered legacy, but Fedora still contains init mechanisms such as upstart which do not support the systemd unit file format. The guidelines for SysV initscripts can be found here: [[Packaging:SysVInitScript]]}}
The systemd equivalent for an SysV initscript is called a Unit file.


=== Naming ===
== Naming ==
Unit files have a naming scheme of foobar.service. When considering what basename to use, keep the following advice in mind:
Unit files have a naming scheme of foobar.service. When considering what basename to use, keep the following advice in mind:


* Unit files should be named after the software implementation that they support, as opposed to the generic type of software. So, a good name would be "apache-httpd.service", and a bad name would be "httpd.service", as there are multiple httpd implementations, but only one Apache httpd.
* Unit files must be named after the software implementation that they support, as opposed to the generic type of software. So, a good name would be "apache-httpd.service", and a bad name would be "httpd.service", as there are multiple httpd implementations, but only one Apache httpd.
* Unit files should have the same base name as the SysV initscript, so if the SysV initscript is /etc/rc.d/init.d/foobar, then the unit file must be /lib/systemd/system/foobar.service. This will enable automatic fallback in systemd: if a native unit file doesn't exist by a specific name it will fall back to the SysV file of the same service. If the SysV initscript was named poorly (e.g. httpd), then you should provide a compatibility symlink for the old SysV basename (apache-httpd.service -> httpd.service).
 
* If the package includes a SysV initscript, it must have the same base name as the systemd unit file. For example, if the unit file is /lib/systemd/system/foobar.service, then the SysV initscript must be /etc/rc.d/init.d/foobar. If systemd cannot find a native unit file by a specific name it will attempt to fall back to the SysV file of the same service.  


It is our intention to unify service names of well-known software across distributions, so that we can eventually ship the service files in the upstream packages. Hence it is a good idea to discuss service names with maintainers of the same packages in other distributions and agree on a common name.
It is our intention to unify service names of well-known software across distributions, so that we can eventually ship the service files in the upstream packages. Hence it is a good idea to discuss service names with maintainers of the same packages in other distributions and agree on a common name.


=== Format ===
== Format ==
Every .service file must begin with a [Unit] section:
Every .service file must begin with a [Unit] section:


Line 34: Line 34:
[Service]
[Service]
Type=...
Type=...
BusName=...
ExecStart=...
ExecStart=...
ExecReload=...
ExecReload=...
Line 60: Line 59:
Strictly speaking ExecStart= (in the [Service] section) is the only option really necessary for a .service file. However, in Fedora you must add the other options mentioned here (as applicable).
Strictly speaking ExecStart= (in the [Service] section) is the only option really necessary for a .service file. However, in Fedora you must add the other options mentioned here (as applicable).


=== Support for /etc/sysconfig files ===
== Support for /etc/sysconfig files ==
If your service supports /etc/sysconfig files, then you must use  
If your service supports /etc/sysconfig files, then you must use EnvironmentFile=/etc/sysconfig/foobar in your .service file, in the [Service] section.
 
Use EnvironmentFile= to support /etc/sysconfig files. You may then refer to variables set in sysconfig files with ${FOOBAR} and $FOOBAR, in the ExecStart= lines (and related lines). (${FOOBAR} expands the variable into one word, $FOOBAR splits up the variable value at whitespace into multiple words) /etc/rc.d/init.d. A rpm macro exists for this directory, <code>%_initddir</code>. Note: The <code>%_initddir</code> macro does not exist on Fedora 9 or older releases, or on RHEL 5 or older. For those releases, you should use the deprecated <code>%_initrddir</code> macro.
 
 
 
=== Filesystem locations ==
Packages with Systemd unit files '''must''' put them into %{_unitdir}. %{_unitdir} evaluates to /lib/systemd/system/ on all Fedora systems. Unit files are architecture independent (hence, not %{_lib}) and needed early in the boot process.
 
 
 
Use EnvironmentFile= to support /etc/sysconfig files. You may then refer to variables set in sysconfig files with ${FOOBAR} and $FOOBAR, in the ExecStart= lines (and related lines). (${FOOBAR} expands the variable into one word, $FOOBAR splits up the variable value at whitespace into multiple words) /etc/rc.d/init.d. A rpm macro exists for this directory, <code>%_initddir</code>. Note: The <code>%_initddir</code> macro does not exist on Fedora 9 or older releases, or on RHEL 5 or older. For those releases, you should use the deprecated <code>%_initrddir</code> macro.
 
 
== Initscript packaging ==
Initscripts must not be marked as %config files.
 
Although init files live in /etc, they are scripts to be executed, not configured. Any configuration should be made available through /etc/sysconfig/<service> rather than in the init script itself.  A valid exception to this rule would be existing packages where configuration is still done via the init file.  In this case, the init file could be marked as %config following the rules from the [[Packaging/Guidelines#Config|  Configuration files]section to preserve a users configuration upon upgrade, hopefully so that the user can migrate said configuration to a new /etc/sysconfig/<service> config file.
 
Init scripts should also have 0755 permissions.
 
{{Anchor|InitscriptScriptlets}}
=== Initscripts in spec file scriptlets ===


Example:
<pre>
<pre>
Requires(post): chkconfig
[Service]
Requires(preun): chkconfig
Type=forking
# This is for /sbin/service
EnvironmentFile=/etc/sysconfig/httpd
Requires(preun): initscripts
ExecStart=/usr/sbin/httpd ${OPTIONS}
...
ExecReload=/usr/sbin/httpd ${OPTIONS} -k restart
%post
# This adds the proper /etc/rc*.d links for the script
/sbin/chkconfig --add <script>
 
%preun
if [ $1 = 0 ] ; then
    /sbin/service <script> stop >/dev/null 2>&1
    /sbin/chkconfig --del <script>
fi
</pre>
</pre>


'if [ $1 = 0 ] ' checks that this is the actual deinstallation of
You may then refer to variables set in sysconfig files with ${FOOBAR} and $FOOBAR, in the ExecStart= lines (and related lines). (${FOOBAR} expands the variable into one word, $FOOBAR splits up the variable value at whitespace into multiple words)
the package, as opposed to just removing the old package on upgrade.
These statements stop the service, and remove the /etc/rc*.d links.


<pre>
== Options to avoid ==
# This is for /sbin/service
For most services, we do not want to use requirement dependencies such as Requires= or Wants=. Instead exclusively use ordering dependencies: Before= and After=. This is used to implement loose coupling: if two services are started at the same time their startup is properly ordered, but do not make it strictly necessary to run one if the other is started.
Requires(postun): initscripts
...
%postun
if [ "$1" -ge "1" ] ; then
    /sbin/service <script> condrestart >/dev/null 2>&1 || :
fi
</pre>
 
'if [ "$1" -ge "1" ]  checks that this is an upgrade of the package.
If so, restart the service if it's running. (This may not be appropriate
for all services.)


=== Why don't we.... ===
If you use a requirement dependency, use Wants= rather than Requires=, to make things a little bit more robust. If you use a requirement dependency in almost all cases you should also add an ordering dependency, as ordering and requirement dependencies are orthogonal in systemd.


* run 'chkconfig <service> on'?
Here's an example of this common case:
# A web application needs postgresql to store its data.
# It is set to start <code>After</code> postgresql.  On startup, the web application does not start until postgresql does.
# Once running, the system administrator needs to restart postgresql due to a config tweak.
# Since only <code>After</code> was used, the web application may be temporarily unable to serve some requests but it does not need to restart in order to serve pages after the database comes back up.


If a service should be enabled by default, make this the default
Avoid referring to runlevelX.target units in all lines taking unit names (such as WantedBy), these are legacy names existing for compatibility with SysV only.
in the init script. Doing otherwise will cause the service to be
turned on on upgrades if the user explicitly disabled it.


Note that the default for most network-listening scripts is
Avoid Names=. Usually it is a better idea to symlink an additional name in the file system. Note that a name listed in Names= is only useful when a service file is already loaded. However, systemd loads only the service files actually referred to in another loaded service, and uses the filenames during the search. Hence a name in Names= is not useful as a search key, but a symlink in the file system is. Also do not put a (redundant) Names=foobar.service line into a file called foobar.service. We want to keep our service files short.
off. This is done for better security. We have multiple tools
that can enable services, including GUIs.


* start the service after installation?
Avoid using StandardOutput=kmsg. Use StandardOutput=syslog instead. (same for StandardError=).


Installations can be in changeroots, in an installer context, or
== Example Unit file ==
in other situations where you don't want the services started.
This is an example systemd unit .service file for ABRT:
 
== Initscript template ==
Below is the template for Fedora SysV-style initscripts. The sections are explained in detail below.


<pre>
<pre>
#!/bin/sh
[Unit]
#
Description=ABRT Automated Bug Reporting Tool
# <daemonname> <summary>
After=syslog.target
#
# chkconfig:  <default runlevel(s)> <start> <stop>
# description: <description, split multiple lines with \
#              a backslash>


### BEGIN INIT INFO
[Service]
# Provides:
Type=dbus
# Required-Start:
BusName=com.redhat.abrt
# Required-Stop:
ExecStart=/usr/sbin/abrtd -d -s
# Should-Start:
# Should-Stop:
# Default-Start:
# Default-Stop:
# Short-Description:
# Description:     
### END INIT INFO


# Source function library.
[Install]
. /etc/rc.d/init.d/functions
WantedBy=multi-user.target
 
exec="/path/to/<daemonname>"
prog="<service name>"
config="<path to major config file>"
 
[ -e /etc/sysconfig/$prog ] && . /etc/sysconfig/$prog
 
lockfile=/var/lock/subsys/$prog
 
start() {
    [ -x $exec ] || exit 5
    [ -f $config ] || exit 6
    echo -n $"Starting $prog: "
    # if not running, start it up here, usually something like "daemon $exec"
    retval=$?
    echo
    [ $retval -eq 0 ] && touch $lockfile
    return $retval
}
 
stop() {
    echo -n $"Stopping $prog: "
    # stop it here, often "killproc $prog"
    retval=$?
    echo
    [ $retval -eq 0 ] && rm -f $lockfile
    return $retval
}
 
restart() {
    stop
    start
}
 
reload() {
    restart
}
 
force_reload() {
    restart
}
 
rh_status() {
    # run checks to determine if the service is running or use generic status
    status $prog
}
 
rh_status_q() {
    rh_status >/dev/null 2>&1
}
 
 
case "$1" in
    start)
        rh_status_q && exit 0
        $1
        ;;
    stop)
        rh_status_q || exit 0
        $1
        ;;
    restart)
        $1
        ;;
    reload)
        rh_status_q || exit 7
        $1
        ;;
    force-reload)
        force_reload
        ;;
    status)
        rh_status
        ;;
    condrestart|try-restart)
        rh_status_q || exit 0
        restart
        ;;
    *)
        echo $"Usage: $0 {start|stop|status|restart|condrestart|try-restart|reload|force-reload}"
        exit 2
esac
exit $?
</pre>
</pre>


== Chkconfig Header ==
== Bus Activation ==
Every Fedora SysV-style initscript must contain a chkconfig header. This header is composed of two parts, a "# chkconfig:" line, and a "# description:" line.
In order to allow parallel startup of a D-Bus service and its consumers it is essential that D-Bus services can be bus activated, and that the D-Bus activation is forwarded to systemd so that you end up with a single service instance only. That means all existing D-Bus services that have previously not been started via bus activation but have been started via SysV scripts should be updated to be capable of bus activation. This is easily implemented by dropping a D-Bus .service file in /usr/share/dbus/system-services/ which uses the SystemdService= directive to redirect activation to systemd. See the D-Bus documentation for more information. (Don't be confused by the fact that both systemd and D-Bus use the .service file suffix, they are different things, though the D-Bus .service often refers to the systemd .service file for the same program with the SystemdService= directive.)


=== # chkconfig: line ===
Note that traditionally bus activated services could not be disabled. systemd does not change this, however in some cases where making it possible to disable a service is desirable (e.g. avahi, NetworkManager), you can easily implement that by directing the D-Bus service to a symlinked alias name of the real service file which is controlled via systemctl enable/disable and which then points to the real service. Example: set SystemdService=dbus-org.freedesktop.Avahi.service instead of SystemdService=avahi-daemon.service, and then make /etc/systemd/system/dbus-org.freedesktop.Avahi.service a symlink → /lib/systemd/system/avahi-daemon.service. A full example for the Avahi case:
The <code>chkconfig: </code> line in a SysV-style initscript is used to determine the runlevels in which the service should be started by default. It is also used to set the "priority", or order in which the services are started within a runlevel. All Fedora SysV-style initscripts must have this line.


Here is the D-Bus .service file for Avahi (/usr/share/dbus-1/system-services/org.freedesktop.Avahi.service):
<pre>
<pre>
# chkconfig: <startlevellist> <startpriority> <endpriority>
[D-BUS Service]
</pre>
Name=org.freedesktop.Avahi
SystemdService=dbus-org.freedesktop.Avahi.service


* <startlevellist> is a list of the runlevels for which the service should be started by default. Only services which are really required for a vital system should define runlevels here. If no runlevels are defined, a <code>-</code> should be used in place of the runlevels list.
# This service should not be bus activated if systemd isn't running,
* <startpriority> is the "priority" weight for starting the service. Services are started in numerical order, starting at 0.
# so that activation won't conflict with the init script startup.
* <endpriority> is the "priority" weight for stopping the service. Services are stopped in numerical order, starting at 0. By default, you should set the <endpriority> equal to 100 - <startpriority>.
Exec=/bin/false
 
For example:
<pre>
# chkconfig: 2345 20 80
</pre>
</pre>


This means that the service will start by default on runlevels 2, 3, 4, and 5, with a startup priority of 20, and a shutdown priority of 80.
Here is the Avahi systemd unit .service file (/lib/systemd/system/avahi-daemon.service):


More commonly, the service is off by default on all runlevels, which looks like this:
<pre>
<pre>
# chkconfig: - 20 80
[Unit]
</pre>
Description=Avahi mDNS/DNS-SD Stack
=== # description: line ===
Requires=avahi-daemon.socket
The second line in the chkconfig header contains a description for the service. All Fedora SysV-style initscripts must have this line.
After=syslog.target


<pre>
[Service]
# description: <description of service>
Type=dbus
</pre>
BusName=org.freedesktop.Avahi
ExecStart=/usr/sbin/avahi-daemon -s
ExecReload=/usr/sbin/avahi-daemon -r
NotifyAccess=main


The description of service may be more than one line long, continued with '\' characters.  The initial comment and following whitespace on any additional lines are ignored, but should be used.
[Install]
 
WantedBy=multi-user.target
For example:
Also=avahi-daemon.socket
<pre>
Alias=dbus-org.freedesktop.Avahi.service
# description: Saves and restores system entropy pool for \
#              higher quality random number generation.
</pre>
 
== LSB Header ==
LSB Headers are not required for Fedora SysV-style initscripts, but they may be used. There is no requirement in the LSB certification for any system scripts to be LSB compliant, and it can cause issues with ordering.
 
If LSB Headers are used in a Fedora SysV-style initscript, it must follow these guidelines.
 
The LSB Header is composed of the following sections:
* <code># Provides:</code>
* <code># Required-Start:</code>
* <code># Required-Stop:</code>
* <code># Should-Start:</code>
* <code># Should-Stop:</code>
* <code># Default-Start:</code>
* <code># Default-Stop:</code>
* <code># Short-Description:</code>
* <code># Description:</code>
 
=== Boundary Comments ===
The LSB Header is bounded by comments, specifically, the beginning of the header is marked with:
<pre>
### BEGIN INIT INFO
</pre>
 
The end of the LSB Header is marked with:
<pre>
### END INIT INFO
</pre>
</pre>


All LSB Header entries must have these boundary comments.
The Alias= line ensures that the existance of the /etc/systemd/system/dbus-org.freedesktop.Avahi.service symlink can be controlled by "systemctl enable" and "systemctl disable".


=== Facility Names ===
In general, it is also recommended to supply native systemd units for all services that are already bus activatable, so that these services can be controlled and supervised centrally like any other service with tools such as systemctl. A similar logic like the one shown above should apply.


Boot facilities are used to indicate dependencies in initialization scripts. Facility names are assigned to scripts by the Provides: keyword. Facility names that begin with a dollar sign ('$') are reserved system facility names. Facility names are only recognized in the context of the initscript comment block (LSB Header) and are not available in the body of the init script. In particular, the use of the leading '$' character does not imply system facility names are subject to shell variable expansion, since they appear inside comments.
= Packaging =


LSB compliant init implementations are supposed to provide the following system facility names:
== Filesystem locations ==
Packages with systemd unit files '''must''' put them into %{_unitdir}. %{_unitdir} evaluates to /lib/systemd/system/ on all Fedora systems. Unit files are architecture independent (hence, not %{_lib}) and needed early in the boot process.


* $local_fs:: all local file systems are mounted
== %files section ==
* $network:: basic networking support is available. Example: a server program could listen on a socket.
Systemd unit .service files must not be marked as %config files. Any configuration should be made available through /etc/sysconfig/<service> rather than in the init script itself.
* $named:: IP name-to-address translation, using the interfaces described in this specification, are available to the level the system normally provides them. Example: if a DNS query daemon normally provides this facility, then that daemon has been started.
Init scripts must have 0755 permissions.
* $portmap:: daemons providing SunRPC/ONCRPC portmapping service as defined in RFC 1833: Binding Protocols for ONC RPC Version 2 (if present) are running.
* $remote_fs:: all remote file systems are available. In some configurations, file systems such as /usr may be remote. Many applications that require $local_fs will probably also require $remote_fs.
* $syslog:: system logger is operational.
* $time:: the system time has been set, for example by using a network-based time program such as ntp or rdate, or via the hardware Real Time Clock.


Other (non-system) facilities may be defined in the <code># Provides:</code> line in the LSB Header.
== Unit files in spec file scriptlets ==


=== # Provides: line ===
Most systemd services must be disabled by default, especially if they listen on the network. Also, a package must never turn on a service on upgrade if it was explicitly disabled.
The <code># Provides:</code> line in the LSB Header lists any boot facilities that this service provides. Other services can reference these boot facilities in their <code># Required-Start:</code> and <code># Required-Stop:</code> lines.
Fedora provides a set of scriptlets to simplify handling the setup of systemd services at package install/upgrade/removal.


<pre>
<pre>
# Provides: boot_facility_1 [boot_facility_2...]
Requires(post): systemd-units
</pre>
Requires(preun): systemd-units
Requires(postun): systemd-units


When an initscript is run with a start argument, the boot facility or facilities specified by the Provides keyword shall be deemed present and hence init scripts which require those boot facilities should be started later. When an initscript is run with a stop argument, the boot facilities specified by the Provides keyword are deemed no longer present.
%post
if [ $1 -eq 1 ]; then
        # Package install, not upgrade
        /bin/systemctl daemon-reload >/dev/null 2>&1 || :
fi


In Fedora, a <code># Provides:</code> line listing the name of the service that the initscript starts is not needed as the name of the service is implicitly Provided.
%preun
if [ $1 -eq 0 ] ; then
        # Package removal, not upgrade
        /bin/systemctl disable httpd.service > /dev/null 2>&1 || :
        /bin/systemctl stop httpd.service > /dev/null 2>&1 || :
fi


=== # Required-Start: line ===
%postun
The <code># Required-Start:</code> line in the LSB Header lists any boot facilities which must be available during startup of this service.
/bin/systemctl daemon-reload >/dev/null 2>&1 || :
 
if [ $1 -ge 1 ] ; then
<pre>
        # Package upgrade, not uninstall
# Required-Start: boot_facility_1 [boot_facility_2...]
        /bin/systemctl try-restart httpd.service >/dev/null 2>&1 || :
fi
</pre>
</pre>


This line is optional, if an initscript has no need for requiring other boot facilities before starting, it should be omitted.
Note that /bin/systemctl daemon-reload will automatically detect new systemd unit .service files placed into %{_unitdir}. There is no equivalent to 'chkconfig --add <service>', because it is unnecessary.


=== # Required-Stop: line ===
== Why don't we.... ==
The <code># Required-Stop:</code> line in the LSB Header lists any boot facilities which should '''NOT''' be stopped before shutting down this service.


<pre>
* Enable most services by default?
# Required-Stop: boot_facility_1 [boot_facility_2...]
</pre>


This line is optional, if an initscript has no need for requiring that other boot facilities must be stopped only after it has shutdown, then the line should be omitted.
Some core services must be enabled by default for a functional system, but the default for most network-listening scripts is
off. This is done for better security. We have multiple tools that can enable services, including GUIs.


=== # Should-Start: line ===
* Start the service after installation?
The <code># Should-Start:</code> line in the LSB Header lists any facilities, which, if present, should be available during startup of this service. The intent is to allow for "optional" dependencies which do not cause the service to fail if a facility is not available.


<pre>
Installations can be in changeroots, in an installer context, or in other situations where you don't want the services autostarted.
# Should-Start: boot_facility_1 [boot_facility_2...]
</pre>
 
This line is optional, if an initscript has no use for starting other optional dependencies before hand, it should be omitted.
 
=== # Should-Stop: line ===
The <code># Should-Stop:</code> line in the LSB Header lists any facilities, which, if present, should only be stopped after shutting down this service. The intent is to allow for "optional" dependencies which do not cause the service to fail if a facility is not available.
 
<pre>
# Should-Stop: boot_facility_1 [boot_facility_2...]
</pre>
 
This line is optional, if an initscript has no use for preventing other optional dependencies from stopping until after it has shutdown, the line should be omitted.
 
=== How LSB Provides actually work in Fedora ===
Fedora uses chkconfig for script enablement (chkconfig --add) and script activation/deactivation (chkconfig on/chkconfig off). When these tasks occur, the LSB dependencies are read, and the start and stop priorities of the scripts are then adjusted to satisfy those dependencies.
 
What this means:
 
* LSB header dependencies are honored (albeit in a static mechanism)
* If you use LSB headers, your start and stop priority may end up being different than what is in the <code># chkconfig:</code> line
 
=== # Default-Start: line ===
The <code># Default-Start:</code> line in the LSB Header lists the runlevels for which the service will be enabled by default. These runlevels are space-separated, unlike the Chkconfig header.
 
<pre>
# Default-Start: run_level_1 [run_level_2...]
</pre>
 
Each Fedora SysV-style initscript which needs to start by default in any runlevel must include this line in the LSB Header, and it must match the list of runlevels defined for startup in the Chkconfig header. Only services which are really required for a vital system should define runlevels here. If the service does not start by default in any runlevel, this line should be omitted.
 
For example, if a service starts by default in runlevels 3, 4, and 5 only, the LSB Header in the initscript would specify:
 
<pre>
# Default-Start: 3 4 5
</pre>
 
More commonly, the service does not start by default in any runlevel. In this case, the line should be omitted.
 
=== # Default-Stop: line ===
The <code># Default-Stop:</code> line in the LSB Header lists the runlevels for which the service will not be started by default. These runlevels are space-separated, and must contain all of the numeric runlevels not used in the <code># Default-Start:</code> line.
 
<pre>
# Default-Stop: run_level_1 [run_level_2...]
</pre>
 
Each Fedora SysV-style initscript which needs to start by default in any runlevel must include this line in the LSB Header (if the <code># Default-Start:</code> line is present, then there must also be a <code># Default-Stop:</code> line.). If the service does not start by default in any runlevel, this line should be omitted.
 
For example, if a service starts by default in runlevels 3, 4, and 5 only, then the <code># Default-Stop:</code> line in the LSB Header must specify runlevels 0, 1, 2, and 6:
 
<pre>
# Default-Stop: 0 1 2 6
</pre>
 
Note that the runlevels must be explicitly set in the <code># Default-Stop:</code> line, there are no automatic default settings derived from the <code># Default-Start:</code> line.
 
=== # Short-Description: line ===
The <code># Short-Description:</code> line in the LSB Header provides a brief summary of the actions of the init script. This must be no longer than a single, 80 character line of text.
 
<pre>
# Short-Description: This service is a mail server.
</pre>
 
All Fedora SysV-style initscripts must contain the <code># Short-Description:</code> line in the LSB Header. It can be considered roughly equivalent to the <code>Summary:</code> field in an RPM spec file.
 
=== # Description: line ===
The <code># Description:</code> line in the LSB Header provides a more complete description of the actions of the initscript. It may span mulitple lines, where each continuation line must begin with a '#' followed by tab character or a '#' followed by at least two space characters. The multiline description is terminated by the first line that does not match this criteria.
 
Example:
<pre>
# Description: Bluetooth services for service discovery, authentication,
#              Human Interface Devices, etc.
</pre>
 
All Fedora SysV-style initscripts must contain the <code># Description:</code> line in the LSB Header. It can be considered roughly equivalent to the <code>%description</code> section in an RPM spec file. It must contain the same text as the <code># description:</code> line in the chkconfig header.
 
=== LSB Header Example ===
Here is a complete LSB Header to illustrate the correct use of the LSB Headers:
 
<pre>
### BEGIN INIT INFO
# Provides: OurDB
# Required-Start: $local_fs $network $remote_fs
# Required-Stop: $local_fs $network $remote_fs
# Default-Start: 2 3 4 5
# Default-Stop: 0 1 6
# Short-Description: start and stop OurDB
# Description: OurDB is a very fast and reliable database
#              engine used for illustrating init scripts
### END INIT INFO
</pre>
 
LSB Headers are not required for Fedora SysV-style initscripts, but if it is used in the initscript, then <code>#Provides:</code>, <code># Short-Description:</code>, and <code># Description:</code> are required to be present.
 
== Initialization of Environment Variables ==
Since initscripts may be run manually by a system administrator with non-standard environment variable values for PATH, USER, LOGNAME, etc., init scripts should not depend on the values of these environment variables. They should be set to known/default values if they are needed.
 
== Required Actions ==
All SysV-style initscripts in Fedora must have implementations of the following actions:
 
* start: starts the service
* stop: stops the service
* restart: stop and restart the service if the service is already running, otherwise just start the service
* condrestart (and try-restart): restart the service if the service is already running, if not, do nothing
* reload: reload the configuration of the service without actually stopping and restarting the service (if the service does not support this, do nothing)
* force-reload: reload the configuration of the service and restart it so that it takes effect
* status: print the current status of the service
* usage: by default, if the initscript is run without any action, it should list a "usage message" that has all actions (intended for use)
 
=== condrestart and try-restart ===
Fedora SysV-style initscripts must support both the '''condrestart''' and '''try-restart''' action. These two actions are intended to serve an identical purpose, and must not differ in behavior. In fact, it is highly recommended that packagers implement '''condrestart''' and '''try-restart''' as equivalent options in the case statement:
 
<pre>
condrestart|try-restart)
    rh_status_q || exit 0
    restart
    ;;
</pre>
 
== Initscripts must be on their best behavior ==
Fedora SysV-style initscripts must behave sensibly if they are started when the service is already running, or stopped when the service is not running. They must not kill unrelated (but perhaps, similarly-named) user processes as a result of their normal actions. The best way to achieve this is to use the init-script functions provided by /etc/rc.d/init.d/functions :
 
<pre>
# Source function library.
. /etc/rc.d/init.d/functions
</pre>
 
If a service reloads its configuration automatically (as in the case of cron, for example), the reload action of the initscript must behave as if the configuration was reloaded successfully. The restart, condrestart, try-restart, reload and force-reload actions may be atomic; that is if a service is known not to be operational after a restart or reload, the script may return an error without any further action.
 
== Exit Codes for the Status Action ==
If the status action is requested, the initscript must return the correct exit status code, from this list:
 
<pre>
0: program is running or service is OK
1: program is dead and /var/run pid file exists
2: program is dead and /var/lock lock file exists
3: program is not running
4: program or service status is unknown
5-99: reserved for future LSB use
100-149: reserved for distribution use
150-199: reserved for application use
200-254: reserved
</pre>
 
Fedora does not currently define any distribution specific status codes.
 
== Exit Codes for non-Status Actions ==
For all other initscript actions, the init script must return an exit status of zero if the action was successful. In addition to straightforward success, the following situations are also to be considered successful:
 
* restarting a service (instead of reloading it) with the '''force-reload''' argument
* running '''start''' on a service already running
* running '''stop''' on a service already stopped or not running
* running '''restart''' on a service already stopped or not running
* running '''condrestart''' or '''try-restart''' on a service already stopped or not running
 
In case of an error while processing any non-Status initscript action, the initscript must print an error message and exit with the appropriate non-zero status code:
 
<pre>
1: generic or unspecified error (current practice)
2: invalid or excess argument(s)
3: unimplemented feature (for example, "reload")
4: user had insufficient privilege
5: program is not installed
6: program is not configured
7: program is not running
8-99: reserved for future LSB use
100-149: reserved for distribution use
150-199: reserved for application use
200-254: reserved
</pre>
 
Fedora does not currently define any distribution specific status codes.
 
== Other Actions ==
You are not prohibited from adding other commands, but you should list all commands which you intend to be used interactively to the usage message.
 
== Functions in /etc/init.d/functions ==
Here are some commonly used functions provided by /etc/init.d/functions:
 
=== daemon function ===
Starts a daemon, if it is not already running.  Does other useful things like keeping the daemon from dumping core if it terminates unexpectedly.
<pre>
daemon  [ --check <name> ]  [ --user <username>]
        [+/-nicelevel]  program [arguments]  [&]
 
        --check <name>:
          Check that <name> is running, as opposed to simply the
          first argument passed to daemon().
        --user <username>:
          Run command as user <username>
</pre>
 
=== killproc function ===
Sends a signal to the program; by default it sends a SIGTERM, and if the process doesn't die, it sends a SIGKILL a few seconds later.
It also tries to remove the pidfile, if it finds one.
<pre>
killproc program [signal]
</pre>
 
=== pidofproc function ===
Tries to find the pid of a program; checking likely pidfiles, and using the pidof program.  Used mainly from within other functions in this file, but also available to scripts.
<pre>
pidofproc program
</pre>
 
=== status function ===
Prints status information.  Assumes that the program name is the same as the servicename.
 
<pre>
status program
</pre>
 
Note that this is different from the Status action, this is a function that is usually used when the Status action is executed:
 
<pre>
case "$1" in
 
...
 
  status)
        status hcid
        RETVAL=$?
        ;;
 
...
</pre>

Revision as of 15:33, 1 December 2010

Fedora systemd Services

This document describes the guidelines for systemd services, for use and inclusion in Fedora packages.

Unit Files

The systemd equivalent for an SysV initscript is called a Unit file. Each package that contains software that wants/needs to start a service at boot must have a systemd unit file.

Note.png
SysV Initscripts
Packages may also provide a SysV initscript file, but are not required to do so. This format is considered legacy, but Fedora still contains init mechanisms such as upstart which do not support the systemd unit file format. The guidelines for SysV initscripts can be found here: Packaging:SysVInitScript

Naming

Unit files have a naming scheme of foobar.service. When considering what basename to use, keep the following advice in mind:

  • Unit files must be named after the software implementation that they support, as opposed to the generic type of software. So, a good name would be "apache-httpd.service", and a bad name would be "httpd.service", as there are multiple httpd implementations, but only one Apache httpd.
  • If the package includes a SysV initscript, it must have the same base name as the systemd unit file. For example, if the unit file is /lib/systemd/system/foobar.service, then the SysV initscript must be /etc/rc.d/init.d/foobar. If systemd cannot find a native unit file by a specific name it will attempt to fall back to the SysV file of the same service.

It is our intention to unify service names of well-known software across distributions, so that we can eventually ship the service files in the upstream packages. Hence it is a good idea to discuss service names with maintainers of the same packages in other distributions and agree on a common name.

Format

Every .service file must begin with a [Unit] section:

[Unit]
Description=A brief human readable string describing the service (not the service file!)
After=syslog.target

The Description= line must not exceed 80 characters, and must describe the service, and not the service file. For example, "Apache Web Server" is a good description, but "Starts and Stops the Apache Web Server" is a bad one.

The After= line is only necessary if the service can log to syslog (most can, so if in doubt, include it).

Next, the .service file must have a [Service] section:

[Service]
Type=...
ExecStart=...
ExecReload=...

The Type= setting is very important. For D-Bus services this should be "dbus", for traditional services "forking" is usually a good idea, for services not offering any interfaces to other services "simple" is best. For "one-short" scripts "oneshot" is ideal, often combined with RemainAfterExit=. See http://0pointer.de/public/systemd-man/systemd.service.html for further discussion on the topic. Since "simple" is the default type, .service files which would normally set Type=simple may simply omit the Type line altogether.

BusName= should be set for all services connecting to D-Bus. (i.e. it is a must for those where Type=dbus, but might make sense otherwise, too) Omit this option if your service does not take a name on the bus.

ExecStart= is necessary for all services. This line defines the string that you would run to start the service daemon, along with any necessary options.

ExecReload= should be specified for all services supporting reload. It is highly recommended to add code here that synchronously reloads the configuration file here (i.e. /bin/kill -HUP $MAINPID is usually a poor choice, due to its asynchronous nature). Omit this option if your service does not support reloading.

Finally, the .service file must have an [Install] section:

[Install]
WantedBy=...

The recommended parameters for WantedBy are either multi-user.target (for most system services) or graphical.target (for services related to the UI).

For more information regarding these options see http://0pointer.de/public/systemd-man/systemd.unit.html and http://0pointer.de/public/systemd-man/systemd.service.html

Strictly speaking ExecStart= (in the [Service] section) is the only option really necessary for a .service file. However, in Fedora you must add the other options mentioned here (as applicable).

Support for /etc/sysconfig files

If your service supports /etc/sysconfig files, then you must use EnvironmentFile=/etc/sysconfig/foobar in your .service file, in the [Service] section.

Example:

[Service]
Type=forking
EnvironmentFile=/etc/sysconfig/httpd
ExecStart=/usr/sbin/httpd ${OPTIONS}
ExecReload=/usr/sbin/httpd ${OPTIONS} -k restart

You may then refer to variables set in sysconfig files with ${FOOBAR} and $FOOBAR, in the ExecStart= lines (and related lines). (${FOOBAR} expands the variable into one word, $FOOBAR splits up the variable value at whitespace into multiple words)

Options to avoid

For most services, we do not want to use requirement dependencies such as Requires= or Wants=. Instead exclusively use ordering dependencies: Before= and After=. This is used to implement loose coupling: if two services are started at the same time their startup is properly ordered, but do not make it strictly necessary to run one if the other is started.

If you use a requirement dependency, use Wants= rather than Requires=, to make things a little bit more robust. If you use a requirement dependency in almost all cases you should also add an ordering dependency, as ordering and requirement dependencies are orthogonal in systemd.

Here's an example of this common case:

  1. A web application needs postgresql to store its data.
  2. It is set to start After postgresql. On startup, the web application does not start until postgresql does.
  3. Once running, the system administrator needs to restart postgresql due to a config tweak.
  4. Since only After was used, the web application may be temporarily unable to serve some requests but it does not need to restart in order to serve pages after the database comes back up.

Avoid referring to runlevelX.target units in all lines taking unit names (such as WantedBy), these are legacy names existing for compatibility with SysV only.

Avoid Names=. Usually it is a better idea to symlink an additional name in the file system. Note that a name listed in Names= is only useful when a service file is already loaded. However, systemd loads only the service files actually referred to in another loaded service, and uses the filenames during the search. Hence a name in Names= is not useful as a search key, but a symlink in the file system is. Also do not put a (redundant) Names=foobar.service line into a file called foobar.service. We want to keep our service files short.

Avoid using StandardOutput=kmsg. Use StandardOutput=syslog instead. (same for StandardError=).

Example Unit file

This is an example systemd unit .service file for ABRT:

[Unit]
Description=ABRT Automated Bug Reporting Tool
After=syslog.target

[Service]
Type=dbus
BusName=com.redhat.abrt
ExecStart=/usr/sbin/abrtd -d -s

[Install]
WantedBy=multi-user.target

Bus Activation

In order to allow parallel startup of a D-Bus service and its consumers it is essential that D-Bus services can be bus activated, and that the D-Bus activation is forwarded to systemd so that you end up with a single service instance only. That means all existing D-Bus services that have previously not been started via bus activation but have been started via SysV scripts should be updated to be capable of bus activation. This is easily implemented by dropping a D-Bus .service file in /usr/share/dbus/system-services/ which uses the SystemdService= directive to redirect activation to systemd. See the D-Bus documentation for more information. (Don't be confused by the fact that both systemd and D-Bus use the .service file suffix, they are different things, though the D-Bus .service often refers to the systemd .service file for the same program with the SystemdService= directive.)

Note that traditionally bus activated services could not be disabled. systemd does not change this, however in some cases where making it possible to disable a service is desirable (e.g. avahi, NetworkManager), you can easily implement that by directing the D-Bus service to a symlinked alias name of the real service file which is controlled via systemctl enable/disable and which then points to the real service. Example: set SystemdService=dbus-org.freedesktop.Avahi.service instead of SystemdService=avahi-daemon.service, and then make /etc/systemd/system/dbus-org.freedesktop.Avahi.service a symlink → /lib/systemd/system/avahi-daemon.service. A full example for the Avahi case:

Here is the D-Bus .service file for Avahi (/usr/share/dbus-1/system-services/org.freedesktop.Avahi.service):

[D-BUS Service]
Name=org.freedesktop.Avahi
SystemdService=dbus-org.freedesktop.Avahi.service

# This service should not be bus activated if systemd isn't running,
# so that activation won't conflict with the init script startup.
Exec=/bin/false

Here is the Avahi systemd unit .service file (/lib/systemd/system/avahi-daemon.service):

[Unit]
Description=Avahi mDNS/DNS-SD Stack
Requires=avahi-daemon.socket
After=syslog.target

[Service]
Type=dbus
BusName=org.freedesktop.Avahi
ExecStart=/usr/sbin/avahi-daemon -s
ExecReload=/usr/sbin/avahi-daemon -r
NotifyAccess=main

[Install]
WantedBy=multi-user.target
Also=avahi-daemon.socket
Alias=dbus-org.freedesktop.Avahi.service

The Alias= line ensures that the existance of the /etc/systemd/system/dbus-org.freedesktop.Avahi.service symlink can be controlled by "systemctl enable" and "systemctl disable".

In general, it is also recommended to supply native systemd units for all services that are already bus activatable, so that these services can be controlled and supervised centrally like any other service with tools such as systemctl. A similar logic like the one shown above should apply.

Packaging

Filesystem locations

Packages with systemd unit files must put them into %{_unitdir}. %{_unitdir} evaluates to /lib/systemd/system/ on all Fedora systems. Unit files are architecture independent (hence, not %{_lib}) and needed early in the boot process.

%files section

Systemd unit .service files must not be marked as %config files. Any configuration should be made available through /etc/sysconfig/<service> rather than in the init script itself. Init scripts must have 0755 permissions.

Unit files in spec file scriptlets

Most systemd services must be disabled by default, especially if they listen on the network. Also, a package must never turn on a service on upgrade if it was explicitly disabled.

Fedora provides a set of scriptlets to simplify handling the setup of systemd services at package install/upgrade/removal.

Requires(post): systemd-units
Requires(preun): systemd-units
Requires(postun): systemd-units

%post
if [ $1 -eq 1 ]; then
        # Package install, not upgrade
        /bin/systemctl daemon-reload >/dev/null 2>&1 || :
fi

%preun
if [ $1 -eq 0 ] ; then
        # Package removal, not upgrade
        /bin/systemctl disable httpd.service > /dev/null 2>&1 || :
        /bin/systemctl stop httpd.service > /dev/null 2>&1 || :
fi

%postun
/bin/systemctl daemon-reload >/dev/null 2>&1 || :
if [ $1 -ge 1 ] ; then
        # Package upgrade, not uninstall
        /bin/systemctl try-restart httpd.service >/dev/null 2>&1 || :
fi

Note that /bin/systemctl daemon-reload will automatically detect new systemd unit .service files placed into %{_unitdir}. There is no equivalent to 'chkconfig --add <service>', because it is unnecessary.

Why don't we....

  • Enable most services by default?

Some core services must be enabled by default for a functional system, but the default for most network-listening scripts is off. This is done for better security. We have multiple tools that can enable services, including GUIs.

  • Start the service after installation?

Installations can be in changeroots, in an installer context, or in other situations where you don't want the services autostarted.