python3Packages.orjson: Disable failing tests on 32 bit
[NixPkgs.git] / nixos / modules / services / misc / snapper.nix
blobcfdfa2830ce955a014d610cd5428652fa6d5e6b2
1 { config, pkgs, lib, ... }:
3 with lib;
5 let
6   cfg = config.services.snapper;
7 in
10   options.services.snapper = {
12     snapshotRootOnBoot = mkOption {
13       type = types.bool;
14       default = false;
15       description = lib.mdDoc ''
16         Whether to snapshot root on boot
17       '';
18     };
20     snapshotInterval = mkOption {
21       type = types.str;
22       default = "hourly";
23       description = lib.mdDoc ''
24         Snapshot interval.
26         The format is described in
27         {manpage}`systemd.time(7)`.
28       '';
29     };
31     cleanupInterval = mkOption {
32       type = types.str;
33       default = "1d";
34       description = lib.mdDoc ''
35         Cleanup interval.
37         The format is described in
38         {manpage}`systemd.time(7)`.
39       '';
40     };
42     filters = mkOption {
43       type = types.nullOr types.lines;
44       default = null;
45       description = lib.mdDoc ''
46         Global display difference filter. See man:snapper(8) for more details.
47       '';
48     };
50     configs = mkOption {
51       default = { };
52       example = literalExpression ''
53         {
54           home = {
55             subvolume = "/home";
56             extraConfig = '''
57               ALLOW_USERS="alice"
58               TIMELINE_CREATE=yes
59               TIMELINE_CLEANUP=yes
60             ''';
61           };
62         }
63       '';
65       description = lib.mdDoc ''
66         Subvolume configuration
67       '';
69       type = types.attrsOf (types.submodule {
70         options = {
71           subvolume = mkOption {
72             type = types.path;
73             description = lib.mdDoc ''
74               Path of the subvolume or mount point.
75               This path is a subvolume and has to contain a subvolume named
76               .snapshots.
77               See also man:snapper(8) section PERMISSIONS.
78             '';
79           };
81           fstype = mkOption {
82             type = types.enum [ "btrfs" ];
83             default = "btrfs";
84             description = lib.mdDoc ''
85               Filesystem type. Only btrfs is stable and tested.
86             '';
87           };
89           extraConfig = mkOption {
90             type = types.lines;
91             default = "";
92             description = lib.mdDoc ''
93               Additional configuration next to SUBVOLUME and FSTYPE.
94               See man:snapper-configs(5).
95             '';
96           };
97         };
98       });
99     };
100   };
102   config = mkIf (cfg.configs != {}) (let
103     documentation = [ "man:snapper(8)" "man:snapper-configs(5)" ];
104   in {
106     environment = {
108       systemPackages = [ pkgs.snapper ];
110       # Note: snapper/config-templates/default is only needed for create-config
111       #       which is not the NixOS way to configure.
112       etc = {
114         "sysconfig/snapper".text = ''
115           SNAPPER_CONFIGS="${lib.concatStringsSep " " (builtins.attrNames cfg.configs)}"
116         '';
118       }
119       // (mapAttrs' (name: subvolume: nameValuePair "snapper/configs/${name}" ({
120         text = ''
121           ${subvolume.extraConfig}
122           FSTYPE="${subvolume.fstype}"
123           SUBVOLUME="${subvolume.subvolume}"
124         '';
125       })) cfg.configs)
126       // (lib.optionalAttrs (cfg.filters != null) {
127         "snapper/filters/default.txt".text = cfg.filters;
128       });
130     };
132     services.dbus.packages = [ pkgs.snapper ];
134     systemd.services.snapperd = {
135       description = "DBus interface for snapper";
136       inherit documentation;
137       serviceConfig = {
138         Type = "dbus";
139         BusName = "org.opensuse.Snapper";
140         ExecStart = "${pkgs.snapper}/bin/snapperd";
141         CapabilityBoundingSet = "CAP_DAC_OVERRIDE CAP_FOWNER CAP_CHOWN CAP_FSETID CAP_SETFCAP CAP_SYS_ADMIN CAP_SYS_MODULE CAP_IPC_LOCK CAP_SYS_NICE";
142         LockPersonality = true;
143         NoNewPrivileges = false;
144         PrivateNetwork = true;
145         ProtectHostname = true;
146         RestrictAddressFamilies = "AF_UNIX";
147         RestrictRealtime = true;
148       };
149     };
151     systemd.services.snapper-timeline = {
152       description = "Timeline of Snapper Snapshots";
153       inherit documentation;
154       requires = [ "local-fs.target" ];
155       serviceConfig.ExecStart = "${pkgs.snapper}/lib/snapper/systemd-helper --timeline";
156       startAt = cfg.snapshotInterval;
157     };
159     systemd.services.snapper-cleanup = {
160       description = "Cleanup of Snapper Snapshots";
161       inherit documentation;
162       serviceConfig.ExecStart = "${pkgs.snapper}/lib/snapper/systemd-helper --cleanup";
163     };
165     systemd.timers.snapper-cleanup = {
166       description = "Cleanup of Snapper Snapshots";
167       inherit documentation;
168       wantedBy = [ "timers.target" ];
169       requires = [ "local-fs.target" ];
170       timerConfig.OnBootSec = "10m";
171       timerConfig.OnUnitActiveSec = cfg.cleanupInterval;
172     };
174     systemd.services.snapper-boot = lib.optionalAttrs cfg.snapshotRootOnBoot {
175       description = "Take snapper snapshot of root on boot";
176       inherit documentation;
177       serviceConfig.ExecStart = "${pkgs.snapper}/bin/snapper --config root create --cleanup-algorithm number --description boot";
178       serviceConfig.type = "oneshot";
179       requires = [ "local-fs.target" ];
180       wantedBy = [ "multi-user.target" ];
181       unitConfig.ConditionPathExists = "/etc/snapper/configs/root";
182     };
184   });