Unverified Commit 872c89e5 authored by Sandro Jäckel's avatar Sandro Jäckel Committed by GitHub
Browse files

Merge pull request #221750 from rhendric/rhendric/nixos/snapper

parents 15aead1d 43e6f67f
Loading
Loading
Loading
Loading
+20 −0
Original line number Diff line number Diff line
@@ -197,6 +197,26 @@ In addition to numerous new and upgraded packages, this release has the followin

- `services.sourcehut.dispatch` and the corresponding package (`sourcehut.dispatchsrht`) have been removed due to [upstream deprecation](https://sourcehut.org/blog/2022-08-01-dispatch-deprecation-plans/).

- The attributes used by `services.snapper.configs.<name>` have changed. Migrate from this:

  ```nix
  services.snapper.configs.example = {
    subvolume = "/example";
    extraConfig = ''
      ALLOW_USERS="alice"
    '';
  };
  ```

  to this:

  ```nix
  services.snapper.configs.example = {
    SUBVOLUME = "/example";
    ALLOW_USERS = [ "alice" ];
  };
  ```

- The [services.snapserver.openFirewall](#opt-services.snapserver.openFirewall) module option default value has been changed from `true` to `false`. You will need to explicitly set this option to `true`, or configure your firewall.

- The [services.tmate-ssh-server.openFirewall](#opt-services.tmate-ssh-server.openFirewall) module option default value has been changed from `true` to `false`. You will need to explicitly set this option to `true`, or configure your firewall.
+107 −39
Original line number Diff line number Diff line
@@ -4,6 +4,81 @@ 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;

  mkKeyValue = k: v: "${k}=${mkValue v}";

  # "it's recommended to always specify the filesystem type"  -- man snapper-configs
  defaultOf = k: if k == "FSTYPE" then null else configOptions.${k}.default or null;

  safeStr = types.strMatching "[^\n\"]*" // {
    description = "string without line breaks or quotes";
    descriptionClass = "conjunction";
  };

  configOptions = {
    SUBVOLUME = mkOption {
      type = types.path;
      description = lib.mdDoc ''
        Path of the subvolume or mount point.
        This path is a subvolume and has to contain a subvolume named
        .snapshots.
        See also man:snapper(8) section PERMISSIONS.
      '';
    };

    FSTYPE = mkOption {
      type = types.enum [ "btrfs" ];
      default = "btrfs";
      description = lib.mdDoc ''
        Filesystem type. Only btrfs is stable and tested.
      '';
    };

    ALLOW_GROUPS = mkOption {
      type = types.listOf safeStr;
      default = [];
      description = lib.mdDoc ''
        List of groups allowed to operate with the config.

        Also see the PERMISSIONS section in man:snapper(8).
      '';
    };

    ALLOW_USERS = mkOption {
      type = types.listOf safeStr;
      default = [];
      example = [ "alice" ];
      description = lib.mdDoc ''
        List of users allowed to operate with the config. "root" is always
        implicitly included.

        Also see the PERMISSIONS section in man:snapper(8).
      '';
    };

    TIMELINE_CLEANUP = mkOption {
      type = types.bool;
      default = false;
      description = lib.mdDoc ''
        Defines whether the timeline cleanup algorithm should be run for the config.
      '';
    };

    TIMELINE_CREATE = mkOption {
      type = types.bool;
      default = false;
      description = lib.mdDoc ''
        Defines whether hourly snapshots should be created.
      '';
    };
  };
in

{
@@ -52,49 +127,23 @@ in
      example = literalExpression ''
        {
          home = {
            subvolume = "/home";
            extraConfig = '''
              ALLOW_USERS="alice"
              TIMELINE_CREATE=yes
              TIMELINE_CLEANUP=yes
            ''';
            SUBVOLUME = "/home";
            ALLOW_USERS = [ "alice" ];
            TIMELINE_CREATE = true;
            TIMELINE_CLEANUP = true;
          };
        }
      '';

      description = lib.mdDoc ''
        Subvolume configuration
        Subvolume configuration. Any option mentioned in man:snapper-configs(5)
        is valid here, even if NixOS doesn't document it.
      '';

      type = types.attrsOf (types.submodule {
        options = {
          subvolume = mkOption {
            type = types.path;
            description = lib.mdDoc ''
              Path of the subvolume or mount point.
              This path is a subvolume and has to contain a subvolume named
              .snapshots.
              See also man:snapper(8) section PERMISSIONS.
            '';
          };
        freeformType = types.attrsOf (types.oneOf [ (types.listOf safeStr) types.bool safeStr types.number ]);

          fstype = mkOption {
            type = types.enum [ "btrfs" ];
            default = "btrfs";
            description = lib.mdDoc ''
              Filesystem type. Only btrfs is stable and tested.
            '';
          };

          extraConfig = mkOption {
            type = types.lines;
            default = "";
            description = lib.mdDoc ''
              Additional configuration next to SUBVOLUME and FSTYPE.
              See man:snapper-configs(5).
            '';
          };
        };
        options = configOptions;
      });
    };
  };
@@ -117,11 +166,7 @@ in

      }
      // (mapAttrs' (name: subvolume: nameValuePair "snapper/configs/${name}" ({
        text = ''
          ${subvolume.extraConfig}
          FSTYPE="${subvolume.fstype}"
          SUBVOLUME="${subvolume.subvolume}"
        '';
        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;
@@ -181,5 +226,28 @@ in
      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}'.
              '';
            }
          ] ++
          map
            (attr: {
              assertion = !(hasAttr attr sub);
              message = ''
                The option definition `services.snapper.configs.${name}.${attr}' has been renamed to `services.snapper.configs.${name}.${toUpper attr}'.
              '';
            })
            [ "fstype" "subvolume" ]
        )
        (attrNames cfg.configs);
  });
}