diff --git a/nixos/modules/services/backup/restic.nix b/nixos/modules/services/backup/restic.nix index 2388f1d6ca1..c38fd361d35 100644 --- a/nixos/modules/services/backup/restic.nix +++ b/nixos/modules/services/backup/restic.nix @@ -31,6 +31,59 @@ in ''; }; + rcloneOptions = mkOption { + type = with types; nullOr (attrsOf (oneOf [ str bool ])); + default = null; + description = '' + Options to pass to rclone to control its behavior. + See for + available options. When specifying option names, strip the + leading --. To set a flag such as + --drive-use-trash, which does not take a value, + set the value to the Boolean true. + ''; + example = { + bwlimit = "10M"; + drive-use-trash = "true"; + }; + }; + + rcloneConfig = mkOption { + type = with types; nullOr (attrsOf (oneOf [ str bool ])); + default = null; + description = '' + Configuration for the rclone remote being used for backup. + See the remote's specific options under rclone's docs at + . When specifying + option names, use the "config" name specified in the docs. + For example, to set --b2-hard-delete for a B2 + remote, use hard_delete = true in the + attribute set. + Warning: Secrets set in here will be world-readable in the Nix + store! Consider using the rcloneConfigFile + option instead to specify secret values separately. Note that + options set here will override those set in the config file. + ''; + example = { + type = "b2"; + account = "xxx"; + key = "xxx"; + hard_delete = true; + }; + }; + + rcloneConfigFile = mkOption { + type = with types; nullOr path; + default = null; + description = '' + Path to the file containing rclone configuration. This file + must contain configuration for the remote specified in this backup + set and also must be readable by root. Options set in + rcloneConfig will override those set in this + file. + ''; + }; + repository = mkOption { type = types.str; description = '' @@ -170,11 +223,22 @@ in ( resticCmd + " forget --prune " + (concatStringsSep " " backup.pruneOpts) ) ( resticCmd + " check" ) ]; + # Helper functions for rclone remotes + rcloneRemoteName = builtins.elemAt (splitString ":" backup.repository) 1; + rcloneAttrToOpt = v: "RCLONE_" + toUpper (builtins.replaceStrings [ "-" ] [ "_" ] v); + rcloneAttrToConf = v: "RCLONE_CONFIG_" + toUpper (rcloneRemoteName + "_" + v); + toRcloneVal = v: if lib.isBool v then lib.boolToString v else v; in nameValuePair "restic-backups-${name}" ({ environment = { RESTIC_PASSWORD_FILE = backup.passwordFile; RESTIC_REPOSITORY = backup.repository; - }; + } // optionalAttrs (backup.rcloneOptions != null) (mapAttrs' (name: value: + nameValuePair (rcloneAttrToOpt name) (toRcloneVal value) + ) backup.rcloneOptions) // optionalAttrs (backup.rcloneConfigFile != null) { + RCLONE_CONFIG = backup.rcloneConfigFile; + } // optionalAttrs (backup.rcloneConfig != null) (mapAttrs' (name: value: + nameValuePair (rcloneAttrToConf name) (toRcloneVal value) + ) backup.rcloneConfig); path = [ pkgs.openssh ]; restartIfChanged = false; serviceConfig = {