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