Expand backup and restore capabilities w.r.t. postgresql. #1582
|
@ -11,8 +11,19 @@
|
||||||
];
|
];
|
||||||
clan.postgresql.users.test = { };
|
clan.postgresql.users.test = { };
|
||||||
clan.postgresql.databases.test.create.options.OWNER = "test";
|
clan.postgresql.databases.test.create.options.OWNER = "test";
|
||||||
|
clan.postgresql.databases.test.restore.stopOnRestore = [ "sample-service" ];
|
||||||
clan.localbackup.targets.hdd.directory = "/mnt/external-disk";
|
clan.localbackup.targets.hdd.directory = "/mnt/external-disk";
|
||||||
|
|
||||||
|
systemd.services.sample-service = {
|
||||||
|
wantedBy = [ "multi-user.target" ];
|
||||||
|
script = ''
|
||||||
|
while true; do
|
||||||
|
echo "Hello, world!"
|
||||||
|
sleep 5
|
||||||
|
done
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
|
||||||
environment.systemPackages = [ config.services.postgresql.package ];
|
environment.systemPackages = [ config.services.postgresql.package ];
|
||||||
};
|
};
|
||||||
testScript =
|
testScript =
|
||||||
|
@ -20,20 +31,22 @@
|
||||||
''
|
''
|
||||||
start_all()
|
start_all()
|
||||||
machine.wait_for_unit("postgresql")
|
machine.wait_for_unit("postgresql")
|
||||||
|
machine.wait_for_unit("sample-service")
|
||||||
# Create a test table
|
# Create a test table
|
||||||
machine.succeed("runuser -u postgres -- /run/current-system/sw/bin/psql -c 'CREATE TABLE test (id serial PRIMARY KEY);' test")
|
machine.succeed("runuser -u postgres -- /run/current-system/sw/bin/psql -c 'CREATE TABLE test (id serial PRIMARY KEY);' test")
|
||||||
|
|
||||||
machine.succeed("/run/current-system/sw/bin/localbackup-create >&2")
|
machine.succeed("/run/current-system/sw/bin/localbackup-create >&2")
|
||||||
|
timestamp_before = int(machine.succeed("systemctl show --property=ExecMainStartTimestampMonotonic sample-service | cut -d= -f2").strip())
|
||||||
|
|
||||||
machine.succeed("test -e /mnt/external-disk/snapshot.0/machine/var/backup/postgres/test/dump.sql.zstd || { echo 'dump.sql.zstd not found'; exit 1; }")
|
machine.succeed("test -e /mnt/external-disk/snapshot.0/machine/var/backup/postgres/test/pg-dump || { echo 'pg-dump not found'; exit 1; }")
|
||||||
machine.succeed("runuser -u postgres -- /run/current-system/sw/bin/psql -d test -c 'INSERT INTO test DEFAULT VALUES;'")
|
machine.succeed("runuser -u postgres -- /run/current-system/sw/bin/psql -d test -c 'INSERT INTO test DEFAULT VALUES;'")
|
||||||
machine.succeed("runuser -u postgres -- /run/current-system/sw/bin/psql -d test -c 'DROP TABLE test;'")
|
machine.succeed("runuser -u postgres -- /run/current-system/sw/bin/psql -d test -c 'DROP TABLE test;'")
|
||||||
machine.succeed("test -e /var/backup/postgres/test/dump.sql.zstd || { echo 'backup.info not found'; exit 1; }")
|
machine.succeed("test -e /var/backup/postgres/test/pg-dump || { echo 'pg-dump not found'; exit 1; }")
|
||||||
|
|
||||||
machine.succeed("rm -rf /var/backup/postgres")
|
machine.succeed("rm -rf /var/backup/postgres")
|
||||||
|
|
||||||
machine.succeed("NAME=/mnt/external-disk/snapshot.0 FOLDERS=/var/backup/postgres/test /run/current-system/sw/bin/localbackup-restore >&2")
|
machine.succeed("NAME=/mnt/external-disk/snapshot.0 FOLDERS=/var/backup/postgres/test /run/current-system/sw/bin/localbackup-restore >&2")
|
||||||
machine.succeed("test -e /var/backup/postgres/test/dump.sql.zstd || { echo 'backup.info not found'; exit 1; }")
|
machine.succeed("test -e /var/backup/postgres/test/pg-dump || { echo 'pg-dump not found'; exit 1; }")
|
||||||
|
|
||||||
machine.succeed("""
|
machine.succeed("""
|
||||||
set -x
|
set -x
|
||||||
|
@ -42,6 +55,9 @@
|
||||||
machine.succeed("runuser -u postgres -- /run/current-system/sw/bin/psql -l >&2")
|
machine.succeed("runuser -u postgres -- /run/current-system/sw/bin/psql -l >&2")
|
||||||
machine.succeed("runuser -u postgres -- /run/current-system/sw/bin/psql -d test -c '\dt' >&2")
|
machine.succeed("runuser -u postgres -- /run/current-system/sw/bin/psql -d test -c '\dt' >&2")
|
||||||
|
|
||||||
|
timestamp_after = int(machine.succeed("systemctl show --property=ExecMainStartTimestampMonotonic sample-service | cut -d= -f2").strip())
|
||||||
|
assert timestamp_before < timestamp_after, f"{timestamp_before} >= {timestamp_after}: expected sample-service to be restarted after restore"
|
||||||
|
|
||||||
# Check that the table is still there
|
# Check that the table is still there
|
||||||
machine.succeed("runuser -u postgres -- /run/current-system/sw/bin/psql -d test -c 'SELECT * FROM test;'")
|
machine.succeed("runuser -u postgres -- /run/current-system/sw/bin/psql -d test -c 'SELECT * FROM test;'")
|
||||||
output = machine.succeed("runuser -u postgres -- /run/current-system/sw/bin/psql --csv -c \"SELECT datdba::regrole FROM pg_database WHERE datname = 'test'\"")
|
output = machine.succeed("runuser -u postgres -- /run/current-system/sw/bin/psql --csv -c \"SELECT datdba::regrole FROM pg_database WHERE datname = 'test'\"")
|
||||||
|
|
|
@ -9,7 +9,8 @@ let
|
||||||
db:
|
db:
|
||||||
let
|
let
|
||||||
folder = "/var/backup/postgres/${db.name}";
|
folder = "/var/backup/postgres/${db.name}";
|
||||||
current = "${folder}/dump.sql.zstd";
|
current = "${folder}/pg-dump";
|
||||||
|
compression = lib.optionalString (lib.versionAtLeast config.services.postgresql.package.version "16") "--compress=zstd";
|
||||||
in
|
in
|
||||||
{
|
{
|
||||||
folders = [ folder ];
|
folders = [ folder ];
|
||||||
|
@ -28,10 +29,9 @@ let
|
||||||
done
|
done
|
||||||
|
|
||||||
mkdir -p "${folder}"
|
mkdir -p "${folder}"
|
||||||
runuser -u postgres -- pg_dump --compress=zstd --dbname=${db.name} -Fc -c > "${current}.tmp"
|
runuser -u postgres -- pg_dump ${compression} --dbname=${db.name} -Fc -c > "${current}.tmp"
|
||||||
mv "${current}.tmp" ${current}
|
mv "${current}.tmp" ${current}
|
||||||
'';
|
'';
|
||||||
|
|
||||||
postRestoreCommand = ''
|
postRestoreCommand = ''
|
||||||
export PATH=${
|
export PATH=${
|
||||||
lib.makeBinPath [
|
lib.makeBinPath [
|
||||||
|
@ -52,10 +52,14 @@ let
|
||||||
done
|
done
|
||||||
|
|
||||||
if [[ -e "${current}" ]]; then
|
if [[ -e "${current}" ]]; then
|
||||||
umask 077 # only root can read the backup
|
(
|
||||||
mkdir -p "${folder}"
|
systemctl stop ${lib.concatStringsSep " " db.restore.stopOnRestore}
|
||||||
runuser -u postgres -- dropdb "${db.name}"
|
trap "systemctl start ${lib.concatStringsSep " " db.restore.stopOnRestore}" EXIT
|
||||||
runuser -u postgres -- pg_restore -C -d postgres "${current}"
|
|
||||||
|
mkdir -p "${folder}"
|
||||||
|
runuser -u postgres -- dropdb "${db.name}"
|
||||||
|
runuser -u postgres -- pg_restore -C -d postgres "${current}"
|
||||||
|
)
|
||||||
else
|
else
|
||||||
echo No database backup found, skipping restore
|
echo No database backup found, skipping restore
|
||||||
fi
|
fi
|
||||||
|
@ -111,10 +115,10 @@ in
|
||||||
OWNER = "foo";
|
OWNER = "foo";
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
backup.enable = lib.mkOption {
|
restore.stopOnRestore = lib.mkOption {
|
||||||
type = lib.types.bool;
|
type = lib.types.listOf lib.types.str;
|
||||||
default = true;
|
default = [ ];
|
||||||
description = "Backup the database.";
|
description = "List of services to stop before restoring the database.";
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
|
@ -33,6 +33,18 @@
|
||||||
e.g. a database dump
|
e.g. a database dump
|
||||||
'';
|
'';
|
||||||
};
|
};
|
||||||
|
|
||||||
|
# TODO: implement this
|
||||||
|
#stopOnRestore = lib.mkOption {
|
||||||
|
# type = lib.types.listOf lib.types.str;
|
||||||
|
# default = [];
|
||||||
|
# description = ''
|
||||||
|
# List of services to stop before restoring the state dir from a backup
|
||||||
|
|
||||||
|
# Utilize this to stop services which currently access these folders or or other services affected by the restore
|
||||||
|
# '';
|
||||||
|
#};
|
||||||
|
|
||||||
preRestoreCommand = lib.mkOption {
|
preRestoreCommand = lib.mkOption {
|
||||||
type = lib.types.nullOr lib.types.str;
|
type = lib.types.nullOr lib.types.str;
|
||||||
default = null;
|
default = null;
|
||||||
|
@ -42,6 +54,7 @@
|
||||||
Utilize this to stop services which currently access these folders
|
Utilize this to stop services which currently access these folders
|
||||||
'';
|
'';
|
||||||
};
|
};
|
||||||
|
|
||||||
postRestoreCommand = lib.mkOption {
|
postRestoreCommand = lib.mkOption {
|
||||||
type = lib.types.nullOr lib.types.str;
|
type = lib.types.nullOr lib.types.str;
|
||||||
default = null;
|
default = null;
|
||||||
|
|
Loading…
Reference in New Issue
Block a user