forked from
lass.pds.lassul.us/superconfig
This repository has no description
3.1 kB
84 lines
1{
2 config,
3 lib,
4 pkgs,
5 ...
6}:
7let
8 flake = "github:lassulus/superconfig";
9
10 # The revision the guard checked; the upgrade is pinned to it, so the
11 # revision recorded afterwards is the one actually switched to.
12 revFile = "/run/nixos-upgrade/rev";
13
14 # system.autoUpgrade switches to whatever the flake currently evaluates to,
15 # forwards or backwards. A machine deployed from an unpushed local checkout
16 # therefore gets reverted to the older remote HEAD on the next timer run.
17 # Refuse to move backwards in time: only upgrade to a revision committed
18 # after the running system was deployed. The deploy time is when its profile
19 # generation was created (/run/current-system's mtime if no generation points
20 # at it); the source's own lastModified is no use, since `clan machines
21 # update` builds from a path: flake, which has none.
22 guard = pkgs.writeShellApplication {
23 name = "autoupgrade-forward-only";
24 runtimeInputs = [
25 config.nix.package
26 pkgs.coreutils
27 pkgs.jq
28 ];
29 text = ''
30 system=$(readlink -f /run/current-system)
31 deployed=0
32 for link in /nix/var/nix/profiles/system-*-link; do
33 if [ "$(readlink -f "$link")" = "$system" ]; then
34 created=$(stat -c %Y "$link")
35 if [ "$created" -gt "$deployed" ]; then deployed=$created; fi
36 fi
37 done
38 if [ "$deployed" -eq 0 ]; then deployed=$(stat -c %Y /run/current-system); fi
39 if ! meta=$(nix flake metadata --refresh --json ${lib.escapeShellArg flake}); then
40 echo "autoupgrade: nix flake metadata ${flake} failed; upgrading unpinned and letting nixos-upgrade report any error"
41 exit 0
42 fi
43 remote=$(jq -r '.lastModified // 0' <<<"$meta")
44 if [ "$remote" -gt "$deployed" ]; then
45 jq -r .revision <<<"$meta" >${revFile}
46 exit 0
47 fi
48 echo "autoupgrade: ${flake} is at $remote, running system was deployed at $deployed; skipping"
49 exit 1
50 '';
51 };
52in
53{
54 system.autoUpgrade = {
55 enable = true;
56 # Goes into the nixos-upgrade script unquoted, so the shell expands the
57 # pinned revision. Without a rev file (guard could not read the flake)
58 # the ref stays unpinned and the recorded revision becomes unknown.
59 flake = "${flake}/$(cat ${revFile} 2>/dev/null)";
60 randomizedDelaySec = "6h";
61 };
62
63 # Containers get the host's nix db read-only; go through the daemon socket.
64 systemd.services.nixos-upgrade.environment = lib.mkIf config.boot.isContainer {
65 NIX_REMOTE = "daemon";
66 };
67
68 systemd.services.nixos-upgrade.serviceConfig = {
69 RuntimeDirectory = "nixos-upgrade";
70 ExecCondition = lib.getExe guard;
71 # Only runs after a successful upgrade. Read by the monitoring agent.
72 ExecStartPost = lib.getExe (
73 pkgs.writeShellApplication {
74 name = "autoupgrade-record-revision";
75 runtimeInputs = [ pkgs.coreutils ];
76 text = ''
77 rev=$(cat ${revFile} 2>/dev/null || echo unknown)
78 echo "$rev" >/var/lib/superconfig-revision.tmp
79 mv /var/lib/superconfig-revision.tmp /var/lib/superconfig-revision
80 '';
81 }
82 );
83 };
84}