summary refs log tree commit diff
path: root/pkgs/build-support/setup-systemd-units.nix
diff options
context:
space:
mode:
Diffstat (limited to 'pkgs/build-support/setup-systemd-units.nix')
-rw-r--r--pkgs/build-support/setup-systemd-units.nix83
1 files changed, 83 insertions, 0 deletions
diff --git a/pkgs/build-support/setup-systemd-units.nix b/pkgs/build-support/setup-systemd-units.nix
new file mode 100644
index 000000000000..4fa2f42c39dc
--- /dev/null
+++ b/pkgs/build-support/setup-systemd-units.nix
@@ -0,0 +1,83 @@
+# | Build a script to install and start a set of systemd units on any
+# systemd-based system.
+#
+# Creates a symlink at /etc/systemd-static/${namespace} for slightly
+# improved atomicity.
+{ writeScriptBin
+, bash
+, coreutils
+, systemd
+, runCommand
+, lib
+}:
+  { units     # : AttrSet String (Either Path { path : Path, wanted-by : [ String ] })
+              # ^ A set whose names are unit names and values are
+              # either paths to the corresponding unit files or a set
+              # containing the path and the list of units this unit
+              # should be wanted-by (none by default).
+              #
+              # The names should include the unit suffix
+              # (e.g. ".service")
+  , namespace # : String
+              # The namespace for the unit files, to allow for
+              # multiple independent unit sets managed by
+              # `setupSystemdUnits`.
+  }:
+    let static = runCommand "systemd-static" {}
+          ''
+            mkdir -p $out
+            ${lib.concatStringsSep "\n" (lib.mapAttrsToList (nm: file:
+                "ln -sv ${file.path or file} $out/${nm}"
+             ) units)}
+          '';
+        add-unit-snippet = name: file:
+          ''
+            oldUnit=$(readlink -f "$unitDir/${name}" || echo "$unitDir/${name}")
+            if [ -f "$oldUnit" -a "$oldUnit" != "${file.path or file}" ]; then
+              unitsToStop+=("${name}")
+            fi
+            ln -sf "/etc/systemd-static/${namespace}/${name}" \
+              "$unitDir/.${name}.tmp"
+            mv -T "$unitDir/.${name}.tmp" "$unitDir/${name}"
+            ${lib.concatStringsSep "\n" (map (unit:
+                ''
+                  mkdir -p "$unitDir/${unit}.wants"
+                  ln -sf "../${name}" \
+                    "$unitDir/${unit}.wants/.${name}.tmp"
+                  mv -T "$unitDir/${unit}.wants/.${name}.tmp" \
+                    "$unitDir/${unit}.wants/${name}"
+                ''
+              ) file.wanted-by or [])}
+            unitsToStart+=("${name}")
+          '';
+    in
+      writeScriptBin "setup-systemd-units"
+        ''
+          #!${bash}/bin/bash -e
+          export PATH=${coreutils}/bin:${systemd}/bin
+
+          unitDir=/etc/systemd/system
+          if [ ! -w "$unitDir" ]; then
+            unitDir=/etc/systemd-mutable/system
+            mkdir -p "$unitDir"
+          fi
+          declare -a unitsToStop unitsToStart
+
+          oldStatic=$(readlink -f /etc/systemd-static/${namespace} || true)
+          if [ "$oldStatic" != "${static}" ]; then
+            ${lib.concatStringsSep "\n"
+                (lib.mapAttrsToList add-unit-snippet units)}
+            if [ ''${#unitsToStop[@]} -ne 0 ]; then
+              echo "Stopping unit(s) ''${unitsToStop[@]}" >&2
+              systemctl stop "''${unitsToStop[@]}"
+            fi
+            mkdir -p /etc/systemd-static
+            ln -sfT ${static} /etc/systemd-static/.${namespace}.tmp
+            mv -T /etc/systemd-static/.${namespace}.tmp /etc/systemd-static/${namespace}
+            systemctl daemon-reload
+            echo "Starting unit(s) ''${unitsToStart[@]}" >&2
+            systemctl start "''${unitsToStart[@]}"
+          else
+            echo "Units unchanged, doing nothing" >&2
+          fi
+        ''