at 23.11-pre 5.4 kB view raw
1{ config, lib, pkgs, ... }: 2 3with lib; 4 5let 6 7 cfg = config.services.postgresqlBackup; 8 9 postgresqlBackupService = db: dumpCmd: 10 let 11 compressSuffixes = { 12 "none" = ""; 13 "gzip" = ".gz"; 14 "zstd" = ".zstd"; 15 }; 16 compressSuffix = getAttr cfg.compression compressSuffixes; 17 18 compressCmd = getAttr cfg.compression { 19 "none" = "cat"; 20 "gzip" = "${pkgs.gzip}/bin/gzip -c -${toString cfg.compressionLevel}"; 21 "zstd" = "${pkgs.zstd}/bin/zstd -c -${toString cfg.compressionLevel}"; 22 }; 23 24 mkSqlPath = prefix: suffix: "${cfg.location}/${db}${prefix}.sql${suffix}"; 25 curFile = mkSqlPath "" compressSuffix; 26 prevFile = mkSqlPath ".prev" compressSuffix; 27 prevFiles = map (mkSqlPath ".prev") (attrValues compressSuffixes); 28 inProgressFile = mkSqlPath ".in-progress" compressSuffix; 29 in { 30 enable = true; 31 32 description = "Backup of ${db} database(s)"; 33 34 requires = [ "postgresql.service" ]; 35 36 path = [ pkgs.coreutils config.services.postgresql.package ]; 37 38 script = '' 39 set -e -o pipefail 40 41 umask 0077 # ensure backup is only readable by postgres user 42 43 if [ -e ${curFile} ]; then 44 rm -f ${toString prevFiles} 45 mv ${curFile} ${prevFile} 46 fi 47 48 ${dumpCmd} \ 49 | ${compressCmd} \ 50 > ${inProgressFile} 51 52 mv ${inProgressFile} ${curFile} 53 ''; 54 55 serviceConfig = { 56 Type = "oneshot"; 57 User = "postgres"; 58 }; 59 60 startAt = cfg.startAt; 61 }; 62 63in { 64 65 imports = [ 66 (mkRemovedOptionModule [ "services" "postgresqlBackup" "period" ] '' 67 A systemd timer is now used instead of cron. 68 The starting time can be configured via <literal>services.postgresqlBackup.startAt</literal>. 69 '') 70 ]; 71 72 options = { 73 services.postgresqlBackup = { 74 enable = mkEnableOption (lib.mdDoc "PostgreSQL dumps"); 75 76 startAt = mkOption { 77 default = "*-*-* 01:15:00"; 78 type = with types; either (listOf str) str; 79 description = lib.mdDoc '' 80 This option defines (see `systemd.time` for format) when the 81 databases should be dumped. 82 The default is to update at 01:15 (at night) every day. 83 ''; 84 }; 85 86 backupAll = mkOption { 87 default = cfg.databases == []; 88 defaultText = literalExpression "services.postgresqlBackup.databases == []"; 89 type = lib.types.bool; 90 description = lib.mdDoc '' 91 Backup all databases using pg_dumpall. 92 This option is mutual exclusive to 93 `services.postgresqlBackup.databases`. 94 The resulting backup dump will have the name all.sql.gz. 95 This option is the default if no databases are specified. 96 ''; 97 }; 98 99 databases = mkOption { 100 default = []; 101 type = types.listOf types.str; 102 description = lib.mdDoc '' 103 List of database names to dump. 104 ''; 105 }; 106 107 location = mkOption { 108 default = "/var/backup/postgresql"; 109 type = types.path; 110 description = lib.mdDoc '' 111 Path of directory where the PostgreSQL database dumps will be placed. 112 ''; 113 }; 114 115 pgdumpOptions = mkOption { 116 type = types.separatedString " "; 117 default = "-C"; 118 description = lib.mdDoc '' 119 Command line options for pg_dump. This options is not used 120 if `config.services.postgresqlBackup.backupAll` is enabled. 121 Note that config.services.postgresqlBackup.backupAll is also active, 122 when no databases where specified. 123 ''; 124 }; 125 126 compression = mkOption { 127 type = types.enum ["none" "gzip" "zstd"]; 128 default = "gzip"; 129 description = lib.mdDoc '' 130 The type of compression to use on the generated database dump. 131 ''; 132 }; 133 134 compressionLevel = mkOption { 135 type = types.ints.between 1 19; 136 default = 6; 137 description = lib.mdDoc '' 138 The compression level used when compression is enabled. 139 gzip accepts levels 1 to 9. zstd accepts levels 1 to 19. 140 ''; 141 }; 142 }; 143 144 }; 145 146 config = mkMerge [ 147 { 148 assertions = [ 149 { 150 assertion = cfg.backupAll -> cfg.databases == []; 151 message = "config.services.postgresqlBackup.backupAll cannot be used together with config.services.postgresqlBackup.databases"; 152 } 153 { 154 assertion = cfg.compression == "none" || 155 (cfg.compression == "gzip" && cfg.compressionLevel >= 1 && cfg.compressionLevel <= 9) || 156 (cfg.compression == "zstd" && cfg.compressionLevel >= 1 && cfg.compressionLevel <= 19); 157 message = "config.services.postgresqlBackup.compressionLevel must be set between 1 and 9 for gzip and 1 and 19 for zstd"; 158 } 159 ]; 160 } 161 (mkIf cfg.enable { 162 systemd.tmpfiles.rules = [ 163 "d '${cfg.location}' 0700 postgres - - -" 164 ]; 165 }) 166 (mkIf (cfg.enable && cfg.backupAll) { 167 systemd.services.postgresqlBackup = 168 postgresqlBackupService "all" "pg_dumpall"; 169 }) 170 (mkIf (cfg.enable && !cfg.backupAll) { 171 systemd.services = listToAttrs (map (db: 172 let 173 cmd = "pg_dump ${cfg.pgdumpOptions} ${db}"; 174 in { 175 name = "postgresqlBackup-${db}"; 176 value = postgresqlBackupService db cmd; 177 }) cfg.databases); 178 }) 179 ]; 180 181}