Unverified Commit 82e51994 authored by Wolfgang Walther's avatar Wolfgang Walther
Browse files

nixos/pgbackrest: add SFTP support

parent d5ddb611
Loading
Loading
Loading
Loading
+21 −0
Original line number Diff line number Diff line
@@ -100,6 +100,7 @@ in
                if name == "localhost" then
                  null
                # "posix" is the default repo type, which uses the -host option.
                # Other types use prefixed options, for example -sftp-host.
                else if config.type or "posix" != type then
                  null
                else
@@ -114,6 +115,26 @@ in
                defaultText = lib.literalExpression "name";
                description = "Repository host when operating remotely";
              };

              options.sftp-host = lib.mkOption {
                type = nullOr str;
                default = setHostForType "sftp";
                defaultText = lib.literalExpression "name";
                description = "SFTP repository host";
              };

              options.sftp-private-key-file = lib.mkOption {
                type = nullOr (pathWith {
                  inStore = false;
                  absolute = true;
                });
                default = null;
                description = ''
                  SFTP private key file.

                  The file must be accessible by both the pgbackrest and the postgres users.
                '';
              };
            }
          )
        );
+1 −0
Original line number Diff line number Diff line
{ runTest }:
{
  posix = runTest ./posix.nix;
  sftp = runTest ./sftp.nix;
}
+95 −0
Original line number Diff line number Diff line
{ lib, pkgs, ... }:
let
  inherit (import ../ssh-keys.nix pkgs) snakeOilPrivateKey snakeOilPublicKey;
  backupPath = "/home/backup";
in
{
  name = "pgbackrest-sftp";

  meta = {
    maintainers = with lib.maintainers; [ wolfgangwalther ];
  };

  nodes.primary =
    {
      pkgs,
      ...
    }:
    {
      services.postgresql = {
        enable = true;
        initialScript = pkgs.writeText "init.sql" ''
          CREATE TABLE t(c text);
          INSERT INTO t VALUES ('hello world');
        '';
      };

      services.pgbackrest = {
        enable = true;
        repos.backup = {
          type = "sftp";
          path = "/home/backup";
          sftp-host-key-check-type = "none";
          sftp-host-key-hash-type = "sha256";
          sftp-host-user = "backup";
          sftp-private-key-file = "/var/lib/pgbackrest/sftp_key";
        };

        stanzas.default.jobs.future = {
          schedule = "3000-01-01";
          type = "diff";
        };
      };
    };

  nodes.backup =
    {
      nodes,
      ...
    }:
    {
      services.openssh.enable = true;
      users.users.backup = {
        name = "backup";
        group = "backup";
        isNormalUser = true;
        createHome = true;
        openssh.authorizedKeys.keys = [
          snakeOilPublicKey
        ];
      };
      users.groups.backup = { };
    };

  testScript =
    { nodes, ... }:
    ''
      start_all()

      primary.wait_for_unit("multi-user.target")
      backup.wait_for_unit("multi-user.target")

      primary.log(primary.succeed("""
        HOME="/var/lib/pgbackrest"
        cat ${snakeOilPrivateKey} > ~/sftp_key
        chown -R pgbackrest:pgbackrest ~/sftp_key
        chmod 770 ~
      """))

      with subtest("backup/restore works with local instance/remote repo (SFTP)"):
        primary.succeed("sudo -u pgbackrest pgbackrest --stanza=default stanza-create", timeout=10)
        primary.succeed("sudo -u pgbackrest pgbackrest --stanza=default check")

        primary.systemctl("start pgbackrest-default-future")

        # corrupt cluster
        primary.systemctl("stop postgresql")
        primary.execute("rm ${nodes.primary.services.postgresql.dataDir}/global/pg_control")

        primary.succeed("sudo -u postgres pgbackrest --stanza=default restore --delta")

        primary.systemctl("start postgresql")
        primary.wait_for_unit("postgresql.service")
        assert "hello world" in primary.succeed("sudo -u postgres psql -c 'TABLE t;'")
    '';
}