112 lines
		
	
	
		
			4.5 KiB
		
	
	
	
		
			Nix
		
	
	
	
	
	
			
		
		
	
	
			112 lines
		
	
	
		
			4.5 KiB
		
	
	
	
		
			Nix
		
	
	
	
	
	
let
 | 
						|
  # Makes a test for a PostgreSQL package, given by name and looked up from `pkgs`.
 | 
						|
  makePostgresqlWalReceiverTest = postgresqlPackage:
 | 
						|
  {
 | 
						|
    name = postgresqlPackage;
 | 
						|
    value =
 | 
						|
      import ./make-test-python.nix ({ pkgs, lib, ... }: let
 | 
						|
 | 
						|
        pkg = pkgs."${postgresqlPackage}";
 | 
						|
        postgresqlDataDir = "/var/lib/postgresql/${pkg.psqlSchema}";
 | 
						|
        replicationUser = "wal_receiver_user";
 | 
						|
        replicationSlot = "wal_receiver_slot";
 | 
						|
        replicationConn = "postgresql://${replicationUser}@localhost";
 | 
						|
        baseBackupDir = "/tmp/pg_basebackup";
 | 
						|
        walBackupDir = "/tmp/pg_wal";
 | 
						|
        atLeast12 = lib.versionAtLeast pkg.version "12.0";
 | 
						|
 | 
						|
        recoveryFile = if atLeast12
 | 
						|
            then pkgs.writeTextDir "recovery.signal" ""
 | 
						|
            else pkgs.writeTextDir "recovery.conf" "restore_command = 'cp ${walBackupDir}/%f %p'";
 | 
						|
 | 
						|
      in {
 | 
						|
        name = "postgresql-wal-receiver-${postgresqlPackage}";
 | 
						|
        meta.maintainers = with lib.maintainers; [ pacien ];
 | 
						|
 | 
						|
        machine = { ... }: {
 | 
						|
          services.postgresql = {
 | 
						|
            package = pkg;
 | 
						|
            enable = true;
 | 
						|
            settings = lib.mkMerge [
 | 
						|
              {
 | 
						|
                wal_level = "archive"; # alias for replica on pg >= 9.6
 | 
						|
                max_wal_senders = 10;
 | 
						|
                max_replication_slots = 10;
 | 
						|
              }
 | 
						|
              (lib.mkIf atLeast12 {
 | 
						|
                restore_command = "cp ${walBackupDir}/%f %p";
 | 
						|
                recovery_end_command = "touch recovery.done";
 | 
						|
              })
 | 
						|
            ];
 | 
						|
            authentication = ''
 | 
						|
              host replication ${replicationUser} all trust
 | 
						|
            '';
 | 
						|
            initialScript = pkgs.writeText "init.sql" ''
 | 
						|
              create user ${replicationUser} replication;
 | 
						|
              select * from pg_create_physical_replication_slot('${replicationSlot}');
 | 
						|
            '';
 | 
						|
          };
 | 
						|
 | 
						|
          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;
 | 
						|
        };
 | 
						|
 | 
						|
        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"
 | 
						|
          )
 | 
						|
        '';
 | 
						|
      });
 | 
						|
    };
 | 
						|
 | 
						|
# Maps the generic function over all attributes of PostgreSQL packages
 | 
						|
in builtins.listToAttrs (map makePostgresqlWalReceiverTest (builtins.attrNames (import ../../pkgs/servers/sql/postgresql { })))
 |