python3Packages.orjson: Disable failing tests on 32 bit
[NixPkgs.git] / nixos / modules / services / backup / postgresql-backup.nix
blobd3c6f3104fc54109bbf78ee87c2957111c0d1dae
1 { config, lib, pkgs, ... }:
3 with lib;
5 let
7   cfg = config.services.postgresqlBackup;
9   postgresqlBackupService = db: dumpCmd:
10     let
11       compressSuffixes = {
12         "none" = "";
13         "gzip" = ".gz";
14         "zstd" = ".zstd";
15       };
16       compressSuffix = getAttr cfg.compression compressSuffixes;
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       };
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;
32       description = "Backup of ${db} database(s)";
34       requires = [ "postgresql.service" ];
36       path = [ pkgs.coreutils config.services.postgresql.package ];
38       script = ''
39         set -e -o pipefail
41         umask 0077 # ensure backup is only readable by postgres user
43         if [ -e ${curFile} ]; then
44           rm -f ${toString prevFiles}
45           mv ${curFile} ${prevFile}
46         fi
48         ${dumpCmd} \
49           | ${compressCmd} \
50           > ${inProgressFile}
52         mv ${inProgressFile} ${curFile}
53       '';
55       serviceConfig = {
56         Type = "oneshot";
57         User = "postgres";
58       };
60       startAt = cfg.startAt;
61     };
63 in {
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   ];
72   options = {
73     services.postgresqlBackup = {
74       enable = mkEnableOption (lib.mdDoc "PostgreSQL dumps");
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       };
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       };
99       databases = mkOption {
100         default = [];
101         type = types.listOf types.str;
102         description = lib.mdDoc ''
103           List of database names to dump.
104         '';
105       };
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       };
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       };
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       };
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     };
144   };
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   ];