0
0
Fork 0
mirror of https://github.com/NixOS/nixpkgs.git synced 2025-07-19 16:40:32 +03:00

nixos/postgresql: move postStart into separate unit

This avoids restarting the postgresql server, when only ensureDatabases
or ensureUsers have been changed. It will also allow to properly wait
for recovery to finish later.

To wait for "postgresql is ready" in other services, we now provide a
postgresql.target.

Resolves #400018

Co-authored-by: Marcel <me@m4rc3l.de>
This commit is contained in:
Wolfgang Walther 2025-05-02 14:58:46 +02:00
parent c119848700
commit 41c5662cbe
No known key found for this signature in database
GPG key ID: B39893FA5F65CAE1
139 changed files with 391 additions and 424 deletions

View file

@ -751,12 +751,23 @@ in
cfg.checkConfig && pkgs.stdenv.hostPlatform == pkgs.stdenv.buildPlatform
) configFileCheck;
systemd.targets.postgresql = {
description = "PostgreSQL";
wantedBy = [ "multi-user.target" ];
bindsTo = [
"postgresql.service"
"postgresql-setup.service"
];
};
systemd.services.postgresql = {
description = "PostgreSQL Server";
wantedBy = [ "multi-user.target" ];
after = [ "network.target" ];
# To trigger the .target also on "systemctl start postgresql".
bindsTo = [ "postgresql.target" ];
environment.PGDATA = cfg.dataDir;
path = [ cfg.finalPackage ];
@ -776,49 +787,6 @@ in
ln -sfn "${configFile}/postgresql.conf" "${cfg.dataDir}/postgresql.conf"
'';
# Wait for PostgreSQL to be ready to accept connections.
postStart =
''
PSQL="psql --port=${builtins.toString cfg.settings.port}"
while ! $PSQL -d postgres -c "" 2> /dev/null; do
if ! kill -0 "$MAINPID"; then exit 1; fi
sleep 0.1
done
if test -e "${cfg.dataDir}/.first_startup"; then
${optionalString (cfg.initialScript != null) ''
$PSQL -f "${cfg.initialScript}" -d postgres
''}
rm -f "${cfg.dataDir}/.first_startup"
fi
''
+ optionalString (cfg.ensureDatabases != [ ]) ''
${concatMapStrings (database: ''
$PSQL -tAc "SELECT 1 FROM pg_database WHERE datname = '${database}'" | grep -q 1 || $PSQL -tAc 'CREATE DATABASE "${database}"'
'') cfg.ensureDatabases}
''
+ ''
${concatMapStrings (
user:
let
dbOwnershipStmt = optionalString user.ensureDBOwnership ''$PSQL -tAc 'ALTER DATABASE "${user.name}" OWNER TO "${user.name}";' '';
filteredClauses = filterAttrs (name: value: value != null) user.ensureClauses;
clauseSqlStatements = attrValues (mapAttrs (n: v: if v then n else "no${n}") filteredClauses);
userClauses = ''$PSQL -tAc 'ALTER ROLE "${user.name}" ${concatStringsSep " " clauseSqlStatements}' '';
in
''
$PSQL -tAc "SELECT 1 FROM pg_roles WHERE rolname='${user.name}'" | grep -q 1 || $PSQL -tAc 'CREATE USER "${user.name}"'
${userClauses}
${dbOwnershipStmt}
''
) cfg.ensureUsers}
'';
serviceConfig = mkMerge [
{
ExecReload = "${pkgs.coreutils}/bin/kill -HUP $MAINPID";
@ -891,6 +859,64 @@ in
unitConfig.RequiresMountsFor = "${cfg.dataDir}";
};
systemd.services.postgresql-setup = {
description = "PostgreSQL Setup Scripts";
requires = [ "postgresql.service" ];
after = [ "postgresql.service" ];
serviceConfig = {
User = "postgres";
Group = "postgres";
Type = "oneshot";
RemainAfterExit = true;
};
path = [ cfg.finalPackage ];
environment.PGPORT = builtins.toString cfg.settings.port;
# Wait for PostgreSQL to be ready to accept connections.
script =
''
while ! psql -d postgres -c "" 2> /dev/null; do
if ! systemctl is-active --quiet postgresql.service; then exit 1; fi
sleep 0.1
done
if test -e "${cfg.dataDir}/.first_startup"; then
${optionalString (cfg.initialScript != null) ''
psql -f "${cfg.initialScript}" -d postgres
''}
rm -f "${cfg.dataDir}/.first_startup"
fi
''
+ optionalString (cfg.ensureDatabases != [ ]) ''
${concatMapStrings (database: ''
psql -tAc "SELECT 1 FROM pg_database WHERE datname = '${database}'" | grep -q 1 || psql -tAc 'CREATE DATABASE "${database}"'
'') cfg.ensureDatabases}
''
+ ''
${concatMapStrings (
user:
let
dbOwnershipStmt = optionalString user.ensureDBOwnership ''psql -tAc 'ALTER DATABASE "${user.name}" OWNER TO "${user.name}";' '';
filteredClauses = filterAttrs (name: value: value != null) user.ensureClauses;
clauseSqlStatements = attrValues (mapAttrs (n: v: if v then n else "no${n}") filteredClauses);
userClauses = ''psql -tAc 'ALTER ROLE "${user.name}" ${concatStringsSep " " clauseSqlStatements}' '';
in
''
psql -tAc "SELECT 1 FROM pg_roles WHERE rolname='${user.name}'" | grep -q 1 || psql -tAc 'CREATE USER "${user.name}"'
${userClauses}
${dbOwnershipStmt}
''
) cfg.ensureUsers}
'';
};
};
meta.doc = ./postgresql.md;