1
0
Fork 0
selfhostblocks/modules/blocks/postgresql.nix
ibizaman 6235b2f414 always restart postgresql service
For example, it can be killed by systemd-oom but it's such a foundational service that we should
always restart it.
2024-08-13 03:45:05 +02:00

150 lines
4.7 KiB
Nix

{ config, lib, pkgs, ... }:
let
cfg = config.shb.postgresql;
upgrade-script = old: new:
let
oldStr = builtins.toString old;
newStr = builtins.toString new;
oldPkg = pkgs.${"postgresql_${oldStr}"};
newPkg = pkgs.${"postgresql_${newStr}"};
in
pkgs.writeScriptBin "upgrade-pg-cluster-${oldStr}-${newStr}" ''
set -eux
# XXX it's perhaps advisable to stop all services that depend on postgresql
systemctl stop postgresql
export NEWDATA="/var/lib/postgresql/${newPkg.psqlSchema}"
export NEWBIN="${newPkg}/bin"
export OLDDATA="/var/lib/postgresql/${oldPkg.psqlSchema}"
export OLDBIN="${oldPkg}/bin"
install -d -m 0700 -o postgres -g postgres "$NEWDATA"
cd "$NEWDATA"
sudo -u postgres $NEWBIN/initdb -D "$NEWDATA"
sudo -u postgres $NEWBIN/pg_upgrade \
--old-datadir "$OLDDATA" --new-datadir "$NEWDATA" \
--old-bindir $OLDBIN --new-bindir $NEWBIN \
"$@"
'';
in
{
options.shb.postgresql = {
debug = lib.mkOption {
type = lib.types.bool;
description = ''
Enable debugging options.
Currently enables shared_preload_libraries = "auto_explain, pg_stat_statements"
See https://www.postgresql.org/docs/current/pgstatstatements.html'';
default = false;
};
enableTCPIP = lib.mkOption {
type = lib.types.bool;
description = "Enable TCP/IP connection on given port.";
default = false;
};
ensures = lib.mkOption {
description = "List of username, database and/or passwords that should be created.";
type = lib.types.listOf (lib.types.submodule {
options = {
username = lib.mkOption {
type = lib.types.str;
description = "Postgres user name.";
};
database = lib.mkOption {
type = lib.types.str;
description = "Postgres database.";
};
passwordFile = lib.mkOption {
type = lib.types.nullOr lib.types.str;
description = "Optional password file for the postgres user. If not given, only peer auth is accepted for this user, otherwise password auth is allowed.";
default = null;
example = "/run/secrets/postgresql/password";
};
};
});
default = [];
};
};
config =
let
commonConfig = {
systemd.services.postgresql.serviceConfig.Restart = "always";
services.postgresql.settings = {
};
};
tcpConfig = {
services.postgresql.enableTCPIP = true;
services.postgresql.authentication = lib.mkOverride 10 ''
#type database DBuser origin-address auth-method
local all all peer
# ipv4
host all all 127.0.0.1/32 password
# ipv6
host all all ::1/128 password
'';
};
dbConfig = ensureCfgs: {
services.postgresql.enable = lib.mkDefault ((builtins.length ensureCfgs) > 0);
services.postgresql.ensureDatabases = map ({ database, ... }: database) ensureCfgs;
services.postgresql.ensureUsers = map ({ username, database, ... }: {
name = username;
ensureDBOwnership = true;
ensureClauses.login = true;
}) ensureCfgs;
};
pwdConfig = ensureCfgs: {
systemd.services.postgresql.postStart =
let
prefix = ''
$PSQL -tA <<'EOF'
DO $$
DECLARE password TEXT;
BEGIN
'';
suffix = ''
END $$;
EOF
'';
exec = { username, passwordFile, ... }: ''
password := trim(both from replace(pg_read_file('${passwordFile}'), E'\n', '''));
EXECUTE format('ALTER ROLE ${username} WITH PASSWORD '''%s''';', password);
'';
cfgsWithPasswords = builtins.filter (cfg: cfg.passwordFile != null) ensureCfgs;
in
if (builtins.length cfgsWithPasswords) == 0 then "" else
prefix + (lib.concatStrings (map exec cfgsWithPasswords)) + suffix;
};
debugConfig = enableDebug: lib.mkIf enableDebug {
services.postgresql.settings.shared_preload_libraries = "auto_explain, pg_stat_statements";
};
in
lib.mkMerge ([
commonConfig
(dbConfig cfg.ensures)
(pwdConfig cfg.ensures)
(lib.mkIf cfg.enableTCPIP tcpConfig)
(debugConfig cfg.debug)
{
environment.systemPackages = lib.mkIf config.services.postgresql.enable [
(upgrade-script 13 14)
(upgrade-script 14 15)
(upgrade-script 15 16)
];
}
]);
}