Managing system and user services with perp - December 2, 2013

Background

Recently I've been looking into various init alternatives to systemd, and came across a couple of service supervisors (for example perp and s6) that mostly do the job but are missing various bits like a script to do early system initialization that make them difficult to use as a drop-in replacement.

So I created a collection of stuff to make this easier. I focused on perp because seemed nice to use it was already packaged in arbor (thanks alip!). However, most of this should apply to other service supervisors as well.

Replacing init

Since perp was not designed to run as init (just to supervise services), I created an extremely simple init that spawns /etc/rc, which is expected to exec into a service supervisor. It also kills all processes, syncs and then reboots on USR1 and powers off on USR2. Under s6, this should be unnecessary and you should be able to set init=/etc/rc.

Installation

Here are some instructions for trying this out on Exherbo:

  1. Install supervisor-extras[perp] (this should pull in perp)
cave resolve supervisor-extras

NOTE: If you enable udev for supervisor-extras, make sure that you have configured perp to start udevd, otherwise rc.local will wait for /run/udev/control indefinitely.

  1. Create /etc/rc.conf from sample and modify to your liking.
cp /usr/share/doc/supervisor-extras-scm/rc.conf.sample.perp /etc/rc.conf
vim /etc/rc.conf
  1. If you want to perform any one-time system initialization, create a script in /etc/rc.local.d/. Remember to make it executable!

  2. Set init provider to supervisor-extras (or, alternatively, add init=/sbin/supervisor-extras.init).

eclectic init set supervisor-extras
  1. Make sure your kernel has automount devtmpfs support (CONFIG_DEVTMPFS and CONFIG_DEVTMPFS_MOUNT).

  2. You probably also want to set up a udevd service, which is available in my repository of services described below.

  3. Reboot and hope things work. If things don't work and you changed your init with eclectic, you can set init=/sbin/systemd.init to boot up with systemd.

You can check the status of services with perpls(8) and stop/start them with perpctl(8).

System Services

Currently, the only service provided by supervisor-extras is getty on tty1. If you'd like to enable getty on other TTY's, you can run cp -r /etc/perp/getty@tty1 /etc/perp/getty@ttyX (a symlink won't work because perp uses the sticky bit on these directories to mark whether they are enabled; the actual rc.main is located in /etc/perp/.config). You also must set the sticky bit (chmod +t) on service directories for perp to start them by default. To learn more about perp service directories, see perpetrate(8).

I have a collection of scripts in my perp-services repository for other packages (dhcpcd, udevd, sshd, dbus, wpa_supplicant), and if there is enough interest, we could add perp options to these packages to install them. There is a generic rc.log located in /etc/perp/.default/rc.log, which you can create a symlink to from <my-service>/rc.log.

User Services

Without systemd and a typical desktop environment, it takes a bit of work to get user services set up appropriately, especially since user services (like dbus and gnome-keyring-daemon) tend to get started automagically when they are needed (using temporary socket paths that aren't propagated through your entire environment). Since perp does not do any system initialization, it is well-suited to manage your user services as well.

supervisor-extras includes some scripts for starting user-service supervisors as well. To enable user services for user steve,

cd /etc/perp
mkdir user-services@steve
ln -s ../.user-services/rc.{main,log} user-services@steve/

This system-service will exec into ~steve/.services/.start/run, connected to the logger in ~steve/.services/.start/log.

Setting up your service directory

A good starting point skeleton for your service directory can be found in the user directory of perp-services.

cp -r perp-services/user ~/.services

Make sure to look through the service directory and remove any that you don't want, and enable the ones you do want (with chmod +t).

NOTE: Both gnome-keyring-daemon and pulseaudio depend upon dbus, so if you enable either of those, make sure dbus is enabled as well.

Additionally, you probably want to set up some environment variables. I put these in ~/.env so that I can use them in zsh (by sourcing it from ~/.zshenv), as well as perp service scripts (.services/.start/run sources it before it execs perpd).

# ~/.env

export PERP_BASE=~/.services
export XDG_RUNTIME_DIR=/run/user/${UID}

# dbus
export DBUS_SESSION_BUS_ADDRESS="unix:path=${XDG_RUNTIME_DIR}/dbus/user_bus_socket"

# gnome-keyring-daemon
export GNOME_KEYRING_CONTROL="${XDG_RUNTIME_DIR}/keyring"
export SSH_AUTH_SOCK="${XDG_RUNTIME_DIR}/keyring/ssh"
export GPG_AGENT_INFO="${XDG_RUNTIME_DIR}/keyring/gpg:0:1"

As with the system services, there is a generic rc.log in .default/log. This log script starts ${LOG_CMD}, as set in /etc/rc.conf, using logging directories ~/.log/<service>. Create a symlink to it in your service directory to enable logging for that service.

Example Process Tree

Here is the process tree of my system after setting things up as described in this post:

init───perpboot─┬─perpd─┬─5*[agetty]
                │       ├─dbus-daemon
                │       ├─dhcpcd
                │       ├─login───zsh───swc-launch───velox─┬─X
                │       │                                  └─st-wl───zsh───pstree
                │       ├─perpd─┬─dbus-daemon
                │       │       ├─gnome-keyring-d───4*[{gnome-keyring-d}]
                │       │       ├─mpd───6*[{mpd}]
                │       │       ├─pulseaudio───2*[{pulseaudio}]
                │       │       └─2*[tinylog]
                │       ├─sshd
                │       ├─4*[tinylog]
                │       ├─udevd
                │       └─wpa_supplicant
                └─tinylog

Looks pretty neat and tidy to me!

Closing Thoughts

I hope this post was useful to you in some way. If you have any comments or questions, feel free to email me or comment below.

This is just one example of how to connect various bits into a robust and easy-to-use initialization and service management system. There are of course other ways that yield similar results, but this setup is working quite nicely for me :)


comments

Valid XHTML 1.0 StrictValid CSS!
Generated on Thu, 12 Dec 2013 20:28:11 UTC