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