From d7ba3b54d82829f57d3a3bbdd0bd2b729ec8b0d4 Mon Sep 17 00:00:00 2001 From: Chris Dombroski Date: Wed, 21 Aug 2024 22:09:46 -0400 Subject: [PATCH] nixos/zwave-js-ui: init module Provides systemd service and allows configuration of data directory --- .../manual/release-notes/rl-2505.section.md | 2 + nixos/modules/module-list.nix | 1 + .../services/home-automation/zwave-js-ui.nix | 120 ++++++++++++++++++ nixos/tests/all-tests.nix | 1 + nixos/tests/zwave-js-ui.nix | 31 +++++ 5 files changed, 155 insertions(+) create mode 100644 nixos/modules/services/home-automation/zwave-js-ui.nix create mode 100644 nixos/tests/zwave-js-ui.nix diff --git a/nixos/doc/manual/release-notes/rl-2505.section.md b/nixos/doc/manual/release-notes/rl-2505.section.md index 3586d5788c79a..5a118c0f99827 100644 --- a/nixos/doc/manual/release-notes/rl-2505.section.md +++ b/nixos/doc/manual/release-notes/rl-2505.section.md @@ -22,6 +22,8 @@ - [crab-hole](https://github.com/LuckyTurtleDev/crab-hole), a cross platform Pi-hole clone written in Rust using hickory-dns/trust-dns. Available as [services.crab-hole](#opt-services.crab-hole.enable). +- [zwave-js-ui](https://zwave-js.github.io/zwave-js-ui/), a full featured Z-Wave Control Panel and MQTT Gateway. Available as [services.zwave-js-ui](#opt-services.zwave-js-ui.enable). + - [Amazon CloudWatch Agent](https://github.com/aws/amazon-cloudwatch-agent), the official telemetry collector for AWS CloudWatch and AWS X-Ray. Available as [services.amazon-cloudwatch-agent](options.html#opt-services.amazon-cloudwatch-agent.enable). - [Bat](https://github.com/sharkdp/bat), a {manpage}`cat(1)` clone with wings. Available as [programs.bat](options.html#opt-programs.bat). diff --git a/nixos/modules/module-list.nix b/nixos/modules/module-list.nix index 31d370ef6ccfb..06538f26b4a02 100644 --- a/nixos/modules/module-list.nix +++ b/nixos/modules/module-list.nix @@ -652,6 +652,7 @@ ./services/home-automation/wyoming/satellite.nix ./services/home-automation/zigbee2mqtt.nix ./services/home-automation/zwave-js.nix + ./services/home-automation/zwave-js-ui.nix ./services/logging/SystemdJournal2Gelf.nix ./services/logging/awstats.nix ./services/logging/filebeat.nix diff --git a/nixos/modules/services/home-automation/zwave-js-ui.nix b/nixos/modules/services/home-automation/zwave-js-ui.nix new file mode 100644 index 0000000000000..631986510b4f2 --- /dev/null +++ b/nixos/modules/services/home-automation/zwave-js-ui.nix @@ -0,0 +1,120 @@ +{ + config, + lib, + pkgs, + ... +}: +let + inherit (lib) + getExe + mkIf + mkEnableOption + mkOption + mkPackageOption + types + ; + cfg = config.services.zwave-js-ui; +in +{ + options.services.zwave-js-ui = { + enable = mkEnableOption "zwave-js-ui"; + + package = mkPackageOption pkgs "zwave-js-ui" { }; + + serialPort = mkOption { + type = types.path; + description = '' + Serial port for the Z-Wave controller. + + Only used to grant permissions to the device; must be additionally configured in the application + ''; + example = "/dev/serial/by-id/usb-example"; + }; + + settings = mkOption { + type = types.submodule { + freeformType = + with types; + attrsOf ( + nullOr (oneOf [ + str + path + package + ]) + ); + + options = { + STORE_DIR = mkOption { + type = types.str; + default = "%S/zwave-js-ui"; + visible = false; + readOnly = true; + }; + + ZWAVEJS_EXTERNAL_CONFIG = mkOption { + type = types.str; + default = "%S/zwave-js-ui/.config-db"; + visible = false; + readOnly = true; + }; + }; + }; + + description = '' + Extra environment variables passed to the zwave-js-ui process. + + Check for possible options + ''; + example = { + HOST = "::"; + PORT = "8091"; + }; + }; + }; + config = mkIf cfg.enable { + systemd.services.zwave-js-ui = { + environment = cfg.settings; + wantedBy = [ "multi-user.target" ]; + serviceConfig = { + ExecStart = getExe cfg.package; + RuntimeDirectory = "zwave-js-ui"; + StateDirectory = "zwave-js-ui"; + RootDirectory = "%t/zwave-js-ui"; + BindReadOnlyPaths = [ + "/nix/store" + ]; + DeviceAllow = [ cfg.serialPort ]; + DynamicUser = true; + SupplementaryGroups = [ "dialout" ]; + CapabilityBoundingSet = [ "" ]; + RestrictAddressFamilies = "AF_INET AF_INET6"; + DevicePolicy = "closed"; + LockPersonality = true; + MemoryDenyWriteExecute = false; + NoNewPrivileges = true; + PrivateUsers = true; + PrivateTmp = true; + ProtectClock = true; + ProtectControlGroups = true; + ProtectHome = true; + ProtectHostname = true; + ProtectKernelLogs = true; + ProtectKernelModules = true; + ProtectKernalTunables = true; + ProtectProc = "invisible"; + ProcSubset = "pid"; + RemoveIPC = true; + RestrictNamespaces = true; + RestrictRealtime = true; + RestrictSUIDSGID = true; + SystemCallArchitectures = "native"; + SystemCallFilter = [ + "@system-service @pkey" + "~@privileged @resources" + ]; + UMask = "0077"; + }; + }; + }; + meta.maintainers = with lib.maintainers; [ cdombroski ]; +} diff --git a/nixos/tests/all-tests.nix b/nixos/tests/all-tests.nix index 927382091e72e..62ffbbe432388 100644 --- a/nixos/tests/all-tests.nix +++ b/nixos/tests/all-tests.nix @@ -1161,4 +1161,5 @@ in { zrepl = handleTest ./zrepl.nix {}; zsh-history = handleTest ./zsh-history.nix {}; zwave-js = handleTest ./zwave-js.nix {}; + zwave-js-ui = handleTest ./zwave-js-ui.nix {}; } diff --git a/nixos/tests/zwave-js-ui.nix b/nixos/tests/zwave-js-ui.nix new file mode 100644 index 0000000000000..3aa90d75bb2e8 --- /dev/null +++ b/nixos/tests/zwave-js-ui.nix @@ -0,0 +1,31 @@ +import ./make-test-python.nix ( + { lib, ... }: + { + name = "zwave-js-ui"; + meta.maintainers = with lib.maintainers; [ cdombroski ]; + + nodes = { + machine = + { ... }: + { + services.zwave-js-ui = { + enable = true; + serialPort = "/dev/null"; + settings = { + HOST = "::"; + PORT = "9999"; + }; + }; + }; + }; + + testScript = '' + start_all() + + machine.wait_for_unit("zwave-js-ui.service") + machine.wait_for_open_port(9999) + machine.wait_until_succeeds("journalctl --since -1m --unit zwave-js-ui --grep 'Listening on port 9999host :: protocol HTTP'") + machine.wait_for_file("/var/lib/zwave-js-ui/nodes.json") + ''; + } +)