Loading nixos/modules/services/databases/postgresql.nix +6 −0 Original line number Diff line number Diff line Loading @@ -911,6 +911,12 @@ in # Wait for PostgreSQL to be ready to accept connections. script = '' # If we're in standby mode, don't perform any setup if [[ -f "${cfg.dataDir}/standby.signal" ]]; then echo "Skipping setup because PostgreSQL is in standby mode" exit 0 fi check-connection() { psql -d postgres -v ON_ERROR_STOP=1 <<-' EOF' SELECT pg_is_in_recovery() \gset Loading nixos/tests/postgresql/default.nix +1 −0 Original line number Diff line number Diff line Loading @@ -31,6 +31,7 @@ in # postgresql postgresql = importWithArgs ./postgresql.nix; postgresql-jit = importWithArgs ./postgresql-jit.nix; postgresql-replication = importWithArgs ./postgresql-replication.nix; postgresql-wal-receiver = importWithArgs ./postgresql-wal-receiver.nix; postgresql-tls-client-cert = importWithArgs ./postgresql-tls-client-cert.nix; Loading nixos/tests/postgresql/postgresql-replication.nix 0 → 100644 +125 −0 Original line number Diff line number Diff line { pkgs, makeTest, genTests, }: let inherit (pkgs) lib; makeTestFor = package: makeTest { name = "postgresql-replication-${package.name}"; meta.maintainers = with lib.maintainers; [ bouk ]; nodes = { primary = { ... }: { services.postgresql = { inherit package; enable = true; enableTCPIP = true; settings = { wal_level = "replica"; max_wal_senders = 10; max_replication_slots = 10; }; authentication = '' local replication postgres peer host replication replication all trust ''; ensureUsers = [ { name = "replication"; ensureClauses.replication = true; } ]; }; networking.firewall.allowedTCPPorts = [ 5432 ]; }; replica = { nodes, ... }: { services.postgresql = { inherit package; enable = true; settings = { hot_standby = "on"; primary_conninfo = "host=${nodes.primary.networking.primaryIPAddress} user=replication"; primary_slot_name = "replica_slot"; }; }; }; }; testScript = '' start_all() primary.wait_for_unit("postgresql.target") primary.succeed( "sudo -u postgres psql -c \"SELECT * FROM pg_create_physical_replication_slot('replica_slot');\"" ) primary.succeed( "sudo -u postgres pg_basebackup -D /tmp/basebackup -S replica_slot -X stream" ) primary.succeed("tar -C /tmp -cf /tmp/shared/basebackup.tar basebackup") replica.wait_for_unit("postgresql.target") replica.succeed("systemctl stop postgresql") replica_data_dir = "/var/lib/postgresql/${package.psqlSchema}" replica.succeed(f"rm -rf {replica_data_dir}") replica.succeed(f"mkdir -p {replica_data_dir}") replica.succeed(f"tar -C {replica_data_dir} --strip-components=1 -xf /tmp/shared/basebackup.tar") replica.succeed(f"touch {replica_data_dir}/standby.signal") replica.succeed(f"chown -R postgres:postgres {replica_data_dir}") replica.succeed(f"chmod 700 {replica_data_dir}") replica.succeed("systemctl start postgresql") replica.wait_for_unit("postgresql.target") replica.wait_until_succeeds( "sudo -u postgres psql -tAc 'SELECT pg_is_in_recovery();' | grep t" ) primary.succeed( "sudo -u postgres psql -c 'CREATE TABLE test_replication (id serial PRIMARY KEY, data text);'" ) primary.succeed( "sudo -u postgres psql -c \"INSERT INTO test_replication (data) VALUES ('hello');\"" ) replica.wait_until_succeeds( "sudo -u postgres psql -c 'SELECT * FROM test_replication;' | grep hello", timeout=30 ) with subtest("Verify replica is in recovery mode"): result = replica.succeed("sudo -u postgres psql -tAc 'SELECT pg_is_in_recovery();'") t.assertEqual(result.strip(), "t") with subtest("Verify replication slot is active"): result = primary.succeed( "sudo -u postgres psql -tAc \"SELECT active FROM pg_replication_slots WHERE slot_name = 'replica_slot';\"" ) t.assertEqual(result.strip(), "t") with subtest("Insert more data and verify replication"): primary.succeed( "sudo -u postgres psql -c \"INSERT INTO test_replication (data) VALUES ('world');\"" ) replica.wait_until_succeeds( "sudo -u postgres psql -c 'SELECT * FROM test_replication;' | grep world", timeout=30 ) primary.shutdown() replica.shutdown() ''; }; in genTests { inherit makeTestFor; } pkgs/servers/sql/postgresql/generic.nix +1 −0 Original line number Diff line number Diff line Loading @@ -612,6 +612,7 @@ let tests = { postgresql = nixosTests.postgresql.postgresql.passthru.override finalAttrs.finalPackage; postgresql-replication = nixosTests.postgresql.postgresql-replication.passthru.override finalAttrs.finalPackage; postgresql-tls-client-cert = nixosTests.postgresql.postgresql-tls-client-cert.passthru.override finalAttrs.finalPackage; postgresql-wal-receiver = nixosTests.postgresql.postgresql-wal-receiver.passthru.override finalAttrs.finalPackage; pkg-config = testers.testMetaPkgConfig finalAttrs.finalPackage; Loading Loading
nixos/modules/services/databases/postgresql.nix +6 −0 Original line number Diff line number Diff line Loading @@ -911,6 +911,12 @@ in # Wait for PostgreSQL to be ready to accept connections. script = '' # If we're in standby mode, don't perform any setup if [[ -f "${cfg.dataDir}/standby.signal" ]]; then echo "Skipping setup because PostgreSQL is in standby mode" exit 0 fi check-connection() { psql -d postgres -v ON_ERROR_STOP=1 <<-' EOF' SELECT pg_is_in_recovery() \gset Loading
nixos/tests/postgresql/default.nix +1 −0 Original line number Diff line number Diff line Loading @@ -31,6 +31,7 @@ in # postgresql postgresql = importWithArgs ./postgresql.nix; postgresql-jit = importWithArgs ./postgresql-jit.nix; postgresql-replication = importWithArgs ./postgresql-replication.nix; postgresql-wal-receiver = importWithArgs ./postgresql-wal-receiver.nix; postgresql-tls-client-cert = importWithArgs ./postgresql-tls-client-cert.nix; Loading
nixos/tests/postgresql/postgresql-replication.nix 0 → 100644 +125 −0 Original line number Diff line number Diff line { pkgs, makeTest, genTests, }: let inherit (pkgs) lib; makeTestFor = package: makeTest { name = "postgresql-replication-${package.name}"; meta.maintainers = with lib.maintainers; [ bouk ]; nodes = { primary = { ... }: { services.postgresql = { inherit package; enable = true; enableTCPIP = true; settings = { wal_level = "replica"; max_wal_senders = 10; max_replication_slots = 10; }; authentication = '' local replication postgres peer host replication replication all trust ''; ensureUsers = [ { name = "replication"; ensureClauses.replication = true; } ]; }; networking.firewall.allowedTCPPorts = [ 5432 ]; }; replica = { nodes, ... }: { services.postgresql = { inherit package; enable = true; settings = { hot_standby = "on"; primary_conninfo = "host=${nodes.primary.networking.primaryIPAddress} user=replication"; primary_slot_name = "replica_slot"; }; }; }; }; testScript = '' start_all() primary.wait_for_unit("postgresql.target") primary.succeed( "sudo -u postgres psql -c \"SELECT * FROM pg_create_physical_replication_slot('replica_slot');\"" ) primary.succeed( "sudo -u postgres pg_basebackup -D /tmp/basebackup -S replica_slot -X stream" ) primary.succeed("tar -C /tmp -cf /tmp/shared/basebackup.tar basebackup") replica.wait_for_unit("postgresql.target") replica.succeed("systemctl stop postgresql") replica_data_dir = "/var/lib/postgresql/${package.psqlSchema}" replica.succeed(f"rm -rf {replica_data_dir}") replica.succeed(f"mkdir -p {replica_data_dir}") replica.succeed(f"tar -C {replica_data_dir} --strip-components=1 -xf /tmp/shared/basebackup.tar") replica.succeed(f"touch {replica_data_dir}/standby.signal") replica.succeed(f"chown -R postgres:postgres {replica_data_dir}") replica.succeed(f"chmod 700 {replica_data_dir}") replica.succeed("systemctl start postgresql") replica.wait_for_unit("postgresql.target") replica.wait_until_succeeds( "sudo -u postgres psql -tAc 'SELECT pg_is_in_recovery();' | grep t" ) primary.succeed( "sudo -u postgres psql -c 'CREATE TABLE test_replication (id serial PRIMARY KEY, data text);'" ) primary.succeed( "sudo -u postgres psql -c \"INSERT INTO test_replication (data) VALUES ('hello');\"" ) replica.wait_until_succeeds( "sudo -u postgres psql -c 'SELECT * FROM test_replication;' | grep hello", timeout=30 ) with subtest("Verify replica is in recovery mode"): result = replica.succeed("sudo -u postgres psql -tAc 'SELECT pg_is_in_recovery();'") t.assertEqual(result.strip(), "t") with subtest("Verify replication slot is active"): result = primary.succeed( "sudo -u postgres psql -tAc \"SELECT active FROM pg_replication_slots WHERE slot_name = 'replica_slot';\"" ) t.assertEqual(result.strip(), "t") with subtest("Insert more data and verify replication"): primary.succeed( "sudo -u postgres psql -c \"INSERT INTO test_replication (data) VALUES ('world');\"" ) replica.wait_until_succeeds( "sudo -u postgres psql -c 'SELECT * FROM test_replication;' | grep world", timeout=30 ) primary.shutdown() replica.shutdown() ''; }; in genTests { inherit makeTestFor; }
pkgs/servers/sql/postgresql/generic.nix +1 −0 Original line number Diff line number Diff line Loading @@ -612,6 +612,7 @@ let tests = { postgresql = nixosTests.postgresql.postgresql.passthru.override finalAttrs.finalPackage; postgresql-replication = nixosTests.postgresql.postgresql-replication.passthru.override finalAttrs.finalPackage; postgresql-tls-client-cert = nixosTests.postgresql.postgresql-tls-client-cert.passthru.override finalAttrs.finalPackage; postgresql-wal-receiver = nixosTests.postgresql.postgresql-wal-receiver.passthru.override finalAttrs.finalPackage; pkg-config = testers.testMetaPkgConfig finalAttrs.finalPackage; Loading