postgresql: add new method to create users and databases

This commit is contained in:
Jörg Thalheim 2024-06-04 12:56:39 +02:00
parent a8fa865825
commit 6404489fbc
2 changed files with 91 additions and 12 deletions

View File

@ -9,14 +9,14 @@
self.clanModules.postgresql
self.clanModules.localbackup
];
clan.postgresl.databases = [ "test" ];
clan.postgresl.databases.test = {};
clan.localbackup.targets.hdd.directory = "/mnt/external-disk";
};
testScript = ''
start_all()
machine.succeed("systemctl status 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")
'';
}

View File

@ -8,7 +8,7 @@ let
createDatatbaseState =
db:
let
folder = "/var/backup/postgresql/${db}";
folder = "/var/backup/postgresql/${db.name}";
curFile = "${folder}/dump.sql.zstd";
prevFile = "${folder}/dump.sql.prev.zstd";
inProgressFile = "${folder}/dump.sql.in-progress.zstd";
@ -21,7 +21,11 @@ let
if [ -e ${curFile} ]; then
mv ${curFile} ${prevFile}
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 | \
> ${inProgressFile}
mv ${inProgressFile} ${curFile}
@ -29,24 +33,99 @@ let
'';
postRestoreCommand = ''
if [[ -f ${prevFile} ]]; then
zstd --decompress --stdout ${prevFile} | psql -d ${db}
zstd --decompress --stdout ${prevFile} | psql -d ${db.name}
fi
'';
};
createDatabase = db: ''
CREATE DATABASE ${db.name} ${
lib.concatStringsSep " " (
lib.mapAttrsToList (name: value: "${name} = ':${value}'") db.createOptions
)
}
'';
createDatabaseArgs = db: ''
${lib.concatStringsSep " " (
lib.mapAttrsToList (name: value: "-v ${name}=${lib.escapeShellArg value}") db.createOptions
)}
'';
cfg = config.clan.postgresl;
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
{
options.clan.postgresl = {
databases = lib.mkOption {
type = lib.types.listOf lib.types.str;
default = [ "clan" ];
default = { };
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 = {
services.postgresql.enable = true;
clanCore.state = lib.listToAttrs (
builtins.map (
db: lib.nameValuePair "postgresql-${db}" (createDatatbaseState db)
) config.clan.postgresl.databases
);
# We are duplicating a bit the upstream module but allow to create databases with options
systemd.services.postgresql.postStart = ''
PSQL="psql --port=${builtins.toString config.services.postgresql.settings.port}"
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.postgresl.databases;
};
}