# | 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 ''