diff options
Diffstat (limited to 'nixos/modules/services/misc/snapper.nix')
-rw-r--r-- | nixos/modules/services/misc/snapper.nix | 305 |
1 files changed, 204 insertions, 101 deletions
diff --git a/nixos/modules/services/misc/snapper.nix b/nixos/modules/services/misc/snapper.nix index 3a3ed1b5c0f56..1b16ef7958ad2 100644 --- a/nixos/modules/services/misc/snapper.nix +++ b/nixos/modules/services/misc/snapper.nix @@ -1,16 +1,32 @@ -{ config, pkgs, lib, ... }: +{ + config, + pkgs, + lib, + ... +}: with lib; let cfg = config.services.snapper; - mkValue = v: - if isList v then "\"${concatMapStringsSep " " (escape [ "\\" " " ]) v}\"" - else if v == true then "yes" - else if v == false then "no" - else if isString v then "\"${v}\"" - else builtins.toJSON v; + mkValue = + v: + if isList v then + "\"${ + concatMapStringsSep " " (escape [ + "\\" + " " + ]) v + }\"" + else if v == true then + "yes" + else if v == false then + "no" + else if isString v then + "\"${v}\"" + else + builtins.toJSON v; mkKeyValue = k: v: "${k}=${mkValue v}"; @@ -43,7 +59,7 @@ let ALLOW_GROUPS = mkOption { type = types.listOf safeStr; - default = []; + default = [ ]; description = '' List of groups allowed to operate with the config. @@ -53,7 +69,7 @@ let ALLOW_USERS = mkOption { type = types.listOf safeStr; - default = []; + default = [ ]; example = [ "alice" ]; description = '' List of users allowed to operate with the config. "root" is always @@ -78,6 +94,54 @@ let Defines whether hourly snapshots should be created. ''; }; + + TIMELINE_LIMIT_HOURLY = mkOption { + type = types.str; + default = "10"; + description = '' + Limits for timeline cleanup. + ''; + }; + + TIMELINE_LIMIT_DAILY = mkOption { + type = types.str; + default = "10"; + description = '' + Limits for timeline cleanup. + ''; + }; + + TIMELINE_LIMIT_WEEKLY = mkOption { + type = types.str; + default = "0"; + description = '' + Limits for timeline cleanup. + ''; + }; + + TIMELINE_LIMIT_MONTHLY = mkOption { + type = types.str; + default = "10"; + description = '' + Limits for timeline cleanup. + ''; + }; + + TIMELINE_LIMIT_QUARTERLY = mkOption { + type = types.str; + default = "0"; + description = '' + Limits for timeline cleanup. + ''; + }; + + TIMELINE_LIMIT_YEARLY = mkOption { + type = types.str; + default = "10"; + description = '' + Limits for timeline cleanup. + ''; + }; }; in @@ -103,6 +167,18 @@ in ''; }; + persistentTimer = mkOption { + default = false; + type = types.bool; + example = true; + description = '' + Set the `Persistent` option for the + {manpage}`systemd.timer(5)` + which triggers the snapshot immediately if the last trigger + was missed (e.g. if the system was powered down). + ''; + }; + cleanupInterval = mkOption { type = types.str; default = "1d"; @@ -140,105 +216,129 @@ in is valid here, even if NixOS doesn't document it. ''; - type = types.attrsOf (types.submodule { - freeformType = types.attrsOf (types.oneOf [ (types.listOf safeStr) types.bool safeStr types.number ]); - - options = configOptions; - }); + type = types.attrsOf ( + types.submodule { + freeformType = types.attrsOf ( + types.oneOf [ + (types.listOf safeStr) + types.bool + safeStr + types.number + ] + ); + + options = configOptions; + } + ); }; }; - config = mkIf (cfg.configs != {}) (let - documentation = [ "man:snapper(8)" "man:snapper-configs(5)" ]; - in { - - environment = { - - systemPackages = [ pkgs.snapper ]; - - # Note: snapper/config-templates/default is only needed for create-config - # which is not the NixOS way to configure. - etc = { - - "sysconfig/snapper".text = '' - SNAPPER_CONFIGS="${lib.concatStringsSep " " (builtins.attrNames cfg.configs)}" - ''; - - } - // (mapAttrs' (name: subvolume: nameValuePair "snapper/configs/${name}" ({ - text = lib.generators.toKeyValue { inherit mkKeyValue; } (filterAttrs (k: v: v != defaultOf k) subvolume); - })) cfg.configs) - // (lib.optionalAttrs (cfg.filters != null) { - "snapper/filters/default.txt".text = cfg.filters; - }); - - }; + config = mkIf (cfg.configs != { }) ( + let + documentation = [ + "man:snapper(8)" + "man:snapper-configs(5)" + ]; + in + { + environment = { + + systemPackages = [ pkgs.snapper ]; + + # Note: snapper/config-templates/default is only needed for create-config + # which is not the NixOS way to configure. + etc = + { + + "sysconfig/snapper".text = '' + SNAPPER_CONFIGS="${lib.concatStringsSep " " (builtins.attrNames cfg.configs)}" + ''; + } + // (mapAttrs' ( + name: subvolume: + nameValuePair "snapper/configs/${name}" ({ + text = lib.generators.toKeyValue { inherit mkKeyValue; } ( + filterAttrs (k: v: v != defaultOf k) subvolume + ); + }) + ) cfg.configs) + // (lib.optionalAttrs (cfg.filters != null) { "snapper/filters/default.txt".text = cfg.filters; }); + }; - services.dbus.packages = [ pkgs.snapper ]; + services.dbus.packages = [ pkgs.snapper ]; + + systemd.services.snapperd = { + description = "DBus interface for snapper"; + inherit documentation; + serviceConfig = { + Type = "dbus"; + BusName = "org.opensuse.Snapper"; + ExecStart = "${pkgs.snapper}/bin/snapperd"; + CapabilityBoundingSet = "CAP_DAC_OVERRIDE CAP_FOWNER CAP_CHOWN CAP_FSETID CAP_SETFCAP CAP_SYS_ADMIN CAP_SYS_MODULE CAP_IPC_LOCK CAP_SYS_NICE"; + LockPersonality = true; + NoNewPrivileges = false; + PrivateNetwork = true; + ProtectHostname = true; + RestrictAddressFamilies = "AF_UNIX"; + RestrictRealtime = true; + }; + }; - systemd.services.snapperd = { - description = "DBus interface for snapper"; - inherit documentation; - serviceConfig = { - Type = "dbus"; - BusName = "org.opensuse.Snapper"; - ExecStart = "${pkgs.snapper}/bin/snapperd"; - CapabilityBoundingSet = "CAP_DAC_OVERRIDE CAP_FOWNER CAP_CHOWN CAP_FSETID CAP_SETFCAP CAP_SYS_ADMIN CAP_SYS_MODULE CAP_IPC_LOCK CAP_SYS_NICE"; - LockPersonality = true; - NoNewPrivileges = false; - PrivateNetwork = true; - ProtectHostname = true; - RestrictAddressFamilies = "AF_UNIX"; - RestrictRealtime = true; + systemd.services.snapper-timeline = { + description = "Timeline of Snapper Snapshots"; + inherit documentation; + requires = [ "local-fs.target" ]; + serviceConfig.ExecStart = "${pkgs.snapper}/lib/snapper/systemd-helper --timeline"; }; - }; - systemd.services.snapper-timeline = { - description = "Timeline of Snapper Snapshots"; - inherit documentation; - requires = [ "local-fs.target" ]; - serviceConfig.ExecStart = "${pkgs.snapper}/lib/snapper/systemd-helper --timeline"; - startAt = cfg.snapshotInterval; - }; + systemd.timers.snapper-timeline = { + wantedBy = [ "timers.target" ]; + timerConfig = { + Persistent = cfg.persistentTimer; + OnCalendar = cfg.snapshotInterval; + }; + }; - systemd.services.snapper-cleanup = { - description = "Cleanup of Snapper Snapshots"; - inherit documentation; - serviceConfig.ExecStart = "${pkgs.snapper}/lib/snapper/systemd-helper --cleanup"; - }; + systemd.services.snapper-cleanup = { + description = "Cleanup of Snapper Snapshots"; + inherit documentation; + serviceConfig.ExecStart = "${pkgs.snapper}/lib/snapper/systemd-helper --cleanup"; + }; - systemd.timers.snapper-cleanup = { - description = "Cleanup of Snapper Snapshots"; - inherit documentation; - wantedBy = [ "timers.target" ]; - requires = [ "local-fs.target" ]; - timerConfig.OnBootSec = "10m"; - timerConfig.OnUnitActiveSec = cfg.cleanupInterval; - }; + systemd.timers.snapper-cleanup = { + description = "Cleanup of Snapper Snapshots"; + inherit documentation; + wantedBy = [ "timers.target" ]; + requires = [ "local-fs.target" ]; + timerConfig.OnBootSec = "10m"; + timerConfig.OnUnitActiveSec = cfg.cleanupInterval; + }; - systemd.services.snapper-boot = lib.optionalAttrs cfg.snapshotRootOnBoot { - description = "Take snapper snapshot of root on boot"; - inherit documentation; - serviceConfig.ExecStart = "${pkgs.snapper}/bin/snapper --config root create --cleanup-algorithm number --description boot"; - serviceConfig.Type = "oneshot"; - requires = [ "local-fs.target" ]; - wantedBy = [ "multi-user.target" ]; - unitConfig.ConditionPathExists = "/etc/snapper/configs/root"; - }; + systemd.services.snapper-boot = lib.mkIf cfg.snapshotRootOnBoot { + description = "Take snapper snapshot of root on boot"; + inherit documentation; + serviceConfig.ExecStart = "${pkgs.snapper}/bin/snapper --config root create --cleanup-algorithm number --description boot"; + serviceConfig.Type = "oneshot"; + requires = [ "local-fs.target" ]; + wantedBy = [ "multi-user.target" ]; + unitConfig.ConditionPathExists = "/etc/snapper/configs/root"; + }; - assertions = - concatMap - (name: - let - sub = cfg.configs.${name}; - in - [ { assertion = !(sub ? extraConfig); - message = '' - The option definition `services.snapper.configs.${name}.extraConfig' no longer has any effect; please remove it. - The contents of this option should be migrated to attributes on `services.snapper.configs.${name}'. - ''; - } - ] ++ + assertions = concatMap ( + name: + let + sub = cfg.configs.${name}; + in + [ + { + assertion = !(sub ? extraConfig); + message = '' + The option definition `services.snapper.configs.${name}.extraConfig' no longer has any effect; please remove it. + The contents of this option should be migrated to attributes on `services.snapper.configs.${name}'. + ''; + } + ] + ++ map (attr: { assertion = !(hasAttr attr sub); @@ -246,8 +346,11 @@ in The option definition `services.snapper.configs.${name}.${attr}' has been renamed to `services.snapper.configs.${name}.${toUpper attr}'. ''; }) - [ "fstype" "subvolume" ] - ) - (attrNames cfg.configs); - }); + [ + "fstype" + "subvolume" + ] + ) (attrNames cfg.configs); + } + ); } |