1{
2 config,
3 lib,
4 pkgs,
5 utils,
6 ...
7}:
8
9let
10 cfg = config.systemd.sysupdate;
11
12 format = pkgs.formats.ini { listToValue = toString; };
13
14 # TODO: Switch back to using utils.systemdUtils.lib.definitions once
15 # https://github.com/systemd/systemd/pull/38187 is resolved. Also ensure
16 # utils.systemdUtils.lib.definitions is capable of setting a custom file
17 # suffix.
18 sysupdateTransfers = lib.mapAttrs' (name: value: {
19 name = "sysupdate.d/${name}.transfer";
20 value.source = format.generate "${name}.transfer" value;
21 }) cfg.transfers;
22in
23{
24 options.systemd.sysupdate = {
25
26 enable = lib.mkEnableOption "systemd-sysupdate" // {
27 description = ''
28 Atomically update the host OS, container images, portable service
29 images or other sources.
30
31 If enabled, updates are triggered in regular intervals via a
32 `systemd.timer` unit.
33
34 Please see {manpage}`systemd-sysupdate(8)` for more details.
35 '';
36 };
37
38 timerConfig = utils.systemdUtils.unitOptions.timerOptions.options.timerConfig // {
39 default = { };
40 description = ''
41 The timer configuration for performing the update.
42
43 By default, the upstream configuration is used:
44 <https://github.com/systemd/systemd/blob/main/units/systemd-sysupdate.timer>
45 '';
46 };
47
48 reboot = {
49 enable = lib.mkEnableOption "automatically rebooting after an update" // {
50 description = ''
51 Whether to automatically reboot after an update.
52
53 If set to `true`, the system will automatically reboot via a
54 `systemd.timer` unit but only after a new version was installed.
55
56 This uses a unit completely separate from the one performing the
57 update because it is typically advisable to download updates
58 regularly while the system is up, but delay reboots until the
59 appropriate time (i.e. typically at night).
60
61 Set this to `false` if you do not want to reboot after an update. This
62 is useful when you update a container image or another source where
63 rebooting is not necessary in order to finalize the update.
64 '';
65 };
66
67 timerConfig = utils.systemdUtils.unitOptions.timerOptions.options.timerConfig // {
68 default = { };
69 description = ''
70 The timer configuration for rebooting after an update.
71
72 By default, the upstream configuration is used:
73 <https://github.com/systemd/systemd/blob/main/units/systemd-sysupdate-reboot.timer>
74 '';
75 };
76 };
77
78 transfers = lib.mkOption {
79 type = with lib.types; attrsOf format.type;
80 default = { };
81 example = {
82 "10-uki" = {
83 Transfer = {
84 ProtectVersion = "%A";
85 };
86
87 Source = {
88 Type = "url-file";
89 Path = "https://download.example.com/";
90 MatchPattern = [
91 "nixos_@v+@l-@d.efi"
92 "nixos_@v+@l.efi"
93 "nixos_@v.efi"
94 ];
95 };
96
97 Target = {
98 Type = "regular-file";
99 Path = "/EFI/Linux";
100 PathRelativeTo = "boot";
101 MatchPattern = ''
102 nixos_@v+@l-@d.efi"; \
103 nixos_@v+@l.efi \
104 nixos_@v.efi
105 '';
106 Mode = "0444";
107 TriesLeft = 3;
108 TriesDone = 0;
109 InstancesMax = 2;
110 };
111 };
112 };
113 description = ''
114 Specify transfers as a set of the names of the transfer files as the
115 key and the configuration as its value. The configuration can use all
116 upstream options. See {manpage}`sysupdate.d(5)`
117 for all available options.
118 '';
119 };
120
121 };
122
123 config = lib.mkIf cfg.enable {
124 assertions = [
125 {
126 assertion = config.systemd.package.withSysupdate;
127 message = "Cannot enable systemd-sysupdate with systemd package not built with sysupdate support";
128 }
129 ];
130
131 systemd.additionalUpstreamSystemUnits = [
132 "systemd-sysupdate.service"
133 "systemd-sysupdate.timer"
134 "systemd-sysupdate-reboot.service"
135 "systemd-sysupdate-reboot.timer"
136 "systemd-sysupdated.service"
137 ];
138
139 systemd.services.systemd-sysupdated.aliases = [ "dbus-org.freedesktop.sysupdate1.service" ];
140
141 systemd.timers = {
142 "systemd-sysupdate" = {
143 wantedBy = [ "timers.target" ];
144 timerConfig = cfg.timerConfig;
145 };
146 "systemd-sysupdate-reboot" = lib.mkIf cfg.reboot.enable {
147 wantedBy = [ "timers.target" ];
148 timerConfig = cfg.reboot.timerConfig;
149 };
150 };
151
152 environment.etc = sysupdateTransfers;
153 };
154
155 meta.maintainers = with lib.maintainers; [
156 nikstur
157 jmbaur
158 ];
159}