142 lines
		
	
	
		
			4.4 KiB
		
	
	
	
		
			Nix
		
	
	
	
	
	
		
		
			
		
	
	
			142 lines
		
	
	
		
			4.4 KiB
		
	
	
	
		
			Nix
		
	
	
	
	
	
| 
								 | 
							
								{ config, lib, pkgs, ...}:
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								with lib;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								let
							 | 
						||
| 
								 | 
							
								  cfg = config.services.duplicity;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  stateDirectory = "/var/lib/duplicity";
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  localTarget = if hasPrefix "file://" cfg.targetUrl
							 | 
						||
| 
								 | 
							
								    then removePrefix "file://" cfg.targetUrl else null;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								in {
							 | 
						||
| 
								 | 
							
								  options.services.duplicity = {
							 | 
						||
| 
								 | 
							
								    enable = mkEnableOption "backups with duplicity";
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    root = mkOption {
							 | 
						||
| 
								 | 
							
								      type = types.path;
							 | 
						||
| 
								 | 
							
								      default = "/";
							 | 
						||
| 
								 | 
							
								      description = ''
							 | 
						||
| 
								 | 
							
								        Root directory to backup.
							 | 
						||
| 
								 | 
							
								      '';
							 | 
						||
| 
								 | 
							
								    };
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    include = mkOption {
							 | 
						||
| 
								 | 
							
								      type = types.listOf types.str;
							 | 
						||
| 
								 | 
							
								      default = [];
							 | 
						||
| 
								 | 
							
								      example = [ "/home" ];
							 | 
						||
| 
								 | 
							
								      description = ''
							 | 
						||
| 
								 | 
							
								        List of paths to include into the backups. See the FILE SELECTION
							 | 
						||
| 
								 | 
							
								        section in <citerefentry><refentrytitle>duplicity</refentrytitle>
							 | 
						||
| 
								 | 
							
								        <manvolnum>1</manvolnum></citerefentry> for details on the syntax.
							 | 
						||
| 
								 | 
							
								      '';
							 | 
						||
| 
								 | 
							
								    };
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    exclude = mkOption {
							 | 
						||
| 
								 | 
							
								      type = types.listOf types.str;
							 | 
						||
| 
								 | 
							
								      default = [];
							 | 
						||
| 
								 | 
							
								      description = ''
							 | 
						||
| 
								 | 
							
								        List of paths to exclude from backups. See the FILE SELECTION section in
							 | 
						||
| 
								 | 
							
								        <citerefentry><refentrytitle>duplicity</refentrytitle>
							 | 
						||
| 
								 | 
							
								        <manvolnum>1</manvolnum></citerefentry> for details on the syntax.
							 | 
						||
| 
								 | 
							
								      '';
							 | 
						||
| 
								 | 
							
								    };
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    targetUrl = mkOption {
							 | 
						||
| 
								 | 
							
								      type = types.str;
							 | 
						||
| 
								 | 
							
								      example = "s3://host:port/prefix";
							 | 
						||
| 
								 | 
							
								      description = ''
							 | 
						||
| 
								 | 
							
								        Target url to backup to. See the URL FORMAT section in
							 | 
						||
| 
								 | 
							
								        <citerefentry><refentrytitle>duplicity</refentrytitle>
							 | 
						||
| 
								 | 
							
								        <manvolnum>1</manvolnum></citerefentry> for supported urls.
							 | 
						||
| 
								 | 
							
								      '';
							 | 
						||
| 
								 | 
							
								    };
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    secretFile = mkOption {
							 | 
						||
| 
								 | 
							
								      type = types.nullOr types.path;
							 | 
						||
| 
								 | 
							
								      default = null;
							 | 
						||
| 
								 | 
							
								      description = ''
							 | 
						||
| 
								 | 
							
								        Path of a file containing secrets (gpg passphrase, access key...) in
							 | 
						||
| 
								 | 
							
								        the format of EnvironmentFile as described by
							 | 
						||
| 
								 | 
							
								        <citerefentry><refentrytitle>systemd.exec</refentrytitle>
							 | 
						||
| 
								 | 
							
								        <manvolnum>5</manvolnum></citerefentry>. For example:
							 | 
						||
| 
								 | 
							
								        <programlisting>
							 | 
						||
| 
								 | 
							
								        PASSPHRASE=<replaceable>...</replaceable>
							 | 
						||
| 
								 | 
							
								        AWS_ACCESS_KEY_ID=<replaceable>...</replaceable>
							 | 
						||
| 
								 | 
							
								        AWS_SECRET_ACCESS_KEY=<replaceable>...</replaceable>
							 | 
						||
| 
								 | 
							
								        </programlisting>
							 | 
						||
| 
								 | 
							
								      '';
							 | 
						||
| 
								 | 
							
								    };
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    frequency = mkOption {
							 | 
						||
| 
								 | 
							
								      type = types.nullOr types.str;
							 | 
						||
| 
								 | 
							
								      default = "daily";
							 | 
						||
| 
								 | 
							
								      description = ''
							 | 
						||
| 
								 | 
							
								        Run duplicity with the given frequency (see
							 | 
						||
| 
								 | 
							
								        <citerefentry><refentrytitle>systemd.time</refentrytitle>
							 | 
						||
| 
								 | 
							
								        <manvolnum>7</manvolnum></citerefentry> for the format).
							 | 
						||
| 
								 | 
							
								        If null, do not run automatically.
							 | 
						||
| 
								 | 
							
								      '';
							 | 
						||
| 
								 | 
							
								    };
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    extraFlags = mkOption {
							 | 
						||
| 
								 | 
							
								      type = types.listOf types.str;
							 | 
						||
| 
								 | 
							
								      default = [];
							 | 
						||
| 
								 | 
							
								      example = [ "--full-if-older-than" "1M" ];
							 | 
						||
| 
								 | 
							
								      description = ''
							 | 
						||
| 
								 | 
							
								        Extra command-line flags passed to duplicity. See
							 | 
						||
| 
								 | 
							
								        <citerefentry><refentrytitle>duplicity</refentrytitle>
							 | 
						||
| 
								 | 
							
								        <manvolnum>1</manvolnum></citerefentry>.
							 | 
						||
| 
								 | 
							
								      '';
							 | 
						||
| 
								 | 
							
								    };
							 | 
						||
| 
								 | 
							
								  };
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  config = mkIf cfg.enable {
							 | 
						||
| 
								 | 
							
								    systemd = {
							 | 
						||
| 
								 | 
							
								      services.duplicity = {
							 | 
						||
| 
								 | 
							
								        description = "backup files with duplicity";
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        environment.HOME = stateDirectory;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        serviceConfig = {
							 | 
						||
| 
								 | 
							
								          ExecStart = ''
							 | 
						||
| 
								 | 
							
								            ${pkgs.duplicity}/bin/duplicity ${escapeShellArgs (
							 | 
						||
| 
								 | 
							
								              [
							 | 
						||
| 
								 | 
							
								                cfg.root
							 | 
						||
| 
								 | 
							
								                cfg.targetUrl
							 | 
						||
| 
								 | 
							
								                "--archive-dir" stateDirectory
							 | 
						||
| 
								 | 
							
								              ]
							 | 
						||
| 
								 | 
							
								              ++ concatMap (p: [ "--include" p ]) cfg.include
							 | 
						||
| 
								 | 
							
								              ++ concatMap (p: [ "--exclude" p ]) cfg.exclude
							 | 
						||
| 
								 | 
							
								              ++ cfg.extraFlags)}
							 | 
						||
| 
								 | 
							
								          '';
							 | 
						||
| 
								 | 
							
								          PrivateTmp = true;
							 | 
						||
| 
								 | 
							
								          ProtectSystem = "strict";
							 | 
						||
| 
								 | 
							
								          ProtectHome = "read-only";
							 | 
						||
| 
								 | 
							
								          StateDirectory = baseNameOf stateDirectory;
							 | 
						||
| 
								 | 
							
								        } // optionalAttrs (localTarget != null) {
							 | 
						||
| 
								 | 
							
								          ReadWritePaths = localTarget;
							 | 
						||
| 
								 | 
							
								        } // optionalAttrs (cfg.secretFile != null) {
							 | 
						||
| 
								 | 
							
								          EnvironmentFile = cfg.secretFile;
							 | 
						||
| 
								 | 
							
								        };
							 | 
						||
| 
								 | 
							
								      } // optionalAttrs (cfg.frequency != null) {
							 | 
						||
| 
								 | 
							
								        startAt = cfg.frequency;
							 | 
						||
| 
								 | 
							
								      };
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								      tmpfiles.rules = optional (localTarget != null) "d ${localTarget} 0700 root root -";
							 | 
						||
| 
								 | 
							
								    };
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    assertions = singleton {
							 | 
						||
| 
								 | 
							
								      # Duplicity will fail if the last file selection option is an include. It
							 | 
						||
| 
								 | 
							
								      # is not always possible to detect but this simple case can be caught.
							 | 
						||
| 
								 | 
							
								      assertion = cfg.include != [] -> cfg.exclude != [] || cfg.extraFlags != [];
							 | 
						||
| 
								 | 
							
								      message = ''
							 | 
						||
| 
								 | 
							
								        Duplicity will fail if you only specify included paths ("Because the
							 | 
						||
| 
								 | 
							
								        default is to include all files, the expression is redundant. Exiting
							 | 
						||
| 
								 | 
							
								        because this probably isn't what you meant.")
							 | 
						||
| 
								 | 
							
								      '';
							 | 
						||
| 
								 | 
							
								    };
							 | 
						||
| 
								 | 
							
								  };
							 | 
						||
| 
								 | 
							
								}
							 |