nut: Apply udev rules on the host

NUT needs some udev rules in order to set the proper permissions on USB
etc. devices so it can run as an otherwise unprivileged user.  Since
udev rules can only be processed on the host, these rules need to be
copied out of the container and evaluated before the NUT server starts.
To enable this, the *nut-server* container image copies the rules it
contains to `/etc/udev/rules.d` if that directory is a mount point.  By
bind mounting a directory on the host at that path, we can get a copy of
the rules files outside the container.  Then, using a systemd path unit,
we can tell the udev daemon to reload and reevaluate its rules.

SELinux prevents processes in containers from writing to
`/etc/udev/rules.d` directly, so we have to use an intermediate location
and then copy the rules files to their final destination.
master
Dustin 2024-01-14 19:12:53 -06:00
parent 0e046d062e
commit 74508faf27
6 changed files with 38 additions and 2 deletions

View File

@ -1,4 +1,5 @@
import pkg import pkg
import pkg.nut import pkg.nut
import pkg.common
render: [pkg.RenderInstruction] = nut.templates render: [pkg.RenderInstruction] = common.templates + nut.templates

21
pkg/common/templates.k Normal file
View File

@ -0,0 +1,21 @@
templates = [
{
template = "common/reload-udev-rules.path"
dest = "/etc/systemd/system/reload-udev-rules.path"
hooks = {
changed = [
{run = "systemctl daemon-reload"}
{run = "systemctl try-restart reload-udev-rules.path"}
]
}
}
{
template = "common/reload-udev-rules.service"
dest = "/etc/systemd/system/reload-udev-rules.service"
hooks = {
changed = [
{run = "systemctl daemon-reload"}
]
}
}
]

View File

@ -41,7 +41,7 @@ templates = [
dest = "/etc/containers/systemd/nut-server.container" dest = "/etc/containers/systemd/nut-server.container"
hooks = { hooks = {
changed = [ changed = [
{run = "systemctl daemon-reload", immediate = True} {run = "systemctl daemon-reload"}
{run = "systemctl restart nut-server"} {run = "systemctl restart nut-server"}
] ]
} }

View File

@ -0,0 +1,3 @@
[Path]
PathChanged=/run/containers/udev-rules
MakeDirectory=yes

View File

@ -0,0 +1,8 @@
[Unit]
ConditionDirectoryNotEmpty=/run/containers/udev-rules
[Service]
Type=oneshot
ExecStart=/bin/sh -c 'cp /run/containers/udev-rules/*.rules /run/udev/rules.d/'
ExecStart=/usr/bin/udevadm control --reload
ExecStart=/usr/bin/udevadm trigger

View File

@ -4,11 +4,14 @@ Description=Network UPS Tools - power devices information server
Wants=network-online.target Wants=network-online.target
After=network-online.target After=network-online.target
Before=nut-monitor.service Before=nut-monitor.service
Wants=reload-udev-rules.path
After=reload-udev-rules.path
[Container] [Container]
Image=git.pyrocufflink.net/containerimages/nut:latest Image=git.pyrocufflink.net/containerimages/nut:latest
Pull=newer Pull=newer
RunInit=true RunInit=true
Volume=%t/containers/udev-rules:/etc/udev/rules.d:rw,z
Volume=/etc/ups:/etc/ups:ro Volume=/etc/ups:/etc/ups:ro
Volume=/dev:/dev:rw Volume=/dev:/dev:rw
ReadOnly=true ReadOnly=true