2024-05-02 00:46:19 +00:00
|
|
|
# | 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.
|
2024-06-30 08:12:46 +00:00
|
|
|
{
|
|
|
|
writeScriptBin,
|
|
|
|
bash,
|
|
|
|
coreutils,
|
|
|
|
systemd,
|
|
|
|
runCommand,
|
|
|
|
lib,
|
2024-05-02 00:46:19 +00:00
|
|
|
}:
|
2024-06-30 08:12:46 +00:00
|
|
|
{
|
|
|
|
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
|
2024-05-02 00:46:19 +00:00
|
|
|
|
2024-06-30 08:12:46 +00:00
|
|
|
unitDir=/etc/systemd/system
|
|
|
|
if [ ! -w "$unitDir" ]; then
|
|
|
|
unitDir=/nix/var/nix/profiles/default/lib/systemd/system
|
|
|
|
mkdir -p "$unitDir"
|
|
|
|
fi
|
|
|
|
declare -a unitsToStop unitsToStart
|
2024-05-02 00:46:19 +00:00
|
|
|
|
2024-06-30 08:12:46 +00:00
|
|
|
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
|
|
|
|
''
|