diff options
Diffstat (limited to 'modules/private/databases/postgresql_replication.nix')
-rw-r--r-- | modules/private/databases/postgresql_replication.nix | 182 |
1 files changed, 0 insertions, 182 deletions
diff --git a/modules/private/databases/postgresql_replication.nix b/modules/private/databases/postgresql_replication.nix deleted file mode 100644 index 135bbed..0000000 --- a/modules/private/databases/postgresql_replication.nix +++ /dev/null | |||
@@ -1,182 +0,0 @@ | |||
1 | { pkgs, config, lib, ... }: | ||
2 | let | ||
3 | cfg = config.myServices.databasesReplication.postgresql; | ||
4 | in | ||
5 | { | ||
6 | options.myServices.databasesReplication.postgresql = { | ||
7 | enable = lib.mkEnableOption "Enable postgresql replication"; | ||
8 | base = lib.mkOption { | ||
9 | type = lib.types.path; | ||
10 | description = '' | ||
11 | Base path to put the replications | ||
12 | ''; | ||
13 | }; | ||
14 | mainPackage = lib.mkOption { | ||
15 | type = lib.types.package; | ||
16 | default = pkgs.postgresql; | ||
17 | description = '' | ||
18 | Postgresql package available in shell | ||
19 | ''; | ||
20 | }; | ||
21 | hosts = lib.mkOption { | ||
22 | default = {}; | ||
23 | description = '' | ||
24 | Hosts to backup | ||
25 | ''; | ||
26 | type = lib.types.attrsOf (lib.types.submodule { | ||
27 | options = { | ||
28 | package = lib.mkOption { | ||
29 | type = lib.types.package; | ||
30 | default = pkgs.postgresql; | ||
31 | description = '' | ||
32 | Postgresql package for this host | ||
33 | ''; | ||
34 | }; | ||
35 | slot = lib.mkOption { | ||
36 | type = lib.types.str; | ||
37 | description = '' | ||
38 | Slot to use for replication | ||
39 | ''; | ||
40 | }; | ||
41 | connection = lib.mkOption { | ||
42 | type = lib.types.str; | ||
43 | description = '' | ||
44 | Connection string to access the psql master | ||
45 | ''; | ||
46 | }; | ||
47 | }; | ||
48 | }); | ||
49 | }; | ||
50 | }; | ||
51 | |||
52 | config = lib.mkIf cfg.enable { | ||
53 | users.users.postgres = { | ||
54 | name = "postgres"; | ||
55 | uid = config.ids.uids.postgres; | ||
56 | group = "postgres"; | ||
57 | description = "PostgreSQL server user"; | ||
58 | home = "/var/lib/postgresql"; | ||
59 | useDefaultShell = true; | ||
60 | extraGroups = [ "keys" ]; | ||
61 | }; | ||
62 | users.groups.postgres.gid = config.ids.gids.postgres; | ||
63 | environment.systemPackages = [ cfg.mainPackage ]; | ||
64 | |||
65 | secrets.keys = lib.listToAttrs (lib.flatten (lib.mapAttrsToList (name: hcfg: [ | ||
66 | (lib.nameValuePair "postgresql_replication/${name}/recovery.conf" { | ||
67 | user = "postgres"; | ||
68 | group = "postgres"; | ||
69 | permissions = "0400"; | ||
70 | text = '' | ||
71 | standby_mode = on | ||
72 | primary_conninfo = '${hcfg.connection}?sslmode=require' | ||
73 | primary_slot_name = '${hcfg.slot}' | ||
74 | ''; | ||
75 | }) | ||
76 | (lib.nameValuePair "postgresql_replication/${name}/connection_string" { | ||
77 | user = "postgres"; | ||
78 | group = "postgres"; | ||
79 | permissions = "0400"; | ||
80 | text = hcfg.connection; | ||
81 | }) | ||
82 | (lib.nameValuePair "postgresql_replication/${name}/postgresql.conf" { | ||
83 | user = "postgres"; | ||
84 | group = "postgres"; | ||
85 | permissions = "0400"; | ||
86 | text = let | ||
87 | dataDir = "${cfg.base}/${name}/postgresql"; | ||
88 | in '' | ||
89 | listen_addresses = ''' | ||
90 | unix_socket_directories = '${dataDir}' | ||
91 | data_directory = '${dataDir}' | ||
92 | wal_level = logical | ||
93 | ''; | ||
94 | }) | ||
95 | ]) cfg.hosts)); | ||
96 | |||
97 | services.cron = { | ||
98 | enable = true; | ||
99 | systemCronJobs = lib.flatten (lib.mapAttrsToList (name: hcfg: | ||
100 | let | ||
101 | dataDir = "${cfg.base}/${name}/postgresql"; | ||
102 | backupDir = "${cfg.base}/${name}/postgresql_backup"; | ||
103 | backup_script = pkgs.writeScript "backup_psql_${name}" '' | ||
104 | #!${pkgs.stdenv.shell} | ||
105 | |||
106 | set -euo pipefail | ||
107 | |||
108 | resume_replication() { | ||
109 | ${hcfg.package}/bin/psql -h ${dataDir} -c "SELECT pg_wal_replay_resume();" >/dev/null || echo "impossible to resume replication" | ||
110 | } | ||
111 | |||
112 | trap resume_replication EXIT | ||
113 | |||
114 | ${hcfg.package}/bin/psql -h ${dataDir} -c "SELECT pg_wal_replay_pause();" >/dev/null || (echo "impossible to pause replication" && false) | ||
115 | |||
116 | ${hcfg.package}/bin/pg_dumpall -h ${dataDir} -f ${backupDir}/$(${pkgs.coreutils}/bin/date -Iminutes).sql | ||
117 | ''; | ||
118 | u = pkgs.callPackage ./utils.nix {}; | ||
119 | cleanup_script = pkgs.writeScript "cleanup_postgresql_${name}" (u.keepLastNDumps "sql" backupDir 6); | ||
120 | in [ | ||
121 | "0 22,4,10,16 * * * postgres ${backup_script}" | ||
122 | "0 3 * * * postgres ${cleanup_script}" | ||
123 | ]) cfg.hosts); | ||
124 | }; | ||
125 | |||
126 | system.activationScripts = lib.attrsets.mapAttrs' (name: hcfg: | ||
127 | lib.attrsets.nameValuePair "psql_replication_${name}" { | ||
128 | deps = [ "users" ]; | ||
129 | text = '' | ||
130 | install -m 0700 -o postgres -g postgres -d ${cfg.base}/${name}/postgresql | ||
131 | install -m 0700 -o postgres -g postgres -d ${cfg.base}/${name}/postgresql_backup | ||
132 | ''; | ||
133 | }) cfg.hosts; | ||
134 | |||
135 | systemd.services = lib.attrsets.mapAttrs' (name: hcfg: | ||
136 | let | ||
137 | dataDir = "${cfg.base}/${name}/postgresql"; | ||
138 | in | ||
139 | lib.attrsets.nameValuePair "postgresql_backup_${name}" { | ||
140 | description = "Postgresql replication for ${name}"; | ||
141 | wantedBy = [ "multi-user.target" ]; | ||
142 | after = [ "network.target" ]; | ||
143 | |||
144 | environment.PGDATA = dataDir; | ||
145 | path = [ hcfg.package ]; | ||
146 | |||
147 | preStart = '' | ||
148 | if ! test -e ${dataDir}/PG_VERSION; then | ||
149 | mkdir -m 0700 -p ${dataDir} | ||
150 | chown -R postgres:postgres ${dataDir} | ||
151 | fi | ||
152 | ''; | ||
153 | script = let | ||
154 | fp = n: config.secrets.fullPaths."postgresql_replication/${name}/${n}"; | ||
155 | in '' | ||
156 | if ! test -e ${dataDir}/PG_VERSION; then | ||
157 | pg_basebackup -d $(cat ${fp "connection_string"}) -D ${dataDir} -S ${hcfg.slot} | ||
158 | fi | ||
159 | ln -sfn ${fp "recovery.conf"} ${dataDir}/recovery.conf | ||
160 | ln -sfn ${fp "postgresql.conf"} ${dataDir}/postgresql.conf | ||
161 | |||
162 | exec postgres | ||
163 | ''; | ||
164 | |||
165 | serviceConfig = { | ||
166 | ExecReload = "${pkgs.coreutils}/bin/kill -HUP $MAINPID"; | ||
167 | User = "postgres"; | ||
168 | Group = "postgres"; | ||
169 | PermissionsStartOnly = true; | ||
170 | RuntimeDirectory = "postgresql"; | ||
171 | Type = "notify"; | ||
172 | |||
173 | KillSignal = "SIGINT"; | ||
174 | KillMode = "mixed"; | ||
175 | # basebackup can take a long time | ||
176 | TimeoutStartSec="infinity"; | ||
177 | TimeoutStopSec = 120; | ||
178 | }; | ||
179 | unitConfig.RequiresMountsFor = dataDir; | ||
180 | }) cfg.hosts; | ||
181 | }; | ||
182 | } | ||