Tags:
create new tag
view all tags

LCFG Systemd cookbook

Adding an LCFG component to systemd

The following macro call declares that the lcfg-updaterpms component should start after the lcfg-auth, lcfg-client and lcfg-file components have been started. The value of 'lcfgmultiuser' for the last parameter tells systemd is required as part of the process of producing a stable system (ie one where no further boot-time reboots will occur).

REGISTER_COMPONENT_WITH_SYSTEMD(updaterpms,,lcfg-auth.service lcfg-client.service lcfg-file.service,lcfgmultiuser)

Start service after all reboots have completed

When a system boots, various LCFG components (e.g. updaterpms, kernel, hardware, network) may flag that a reboot is required to apply important changes. It is recommended that any services which are not required in the early part of the boot process (e.g. apache) be configured to start after the lcfg-multi-user-stable.target target has been reached. Once that target has been reached in the boot sequence LCFG will not enforce any further reboot requests.

For example, an LCFG component could be configured like this:

REGISTER_COMPONENT_WITH_SYSTEMD(yum,,lcfg-multi-user-stable.target,multiusertarget)

Other services can be configured like this:

LCFG_SYSTEMD_UNIT_WANTEDBY(lldpd,lldpd.service,multiusertarget)
LCFG_SYSTEMD_WAIT(lldpd,lldpd.service,lcfg-multi-user-stable.target)

Enabling a standalone service

To enable a simple standalone service (e.g. ypbind)

LCFG_SYSTEMD_UNIT_WANTEDBY(ypbind,ypbind.service,multiusertarget)

The macro takes LCFG tag name, service unit and target.

To find out the correct target name (multiusertarget in this case) you can look at the [Install] section of the unit file (which has WantedBy=multi-user.target)

In the filesystem this effectively does:

ln -s '/usr/lib/systemd/system/ypbind.service' '/etc/systemd/system/multi-user.target.wants/ypbind.service'

Enabling systemd debugging output

You can enable systemd debugging output (to the console) by setting the following resource :-

!systemd.loglevel   mSET(debug)

This produces very verbose output, so it's best to debug systemd issues on a machine whose console output is stored to file (eg a KVM guest).

You can redirect the output of systemd messages to other locations (eg 'journal' or 'syslog'), using the systemd.logtarget resource, but it seems that this deadlocks the system if systemd.loglevel is set to 'debug'.

Capturing console input from a systemd unit

If you wish to capture console input from a systemd unit, you need to set StandardInput for your unit to tty-force. The following resources configure the lcfg-updaterpms component so that it can read from the console.

!systemd.specopts_lcfgupdaterpms        mADD(stdin)
systemd.specopt_lcfgupdaterpms_stdin    StandardInput=tty-force

Delaying the start of pre-defined units

To delay the start of a pre-defined unit (ie one defined solely in /usr) you can use the LCFG_SYSTEMD_WAIT(tag,delayed-unit,dependency-unit) macro.

For example, the following delays the start of the display-manager service until after the lcfg-multi-user-stable target has been reached.

LCFG_SYSTEMD_WAIT(dm,display-manager.service, lcfg-multi-user-stable.target)

Detecting which init is used on a system

The init used on a system (e.g. SysVinit, upstart, systemd, launchd) is recorded in the sysinfo.init resource. The ControllingDaemons page has information on how to write init-independent components which manage daemons.

Delaying the start of a unit to after a fully routed network is available

Some units, eg lcfg-updaterpms, need a fully routed network connection to start correctly. The target internet-online.target is reached once such a connection is available and such units should wait on this target.

For LCFG components, add internet-online.target to the 'after' parameter to REGISTER_COMPONENT_WITH_SYSTEMD. Eg. :-

REGISTER_COMPONENT_WITH_SYSTEMD(updaterpms,,lcfg-auth.service lcfg-client.service lcfg-file.service internet-online.target,lcfgmultiuser)

For pre-defined units, use LCFG_SYSTEMD_WAIT. Eg. :-

LCFG_SYSTEMD_WAIT(afs,openafs-client.service, internet-online.target)

Delaying the start of a component until after its associated service unit has started

When using an LCFG component merely to (re)configure a daemon managed by an pre-defined (ie stock RHEL) service unit, it is often necessary to start the component after the service unit has finished starting up.

This can be achieved by adding the name of the service unit in the 3rd parameter of REGISTER_COMPONENT_WITH_SYSTEMD. Eg in the following, the lcfg-openssh component won't be started until after the sshd.service unit has finished starting up.

REGISTER_COMPONENT_WITH_SYSTEMD(openssh,,sshd.service,multiusertarget)

If you don't want to modify the REGISTER_COMPONENT_WITH_SYSTEMD call for some reason, for example you wish to delay just on one machine, the following will achieve the same result as the above :-

systemd.after_lcfgopenssh mADD(sshd.service)

Note that the unit tag created by REGISTER_COMPONENT_WITH_SYSTEMD for an lcfg component is the name of the component prefixed by 'lcfg'. There is no '-', for obvious reasons.

Running a command before a service starts

It is possible to run commands before any service is started by using ExecStartPre. Here is an example of running a command prior to the autofs service being started:

!systemd.extraconfigs                   mADD(homelink)
!systemd.extraunit_homelink             mSET(autofs.service)
!systemd.extralines_homelink            mSET(1 2)
!systemd.extraline_homelink_1           mSET([Service])
!systemd.extraline_homelink_2           mSETQ("ExecStartPre=/usr/bin/bash -c 'test -L /home || ( rmdir /home && ln -s /autofs/nethome /home ) || logger \"Failed to fix /home link for autofs\"'")

It is worth noting that this is added to a Service section. Also note that the command must be an absolute path to an executable, if shell code is required the path to the shell should be specified.

Keep processes running after unit is stopped

By default when a unit/service is stopped all processes that were launched, even if backgrounded, will be killed. This behaviour can be modified by tweaking the KillMode option (see systemd.kill(5) manual page for full details). By default it is set to control-group which means that all processes in the same cgroup as the parent will be killed. To keep child processes running it's probably best to change it to process. In LCFG resources this can be done like this:

!systemd.extraconfigs                 mADD(sleepkill)
systemd.extraunit_sleepkill             systemd-suspend.service
systemd.extralines_sleepkill             head killmode
systemd.extraline_sleepkill_head       [Service]
systemd.extraline_sleepkill_killmode  KillMode=none

This is particularly an issue for the sleep.target as it also has the StopWhenUnneeded option ( see systemd.unit(5) manual page for details) set to yes which means it is stopped once a machine has woken.

How to change the default target

The default target will typically either be multi-user.target (usually servers) or graphical.target (usually desktops). To permanently change the default target for a machine use the systemd.link_defaulttarget resource:

!systemd.link_defaulttarget mSET(multi-user.target)

To temporarily change the default target you can override the setting by editting the linux kernel command line through grub to append something like systemd.unit=multi-user.target

-- Main.ascobie - 2014-10-09

Topic revision: r16 - 2017-09-27 - squinney
 
This site is powered by the TWiki collaboration platform Powered by PerlCopyright © 2008-2019 by the contributing authors. All material on this collaboration platform is the property of the contributing authors.
Ideas, requests, problems regarding TWiki? Send feedback