systemd: support sd-switch

This adds support for sd-switch, a tool to perform systemd generation
switches. It can be activated by setting

    systemd.startServices = "sd-switch";
This commit is contained in:
Robert Helgesson 2020-12-13 21:53:49 +01:00
parent b6ed605d4a
commit 708cb61e82
No known key found for this signature in database
GPG key ID: 36BDAA14C2797E89

View file

@ -170,21 +170,54 @@ in
}; };
startServices = mkOption { startServices = mkOption {
default = false; default = "suggest";
type = types.bool; type = with types; either bool (enum ["suggest" "legacy" "sd-switch"]);
apply = p:
if isBool p then if p then "legacy" else "suggest"
else p;
description = '' description = ''
Start all services that are wanted by active targets. Whether new or changed services that are wanted by active targets
Additionally, stop obsolete services from the previous should be started. Additionally, stop obsolete services from the
generation. previous generation.
</para><para>
The alternatives are
<variablelist>
<varlistentry>
<term><literal>suggest</literal> (or <literal>false</literal>)</term>
<listitem><para>
Use a very simple shell script to print suggested
<command>systemctl</command> commands to run. You will have to
manually run those commands after the switch.
</para></listitem>
</varlistentry>
<varlistentry>
<term><literal>legacy</literal> (or <literal>true</literal>)</term>
<listitem><para>
Use a Ruby script to, in a more robust fashion, determine the
necessary changes and automatically run the
<command>systemctl</command> commands.
</para></listitem>
</varlistentry>
<varlistentry>
<term><literal>sd-switch</literal></term>
<listitem><para>
Use sd-switch, a third party application, to perform the service
updates. This tool offers more features while having a small
closure size. Note, it requires a fully functional user D-Bus
session. Once tested and deemed sufficiently robust, this will
become the default.
</para></listitem>
</varlistentry>
</variablelist>
''; '';
}; };
servicesStartTimeoutMs = mkOption { servicesStartTimeoutMs = mkOption {
default = 0; default = 0;
type = types.int; type = types.ints.unsigned;
description = '' description = ''
How long to wait for started services to fail until their How long to wait for started services to fail until their start is
start is considered successful. considered successful. The value 0 indicates no timeout.
''; '';
}; };
@ -252,14 +285,30 @@ in
# set it ourselves in that case. # set it ourselves in that case.
home.activation.reloadSystemd = hm.dag.entryAfter ["linkGeneration"] ( home.activation.reloadSystemd = hm.dag.entryAfter ["linkGeneration"] (
let let
autoReloadCmd = '' cmd = {
${pkgs.ruby}/bin/ruby ${./systemd-activate.rb} \ suggest = ''
"''${oldGenPath=}" "$newGenPath" "${servicesStartTimeoutMs}" PATH=${dirOf cfg.systemctlPath}:$PATH \
''; bash ${./systemd-activate.sh} "''${oldGenPath=}" "$newGenPath"
'';
legacyReloadCmd = '' legacy = ''
bash ${./systemd-activate.sh} "''${oldGenPath=}" "$newGenPath" PATH=${dirOf cfg.systemctlPath}:$PATH \
''; ${pkgs.ruby}/bin/ruby ${./systemd-activate.rb} \
"''${oldGenPath=}" "$newGenPath" "${servicesStartTimeoutMs}"
'';
sd-switch =
let
timeoutArg =
if cfg.servicesStartTimeoutMs != 0 then
"--timeout " + servicesStartTimeoutMs
else
"";
in ''
${pkgs.sd-switch}/bin/sd-switch \
''${DRY_RUN:+--dry-run} $VERBOSE_ARG ${timeoutArg} \
''${oldGenPath:+--old-units $oldGenPath/home-files/.config/systemd/user} \
--new-units $newGenPath/home-files/.config/systemd/user
'';
};
ensureRuntimeDir = "XDG_RUNTIME_DIR=\${XDG_RUNTIME_DIR:-/run/user/$(id -u)}"; ensureRuntimeDir = "XDG_RUNTIME_DIR=\${XDG_RUNTIME_DIR:-/run/user/$(id -u)}";
@ -276,8 +325,7 @@ in
fi fi
${ensureRuntimeDir} \ ${ensureRuntimeDir} \
PATH=${dirOf cfg.systemctlPath}:$PATH \ ${getAttr cfg.startServices cmd}
${if cfg.startServices then autoReloadCmd else legacyReloadCmd}
else else
echo "User systemd daemon not running. Skipping reload." echo "User systemd daemon not running. Skipping reload."
fi fi