at 25.11-pre 4.0 kB view raw
1{ lib, pkgs, ... }: 2let 3 inherit (import ../ssh-keys.nix pkgs) snakeOilPrivateKey snakeOilPublicKey; 4 backupPath = "/var/lib/pgbackrest"; 5in 6{ 7 name = "pgbackrest-posix"; 8 9 meta = { 10 maintainers = with lib.maintainers; [ wolfgangwalther ]; 11 }; 12 13 nodes.primary = 14 { 15 pkgs, 16 ... 17 }: 18 { 19 services.openssh.enable = true; 20 users.users.postgres.openssh.authorizedKeys.keys = [ 21 snakeOilPublicKey 22 ]; 23 24 services.postgresql = { 25 enable = true; 26 initialScript = pkgs.writeText "init.sql" '' 27 CREATE TABLE t(c text); 28 INSERT INTO t VALUES ('hello world'); 29 ''; 30 }; 31 32 services.pgbackrest = { 33 enable = true; 34 repos.backup = { 35 type = "posix"; 36 path = backupPath; 37 host-user = "pgbackrest"; 38 }; 39 }; 40 }; 41 42 nodes.backup = 43 { 44 nodes, 45 ... 46 }: 47 { 48 services.openssh.enable = true; 49 users.users.pgbackrest.openssh.authorizedKeys.keys = [ 50 snakeOilPublicKey 51 ]; 52 53 services.pgbackrest = { 54 enable = true; 55 repos.localhost.path = backupPath; 56 57 stanzas.default = { 58 jobs.future = { 59 schedule = "3000-01-01"; 60 type = "full"; 61 }; 62 instances.primary = { 63 path = nodes.primary.services.postgresql.dataDir; 64 user = "postgres"; 65 }; 66 }; 67 68 # Examples from https://pgbackrest.org/configuration.html#introduction 69 # Not used for the test, except for dumping the config. 70 stanzas.config-format.settings = { 71 start-fast = true; 72 compress-level = 3; 73 buffer-size = "2MiB"; 74 db-timeout = 600; 75 db-exclude = [ 76 "db1" 77 "db2" 78 "db5" 79 ]; 80 tablespace-map = { 81 ts_01 = "/db/ts_01"; 82 ts_02 = "/db/ts_02"; 83 }; 84 }; 85 }; 86 }; 87 88 testScript = 89 { nodes, ... }: 90 '' 91 start_all() 92 93 primary.wait_for_unit("multi-user.target") 94 backup.wait_for_unit("multi-user.target") 95 96 with subtest("config file is written correctly"): 97 from textwrap import dedent 98 have = backup.succeed("cat /etc/pgbackrest/pgbackrest.conf") 99 want = dedent("""\ 100 [config-format] 101 buffer-size=2MiB 102 compress-level=3 103 db-exclude=db1 104 db-exclude=db2 105 db-exclude=db5 106 db-timeout=600 107 start-fast=y 108 tablespace-map=ts_01=/db/ts_01 109 tablespace-map=ts_02=/db/ts_02 110 """) 111 assert want in have, repr((want, have)) 112 113 primary.log(primary.succeed(""" 114 HOME="${nodes.primary.services.postgresql.dataDir}" 115 mkdir -m 700 -p ~/.ssh 116 cat ${snakeOilPrivateKey} > ~/.ssh/id_ecdsa 117 chmod 400 ~/.ssh/id_ecdsa 118 ssh-keyscan backup >> ~/.ssh/known_hosts 119 chown -R postgres:postgres ~/.ssh 120 """)) 121 122 backup.log(backup.succeed(""" 123 HOME="${backupPath}" 124 mkdir -m 700 -p ~/.ssh 125 cat ${snakeOilPrivateKey} > ~/.ssh/id_ecdsa 126 chmod 400 ~/.ssh/id_ecdsa 127 ssh-keyscan primary >> ~/.ssh/known_hosts 128 chown -R pgbackrest:pgbackrest ~ 129 """)) 130 131 with subtest("backup/restore works with remote instance/local repo (SSH)"): 132 backup.succeed("sudo -u pgbackrest pgbackrest --stanza=default stanza-create") 133 backup.succeed("sudo -u pgbackrest pgbackrest --stanza=default check") 134 135 backup.systemctl("start pgbackrest-default-future") 136 137 # corrupt cluster 138 primary.systemctl("stop postgresql") 139 primary.execute("rm ${nodes.primary.services.postgresql.dataDir}/global/pg_control") 140 141 primary.succeed("sudo -u postgres pgbackrest --stanza=default restore --delta") 142 143 primary.systemctl("start postgresql") 144 primary.wait_for_unit("postgresql.service") 145 assert "hello world" in primary.succeed("sudo -u postgres psql -c 'TABLE t;'") 146 ''; 147}