sections in this module City College of San Francisco - CS260A
Linux System Administration

Module: StartupShutdown III
module list

systemd unit files

[ Note: the man pages for systemd are very good. You may want to look there for a companion to (or substitute for) this reading. See the man pages on systemd.unit, systemd.service and systemd.target for a start. They are only on RH7, of course. ]

Unit files

Now that we've seen the systemd is not so difficult, let's look at a unit file for the sshd service (a .service file) and see if we can make sense of it.

System Unit files can be located in three places:

Since sshd is an installed service, its unit file should be in /usr/lib/systemd/system

[root@localhost ~]# cd /usr/lib/systemd/system
[root@localhost system]# cat sshd.service
[Unit]
Description=OpenSSH server daemon
After=syslog.target network.target auditd.service

[Service]
EnvironmentFile=/etc/sysconfig/sshd
ExecStartPre=/usr/sbin/sshd-keygen
ExecStart=/usr/sbin/sshd -D $OPTIONS
ExecReload=/bin/kill -HUP $MAINPID
KillMode=process
Restart=on-failure
RestartSec=42s

[Install]
WantedBy=multi-user.target
[root@localhost system]#

If you took the time to examine an upstart script on 6.5, this format is familiar. The file contains three sections: a Unit section and Install section, which are common to all unit files, and a Service section, which is particular to service unit files. (The format is a takeoff of [yes] Microsoft Windows .ini files.)

There are many other types of unit files besides service units. One we will encounter shortly is a target. Target units simply control other units, activating and deactivating them as a group. Unlike service units, which actually start a process, target units simply cause transitions or add dependencies.

Note: you can see from the example above the simple format of unit files. Blank lines and lines that start with either a semi-colon (;) or a hash mark (#) are ignored.

The Unit section

The Unit section describes the unit and its dependencies. There are a lot of options in this section. Let's go over the most important ones:

Option
Meaning
Description
Free-form description string
Documentation
Where to go for documentation. In the example above, you're on your own
Requires
units that must be activated if this one is. If a required unit fails or is deactivated, this unit will be as well. Thus if unit y has Requires=x, unit y requires unit x.
Additional requires dependencies may be encoded using symlinks in a directory named the same as the unit file with the extension .requires  Thus for unit file x.service, the requires consist of its Requires= list plus those unit files that have symlinks in the directory x.service.requires (Note that there may be X.service.requires directories in all three locations for unit files.)
Wants
units that should be activated if this one is. However, if they cant be activated, go ahead and activate this unit anyway. Additional wants dependencies may be encoded using symlinks in a .wants directory similar to Requires (above)
Conflicts
units that cannot be active at the same time as this unit. If the conflicting unit is active when this one is started, the conflicting unit is stopped. If the conflicting unit is started while this one is active, this unit will be stopped.
After
Before and After are very confusing (at least to me). To get them straight, prefix the word with Start me and delete the = sign. Thus After=xxx.service means Start me after xxx.service.
Note that this does not mean that xxx.service will be started, but if it is started, this unit will not be started until after it is running.
Before
The current unit must be running before these can be started, if they are to be part of the running system.
AllowIsolate
If set to yes (the default is no), this unit may be used with the systemctl isolate command. (Note, the documentation says the values for this option are true and false, but the installed unit files have yes or no.)

The wants and requires of unit X form a group of units that are activated when unit X is. The requires elements are required - the failure of a requires unit will cause the shutdown of unit X. The wants elements are not required, but at attempt should be made to activate them with unit X.

Before we go on, let's look again at the Unit section of our sample sshd.service:

[Unit]
Description=OpenSSH server daemon
After=syslog.target network.target auditd.service

This indicates that sshd should be started after syslog.target, network.target and auditd.service, if those units are to be part of the running system.

The Install section

The Install section specifies how to install the unit. It is only used during the install process, but it can specify additional dependencies using two options Wantedby= and Requiredby=. If x.service has a Wantedby=foo.service directive in its Install section, then a symlink to x.service is created in a directory foo.service.wants, creating a dependency identical to the appearance of a Wants=x.service in the foo.service unit file.

That last paragraph was unclear, I'm sure. Suffice it to say that dependencies are complex because they can form a chain that is not obvious until systemd analyzes it. When a change in state is imminent, the dependencies must be satisfied correctly. To speed this up at runtime, as many of the dependencies as possible are stored in filesystem objects when the units are installed. Suppose unit Y is installed. In its unit file it encodes the units that it wants and knows must exist. There very well may be other units that are optional on the system that it would want if they exist but they are not encoded in the unit file since they are optional. Suppose unit X is such a unit - it would be wanted by unit Y if it existed. This want is added to unit Y by a WantedBy option in unit X. (sorry, you may have to read this paragraph a couple of times.)

The most common examples of this are the big system state targets: basic, multi-user and graphical. Let's take the example of multi-user.target. As you might expect, it wants a lot of stuff - everything that should be up at multi-user mode should be wanted by multi-user.target. But at installation, the file created for multi-user.target does not know what is installed - other than those units that are required for basic system functionality. Thus, its Wants (and Requires) are limited:

# grep -e Wants -e Requires multi-user.target
Requires=basic.target

Then, everything that should be started in multi-user mode should have a unit file that indicates it is WantedBy multi-user.target

# grep 'WantedBy=multi-user.target' *.{target,service} | wc -l
74

A couple of the ones that are in this list that we will recognize are rsyslog.service, NetworkManager.service, and sshd.service. To add a Want of their unit by multi-user.target a symlink is created in multi-user.target.wants that points to their service. (This symlink could be in a multi-user.target.wants directory in either /usr/lib/systemd/systemd or in /etc/systemd/system.) In fact, we find the symlinks in the latter location:

# cd /etc/systemd/system
# ls -l multi-user.target.wants/{NetworkManager.service,sshd.service,rsyslog.service}
lrwxrwxrwx. 1 root root 46 Jul  3 10:53 multi-user.target.wants/NetworkManager.service -> /usr/lib/systemd/system/NetworkManager.service
lrwxrwxrwx. 1 root root 39 Jul  3 10:52 multi-user.target.wants/rsyslog.service -> /usr/lib/systemd/system/rsyslog.service
lrwxrwxrwx. 1 root root 36 Jul  3 11:06 multi-user.target.wants/sshd.service -> /usr/lib/systemd/system/sshd.service

Now, you might think that there would be 74 symlinks since we found 74 instances of WantedBy=multi-user.target, but, due to interdependencies between them, the actual number is less. Again, they can be distributed between two locations:

# ls /etc/systemd/system/multi-user.target.wants | wc -l
35

# ls /usr/lib/systemd/system/multi-user.target.wants | wc -l
8

OK, believe it or not, that was a simple example - at least the simplest I could find. Suffice it to say that the dependency resolution is difficult. You cannot understand all the dependencies of a unit by simply looking at the unit file, even if you remember to look in the wants directories. Instead, use systemctl show

# systemctl show multi-user.target
Id=multi-user.target
Names=multi-user.target runlevel2.target runlevel4.target runlevel3.target
Requires=basic.target
Wants=remote-fs.target crond.service rpcbind.service mdmonitor.service sysstat.service avahi-daemon.service nfs.target libstoragemgmt.service libvirtd.service auditd.service vmtoolsd.service hypervkvpd.service hypervvssd.service chronyd.service rsyslog.service ksm.service ksmtuned.service rhsmcertd.service abrtd.service abrt-oops.service abrt-vmc ore.service abrt-ccpp.service abrt-xorg.service NetworkManager.service cups.path ModemManager.service postfix.service irqbalance.service smartd.service tuned.service sshd.service atd.service rngd.servic ntpdate.service trackusers.service getty.target systemd-ask-password-wall.path systemd-logind.service  systemd-user-sessions.service dbus.service brandbot.path plymouth-quit-wait.service plymouth-quit.service systemd-update-utmp-runlevel.service network.service rhnsd.service iprupdate.service iprdump.service iprinit.service
RequiredBy=graphical.target
...

The Service section

Many of the specialized unit types have a section that is specific for their specialization. Thus, service units have a Service section that encodes how the service is to be started and managed. Before we cover the options in the Service section in general, let's return to our simple service, sshd, and look at its Service section:

[Service]
EnvironmentFile=/etc/sysconfig/sshd
ExecStartPre=/usr/sbin/sshd-keygen
ExecStart=/usr/sbin/sshd -D $OPTIONS
ExecReload=/bin/kill -HUP $MAINPID
KillMode=process
Restart=on-failure
RestartSec=42s

There are a lot of options in the Service section. We will only cover the most basic ones:

Variable
Meaning
Type
How to manage the service. There are several alternatives - we will cover simple, forking and oneshot. simple is the default.
  • simple - the ExecStart process is the main process. systemd will continue after starting the main process, so whatever this main process needs should be set up. In the case of sshd, a socket needs to be created. This is configured by creating sshd.socket - systemd creates the socket before starting the service. (If a file with the extension .socket and the same base name as the service exists that socket is created before the service is started. In fact, there is an sshd.socket file in the system directory)
  • oneshot - similar to simple, but the process performs some initialization that must complete before systemd starts 'follow-up' units (all the documentation refers to 'follow-up' units, but noone explains it. I assume this means the other services in the current transaction.)
  • forking - here the ExecStart process is expected to fork, and the child will be the main process. In this case the process is expected to create a pid file for systemd to be able to track it reliably. The absolute path to the pid file should be specified in the PIDFile= option in the Service section.
ExecStart
The command to run to start the service. In the example above, $OPTIONS come from the EnvironmentFile, that systemd reads to set internal variables for substitution or from variables set in the Environment= directive. Note: this is not a shell command! Specifically, redirection operators are not allowed. If you want a shell command you must use a shell to interpret the command.
An absolute path to the executable must be used.
ExecStartPre
ExecStartPost
Commands to be run before and after ExecStart
ExecReload
ExecStop
Commands to execute to reload the configuration of the service and to stop the service.
Restart
Whether to restart the process if it exits. Some of the choices are no (the default), on-failure, on-success, and always. This goes with the option RestartSec=
RestartSec
How long to wait after the unit exits until it is restarted, assuming Restart= is not set to no. The unit value is secs, unless a suffix (min,msec,sec) is added.
KillMode
How to kill the unit. Choices are none (just execute the ExecStop), process (kill the main process only), control-group (kill all processes in the control group, the default)

Scope units

scope units are similar to service units except they manage a set of processes that were started external to systemd - i.e., systemd does not start anything. An example is the desktop processes that are created for you at login to the GUI by gdm. These are placed in a separate automatically-created scope. Interested readers are referred to systemd.scope

Slice units

A slice is a new level of heirarchy inserted into the tree of control groups as defined by a slice unit. They are used for controlling huge groupings of systemd processes and provide the ability to limit their resources as a group. You probably wont need to muck with slices - there are four default ones created for you: the parent slice, named - (yes, dash), the system slice, which contains all the system cgroups, the user slice, which contains all user cgroups (such as the processes created in a login session) and the machine slice, which contains all virtual machines.

Other unit types

Other unit types are specialized and are usually resources used by services. These are:

mount, automount, swap
filesystem control. mount units control mount points; automount units control automount points, and swap units control activation of swap devices
timer, device, path
these control activation of a unit due to a timer event, a device access, or a path access. (Units can be configured to be activated by touching these objects)
socket
also used for activation of a unit, socket units also force the creation of sockets when a service unit is started. If x.service is started and x.socket exists, the socket described in x.socket is created and given to x.service when it is started.

for more information see the man page on systemd.x where x is the unit type.

Prev This page was made entirely with free software on linux:  
Kompozer, the Mozilla Project
and Openoffice.org      
Next

Copyright 2015 Greg Boyd - All Rights Reserved.