Expand backup and restore capabilities w.r.t. postgresql. #1582
@ -9,14 +9,14 @@
|
|||||||
self.clanModules.postgresql
|
self.clanModules.postgresql
|
||||||
self.clanModules.localbackup
|
self.clanModules.localbackup
|
||||||
];
|
];
|
||||||
clan.postgresl.databases = [ "test" ];
|
clan.postgresl.databases.test = {};
|
||||||
clan.localbackup.targets.hdd.directory = "/mnt/external-disk";
|
clan.localbackup.targets.hdd.directory = "/mnt/external-disk";
|
||||||
};
|
};
|
||||||
testScript = ''
|
testScript = ''
|
||||||
start_all()
|
start_all()
|
||||||
machine.succeed("systemctl status postgresql")
|
machine.succeed("systemctl status postgresql")
|
||||||
machine.wait_for_unit("postgresql")
|
machine.wait_for_unit("postgresql")
|
||||||
machine.succeed("localbackup-create")
|
machine.succeed("/run/current-system/sw/bin/localbackup-create >&2")
|
||||||
machine.succeed("ls -la /var/backups/postgresql")
|
machine.succeed("ls -la /var/backups/postgresql")
|
||||||
'';
|
'';
|
||||||
})
|
})
|
||||||
|
@ -101,7 +101,6 @@ in
|
|||||||
'';
|
'';
|
||||||
};
|
};
|
||||||
|
|
||||||
services.postgresql.enable = true;
|
|
||||||
services.nginx = {
|
services.nginx = {
|
||||||
enable = true;
|
enable = true;
|
||||||
virtualHosts = {
|
virtualHosts = {
|
||||||
|
@ -8,7 +8,7 @@ let
|
|||||||
createDatatbaseState =
|
createDatatbaseState =
|
||||||
db:
|
db:
|
||||||
let
|
let
|
||||||
folder = "/var/backup/postgresql/${db}";
|
folder = "/var/backup/postgresql/${db.name}";
|
||||||
curFile = "${folder}/dump.sql.zstd";
|
curFile = "${folder}/dump.sql.zstd";
|
||||||
prevFile = "${folder}/dump.sql.prev.zstd";
|
prevFile = "${folder}/dump.sql.prev.zstd";
|
||||||
inProgressFile = "${folder}/dump.sql.in-progress.zstd";
|
inProgressFile = "${folder}/dump.sql.in-progress.zstd";
|
||||||
@ -21,7 +21,11 @@ let
|
|||||||
if [ -e ${curFile} ]; then
|
if [ -e ${curFile} ]; then
|
||||||
mv ${curFile} ${prevFile}
|
mv ${curFile} ${prevFile}
|
||||||
fi
|
fi
|
||||||
pg_dump -C ${db} | \
|
while [[ "$(systemctl is-active postgres)" == activating ]]; then
|
||||||
|
sleep 1
|
||||||
|
done
|
||||||
|
systemctl is-active postgres
|
||||||
|
pg_dump -C ${db.name} | \
|
||||||
${pkgs.zstd}/bin/zstd --rsyncable | \
|
${pkgs.zstd}/bin/zstd --rsyncable | \
|
||||||
> ${inProgressFile}
|
> ${inProgressFile}
|
||||||
mv ${inProgressFile} ${curFile}
|
mv ${inProgressFile} ${curFile}
|
||||||
@ -29,24 +33,93 @@ let
|
|||||||
'';
|
'';
|
||||||
postRestoreCommand = ''
|
postRestoreCommand = ''
|
||||||
if [[ -f ${prevFile} ]]; then
|
if [[ -f ${prevFile} ]]; then
|
||||||
zstd --decompress --stdout ${prevFile} | psql -d ${db}
|
zstd --decompress --stdout ${prevFile} | psql -d ${db.name}
|
||||||
fi
|
fi
|
||||||
'';
|
'';
|
||||||
};
|
};
|
||||||
|
|
||||||
|
createDatabase = db: ''
|
||||||
|
CREATE DATABASE "${db.name}" ${
|
||||||
|
lib.concatStringsSep " " (
|
||||||
|
lib.mapAttrsToList (name: value: "${name} = ':${value}'") db.createOptions
|
||||||
|
)
|
||||||
|
}
|
||||||
|
'';
|
||||||
|
cfg = config.clan.postgresql;
|
||||||
|
|
||||||
|
userClauses = lib.mapAttrsToList (
|
||||||
|
_: user: ""
|
||||||
|
''$PSQL -tAc "SELECT 1 FROM pg_roles WHERE rolname='${user.name}'" | grep -q 1 || $PSQL -tAc 'CREATE USER "${user.name}"' ''
|
||||||
|
) cfg.users;
|
||||||
|
databaseClauses = lib.mapAttrsToList (
|
||||||
|
name: db:
|
||||||
|
lib.optionalString (db.create) ''$PSQL -d postgres -c "SELECT 1 FROM pg_database WHERE datname = '${name}'" | grep -q 1 || $PSQL -d postgres -c ${lib.escapeShellArg (createDatabase db)} ${createDatabaseArgs db}''
|
||||||
|
) cfg.databases;
|
||||||
in
|
in
|
||||||
{
|
{
|
||||||
options.clan.postgresl = {
|
options.clan.postgresl = {
|
||||||
databases = lib.mkOption {
|
databases = lib.mkOption {
|
||||||
type = lib.types.listOf lib.types.str;
|
default = { };
|
||||||
default = [ "clan" ];
|
type = lib.types.attrsOf (
|
||||||
|
lib.types.submodule (
|
||||||
|
{ name, ... }:
|
||||||
|
{
|
||||||
|
options = {
|
||||||
|
name = lib.mkOption {
|
||||||
|
type = lib.types.str;
|
||||||
|
default = name;
|
||||||
|
};
|
||||||
|
# set to false, in case the upstream module uses ensureDatabase option
|
||||||
|
create = lib.mkOption {
|
||||||
|
type = lib.types.bool;
|
||||||
|
default = true;
|
||||||
|
};
|
||||||
|
createOptions = lib.mkOption {
|
||||||
|
type = lib.types.lazyAttrsOf lib.types.str;
|
||||||
|
default = { };
|
||||||
|
example = {
|
||||||
|
TEMPLATE = "template0";
|
||||||
|
LC_COLLATE = "C";
|
||||||
|
LC_CTYPE = "C";
|
||||||
|
ENCODING = "UTF8";
|
||||||
|
OWNER = "foo";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
}
|
||||||
|
)
|
||||||
|
);
|
||||||
|
};
|
||||||
|
users = lib.mkOption {
|
||||||
|
default = { };
|
||||||
|
type = lib.types.attrsOf (
|
||||||
|
lib.types.submodule (
|
||||||
|
{ name, ... }:
|
||||||
|
{
|
||||||
|
options.name = lib.mkOption {
|
||||||
|
type = lib.types.str;
|
||||||
|
default = name;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
)
|
||||||
|
);
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
config = {
|
config = {
|
||||||
services.postgresql.enable = true;
|
services.postgresql.enable = true;
|
||||||
clanCore.state = lib.listToAttrs (
|
# We are duplicating a bit the upstream module but allow to create databases with options
|
||||||
builtins.map (
|
systemd.services.postgresql.postStart = ''
|
||||||
db: lib.nameValuePair "postgresql-${db}" (createDatatbaseState db)
|
PSQL="psql --port=${builtins.toString config.services.postgresql.settings.port}"
|
||||||
) config.clan.postgresl.databases
|
|
||||||
);
|
while ! $PSQL -d postgres -c "" 2> /dev/null; do
|
||||||
|
if ! kill -0 "$MAINPID"; then exit 1; fi
|
||||||
|
sleep 0.1
|
||||||
|
done
|
||||||
|
${lib.concatStringsSep "\n" userClauses}
|
||||||
|
${lib.concatStringsSep "\n" databaseClauses}
|
||||||
|
'';
|
||||||
|
clanCore.state = lib.mapAttrs' (
|
||||||
|
_: db: lib.nameValuePair "postgresql-${db.name}" (createDatatbaseState db)
|
||||||
|
) config.clan.postgresql.databases;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user