Day 28 in the #vDM30in30

Image source: https://flic.kr/p/y1DUPj

So previously I blogged about about how to ensure a /var/run directory exists before a systemd service starts, using the ExecStartPre steps to ensure the directory exists.

ExecStartPre=-/usr/bin/mkdir /run/jmxtrans/
ExecStartPre=/usr/bin/chown -R jmxtrans:jmxtrans /run/jmxtrans/

I took the idea from a blog by Jari Turkia.

However, I made the rookie mistake of not checking the comments to see if things had changed and there was a better way, since the original post was written in 2013.

In March 2014, there was a new new RuntimeDirectory setting. It was made exactly for this use-case:

System daemons frequently require private runtime directories below /run to place communication sockets and similar in. For these, consider declaring them in their unit files using RuntimeDirectory= (see systemd.exec(5) for details), if this is feasible.

Source:https://freedesktop.org/software/systemd/man/tmpfiles.d.html#Description

This has been available since systemd 211.

So the systemd service file will actually be much easier:

[Unit]
Description=JMX Transformer - more than meets the eye
After=syslog.target network.target

[Service]
Type=forking
User=jmxtrans
Group=jmxtrans
RuntimeDirectory=jmxtrans
PIDFile=/var/run/jmxtrans/jmxtrans.pid
ExecStart=/usr/share/jmxtrans/bin/jmxtrans start

[Install]
WantedBy=multi-user.target

As we only have to specify the RuntimeDirectory setting.

Funnily enough this also happened in the Redis module I was working on.

I found that the Beaker tests would sometimes fail with Debian 8 (Jessie), which was using a redis package.

It was using the dotdeb-redis package which had a systemd file that looked like this:

[Unit]
Description=Advanced key-value store
After=network.target
Documentation=http://redis.io/documentation, man:redis-server(1)

[Service]
Type=forking
ExecStart=/usr/bin/redis-server /etc/redis/redis.conf
PIDFile=/var/run/redis/redis-server.pid
TimeoutStopSec=0
Restart=always
User=redis
Group=redis

ExecStartPre=-/bin/run-parts --verbose /etc/redis/redis-server.pre-up.d
ExecStartPost=-/bin/run-parts --verbose /etc/redis/redis-server.post-up.d
ExecStop=-/bin/run-parts --verbose /etc/redis/redis-server.pre-down.d
ExecStop=/bin/kill -s TERM $MAINPID
ExecStopPost=-/bin/run-parts --verbose /etc/redis/redis-server.post-down.d

PrivateTmp=yes
LimitNOFILE=65535
PrivateDevices=yes
ProtectHome=yes
ReadOnlyDirectories=/
ReadWriteDirectories=-/var/lib/redis
ReadWriteDirectories=-/var/log/redis
ReadWriteDirectories=-/var/run/redis
CapabilityBoundingSet=~CAP_SYS_PTRACE

# redis-server writes its own config file when in cluster mode so we allow
# writing there (NB. ProtectSystem=true over ProtectSystem=full)
ProtectSystem=true
ReadWriteDirectories=-/etc/redis

[Install]
WantedBy=multi-user.target
Alias=redis.service

So this service file would have the same issue: if the directory for the pid was missing, it would refuse to start:

root@debian-redis-test:~# systemctl stop redis-server

root@debian-redis-test:~# rm -rf /var/run/redis/

root@debian-redis-test:~# systemctl start redis-server
Job for redis-server.service failed. See 'systemctl status
redis-server.service' and 'journalctl -xn' for details.

root@debian-redis-test:~# journalctl -u redis-server --no-pager | grep pid
Nov 30 13:29:04 debian-redis-test systemd[1]: PID file
/var/run/redis/redis-server.pid not readable (yet?) after start-post.

I would assume this would affect the upstream debian package, but for some reason it’s not… but I thought it would be a good idea to add that field to the systemd unit file anyways. Plus it gives me an excuse to open my first Debian bug:

https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=846350