about summary refs log tree commit diff
path: root/nixos/lib/systemd-lib.nix
diff options
context:
space:
mode:
Diffstat (limited to 'nixos/lib/systemd-lib.nix')
-rw-r--r--nixos/lib/systemd-lib.nix117
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}