A real-world worked example of setting up and running a service with nosh

nosh pages:

This is a real-world worked example of setting up and running a service with the nosh package. The service is the ntpd daemon.


We start with some things that we pre-prepared, namely an unprivileged user for the ntpd logging service to run as, and a directory for the logs to go into. Logging services are first class services in their own right under nosh, and we will be setting up a logging service to take the standard output and standard error of ntpd and record it in a set of auto-rotated size-capped log files. Remember that you are not required, with nosh, to have a 1:1 relationship between logging daemons and the daemons whose output they are logging. However: First, this is the familiar modus operandi for those coming from other daemontools-family daemon supervision systems. Second, setting things up this way gives us the opportunity to demonstrate a couple more of the mechanisms and features of the nosh toolset.

root /var/sv #fgrep ntp /etc/passwd
ntpd-log:*:1005:1006:User &:/home/ntpd-log:/bin/false
root /var/sv #ls -dl /var/log/sv/ntpd
drwxrwxr-x  2 ntpd-log  log  512 Mar  3  2014 /var/log/sv/ntpd
root /var/sv #

As you can see, our service bundles are going to be made in the current directory, /var/sv/, and the log directory is /var/log/sv/. (If you want equivalent places for "local" services and log directories, the obvious ones are of course /var/local/sv/ and /var/log/local/sv.)

For this worked example we will be requiring the contents of the nosh-exec, nosh-service-management, nosh-systemd-shims, and nosh-bundles packages, as well as a couple of things from the nosh source archive. ntpd is in fact one of the pre-packaged service bundles in the nosh-bundles package. (The nosh-bundles package provides a whole load of pre-built service bundles, and it is of course the goal that the world make and publish more and more such service bundles. In such a scenario one would skip the creation of the service bundle and go straight to the enabling and starting section. But the purpose of this worked example is in part to show how one gets to a running service from a systemd unit file with nosh.) We've manually removed the pre-packaged bundle directories that we are hand-rebuilding here.

making the log service

One of the things in the nosh package's source archive that we're using is the cyclog@.service service template unit file, which we've copied into the current directory. This is a systemd service unit file — a templated one. It invokes the nosh package's cyclog command to do the logging. (Of course, you can use another logging program if you like.)

root /var/sv #cat cyclog@.service
## **************************************************************************
## For copyright and licensing terms, see the file named COPYING.
## **************************************************************************

Description=Standard format %P logging service for %I

ExecStart=%P %I/

root /var/sv #

Using the convert-systemd-units subcommand of the system-control command, we create a service bundle for the log service, using ntpd as the template parameter. (The nosh-systemd-shims package provides symbolic links that make the system-control command available as systemctl. We use system-control here to emphasize that convert-system-units is not a systemd subcommand. We'll be using some systemd subcommands, and the name systemctl, later on, though.)

root /var/sv #system-control convert-systemd-units ./cyclog@ntpd.service
root /var/sv #

This has generated an entire service bundle, in the current directory, named cyclog@ntpd. There's a full description of service bundles in the manual pages of the system-control and service-manager commands; so we won't go into that in depth here. Of particular note are the service/ subdirectory and the run program, which is a nosh script. As you can see, the convert-systemd-units subcommand has created a script that invokes several chain-loading commands to do the things that the service unit specified, including changing user and working directory. It has also created some other scripts, not shown here because they are fairly trivial in this case, in particular a restart program that always exits success, to enact the service unit's Restart=always setting.

root /var/sv #ls -l cyclog@ntpd/service/
total 32
-rwxr-xr-x  1 root  wheel   93 Sep 27 22:32 restart
-rwxr-xr-x  1 root  wheel  206 Sep 27 22:32 run
-rwxr-xr-x  1 root  wheel   62 Sep 27 22:32 start
-rwxr-xr-x  1 root  wheel   61 Sep 27 22:32 stop
root /var/sv #
root /var/sv #
root /var/sv #cat cyclog@ntpd/service/run
#Run file generated from ./cyclog@.service
#Standard format cyclog logging service for ntpd
chdir /var/log/sv/
setuidgid ntpd-log
setenv HOME /home/ntpd-log
setenv SHELL /bin/false
cyclog ntpd/
root /var/sv #

(The setenv commands are there because of an undocumented feature in systemd, an explanation of which can be found on the page about converting systemd units in the nosh Guide. The aren't necessary for, or even used by, cyclog. But convert-systemd-units doesn't know that it isn't dealing with a service that relies upon these undocumented features.)

making the main service

Now we come to making the main ntpd service. Again, we're going to use a systemd service unit file taken from the nosh package source archive — ntpd.service this time.

root /var/sv #cat ntpd.service
## **************************************************************************
## For copyright and licensing terms, see the file named COPYING.
## **************************************************************************

Description=BSD NTP daemon

ExecStart=ntpd -n -g -f /var/db/ntpd.drift

root /var/sv #

And again we convert it to a service bundle using the convert-systemd-units subcommand. (As an aside: Note that it is -units plural because one of the things that it can convert is a linked pair of a socket unit file and a service unit file. It works out what you are converting from the suffix of the filename. See the system-control manual page for the details.)

root /var/sv #system-control convert-systemd-units ./ntpd.service
root /var/sv #

And again this makes, amongst other things in the service bundle, a service/ directory and a run program.

root /var/sv #ls -l ntpd/service/
total 32
-rwxr-xr-x  1 root  wheel   90 Sep 27 22:34 restart
-rwxr-xr-x  1 root  wheel  129 Sep 27 22:34 run
-rwxr-xr-x  1 root  wheel   59 Sep 27 22:34 start
-rwxr-xr-x  1 root  wheel   58 Sep 27 22:34 stop
root /var/sv #
root /var/sv #
root /var/sv #cat ntpd/service/run
#Run file generated from ./ntpd.service
#BSD NTP daemon
fdmove -c 2 1
ntpd -n -g -f /var/db/ntpd.drift
root /var/sv #

You may have noticed the presence of the systemdWorkingDirectory=false setting in the service unit, and the absence of a chdir command in the run script. There is another undocumented systemd feature with respect to working directories. But since it's a marked difference from the daemontools world, there's an explicit setting, an extension to the systemd service unit specification, for turning it off for services that don't really need it and are quite happy running with the daemontools conventions for working directories, which is in fact most services. (The number of services currently known to rely upon the undocumented systemd behaviour stands at just one.) Again, for more details see the aforementioned nosh Guide page.

A simple symbolic link serves to tell the system-control command, when it comes to tell the service manager to plumb the services together, where the log service is.

root /var/sv #ln -s ../cyclog@ntpd ntpd/log
root /var/sv #

enabling and starting the services

The nosh package supports running things the daemontools way, with the service manager started by some external system initialization system and services managed through symbolic links in a /service/ (or /etc/service/, or /var/service/ …) directory. However, for this worked example we are using a system that has the nosh system manager running as process #1, and that has the "standard targets" installed from the nosh-bundles package.

We want to make sure that the services are "enabled", i.e. that they will be automatically brought up when the system is bootstrapped. The command to do this is very familiar to those who have used systemd. (With the systemv shims package installed, one can even use chkconfig on if one is so minded.)

root /var/sv #systemctl enable ntpd.service cyclog@ntpd.service
root /var/sv #

Log services and main services are first-class citizens in nosh, remember. They are both, to the service manager, just plain old services, that just happen to be plumbed together through a pipe in a particular way. So one has to enable both of them.

The fileystem is the database in nosh. So what enabling does is record in the "wants" list of the workstation service bundle (which is a standard target) pointers to the service bundles of the log and main services. For details of the workstation target, and how it is started through the normal target at (normal mode) system bootstrap, see the nosh Guide and the system-control manual page.

root /var/sv #ls -l /etc/service-bundles/targets/workstation/wants/*ntpd
lrwxr-xr-x  1 root  JdeBP  19 Sep 27 22:37 /etc/service-bundles/targets/workstation/wants/cyclog@ntpd -> /var/sv/cyclog@ntpd
lrwxr-xr-x  1 root  JdeBP  12 Sep 27 22:37 /etc/service-bundles/targets/workstation/wants/ntpd -> /var/sv/ntpd
root /var/sv #

We also want to bring up the services right now, i.e. to "start" them. Again, this is a familiar command for those from the systemd world. (And again, if one were so minded one could use service … start from the systemv shims package instead.)

root /var/sv #systemctl start ntpd cyclog@ntpd
root /var/sv #

The svstat command, familiar in turn to those who have used daemontools, shows that the services are now up. (A similar svshow command is provided for generating output that is intended to be machine-readable, rather than human-readable as here. And yes, systemctl show and systemctl status are also there if you have the systemd shim package installed.)

root /var/sv #svstat ntpd cyclog@ntpd
ntpd: running (pid 73912) 41s ago
cyclog@ntpd: running (pid 73910) 42s ago
root /var/sv #

Because this machine is running the nosh system manager, there's a log of the service manager's output (amongst other things) in /run/system-manager/log/ which shows what the service manager was told to do by systemctl.

root /var/sv #fgrep ntpd /run/system-manager/log/current|tai64nlocal
2014-09-27 22:40:22.725985314 service-manager: DEBUG: load cyclog@ntpd
2014-09-27 22:40:22.726334939 service-manager: DEBUG: load ntpd
2014-09-27 22:40:22.727323468 service-manager: DEBUG: plumb ntpd to cyclog@ntpd
2014-09-27 22:40:22.727858659 service-manager: INFO: cyclog@ntpd/start: pid 73909
2014-09-27 22:40:22.731414544 service-manager: INFO: cyclog@ntpd/run: pid 73910
2014-09-27 22:40:23.744722046 service-manager: INFO: ntpd/start: pid 73911
2014-09-27 22:40:23.748205505 service-manager: INFO: ntpd/run: pid 73912
root /var/sv #

As you can see, it loaded up both service bundles, plumbed them together with a pipe (because of the symbolic link made earlier), ran their respective start commands, and then ran their respective run commands.


And for those who haven't already figured it out from some offhand tidbits in the aforegiven, here is a surprise. This isn't a Linux system running this worked example, going from systemd unit files to running services, at all.

root /var/sv #uname -sr
FreeBSD 10.0-RELEASE-p1
root /var/sv #

© Copyright 2014 Jonathan de Boyne Pollard. "Moral" rights asserted.
Permission is hereby granted to copy and to distribute this WWW page in its original, unmodified form as long as its last modification datestamp information is preserved.