feat: add nut-client

Add Network UPS Tools client extension.

Co-authored-by: Noel Georgi <git@frezbo.dev>
Signed-off-by: Noel Georgi <git@frezbo.dev>
This commit is contained in:
Daniel Quinlan 2022-08-20 11:33:54 -07:00 committed by Noel Georgi
parent e5a68ddac7
commit 47bd65c61b
No known key found for this signature in database
GPG Key ID: B1F736354201D483
12 changed files with 281 additions and 6 deletions

View File

@ -35,7 +35,7 @@ COMMON_ARGS += --build-arg=TAG=$(TAG)
empty :=
space = $(empty) $(empty)
TARGETS = amd-ucode bnx2-bnx2x gvisor hello-world-service intel-ucode iscsi-tools nvidia-container-toolkit nvidia-fabricmanager nvidia-open-gpu-kernel-modules
TARGETS = amd-ucode bnx2-bnx2x gvisor hello-world-service intel-ucode iscsi-tools nut-client nvidia-container-toolkit nvidia-fabricmanager nvidia-open-gpu-kernel-modules
NONFREE_TARGETS =
all: $(TARGETS) ## Builds all known pkgs.

View File

@ -34,6 +34,12 @@ All system extensions provided by Sidero Labs can be found in the [ghcr.io regis
| ----------------------------------- | ----------------------------------------------------------------------------------------------------- | ---------------- | -------------- |
| [iscsi-tools](storage/iscsi-tools/) | [ghcr.io/siderolabs/iscsi-tools](https://github.com/siderolabs/extensions/pkgs/container/iscsi-tools) | Open iSCSI tools | `v0.1.0` |
### Power
| Name | Image | Description | Version Format |
| ----------------------------------- | --------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------- | ---------------------------------- |
| [nut-client](power/nut-client/) | [ghcr.io/siderolabs/nut-client](https://github.com/siderolabs/talos-extensions/pkgs/container/nut-client) | [Network UPS Tools](https://networkupstools.org) upsmon client | `upstream version`-`talos version` |
### NVIDIA GPU
| Name | Description | Version Format |

View File

@ -6,9 +6,9 @@ github_repo = "siderolabs/extensions"
match_deps = "^github.com/((talos-systems|siderolabs)/[a-zA-Z0-9-]+)$"
# previous release
previous = "v1.2.0"
previous = "v1.2.1"
pre_release = false
pre_release = true
preface = """\
See [Talos Linux documentation](https://www.talos.dev/v1.2/talos-guides/configuration/system-extensions/) for information on using system extensions.
@ -16,10 +16,10 @@ See [Talos Linux documentation](https://www.talos.dev/v1.2/talos-guides/configur
[notes]
[notes.updates]
title = "Updates"
[notes.power]
title = "Power management"
description = """\
Update to support Talos v1.2.1
Support for Network UPS Tools client system extension to handle node graceful shutdown on power events from supported UPS's.
"""

View File

@ -0,0 +1,61 @@
# nut-client extension
## Usage
Enable the extension in the machine configuration before installing Talos:
```yaml
machine:
install:
extensions:
- image: ghcr.io/siderolabs/nut-client:<VERSION>
```
Configure the extension via .machine.files
You must replace upsmonHost and upsmonPasswd to match configuration on your nut server.
See [upsd.users](https://networkupstools.org/docs/man/upsd.users.html) man page for details.
On Talos SHUTDOWNCMD must be `/sbin/poweroff`
```yaml
machine:
files:
- path: /var/etc/nut/upsmon.conf
permissions: 0o600
op: create
content: |-
MONITOR ${upsmonHost} 1 remote ${upsmonPasswd} slave
SHUTDOWNCMD "/sbin/poweroff"
```
## Testing
Confirm extension service is running
```bash
$ talosctl service ext-nut-client
NODE 192.168.1.1
ID ext-nut-client
STATE Running
HEALTH ?
EVENTS [Running]: Started task ext-nut-client (PID 2263) for container ext-nut-client (59m59s ago)
[Preparing]: Creating service runner (59m59s ago)
[Preparing]: Running pre state (59m59s ago)
[Waiting]: Waiting for service "cri" to be "up" (59m59s ago)
[Waiting]: Waiting for service "cri" to be "up", network (1h0m0s ago)
[Waiting]: Waiting for service "cri" to be registered, network (1h0m1s ago)
[Waiting]: Waiting for service "containerd" to be "up", service "cri" to be registered, network (1h0m2s ago)
[Waiting]: Waiting for service "containerd" to be "up", service "cri" to be "up", network (1h0m3s ago)
```
**CAUTION** this will power off all connected systems.
Trigger a 'Full System Shutdown' on the nut-server
```bash
# upsmon -c fsd
```
all connected upsmon clients should perform a full shutdown and power off.

View File

@ -0,0 +1,2 @@
dialout:x:20:nut
nut:x:131:

View File

@ -0,0 +1,2 @@
root:x:0:0:root:/:/sbin/false
nut:x:123:131::/var/lib/nut:/sbin/false

View File

@ -0,0 +1,10 @@
version: v1alpha1
metadata:
name: nut-client
version: "$VERSION"
author: Sidero Labs
description: |
This system extension provides the network-ups-tools upsmon service.
compatibility:
talos:
version: ">= v1.2.0"

View File

@ -0,0 +1,47 @@
name: nut-client
depends:
- service: cri
- network:
- addresses
- connectivity
- etcfiles
container:
entrypoint: ./upsmon
args:
- -F
mounts:
- source: /lib
destination: /lib
type: bind
options:
- bind
- ro
- source: /usr/lib
destination: /usr/lib
type: bind
options:
- bind
- ro
# config via .machine.files
- source: /var/etc/nut
destination: /usr/local/etc/nut
type: bind
options:
- bind
- ro
# /sbin/init talks to apid
- source: /system/run/apid/apid.sock
destination: /system/run/apid/apid.sock
type: bind
options:
- rshared
- rbind
- rw
# symlinked to /sbin/poweroff
- source: /sbin/init
destination: /sbin/init
type: bind
options:
- bind
- ro
restart: always

View File

@ -0,0 +1,43 @@
--- a/clients/upsmon.c 2022-04-23 04:56:06.000000000 -0700
+++ b/clients/upsmon.c 2022-09-04 13:21:28.072170502 -0700
@@ -26,6 +26,7 @@
#include <sys/socket.h>
#include <unistd.h>
#include <fcntl.h>
+#include <spawn.h>
#include "nut_stdint.h"
#include "upsclient.h"
@@ -1874,6 +1875,23 @@
static void runparent(int fd)
__attribute__((noreturn));
+static int runcmd(const char *cmd)
+{
+ int sret, status;
+ pid_t pid;
+ char *argv[] = {cmd, NULL};
+ char *env[] = {NULL};
+
+ /* TODO support tokenizing cmd */
+ sret = posix_spawn(&pid, cmd, NULL, NULL, argv, env);
+ if (sret != 0)
+ /* parent */
+ exit(EXIT_SUCCESS);
+
+ sret = waitpid(pid, &status, 0);
+ return status;
+}
+
static void runparent(int fd)
{
ssize_t ret;
@@ -1907,7 +1925,7 @@
/* have to do this here - child is unprivileged */
set_pdflag();
- sret = system(shutdowncmd);
+ sret = runcmd(shutdowncmd);
if (sret != 0)
upslogx(LOG_ERR, "parent: Unable to call shutdown command: %s",

101
power/nut-client/pkg.yaml Normal file
View File

@ -0,0 +1,101 @@
name: nut-client
variant: scratch
shell: /toolchain/bin/bash
dependencies:
- stage: base
- image: "{{ .PKGS_PREFIX }}/openssl:{{ .PKGS_VERSION }}"
- image: "{{ .PKGS_PREFIX }}/util-linux:{{ .PKGS_VERSION }}"
steps:
- sources:
- url: https://github.com/networkupstools/nut/releases/download/v{{ .NUT_VERSION }}/nut-{{ .NUT_VERSION }}.tar.gz
destination: nut.tar.gz
sha256: c3e5a708da797b7c70b653d37b1206a000fcb503b85519fe4cdf6353f792bfe5
sha512: 3c413ae54088045a713eb80cf1bdda474f41bb3b67c7c0248aa7a0c4d441dce1ff42627a2735273d7e36892d1f2eeb895220cf28af63fec2fa0c7a267f82d577
prepare:
- |
sed -i 's#$VERSION#{{ .VERSION }}#' /pkg/manifest.yaml
- |
tar -xzf nut.tar.gz --strip-components=1
- |
# no shell for you
patch -p1 < /pkg/patches/replace_system.patch
- |
export PATH="$PATH:/toolchain/bin"
# Create symlinks for binaries required by libtoolize.
ln -s /toolchain/bin/sed /bin/sed
ln -s /toolchain/bin/grep /bin/grep
# Create symlinks for files used when building.
mkdir -p /usr/bin
ln -s /toolchain/bin/pkg-config /usr/bin/pkg-config
ln -s /toolchain/bin/file /usr/bin/file
cp /toolchain/share/automake-1.16/config.guess config.guess
cp /toolchain/lib/libstdc++* /lib
autoreconf -if
export PKG_CONFIG_PATH=/usr/lib/pkgconfig
./configure \
--prefix=/usr/local \
--libexecdir=/usr/local/lib/nut \
--datadir=/usr/local/share/nut \
--sysconfdir=/usr/local/etc/nut \
--with-drvpath=/usr/local/lib/nut \
--with-statepath=/var/run/nut \
--with-altpidpath=/var/run/nut \
--with-udev-dir=/usr/local/etc/udev \
--with-systemdsystemunitdir=no \
--with-systemdshutdowndir=no \
--with-systemdtmpfilesdir=no \
--with-user=nut \
--with-group=nut \
--with-openssl \
--disable-static \
--without-avahi \
--without-cgi \
--without-freeipmi \
--without-ipmi \
--without-libltdl \
--without-modbus \
--without-neon \
--without-nss \
--without-powerman \
--without-serial \
--without-snmp \
--without-wrap \
--without-usb
build:
- |
make -j $(nproc) all
install:
- |
make DESTDIR=/rootfs install-exec
containerRoot=/rootfs/usr/local/lib/containers/nut-client
mkdir -p "$containerRoot"/{etc,sbin,usr/local/lib}
cp /rootfs/usr/local/sbin/upsmon "$containerRoot/upsmon"
mv /rootfs/usr/local/lib/lib* "$containerRoot/usr/local/lib/"
cp /pkg/files/* "$containerRoot/etc/"
# TODO replace /usr/bin/wall with either a wrapper for printk or a
# Go cmd to log to Talos Events
# /sbin/init is bind mounted in nut-client.yaml
pushd "$containerRoot/sbin"
ln -sv ./init poweroff
popd
# cleanup
rm -rf /rootfs/usr/local/bin
rm -rf /rootfs/usr/local/etc
rm -rf /rootfs/usr/local/lib/nut
rm -rf /rootfs/usr/local/sbin
finalize:
- from: /rootfs
to: /rootfs
- from: /pkg/manifest.yaml
to: /
- from: /pkg/nut-client.yaml
to: /rootfs/usr/local/etc/containers/

View File

@ -0,0 +1 @@
VERSION: "{{ .NUT_VERSION }}-{{ .BUILD_ARG_TAG }}"

2
power/vars.yaml Normal file
View File

@ -0,0 +1,2 @@
# renovate: datasource=github-releases extractVersion=^(?<version>.*)$ depName=networkupstools/nut
NUT_VERSION: 2.8.0