(critique of naming) |
(critique of other areas, results of testing) |
||
Line 1: | Line 1: | ||
= Fedora systemd Services = | = Fedora systemd Services = | ||
This document describes the guidelines for systemd services, for use and inclusion in Fedora packages. | This document describes the guidelines for systemd services, for use and inclusion in Fedora packages. | ||
= Unit Files = | = Unit Files = | ||
Line 6: | Line 6: | ||
{{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]]}} | {{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]]}} | ||
{{admon/question||Add that alternate initscripts go in a subpackage to not confuse sysadmins. --[[User:Toshio|abadger1999]] 15:49, 8 December 2010 (UTC)}} | |||
== Naming == | == Naming == | ||
Line 12: | Line 13: | ||
* 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 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 also 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 specified name it will attempt to fall back to the SysV file with the same specified name. | * If the package also 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 specified name it will attempt to fall back to the SysV file with the same specified 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. | 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. | ||
{{admon/question||Change bullet two -- in original draft, it meant "name the unit file the same as the sysv init script that was previously in the package". add note about compat symlink. --[[User:Toshio|abadger1999]] | {{admon/question||Change bullet two -- in original draft, it meant "name the unit file the same as the sysv init script that was previously in the package". add note about compat symlink. --[[User:Toshio|abadger1999]] 15:49, 8 December 2010 (UTC)}} | ||
== Format == | == Format == | ||
{{admon/question|Organization|Make a section Unit files. s/Format/Basic Format/, also include sysconfig files, s/Options to avoid/Other fields/, Example unit file --[[User:Toshio|abadger1999]] 15:49, 8 December 2010 (UTC)}} | |||
{{admon/question||Are these case-sensitive? --[[User:Toshio|abadger1999]] 15:49, 8 December 2010 (UTC)}} | |||
Every .service file must begin with a [Unit] section: | Every .service file must begin with a [Unit] section: | ||
Line 27: | Line 30: | ||
</pre> | </pre> | ||
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 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 | {{admon/question||Better <code>After</code> line: "<code>After</code> specifies that this service may only start after the listed services have started. In this example, the service starts after syslog since syslog can be used for logging. (Most daemon programs can use syslog for logging so when in doubt, it's good to include this.)" --[[User:Toshio|abadger1999]] 15:49, 8 December 2010 (UTC)}} | ||
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: | Next, the .service file must have a [Service] section: | ||
Line 73: | Line 77: | ||
</pre> | </pre> | ||
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) | 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 == | == Options to avoid == | ||
{{admon/question||What sections do each of these tags go in? --[[User:Toshio|abadger1999]] 15:49, 8 December 2010 (UTC)}} | |||
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. | 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. | ||
{{admon/question||"if someone asks two services to start at the same time systemd will properly order their startup but not make it strictly necessary to run one if the other is started." --[[User:Toshio|abadger1999]] 15:49, 8 December 2010 (UTC)}} | |||
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. | 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. | ||
Line 91: | Line 98: | ||
Avoid using StandardOutput=kmsg. Use StandardOutput=syslog instead. (same for StandardError=). | Avoid using StandardOutput=kmsg. Use StandardOutput=syslog instead. (same for StandardError=). | ||
{{admon/question||Little more about what StandardOutput/StandardError is for and why syslog is a a good target. --[[User:Toshio|abadger1999]] 15:49, 8 December 2010 (UTC)}} | |||
== Example Unit file == | == Example Unit file == | ||
Line 110: | Line 119: | ||
== Bus Activation == | == Bus Activation == | ||
{{admon/question|Clarify language|Split some sentences to make the information clearer. --[[User:Toshio|abadger1999]] 15:49, 8 December 2010 (UTC)}} | |||
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.) | 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: | 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: | ||
{{admon/question||Also show what the dbus service file looks like if we make it so that it is not disablable (so we have an idea of before and after)) --[[User:Toshio|abadger1999]] 15:49, 8 December 2010 (UTC)}} | |||
Here is the D-Bus .service file for Avahi (/usr/share/dbus-1/system-services/org.freedesktop.Avahi.service): | Here is the D-Bus .service file for Avahi (/usr/share/dbus-1/system-services/org.freedesktop.Avahi.service): | ||
Line 156: | Line 168: | ||
== %files section == | == %files section == | ||
{{admon/question||s/initscript/unit file/ --[[User:Toshio|abadger1999]] 15:49, 8 December 2010 (UTC)}} | |||
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. | 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. | ||
== Unit files in spec file scriptlets == | == Unit files in spec file scriptlets == | ||
{{admon/question||Add to scriptletsnippets instead and leave a link here. --[[User:Toshio|abadger1999]] 15:49, 8 December 2010 (UTC)}} | |||
{{admon/question||s/Also, a package must never turn on a service on upgrade if it was explicitly disabled./On upgrade, a package may only restart a service if it is running; it may not start it if it is off. Also, the service may not enable itself if it is currently disabled. --[[User:Toshio|abadger1999]] 15:49, 8 December 2010 (UTC)}} | |||
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. | |||
{{admon/question||These are the recommended scriptlets to conform to these requirements: --[[User:Toshio|abadger1999]] 15:49, 8 December 2010 (UTC)}} | |||
Fedora provides a set of scriptlets to simplify handling the setup of systemd services at package install/upgrade/removal. | Fedora provides a set of scriptlets to simplify handling the setup of systemd services at package install/upgrade/removal. | ||
Line 190: | Line 206: | ||
</pre> | </pre> | ||
{{admon/question||When upgrading from sysvinit package to a unit file package, we need to run daemon-reload (otherwise, systemd will think we're still using the init script, not the unit file). That means we should run it unconditionally in %post. That also means for many packages we'll be running daemon-reload twice. --[[User:Toshio|abadger1999]] 15:49, 8 December 2010 (UTC)}} | |||
{{admon/question||daemon-reload isn't being run properly. For instance, go from a unit file package to a non-unitfile package and systemd won't be able to start the sysv script until systemctl daemon-reload is run --[[User:Toshio|abadger1999]] 15:49, 8 December 2010 (UTC)}} | |||
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. | 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.... == | == Why don't we.... == |
Revision as of 15:49, 8 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.
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 also 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 specified name it will attempt to fall back to the SysV file with the same specified 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
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:
- A web application needs postgresql to store its data.
- It is set to start
After
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
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.
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.