2021-01-05 03:05:38 +00:00
|
|
|
{ system ? builtins.currentSystem,
|
|
|
|
config ? {},
|
2024-03-03 10:48:15 +00:00
|
|
|
pkgs ? import ../.. { inherit system config; },
|
2021-01-05 03:05:38 +00:00
|
|
|
}:
|
|
|
|
|
|
|
|
with import ../lib/testing-python.nix { inherit system pkgs; };
|
|
|
|
|
2019-08-11 17:09:42 +00:00
|
|
|
let
|
2021-01-05 03:12:53 +00:00
|
|
|
lib = pkgs.lib;
|
|
|
|
|
2024-03-03 10:48:15 +00:00
|
|
|
makePostgresqlWalReceiverTest = pkg:
|
|
|
|
let
|
|
|
|
postgresqlDataDir = "/var/lib/postgresql/${pkg.psqlSchema}";
|
|
|
|
replicationUser = "wal_receiver_user";
|
|
|
|
replicationSlot = "wal_receiver_slot";
|
|
|
|
replicationConn = "postgresql://${replicationUser}@localhost";
|
2024-09-30 15:23:10 +00:00
|
|
|
baseBackupDir = "/var/cache/wals/pg_basebackup";
|
|
|
|
walBackupDir = "/var/cache/wals/pg_wal";
|
2024-03-03 10:48:15 +00:00
|
|
|
|
2024-03-17 14:39:16 +00:00
|
|
|
recoveryFile = pkgs.writeTextDir "recovery.signal" "";
|
2024-03-03 10:48:15 +00:00
|
|
|
|
|
|
|
in makeTest {
|
|
|
|
name = "postgresql-wal-receiver-${pkg.name}";
|
|
|
|
meta.maintainers = with lib.maintainers; [ pacien ];
|
|
|
|
|
|
|
|
nodes.machine = { ... }: {
|
2024-09-30 15:23:10 +00:00
|
|
|
systemd.tmpfiles.rules = [
|
|
|
|
"d /var/cache/wals 0750 postgres postgres - -"
|
|
|
|
];
|
|
|
|
|
2024-03-03 10:48:15 +00:00
|
|
|
services.postgresql = {
|
|
|
|
package = pkg;
|
|
|
|
enable = true;
|
2024-03-17 14:39:16 +00:00
|
|
|
settings = {
|
|
|
|
max_replication_slots = 10;
|
|
|
|
max_wal_senders = 10;
|
|
|
|
recovery_end_command = "touch recovery.done";
|
|
|
|
restore_command = "cp ${walBackupDir}/%f %p";
|
|
|
|
wal_level = "archive"; # alias for replica on pg >= 9.6
|
|
|
|
};
|
2024-03-03 10:48:15 +00:00
|
|
|
authentication = ''
|
|
|
|
host replication ${replicationUser} all trust
|
|
|
|
'';
|
|
|
|
initialScript = pkgs.writeText "init.sql" ''
|
|
|
|
create user ${replicationUser} replication;
|
|
|
|
select * from pg_create_physical_replication_slot('${replicationSlot}');
|
|
|
|
'';
|
2020-08-26 08:51:10 +00:00
|
|
|
};
|
2019-08-11 17:09:42 +00:00
|
|
|
|
2024-03-03 10:48:15 +00:00
|
|
|
services.postgresqlWalReceiver.receivers.main = {
|
|
|
|
postgresqlPackage = pkg;
|
|
|
|
connection = replicationConn;
|
|
|
|
slot = replicationSlot;
|
|
|
|
directory = walBackupDir;
|
|
|
|
};
|
|
|
|
# This is only to speedup test, it isn't time racing. Service is set to autorestart always,
|
|
|
|
# default 60sec is fine for real system, but is too much for a test
|
|
|
|
systemd.services.postgresql-wal-receiver-main.serviceConfig.RestartSec = lib.mkForce 5;
|
2024-09-30 15:23:10 +00:00
|
|
|
systemd.services.postgresql.serviceConfig.ReadWritePaths = [ "/var/cache/wals" ];
|
2021-01-05 03:05:38 +00:00
|
|
|
};
|
2024-03-03 10:48:15 +00:00
|
|
|
|
|
|
|
testScript = ''
|
|
|
|
# make an initial base backup
|
|
|
|
machine.wait_for_unit("postgresql")
|
|
|
|
machine.wait_for_unit("postgresql-wal-receiver-main")
|
|
|
|
# WAL receiver healthchecks PG every 5 seconds, so let's be sure they have connected each other
|
|
|
|
# required only for 9.4
|
|
|
|
machine.sleep(5)
|
|
|
|
machine.succeed(
|
|
|
|
"${pkg}/bin/pg_basebackup --dbname=${replicationConn} --pgdata=${baseBackupDir}"
|
|
|
|
)
|
|
|
|
|
|
|
|
# create a dummy table with 100 records
|
|
|
|
machine.succeed(
|
|
|
|
"sudo -u postgres psql --command='create table dummy as select * from generate_series(1, 100) as val;'"
|
|
|
|
)
|
|
|
|
|
|
|
|
# stop postgres and destroy data
|
|
|
|
machine.systemctl("stop postgresql")
|
|
|
|
machine.systemctl("stop postgresql-wal-receiver-main")
|
|
|
|
machine.succeed("rm -r ${postgresqlDataDir}/{base,global,pg_*}")
|
|
|
|
|
|
|
|
# restore the base backup
|
|
|
|
machine.succeed(
|
|
|
|
"cp -r ${baseBackupDir}/* ${postgresqlDataDir} && chown postgres:postgres -R ${postgresqlDataDir}"
|
|
|
|
)
|
|
|
|
|
|
|
|
# prepare WAL and recovery
|
|
|
|
machine.succeed("chmod a+rX -R ${walBackupDir}")
|
|
|
|
machine.execute(
|
|
|
|
"for part in ${walBackupDir}/*.partial; do mv $part ''${part%%.*}; done"
|
|
|
|
) # make use of partial segments too
|
|
|
|
machine.succeed(
|
|
|
|
"cp ${recoveryFile}/* ${postgresqlDataDir}/ && chmod 666 ${postgresqlDataDir}/recovery*"
|
|
|
|
)
|
|
|
|
|
|
|
|
# replay WAL
|
|
|
|
machine.systemctl("start postgresql")
|
|
|
|
machine.wait_for_file("${postgresqlDataDir}/recovery.done")
|
|
|
|
machine.systemctl("restart postgresql")
|
|
|
|
machine.wait_for_unit("postgresql")
|
|
|
|
|
|
|
|
# check that our records have been restored
|
|
|
|
machine.succeed(
|
|
|
|
"test $(sudo -u postgres psql --pset='pager=off' --tuples-only --command='select count(distinct val) from dummy;') -eq 100"
|
|
|
|
)
|
|
|
|
'';
|
2020-08-26 08:51:10 +00:00
|
|
|
};
|
2024-03-03 10:48:15 +00:00
|
|
|
in
|
2024-11-01 18:21:50 +00:00
|
|
|
lib.concatMapAttrs (n: p: { ${n} = makePostgresqlWalReceiverTest p; }) pkgs.postgresqlVersions
|
|
|
|
// {
|
|
|
|
passthru.override = p: makePostgresqlWalReceiverTest p;
|
|
|
|
}
|