nix/shared/db/postgres.nix

102 lines
No EOL
4 KiB
Nix

{ config, pkgs, lib, ... }:
let
# Import nodes
nodes = import ./../../nodes.nix;
myName = config.hostName;
myNode = nodes."${myName}";
# And mapping
mapping = import ./../../mapping.nix;
cfg = config.services.postgresql;
masterNode = nodes.${mapping.db.master};
masterIP = "172.19.${toString masterNode.zone}.${toString masterNode.id}";
in
{
services.postgresql = {
enable = true;
# Force postgres package major version
# to avoid any unwanted upgrades
package = pkgs.postgresql_17;
identMap = ''
# ArbitraryMapName systemUser DBUser
superuser_map root postgres
superuser_map postgres postgres
'';
# Replication tasks are not authenticated
# The wireguard mesh cryptographically
# ensures the sender is who we expect.
authentication = lib.mkForce (builtins.concatStringsSep "\n" ([''
#type database DBuser auth-method optional_ident_map
local all all peer map=superuser_map
'']
++ lib.optionals (myName == mapping.db.master)
(map (slaveName: let slaveNode = nodes.${slaveName}; in
"host replication replication 172.19.${toString slaveNode.zone}.${toString slaveNode.id}/32 trust"
) mapping.db.slaves)
++ lib.optionals (builtins.elem myName mapping.db.slaves) [
"host replication replication ${masterIP}/32 trust"
]));
ensureUsers = lib.mkIf (myName == mapping.db.master) [{
name = "replication";
ensureClauses.replication = true;
}];
settings = {
listen_addresses = lib.mkForce "localhost,172.19.${toString myNode.zone}.${toString myNode.id}";
port = 5432;
log_connections = true;
log_statement = "none";
logging_collector = true;
log_disconnections = true;
max_wal_senders = 16;
wal_level = "logical";
} // lib.optionalAttrs (myName == mapping.db.master) {
wal_sender_timeout = "60s";
wal_keep_size = 1000; # In MB
} // lib.optionalAttrs (builtins.elem myName mapping.db.slaves) {
wal_receiver_timeout = "60s";
hot_standby = "on";
primary_conninfo = "host=${masterIP} port=5432 user=replication";
};
};
# This preStart script sync the slaves to the master
# systemd.services.<name>.preStart has a mergeable type
systemd.services.postgresql.preStart = lib.mkIf (builtins.elem myName mapping.db.slaves) ''
if test -e ${cfg.dataDir}/.first_startup; then
echo "Setting up PostgreSQL slave replication..."
# This is a sl that's defined by the default preStart script
# We need an empty dataDir for the pg_basebackup
# And there is no easy ways that I'm aware of
# to get the hash of that file without recomputing it
PSQL_CONF_PATH="${cfg.dataDir}/postgresql.conf"
PSQL_CONF_TARGET=$(readlink "$PSQL_CONF_PATH")
# Remove data dir
if [ -d "${cfg.dataDir}" ]; then
echo "Deleting postgres data dir: ${cfg.dataDir}"
rm -rf "${cfg.dataDir}"
fi
# Perform base backup from master
echo "Starting base backup from master: ${masterIP}"
${cfg.package}/bin/pg_basebackup \
-h "${masterIP}" \
-U replication \
-p ${toString cfg.settings.port} \
-D "${cfg.dataDir}" \
-P \
-Xs \
-R
# Symlink back the psql configFile
ln -sf "$PSQL_CONF_TARGET" "$PSQL_CONF_PATH"
echo "PostgreSQL slave setup completed successfully"
else
echo "PostgreSQL standby already configured (standby.signal exists), skipping base backup"
fi
'';
}