home-assistant: refresh cherry-picks (#363666)

This commit is contained in:
Martin Weinelt
2024-12-09 19:17:12 +01:00
committed by GitHub
3 changed files with 94 additions and 29 deletions
@@ -1,8 +1,41 @@
{ config, lib, pkgs, ... }:
with lib;
{ config, lib, pkgs, utils, ... }:
let
inherit (lib)
any
attrByPath
attrValues
concatMap
converge
elem
escapeShellArg
escapeShellArgs
filter
filterAttrsRecursive
hasAttrByPath
isAttrs
isDerivation
isList
literalExpression
mkEnableOption
mkIf
mkMerge
mkOption
mkRemovedOptionModule
mkRenamedOptionModule
optionals
optionalString
recursiveUpdate
singleton
splitString
types
unique
;
inherit (utils)
escapeSystemdExecArgs
;
cfg = config.services.home-assistant;
format = pkgs.formats.yaml {};
@@ -17,7 +50,7 @@ let
# Filter null values from the configuration, so that we can still advertise
# optional options in the config attribute.
filteredConfig = lib.converge (lib.filterAttrsRecursive (_: v: ! elem v [ null ])) (lib.recursiveUpdate customLovelaceModulesResources (cfg.config or {}));
filteredConfig = converge (filterAttrsRecursive (_: v: ! elem v [ null ])) (recursiveUpdate customLovelaceModulesResources (cfg.config or {}));
configFile = renderYAMLFile "configuration.yaml" filteredConfig;
lovelaceConfigFile = renderYAMLFile "ui-lovelace.yaml" cfg.lovelaceConfig;
@@ -42,7 +75,7 @@ let
if isDerivation config then
[ ]
else if isAttrs config then
optional (config ? platform) config.platform
optionals (config ? platform) [ config.platform ]
++ concatMap usedPlatforms (attrValues config)
else if isList config then
concatMap usedPlatforms config
@@ -67,7 +100,7 @@ let
extraComponents = oldArgs.extraComponents or [] ++ extraComponents;
extraPackages = ps: (oldArgs.extraPackages or (_: []) ps)
++ (cfg.extraPackages ps)
++ (lib.concatMap (component: component.propagatedBuildInputs or []) cfg.customComponents);
++ (concatMap (component: component.propagatedBuildInputs or []) cfg.customComponents);
}));
# Create a directory that holds all lovelace modules
@@ -93,7 +126,7 @@ in {
meta = {
buildDocsInSandbox = false;
maintainers = teams.home-assistant.members;
maintainers = lib.teams.home-assistant.members;
};
options.services.home-assistant = {
@@ -101,6 +134,15 @@ in {
# https://github.com/home-assistant/architecture/blob/master/adr/0012-define-supported-installation-method.md#decision
enable = mkEnableOption "Home Assistant. Please note that this installation method is unsupported upstream";
extraArgs = mkOption {
type = types.listOf types.str;
default = [ ];
example = [ "--debug" ];
description = ''
Extra arguments to pass to the hass executable.
'';
};
configDir = mkOption {
default = "/var/lib/hass";
type = types.path;
@@ -471,12 +513,12 @@ in {
networking.firewall.allowedTCPPorts = mkIf cfg.openFirewall [ cfg.config.http.server_port ];
# symlink the configuration to /etc/home-assistant
environment.etc = lib.mkMerge [
(lib.mkIf (cfg.config != null && !cfg.configWritable) {
environment.etc = mkMerge [
(mkIf (cfg.config != null && !cfg.configWritable) {
"home-assistant/configuration.yaml".source = configFile;
})
(lib.mkIf (cfg.lovelaceConfig != null && !cfg.lovelaceConfigWritable) {
(mkIf (cfg.lovelaceConfig != null && !cfg.lovelaceConfigWritable) {
"home-assistant/ui-lovelace.yaml".source = lovelaceConfigFile;
})
];
@@ -491,8 +533,8 @@ in {
"mysql.service"
"postgresql.service"
];
reloadTriggers = lib.optional (cfg.config != null) configFile
++ lib.optional (cfg.lovelaceConfig != null) lovelaceConfigFile;
reloadTriggers = optionals (cfg.config != null) [ configFile ]
++ optionals (cfg.lovelaceConfig != null) [ lovelaceConfigFile ];
preStart = let
copyConfig = if cfg.configWritable then ''
@@ -541,20 +583,20 @@ in {
environment.PYTHONPATH = package.pythonPath;
serviceConfig = let
# List of capabilities to equip home-assistant with, depending on configured components
capabilities = lib.unique ([
capabilities = unique ([
# Empty string first, so we will never accidentally have an empty capability bounding set
# https://github.com/NixOS/nixpkgs/issues/120617#issuecomment-830685115
""
] ++ lib.optionals (builtins.any useComponent componentsUsingBluetooth) [
] ++ optionals (any useComponent componentsUsingBluetooth) [
# Required for interaction with hci devices and bluetooth sockets, identified by bluetooth-adapters dependency
# https://www.home-assistant.io/integrations/bluetooth_le_tracker/#rootless-setup-on-core-installs
"CAP_NET_ADMIN"
"CAP_NET_RAW"
] ++ lib.optionals (useComponent "emulated_hue") [
] ++ optionals (useComponent "emulated_hue") [
# Alexa looks for the service on port 80
# https://www.home-assistant.io/integrations/emulated_hue
"CAP_NET_BIND_SERVICE"
] ++ lib.optionals (useComponent "nmap_tracker") [
] ++ optionals (useComponent "nmap_tracker") [
# https://www.home-assistant.io/integrations/nmap_tracker#linux-capabilities
"CAP_NET_ADMIN"
"CAP_NET_BIND_SERVICE"
@@ -582,12 +624,14 @@ in {
"inkbird"
"improv_ble"
"keymitt_ble"
"leaone-ble"
"ld2410_ble"
"leaone"
"led_ble"
"medcom_ble"
"melnor"
"moat"
"mopeka"
"motionblinds_ble"
"oralb"
"private_ble_device"
"qingping"
@@ -621,25 +665,34 @@ in {
# mostly the ones using config flows already.
"acer_projector"
"alarmdecoder"
"aurora_abb_powerone"
"blackbird"
"bryant_evolution"
"crownstone"
"deconz"
"dsmr"
"edl21"
"elkm1"
"elv"
"enocean"
"homeassistant_hardware"
"homeassistant_yellow"
"firmata"
"flexit"
"gpsd"
"insteon"
"kwb"
"lacrosse"
"landisgyr_heat_meter"
"modbus"
"modem_callerid"
"mysensors"
"nad"
"numato"
"nut"
"opentherm_gw"
"otbr"
"rainforst_raven"
"rflink"
"rfxtrx"
"scsgate"
@@ -655,12 +708,21 @@ in {
"zwave_js"
];
in {
ExecStart = "${package}/bin/hass --config '${cfg.configDir}'";
ExecReload = "${pkgs.coreutils}/bin/kill -HUP $MAINPID";
ExecStart = escapeSystemdExecArgs ([
(lib.getExe package)
"--config" cfg.configDir
] ++ cfg.extraArgs);
ExecReload = (escapeSystemdExecArgs [
(lib.getExe' pkgs.coreutils "kill")
"-HUP"
]) + " $MAINPID";
User = "hass";
Group = "hass";
WorkingDirectory = cfg.configDir;
Restart = "on-failure";
# Signal handling
# homeassistant/helpers/signal.py
RestartForceExitStatus = "100";
SuccessExitStatus = "100";
KillSignal = "SIGINT";
+1 -1
View File
@@ -456,7 +456,7 @@ in {
hitch = handleTest ./hitch {};
hledger-web = handleTest ./hledger-web.nix {};
hockeypuck = handleTest ./hockeypuck.nix { };
home-assistant = handleTest ./home-assistant.nix {};
home-assistant = runTest ./home-assistant.nix;
hostname = handleTest ./hostname.nix {};
hound = handleTest ./hound.nix {};
hub = handleTest ./git/hub.nix {};
+12 -9
View File
@@ -1,4 +1,7 @@
import ./make-test-python.nix ({ pkgs, lib, ... }:
{
lib,
...
}:
let
configDir = "/var/lib/foobar";
@@ -122,7 +125,7 @@ in {
# Cause a configuration change that requires a service restart as we added a new runtime dependency
specialisation.newFeature = {
inheritParentConfig = true;
configuration.services.home-assistant.config.backup = {};
configuration.services.home-assistant.config.prometheus = {};
};
specialisation.removeCustomThings = {
@@ -206,25 +209,25 @@ in {
with subtest("Check extra components are considered in systemd unit hardening"):
hass.succeed("systemctl show -p DeviceAllow home-assistant.service | grep -q char-ttyUSB")
with subtest("Check service reloads when configuration changes"):
with subtest("Check service restart from SIGHUP"):
pid = hass.succeed("systemctl show --property=MainPID home-assistant.service")
cursor = get_journal_cursor()
hass.succeed("${system}/specialisation/differentName/bin/switch-to-configuration test")
new_pid = hass.succeed("systemctl show --property=MainPID home-assistant.service")
assert pid == new_pid, "The PID of the process should not change between process reloads"
wait_for_homeassistant(cursor)
new_pid = hass.succeed("systemctl show --property=MainPID home-assistant.service")
assert pid != new_pid, "The PID of the process must change after sending SIGHUP"
with subtest("Check service restarts when dependencies change"):
pid = new_pid
cursor = get_journal_cursor()
hass.succeed("${system}/specialisation/newFeature/bin/switch-to-configuration test")
new_pid = hass.succeed("systemctl show --property=MainPID home-assistant.service")
assert pid != new_pid, "The PID of the process should change when its PYTHONPATH changess"
wait_for_homeassistant(cursor)
new_pid = hass.succeed("systemctl show --property=MainPID home-assistant.service")
assert pid != new_pid, "The PID of the process must change when its PYTHONPATH changess"
with subtest("Check that new components get setup after restart"):
journal = get_journal_since(cursor)
for domain in ["backup"]:
for domain in ["prometheus"]:
assert f"Setup of domain {domain} took" in journal, f"{domain} setup missing"
with subtest("Check custom components and custom lovelace modules get removed"):
@@ -242,4 +245,4 @@ in {
hass.log(hass.succeed("systemctl cat home-assistant.service"))
hass.log(hass.succeed("systemd-analyze security home-assistant.service"))
'';
})
}