at 23.05-pre 5.2 kB view raw
1{ config, pkgs, lib, ... }: 2 3with lib; 4 5let 6 cfg = config.services.snapper; 7in 8 9{ 10 options.services.snapper = { 11 12 snapshotRootOnBoot = mkOption { 13 type = types.bool; 14 default = false; 15 description = lib.mdDoc '' 16 Whether to snapshot root on boot 17 ''; 18 }; 19 20 snapshotInterval = mkOption { 21 type = types.str; 22 default = "hourly"; 23 description = lib.mdDoc '' 24 Snapshot interval. 25 26 The format is described in 27 {manpage}`systemd.time(7)`. 28 ''; 29 }; 30 31 cleanupInterval = mkOption { 32 type = types.str; 33 default = "1d"; 34 description = lib.mdDoc '' 35 Cleanup interval. 36 37 The format is described in 38 {manpage}`systemd.time(7)`. 39 ''; 40 }; 41 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 }; 49 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 ''; 64 65 description = lib.mdDoc '' 66 Subvolume configuration 67 ''; 68 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 }; 80 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 }; 88 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 }; 101 102 config = mkIf (cfg.configs != {}) (let 103 documentation = [ "man:snapper(8)" "man:snapper-configs(5)" ]; 104 in { 105 106 environment = { 107 108 systemPackages = [ pkgs.snapper ]; 109 110 # Note: snapper/config-templates/default is only needed for create-config 111 # which is not the NixOS way to configure. 112 etc = { 113 114 "sysconfig/snapper".text = '' 115 SNAPPER_CONFIGS="${lib.concatStringsSep " " (builtins.attrNames cfg.configs)}" 116 ''; 117 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 }); 129 130 }; 131 132 services.dbus.packages = [ pkgs.snapper ]; 133 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 }; 150 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 }; 158 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 }; 164 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 }; 173 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 }; 183 184 }); 185}