diff options
Diffstat (limited to 'nixos/lib/systemd-lib.nix')
-rw-r--r-- | nixos/lib/systemd-lib.nix | 117 |
1 files changed, 94 insertions, 23 deletions
diff --git a/nixos/lib/systemd-lib.nix b/nixos/lib/systemd-lib.nix index 198a710f052dd..dac5cc7b700c8 100644 --- a/nixos/lib/systemd-lib.nix +++ b/nixos/lib/systemd-lib.nix @@ -1,4 +1,4 @@ -{ config, lib, pkgs }: +{ config, lib, pkgs, utils }: let inherit (lib) @@ -14,10 +14,13 @@ let elem filter filterAttrs + flatten flip head isInt + isFloat isList + isPath length makeBinPath makeSearchPathOutput @@ -28,6 +31,7 @@ let optional optionalAttrs optionalString + pipe range replaceStrings reverseList @@ -149,7 +153,7 @@ in rec { "Systemd ${group} field `${name}' is outside the range [${toString min},${toString max}]"; assertRangeOrOneOf = name: min: max: values: group: attr: - optional (attr ? ${name} && !((min <= attr.${name} && max >= attr.${name}) || elem attr.${name} values)) + optional (attr ? ${name} && !(((isInt attr.${name} || isFloat attr.${name}) && min <= attr.${name} && max >= attr.${name}) || elem attr.${name} values)) "Systemd ${group} field `${name}' is not a value in range [${toString min},${toString max}], or one of ${toString values}"; assertMinimum = name: min: group: attr: @@ -178,6 +182,30 @@ in rec { in if errors == [] then true else trace (concatStringsSep "\n" errors) false; + checkUnitConfigWithLegacyKey = legacyKey: group: checks: attrs: + let + dump = lib.generators.toPretty { } + (lib.generators.withRecursion { depthLimit = 2; throwOnDepthLimit = false; } attrs); + attrs' = + if legacyKey == null + then attrs + else if ! attrs?${legacyKey} + then attrs + else if removeAttrs attrs [ legacyKey ] == {} + then attrs.${legacyKey} + else throw '' + The declaration + + ${dump} + + must not mix unit options with the legacy key '${legacyKey}'. + + This can be fixed by moving all settings from within ${legacyKey} + one level up. + ''; + in + checkUnitConfig group checks attrs'; + toOption = x: if x == true then "true" else if x == false then "false" @@ -366,9 +394,17 @@ in rec { // optionalAttrs (config.requisite != []) { Requisite = toString config.requisite; } // optionalAttrs (config ? restartTriggers && config.restartTriggers != []) - { X-Restart-Triggers = "${pkgs.writeText "X-Restart-Triggers-${name}" (toString config.restartTriggers)}"; } + { X-Restart-Triggers = "${pkgs.writeText "X-Restart-Triggers-${name}" (pipe config.restartTriggers [ + flatten + (map (x: if isPath x then "${x}" else x)) + toString + ])}"; } // optionalAttrs (config ? reloadTriggers && config.reloadTriggers != []) - { X-Reload-Triggers = "${pkgs.writeText "X-Reload-Triggers-${name}" (toString config.reloadTriggers)}"; } + { X-Reload-Triggers = "${pkgs.writeText "X-Reload-Triggers-${name}" (pipe config.reloadTriggers [ + flatten + (map (x: if isPath x then "${x}" else x)) + toString + ])}"; } // optionalAttrs (config.description != "") { Description = config.description; } // optionalAttrs (config.documentation != []) { @@ -385,8 +421,41 @@ in rec { }; }; - serviceConfig = { config, ... }: { - config.environment.PATH = mkIf (config.path != []) "${makeBinPath config.path}:${makeSearchPathOutput "bin" "sbin" config.path}"; + serviceConfig = { name, config, ... }: { + config = { + name = "${name}.service"; + environment.PATH = mkIf (config.path != []) "${makeBinPath config.path}:${makeSearchPathOutput "bin" "sbin" config.path}"; + }; + }; + + pathConfig = { name, config, ... }: { + config = { + name = "${name}.path"; + }; + }; + + socketConfig = { name, config, ... }: { + config = { + name = "${name}.socket"; + }; + }; + + sliceConfig = { name, config, ... }: { + config = { + name = "${name}.slice"; + }; + }; + + targetConfig = { name, config, ... }: { + config = { + name = "${name}.target"; + }; + }; + + timerConfig = { name, config, ... }: { + config = { + name = "${name}.timer"; + }; }; stage2ServiceConfig = { @@ -405,6 +474,7 @@ in rec { mountConfig = { config, ... }: { config = { + name = "${utils.escapeSystemdPath config.where}.mount"; mountConfig = { What = config.what; Where = config.where; @@ -418,6 +488,7 @@ in rec { automountConfig = { config, ... }: { config = { + name = "${utils.escapeSystemdPath config.where}.automount"; automountConfig = { Where = config.where; }; @@ -433,8 +504,8 @@ in rec { WantedBy=${concatStringsSep " " def.wantedBy} ''; - targetToUnit = name: def: - { inherit (def) aliases wantedBy requiredBy upheldBy enable overrideStrategy; + targetToUnit = def: + { inherit (def) name aliases wantedBy requiredBy upheldBy enable overrideStrategy; text = '' [Unit] @@ -442,8 +513,8 @@ in rec { ''; }; - serviceToUnit = name: def: - { inherit (def) aliases wantedBy requiredBy upheldBy enable overrideStrategy; + serviceToUnit = def: + { inherit (def) name aliases wantedBy requiredBy upheldBy enable overrideStrategy; text = commonUnitText def ('' [Service] '' + (let env = cfg.globalEnvironment // def.environment; @@ -452,7 +523,7 @@ in rec { "Environment=${toJSON "${n}=${env.${n}}"}\n"; # systemd max line length is now 1MiB # https://github.com/systemd/systemd/commit/e6dde451a51dc5aaa7f4d98d39b8fe735f73d2af - in if stringLength s >= 1048576 then throw "The value of the environment variable ‘${n}’ in systemd service ‘${name}.service’ is too long." else s) (attrNames env)) + in if stringLength s >= 1048576 then throw "The value of the environment variable ‘${n}’ in systemd service ‘${def.name}.service’ is too long." else s) (attrNames env)) + (if def ? reloadIfChanged && def.reloadIfChanged then '' X-ReloadIfChanged=true '' else if (def ? restartIfChanged && !def.restartIfChanged) then '' @@ -463,8 +534,8 @@ in rec { '' + attrsToSection def.serviceConfig); }; - socketToUnit = name: def: - { inherit (def) aliases wantedBy requiredBy upheldBy enable overrideStrategy; + socketToUnit = def: + { inherit (def) name aliases wantedBy requiredBy upheldBy enable overrideStrategy; text = commonUnitText def '' [Socket] ${attrsToSection def.socketConfig} @@ -473,40 +544,40 @@ in rec { ''; }; - timerToUnit = name: def: - { inherit (def) aliases wantedBy requiredBy upheldBy enable overrideStrategy; + timerToUnit = def: + { inherit (def) name aliases wantedBy requiredBy upheldBy enable overrideStrategy; text = commonUnitText def '' [Timer] ${attrsToSection def.timerConfig} ''; }; - pathToUnit = name: def: - { inherit (def) aliases wantedBy requiredBy upheldBy enable overrideStrategy; + pathToUnit = def: + { inherit (def) name aliases wantedBy requiredBy upheldBy enable overrideStrategy; text = commonUnitText def '' [Path] ${attrsToSection def.pathConfig} ''; }; - mountToUnit = name: def: - { inherit (def) aliases wantedBy requiredBy upheldBy enable overrideStrategy; + mountToUnit = def: + { inherit (def) name aliases wantedBy requiredBy upheldBy enable overrideStrategy; text = commonUnitText def '' [Mount] ${attrsToSection def.mountConfig} ''; }; - automountToUnit = name: def: - { inherit (def) aliases wantedBy requiredBy upheldBy enable overrideStrategy; + automountToUnit = def: + { inherit (def) name aliases wantedBy requiredBy upheldBy enable overrideStrategy; text = commonUnitText def '' [Automount] ${attrsToSection def.automountConfig} ''; }; - sliceToUnit = name: def: - { inherit (def) aliases wantedBy requiredBy upheldBy enable overrideStrategy; + sliceToUnit = def: + { inherit (def) name aliases wantedBy requiredBy upheldBy enable overrideStrategy; text = commonUnitText def '' [Slice] ${attrsToSection def.sliceConfig} |