commit 778c6d440d97a0b2299c210b451667c84bce699b Author: Dustin C. Hatch Date: Thu Jan 11 20:53:17 2024 -0600 Initial commit diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 0000000..c4d1268 --- /dev/null +++ b/.editorconfig @@ -0,0 +1,17 @@ +root = true + +[*] +charset = utf-8 +end_of_line = lf +insert_final_newline = true +trim_trailing_whitespace = true + +[**.k] +max_line_length = 79 +indent_style = space +indent_size = 4 + +[**.sh] +max_line_length = 79 +indent_style = space +indent_size = 4 diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..ffdebf3 --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +/.kclvm +/keys.txt diff --git a/app/nut/base/base.k b/app/nut/base/base.k new file mode 100644 index 0000000..55ae540 --- /dev/null +++ b/app/nut/base/base.k @@ -0,0 +1,7 @@ +import pkg.nut + +nut: nut.Nut { + users.upsmon = { + upsmon = "primary" + } +} diff --git a/app/nut/config.sh b/app/nut/config.sh new file mode 100644 index 0000000..4b33fe7 --- /dev/null +++ b/app/nut/config.sh @@ -0,0 +1,13 @@ +#!/bin/sh + +set -e + +: "${DESTDIR=/host}" +env="$1" + +kcl nut/base nut/"${env}" -o nut.yaml +mkdir -p "${DESTDIR}"/etc/ups +tera --template nut/templates/ups.conf nut.yaml \ + > "${DESTDIR}"/etc/ups/ups.conf +tera --template nut/templates/upsd.users nut.yaml \ + > "${DESTDIR}"/etc/ups/upsd.users diff --git a/app/nut/prod/main.k b/app/nut/prod/main.k new file mode 100644 index 0000000..a32d38e --- /dev/null +++ b/app/nut/prod/main.k @@ -0,0 +1,24 @@ +import pkg.nut + +nut: nut.Nut { + ups = { + apc1500 = { + driver = "usbhid-ups" + port = "auto" + desc = "Back-UPS XS 1500G" + vendorid = "051d" + product = ".*1500M.*" + pollonly = "enabled" + pollinterval = 1 + } + apc1300 = { + driver = "usbhid-ups" + port = "auto" + desc = "Back-UPS XS 1300G" + vendorid = "051d" + product = ".*1300G.*" + pollonly = "enabled" + pollinterval = 1 + } + } +} diff --git a/app/nut/prod/secrets.k b/app/nut/prod/secrets.k new file mode 100644 index 0000000..13b3eac --- /dev/null +++ b/app/nut/prod/secrets.k @@ -0,0 +1,23 @@ +import pkg.nut + +nut: nut.Nut { + users.homeassistant.password = """\ +-----BEGIN AGE ENCRYPTED FILE----- +YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSAxZUZleGt3emxXdDFtcEtN +Wll3K0hrS2c2M1oyMWh2VlBnMER0bkZOb1VVCnU3aTI2eVJoV1dKNWxEd0VnbVNa +NlMxVWRuZWpNbTJRVUhWR2w3bUlwaEUKLS0tIGZLcGNQRy9LNUF1Y0JzZEZGdXBn +bUJjYlBSSEYwRUpwemlMZ0xCZnpTS2cKUFke27YDeTME9OBgEcQdbJ3jsDZS43km +tK61kLMcexq3lXQb30gx4fzMuYa0MXFygawscTnxTrOrXUd36Iga4A== +-----END AGE ENCRYPTED FILE----- +""" + + users.upsmon.password = """\ +-----BEGIN AGE ENCRYPTED FILE----- +YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBzdnZMZ1F1d05RRi84ZENT +SmdRNkFLWDRPMTBFTkdOdFRBMC8xK0gvUVV3CjRhWVljR3ZiU1hwWEJBN2hCcTM1 +NWFQWWdmVm1XK1pKUHFnRjJjYXdDNjgKLS0tIERvOU44ellHdGZYVXRDMHN4NkpV +QkhtVlVQUS96UStlQWo2QWJISUlGL2cKc8AC3UujJMIafbV31pjAzniqSHBNwYDw +zhh094auKibUcg6Tbyc= +-----END AGE ENCRYPTED FILE----- +""" +} diff --git a/app/nut/test/secrets.k b/app/nut/test/secrets.k new file mode 100644 index 0000000..01dde83 --- /dev/null +++ b/app/nut/test/secrets.k @@ -0,0 +1,23 @@ +import pkg.nut + +nut: nut.Nut { + users.dustin.password = """\ +-----BEGIN AGE ENCRYPTED FILE----- +YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBsdWVBOXZpb3Fxclk4SGJv +N0JyeEthbzFOTzQySkw3cWZhSEk2Y1poWm0wCnhEVkJhWWtIdUxnVUFSa2xCSDNU +ak1rbzhaUzN1WUxKajdvOTluVGJwaGsKLS0tIG9NL3ZrMDY5Z2prMnNWL003cDRP +T3NySlREeXZoaVhGcUdTVmxrYXNyUDQKXFvRM9INd7E334OOYlFgp9pu1w4b3szL +yVmqMxpy98iHA6HKvuw= +-----END AGE ENCRYPTED FILE----- +""" + + users.upsmon.password = """\ +-----BEGIN AGE ENCRYPTED FILE----- +YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBzdnZMZ1F1d05RRi84ZENT +SmdRNkFLWDRPMTBFTkdOdFRBMC8xK0gvUVV3CjRhWVljR3ZiU1hwWEJBN2hCcTM1 +NWFQWWdmVm1XK1pKUHFnRjJjYXdDNjgKLS0tIERvOU44ellHdGZYVXRDMHN4NkpV +QkhtVlVQUS96UStlQWo2QWJISUlGL2cKc8AC3UujJMIafbV31pjAzniqSHBNwYDw +zhh094auKibUcg6Tbyc= +-----END AGE ENCRYPTED FILE----- +""" +} diff --git a/host/nut0.pyrocufflink.blue.k b/host/nut0.pyrocufflink.blue.k new file mode 100644 index 0000000..6ca473c --- /dev/null +++ b/host/nut0.pyrocufflink.blue.k @@ -0,0 +1,4 @@ +import pkg +import pkg.nut + +render: [pkg.RenderInstruction] = nut.templates diff --git a/host/nut0.pyrocufflink.blue.yaml b/host/nut0.pyrocufflink.blue.yaml new file mode 100644 index 0000000..b9c8f37 --- /dev/null +++ b/host/nut0.pyrocufflink.blue.yaml @@ -0,0 +1,4 @@ +kcl_cli_configs: + files: + - ../app/nut/base + - ../app/nut/test diff --git a/kcl.mod b/kcl.mod new file mode 100644 index 0000000..14ef1f8 --- /dev/null +++ b/kcl.mod @@ -0,0 +1,5 @@ +[package] +name = "dch" +edition = "0.0.1" +version = "0.0.1" + diff --git a/kcl.mod.lock b/kcl.mod.lock new file mode 100644 index 0000000..e69de29 diff --git a/pkg/instructions.k b/pkg/instructions.k new file mode 100644 index 0000000..886e4f4 --- /dev/null +++ b/pkg/instructions.k @@ -0,0 +1,17 @@ +schema Hook: + run: str + immediate?: bool + +schema Hooks: + changed?: [Hook] + +schema RenderInstruction: + template: str + dest: str + owner?: str + group?: str + mode?: str + hooks?: Hooks + +schema Instructions: + render: [RenderInstruction] diff --git a/pkg/nut/main.k b/pkg/nut/main.k new file mode 100644 index 0000000..75021ec --- /dev/null +++ b/pkg/nut/main.k @@ -0,0 +1,35 @@ +schema Ups: + """Schema for ups.conf sections""" + + driver: str + port?: str + desc?: str + vendorid?: str + productid?: str + product?: str + serial?: str + vendor?: str + bus?: str + pollonly?: "enabled" | "disabled" + pollinterval?: int + +schema User: + """Schema for upsd.users sections""" + + password: str + actions?: [str] + instcmds?: [str] + upsmon?: "primary" | "secondary" + +schema Listen: + """Schema for listen socket address""" + + address: str = "::" + port: int = 3493 + +schema Nut: + """Schema for NUT configuration""" + + listen = Listen() + ups: {str:Ups} = {} + users: {str:User} = {} diff --git a/pkg/nut/templates.k b/pkg/nut/templates.k new file mode 100644 index 0000000..dab07bb --- /dev/null +++ b/pkg/nut/templates.k @@ -0,0 +1,46 @@ +templates = [ + { + template = "nut/nut.sysusers" + dest = "/etc/sysusers.d/nut.conf" + hooks = { + changed = [{ + run = "systemd-sysusers %s" + immediate = True + }] + } + } + { + template = "nut/ups.conf" + dest = "/etc/ups/ups.conf" + hooks = { + changed = [{run = "systemctl try-restart nut-server"}] + } + } + { + template = "nut/upsd.conf" + dest = "/etc/ups/upsd.conf" + owner = "root" + group = "nut" + mode = "u=rw,g=r,o=" + hooks = { + changed = [{run = "systemctl try-reload-or-restart nut-server"}] + } + } + { + template = "nut/upsd.users" + dest = "/etc/ups/upsd.users" + owner = "root" + group = "nut" + mode = "u=rw,g=r,o=" + hooks = { + changed = [{run = "systemctl try-reload-or-restart nut-server"}] + } + } + { + template = "nut/nut-server.container" + dest = "/etc/containers/systemd/nut-server.container" + hooks = { + changed = [{run = "systemctl restart nut-server"}] + } + } +] diff --git a/templates/nut/nut-server.container b/templates/nut/nut-server.container new file mode 100644 index 0000000..949a81f --- /dev/null +++ b/templates/nut/nut-server.container @@ -0,0 +1,23 @@ +# vim: set ft=systemd : +[Unit] +Description=Network UPS Tools - power devices information server +Wants=network-online.target +After=network-online.target +Before=nut-monitor.service + +[Container] +Image=git.pyrocufflink.net/containerimages/nut:latest +Pull=newer +RunInit=true +Volume=/etc/ups:/etc/ups:ro +Volume=/dev:/dev:rw +ReadOnly=true +VolatileTmp=true +PodmanArgs=--privileged +Network=host + +[Service] +ExecReload=podman exec systemd-%N upsd -c reload + +[Install] +WantedBy=multi-user.target diff --git a/templates/nut/nut.sysusers b/templates/nut/nut.sysusers new file mode 100644 index 0000000..08c04aa --- /dev/null +++ b/templates/nut/nut.sysusers @@ -0,0 +1,4 @@ +g nut 57 +u nut 57:57 "Network UPS Tools" /var/lib/ups /bin/false +m nut tty +m nut dialout diff --git a/templates/nut/ups.conf b/templates/nut/ups.conf new file mode 100644 index 0000000..6ef1575 --- /dev/null +++ b/templates/nut/ups.conf @@ -0,0 +1,7 @@ +{% for name, ups in nut.ups %}{% if not loop.first %} +{% endif -%} +[{{ name }}] +{% for key, value in ups -%} +{{ key }} = "{{ value }}" +{% endfor -%} +{% endfor -%} diff --git a/templates/nut/upsd.conf b/templates/nut/upsd.conf new file mode 100644 index 0000000..a2922d6 --- /dev/null +++ b/templates/nut/upsd.conf @@ -0,0 +1 @@ +LISTEN {{ nut.listen.address }} {{ nut.listen.port }} diff --git a/templates/nut/upsd.users b/templates/nut/upsd.users new file mode 100644 index 0000000..caf73c7 --- /dev/null +++ b/templates/nut/upsd.users @@ -0,0 +1,14 @@ +{% for username, settings in nut.users %}{% if not loop.first %} +{% endif -%} +[{{ username }}] +password = {{ settings.password | decrypt }} +{% for action in settings.actions|default(value=[]) -%} +actions = {{ action }} +{% endfor -%} +{% for instcmds in settings.instcmds|default(value=[]) -%} +instcmds = {{ instcmds }} +{% endfor -%} +{% if settings.upsmon is defined -%} +upsmon {{ settings.upsmon }} +{% endif -%} +{% endfor -%}