591 lines
23 KiB
Bash
Executable file
591 lines
23 KiB
Bash
Executable file
#!/bin/sh
|
|
|
|
# Ce script sert à créer ou détruire :
|
|
# - une instance PostgreSQL (PGDATA).
|
|
|
|
# Il peut également gérer un serveur esclave en définissant la
|
|
# variable $ESCLAVE . Dans ce cas là, mieux vaut avoir une authentification
|
|
# par clef (les opérations se font par ssh)
|
|
#
|
|
# Attention, ce script affiche les identifiants à l'écran.
|
|
|
|
# Prérequis :
|
|
# - PostgreSQL
|
|
# Si utilisation d'un esclave :
|
|
# - une authentification pour l'utilisateur root local vers root@$ESCLAVE par clef,
|
|
# - une authentification pour l'utilisateur postgres local vers postgres@$ESCLAVE par clef.
|
|
|
|
# Trucs à nettoyer (si quelque chose part en vrille, ou simplement
|
|
# pour désinstaller ):
|
|
# - TODO
|
|
|
|
# Version de PostgreSQL : 9.1 seule testée
|
|
VERSION_POSTGRESQL="9.1"
|
|
# Mettre ci-dessous le nom d'hôte ou l'IP du serveur esclave
|
|
# (utilisé par la config PG + les connexions SSH pour l'exécution
|
|
# des commandes distantes de ce script)
|
|
ESCLAVE=""
|
|
# idem pour le maître (vu depuis l'esclave en cas de réseau privé)
|
|
# (utilisé pour la config PG)
|
|
MAITRE=""
|
|
|
|
# Initialisation des variables globales
|
|
MODE_CREATION=0
|
|
MODE_DESTRUCTION=0
|
|
POSTGRESQL_REPLICATION_USER_NAME="repliquser"
|
|
POSTGRESQL_LOCALE="fr_FR.utf8"
|
|
POSTGRESQL_PORT=""
|
|
|
|
# Par défaut, on arrête le script à la première erreur non "catchée"
|
|
set -e
|
|
|
|
# On s'exécute dans un dossier accessible à l'utilisateur postgres
|
|
cd /tmp
|
|
|
|
# Fonctions
|
|
# affiche le message d'aide
|
|
usage() {
|
|
cat <<EOF
|
|
$0 -c cluster-name [ -e <hostname de l'esclave> -m <hostname du maître> ] [ -p <numéro de port> ]
|
|
$0 -d cluster-name [ -e <hostname de l'esclave> -m <hostname du maître> ]
|
|
$0 -h
|
|
|
|
-c xxx : création d'une instance/cluster nommée 'xxx'
|
|
-d xxx : destruction de l'instance nommée 'xxx'
|
|
|
|
-p nnn : numéro de port à affecter au nouveau cluster (par défaut, 'auto')
|
|
|
|
# Ce script peut générer la configuration nécessaire au streaming replication
|
|
-e esclave : nom d'hôte ou IP de l'esclave
|
|
-m maitre : nom d'hôte ou IP du serveur maître
|
|
|
|
-h : ce message d'aide
|
|
EOF
|
|
}
|
|
|
|
# Arguments
|
|
# $1 : IPv4, IPv6 ou nom d'hôte
|
|
# Cette fonction suffixe d'un /32 ou /128
|
|
# la chaîne si celle-ci est une adresse IP
|
|
add_mask_ip() {
|
|
test -n "$1" || exit 1
|
|
|
|
if [ $( echo "$1" | egrep -c "^([[:digit:]]{1,3}\.){3}[[:digit:]]{1,3}$" ) -gt 0 ]; then
|
|
printf "$1/32"
|
|
elif [ $( echo "$1" | egrep -c "^[[:xdigit:]:]*$" ) -gt 0 ]; then
|
|
printf "$1/128"
|
|
else
|
|
printf "$1"
|
|
fi
|
|
}
|
|
|
|
# Arguments
|
|
# $1 : IP esclave
|
|
# $2 : version PostgreSQL
|
|
# $3 : nom de l'instance
|
|
generate_patch_postgresqlconf_master() {
|
|
test -n "$1" && test -n "$2" && test -n "$3" || exit 1
|
|
cat <<EOF
|
|
@@ -56,6 +56,8 @@
|
|
|
|
# - Connection Settings -
|
|
|
|
+# Script MI PostgreSQL : écoute sur toutes les interfaces nécessaire pour la streaming replication
|
|
+listen_addresses = '*'
|
|
#listen_addresses = 'localhost' # what IP address(es) to listen on;
|
|
# comma-separated list of addresses;
|
|
# defaults to 'localhost', '*' = all
|
|
@@ -150,6 +152,8 @@ shared_buffers = 24MB # min 128kB
|
|
|
|
# - Settings -
|
|
|
|
+# Script MI PostgreSQL : serveur maître
|
|
+wal_level = hot_standby
|
|
#wal_level = minimal # minimal, archive, or hot_standby
|
|
# (change requires restart)
|
|
#fsync = on # turns forced synchronization on or off
|
|
@@ -178,9 +182,10 @@ shared_buffers = 24MB # min 128kB
|
|
|
|
# - Archiving -
|
|
|
|
-#archive_mode = off # allows archiving to be done
|
|
+# Script MI PostgreSQL : Serveur maître: activation de l'archivage et de l'envoi vers l'esclave
|
|
+archive_mode = on # allows archiving to be done
|
|
# (change requires restart)
|
|
-#archive_command = '' # command to use to archive a logfile segment
|
|
+archive_command = 'scp -q -B -C %p postgres@$1:/var/lib/postgresql/$2/$3/archives_from_master/%f' # command to use to archive a logfile segment
|
|
#archive_timeout = 0 # force a logfile segment switch after this
|
|
# number of seconds; 0 disables
|
|
|
|
@@ -193,10 +198,12 @@
|
|
|
|
# These settings are ignored on a standby server
|
|
|
|
+max_wal_senders = 3
|
|
#max_wal_senders = 0 # max number of walsender processes
|
|
# (change requires restart)
|
|
#wal_sender_delay = 1s # walsender cycle time, 1-10000 milliseconds
|
|
-#wal_keep_segments = 0 # in logfile segments, 16MB each; 0 disables
|
|
+# Script MI PostgreSQL : serveur maître: conservation des WAL
|
|
+wal_keep_segments = 32 # in logfile segments, 16MB each; 0 disables
|
|
#vacuum_defer_cleanup_age = 0 # number of xacts by which cleanup is delayed
|
|
#replication_timeout = 60s # in milliseconds; 0 disables
|
|
#synchronous_standby_names = '' # standby servers that provide sync rep
|
|
@@ -207,6 +213,9 @@ shared_buffers = 24MB # min 128kB
|
|
|
|
# These settings are ignored on a master server
|
|
|
|
+# Script MI PostgreSQL : mis en place sur le maître comme sur l'esclave, pour homogénéiser
|
|
+# comme il est ignoré sur le maître, ça ne pose pas de souci :)
|
|
+hot_standby = on
|
|
#hot_standby = off # "on" allows queries during recovery
|
|
# (change requires restart)
|
|
#max_standby_archive_delay = 30s # max delay before canceling queries
|
|
EOF
|
|
}
|
|
|
|
# Arguments
|
|
# $1 : nom de l'instance
|
|
generate_patch_postgresql_pghbaconf() {
|
|
test -n "$1" || exit 1
|
|
cat <<EOF
|
|
@@ -87,11 +87,11 @@ local all postgres peer
|
|
# TYPE DATABASE USER ADDRESS METHOD
|
|
|
|
# "local" is for Unix domain socket connections only
|
|
-local all all peer
|
|
+local $1 $1 md5
|
|
# IPv4 local connections:
|
|
-host all all 127.0.0.1/32 md5
|
|
+host $1 $1 127.0.0.1/32 md5
|
|
# IPv6 local connections:
|
|
-host all all ::1/128 md5
|
|
+host $1 $1 ::1/128 md5
|
|
# Allow replication connections from localhost, by a user with the
|
|
# replication privilege.
|
|
#local replication postgres peer
|
|
EOF
|
|
}
|
|
|
|
# Pas d'arguments
|
|
generate_patch_postgresqlconf_slave() {
|
|
cat <<EOF
|
|
@@ -56,6 +56,8 @@
|
|
|
|
# - Connection Settings -
|
|
|
|
+# Script MI PostgreSQL : écoute sur toutes les interfaces nécessaire pour la streaming replication
|
|
+listen_addresses = '*'
|
|
#listen_addresses = 'localhost' # what IP address(es) to listen on;
|
|
# comma-separated list of addresses;
|
|
# defaults to 'localhost', '*' = all
|
|
@@ -150,6 +152,8 @@ shared_buffers = 24MB # min 128kB
|
|
|
|
# - Settings -
|
|
|
|
+# Script MI PostgreSQL : serveur esclave
|
|
+wal_level = hot_standby
|
|
#wal_level = minimal # minimal, archive, or hot_standby
|
|
# (change requires restart)
|
|
#fsync = on # turns forced synchronization on or off
|
|
@@ -193,10 +198,12 @@
|
|
|
|
# These settings are ignored on a standby server
|
|
|
|
+max_wal_senders = 3
|
|
#max_wal_senders = 0 # max number of walsender processes
|
|
# (change requires restart)
|
|
#wal_sender_delay = 1s # walsender cycle time, 1-10000 milliseconds
|
|
-#wal_keep_segments = 0 # in logfile segments, 16MB each; 0 disables
|
|
+# Script MI PostgreSQL : serveur maître: conservation des WAL
|
|
+wal_keep_segments = 32 # in logfile segments, 16MB each; 0 disables
|
|
#vacuum_defer_cleanup_age = 0 # number of xacts by which cleanup is delayed
|
|
#replication_timeout = 60s # in milliseconds; 0 disables
|
|
#synchronous_standby_names = '' # standby servers that provide sync rep
|
|
@@ -207,6 +213,9 @@ shared_buffers = 24MB # min 128kB
|
|
|
|
# These settings are ignored on a master server
|
|
|
|
+# Script MI PostgreSQL : mis en place sur le maître comme sur l'esclave, pour homogénéiser
|
|
+# comme il est ignoré sur le maître, ça ne pose pas de souci :)
|
|
+hot_standby = on
|
|
#hot_standby = off # "on" allows queries during recovery
|
|
# (change requires restart)
|
|
#max_standby_archive_delay = 30s # max delay before canceling queries
|
|
EOF
|
|
}
|
|
|
|
# Arguments:
|
|
# $1 : IP maître
|
|
# $2 : port maître (idem esclave, en fait)
|
|
# $3 : utilisateur dédié à la réplication
|
|
# $4 : mot de passe dudit utilisateur
|
|
# $5 : version de PostgreSQL
|
|
# $6 : nom de l'instance
|
|
# $7 : chemin complet de pg_archivecleanup (si vide, désactivé)
|
|
generate_file_postgresqlrecoveryconf_slave() {
|
|
local ARCHIVE_CLEANUP_COMMAND
|
|
test -n "$1" && test -n "$2" && test -n "$3" && test -n "$4" && test -n "$5" && test -n "$6" || exit 1
|
|
|
|
if ! test -n "$7"; then
|
|
ARCHIVE_CLEANUP_COMMAND="#archive_cleanup_command = 'pg_archivecleanup /var/lib/postgresql/$5/$6/archives_from_master %r'"
|
|
else
|
|
ARCHIVE_CLEANUP_COMMAND="archive_cleanup_command = '$7 /var/lib/postgresql/$5/$6/archives_from_master %r'"
|
|
fi
|
|
|
|
cat <<EOF
|
|
# Note that recovery.conf must be in \$PGDATA directory.
|
|
|
|
# Specifies whether to start the server as a standby. In streaming replication,
|
|
# this parameter must be set to on.
|
|
standby_mode = 'on'
|
|
|
|
# Specifies a connection string which is used for the standby server to connect
|
|
# with the primary.
|
|
primary_conninfo = 'host=$1 port=$2 user=$3 password=$4'
|
|
|
|
# Specifies a trigger file whose presence should cause streaming replication to
|
|
# end (i.e., failover).
|
|
# Cf pg_ctlcluster promote pour une alternative
|
|
trigger_file = '/var/lib/postgresql/trigger-postgresql'
|
|
|
|
# Specifies a command to load archive segments from the WAL archive. If
|
|
# wal_keep_segments is a high enough number to retain the WAL segments
|
|
# required for the standby server, this may not be necessary. But
|
|
# a large workload can cause segments to be recycled before the standby
|
|
# is fully synchronized, requiring you to start again from a new base backup.
|
|
restore_command = 'cp /var/lib/postgresql/$5/$6/archives_from_master/%f "%p"'
|
|
|
|
# Specifies a command to clean up obsolete archive logs
|
|
$ARCHIVE_CLEANUP_COMMAND
|
|
EOF
|
|
}
|
|
|
|
# Arguments:
|
|
# $1 : Nom de la bdd / de l'utilisateur
|
|
# $2 : mot de passe de l'utilisateur
|
|
generate_script_postgresql_creation_db_et_user() {
|
|
local NOM_INSTANCE POSTGRESQL_PASSWORD
|
|
test -n "$1" && test -n "$2" || exit 1
|
|
NOM_INSTANCE="$1"
|
|
POSTGRESQL_PASSWORD="$2"
|
|
|
|
cat <<EOF
|
|
-- Création de l'utilisateur principal
|
|
CREATE USER "$NOM_INSTANCE" WITH PASSWORD '$POSTGRESQL_PASSWORD' CONNECTION LIMIT 50;
|
|
|
|
|
|
-- Restriction des privilèges par défaut
|
|
-- Cette partie du script vient en grande partie de :
|
|
-- http://wiki.postgresql.org/wiki/Shared_Database_Hosting
|
|
|
|
-- Connexion à template1
|
|
\c template1
|
|
-- Révocation sur la base template1
|
|
REVOKE ALL ON DATABASE template1 FROM public;
|
|
REVOKE ALL ON SCHEMA public FROM public;
|
|
GRANT ALL ON SCHEMA public TO postgres;
|
|
|
|
-- Ce passage-là est plus parano, mais à étudier avant suppression
|
|
REVOKE ALL ON pg_user FROM public;
|
|
REVOKE ALL ON pg_roles FROM public;
|
|
REVOKE ALL ON pg_group FROM public;
|
|
REVOKE ALL ON pg_authid FROM public;
|
|
REVOKE ALL ON pg_auth_members FROM public;
|
|
REVOKE ALL ON pg_database FROM public;
|
|
REVOKE ALL ON pg_tablespace FROM public;
|
|
REVOKE ALL ON pg_settings FROM public;
|
|
|
|
|
|
-- Création de la nouvelle base de données
|
|
CREATE DATABASE "$NOM_INSTANCE" WITH OWNER = "$NOM_INSTANCE" ENCODING = 'UTF8';
|
|
REVOKE ALL ON DATABASE "$NOM_INSTANCE" FROM public;
|
|
\c $NOM_INSTANCE
|
|
REVOKE ALL ON SCHEMA public FROM public;
|
|
GRANT ALL ON SCHEMA public TO "$NOM_INSTANCE";
|
|
EOF
|
|
}
|
|
|
|
# Arguments:
|
|
# $1 : nom de l'utilisateur dédié à la réplication
|
|
# $2 : mot de passe dudit utilisateur
|
|
generate_script_postgresql_creation_replication_user() {
|
|
test -n "$1" && test -n "$2" || exit 1
|
|
POSTGRESQL_REPLICATION_USER_NAME="$1"
|
|
POSTGRESQL_REPLICATION_PASSWORD="$2"
|
|
|
|
cat <<EOF
|
|
-- Création de l'utilisateur utilisé par l'esclave pour la streaming replication
|
|
CREATE USER $POSTGRESQL_REPLICATION_USER_NAME WITH PASSWORD '$POSTGRESQL_REPLICATION_PASSWORD' REPLICATION;
|
|
EOF
|
|
}
|
|
|
|
# Arguments
|
|
# none
|
|
log_alias() {
|
|
# Cette fonction est utilisée pour "capturer" les sorties des différentes
|
|
# commandes (hors messages générés par le script lui-même)
|
|
# Note : elle peut être modifiée pour envoyer les messages vers un fichier
|
|
# de log temporaire. Ça serait plus propre.
|
|
sed 's/^/ /'
|
|
}
|
|
fancylog() {
|
|
BEGINNING="$( printf "%s" "$1" | head -n 1 | sed -n "s/^\([A-Z]\+\):.*/\1/p" )"
|
|
if [ -n "$BEGINNING" ] && [ -t 1 ] && tput setaf 1 >/dev/null 2>&1; then
|
|
case "$BEGINNING" in
|
|
"ERREUR"|"ERROR")
|
|
tput setaf 1;;
|
|
"WARN"|"WARNING")
|
|
tput setaf 3;;
|
|
"INFO"|"DEBUG")
|
|
tput setaf 2;;
|
|
esac
|
|
printf "%s" "$BEGINNING"
|
|
tput op
|
|
printf "%s\n" "$( printf "%s" "$1" | sed '1 s/^[A-Z]\+:/:/' )"
|
|
else
|
|
printf "%s\n" "$1"
|
|
fi
|
|
}
|
|
|
|
|
|
# Début du code
|
|
# gestion des options de lancement
|
|
while getopts c:d:e:m:p:h f; do
|
|
case $f in
|
|
'c')
|
|
MODE_CREATION=1
|
|
NOM_INSTANCE="$OPTARG"
|
|
;;
|
|
|
|
'd')
|
|
MODE_DESTRUCTION=1
|
|
NOM_INSTANCE="$OPTARG"
|
|
;;
|
|
|
|
'e')
|
|
ESCLAVE="$OPTARG"
|
|
;;
|
|
|
|
'm')
|
|
MAITRE="$OPTARG"
|
|
;;
|
|
|
|
'p')
|
|
if [ "$OPTARG" = "auto" ]; then
|
|
unset POSTGRESQL_PORT
|
|
else
|
|
POSTGRESQL_PORT="$( printf "%d" "$OPTARG" )"
|
|
fi
|
|
;;
|
|
|
|
'h')
|
|
usage
|
|
exit 0
|
|
;;
|
|
|
|
\?)
|
|
usage >&2
|
|
exit 1
|
|
;;
|
|
esac
|
|
done
|
|
#(code inutile, mais que je garde parce qu'on ne sait jamais)
|
|
#shift $( expr $OPTIND - 1 )
|
|
#DATA="$1"
|
|
if [ -n "$MAITRE" ] && [ -n "$ESCLAVE" ]; then
|
|
MAITRE_WITH_MASK=$( add_mask_ip "$MAITRE" )
|
|
ESCLAVE_WITH_MASK=$( add_mask_ip "$ESCLAVE" )
|
|
fi
|
|
|
|
# Petite vérif.
|
|
case $(( $MODE_CREATION + $MODE_DESTRUCTION )) in
|
|
'0')
|
|
fancylog "ERREUR: veuillez choisir entre création et destruction." >&2
|
|
usage >&2
|
|
exit 1
|
|
;;
|
|
'2')
|
|
fancylog "ERREUR: tu veux créer et détruire en même temps, petit malin ?" >&2
|
|
exit 1
|
|
;;
|
|
esac
|
|
|
|
# Petites vérifications préliminaires :
|
|
fancylog "INFO: petites vérifications préliminaires..."
|
|
# - vérifications sur le nom du clustername fourni
|
|
OLD_LC_ALL="$LC_ALL"
|
|
export LC_ALL=C
|
|
export LANG=C
|
|
if [ $( printf "$NOM_INSTANCE" | egrep -c "^[a-z][a-z0-9_]{0,14}$" ) -ne 1 ]; then
|
|
fancylog "ERREUR: clustername vide ou contenant des caractères interdits : regexp : [a-z][a-z0-9_]{0,14}" >&2
|
|
exit 1
|
|
fi
|
|
export LC_ALL="$OLD_LC_ALL"
|
|
export LANG="$OLD_LC_ALL"
|
|
# - est-ce que l'auth. SSH par clef fonctionne pour root et postgres ?
|
|
if [ -n "$ESCLAVE" ]; then
|
|
# - vérification de l'auth. par clefs SSH
|
|
if ! ssh -o BatchMode=yes root@$ESCLAVE /bin/true; then
|
|
fancylog "ERREUR: auth. par clef SSH non configurée pour l'utilisateur 'root'."
|
|
exit 1
|
|
fi
|
|
if ! su -c "ssh -o BatchMode=yes postgres@$ESCLAVE /bin/true" postgres; then
|
|
fancylog "ERREUR: auth. par clef SSH non configurée pour l'utilisateur 'postgres'."
|
|
exit 1
|
|
fi
|
|
|
|
# - vérification de la présence de $MAITRE
|
|
if [ ! -n "$MAITRE" ]; then
|
|
fancylog "ERREUR: serveur esclave indiqué, mais pas de serveur maître (option -m)." >&2
|
|
exit 1
|
|
fi
|
|
fi
|
|
|
|
# - est-ce qu'on est bien sur une Debian 6 ou 7
|
|
# (c'est surtout pour éviter les mauvaises surprises, ce script n'ayant pas été testé ailleurs)
|
|
if [ ! -f "/etc/debian_version" ] || [ $( egrep -c "^(6.|7.)" /etc/debian_version ) -ne 1 ]; then
|
|
fancylog "ERREUR: mauvaise version de Debian détectée. Arrêt par prudence. Vérifiez le code de ce script avant de forcer." >&2
|
|
exit 1
|
|
fi
|
|
if [ -n "$ESCLAVE" ] && [ "$( ssh root@$ESCLAVE 'egrep -c "^(6.|7.)" /etc/debian_version' )" -ne 1 ]; then
|
|
fancylog "ERREUR: ESCLAVE: mauvaise version de Debian détectée. Arrêt par prudence. Vérifiez le code de ce script avant de forcer." >&2
|
|
exit 1
|
|
fi
|
|
|
|
# - est-ce que la version attendue de PostgreSQL est bien installée ?
|
|
if ! dpkg -s "postgresql-$VERSION_POSTGRESQL" >/dev/null 2>&1; then
|
|
fancylog "ERREUR: PostgreSQL $VERSION_POSTGRESQL ne semble pas installée." >&2
|
|
exit 1
|
|
fi
|
|
if [ -n "$ESCLAVE" ] && ! ssh root@$ESCLAVE dpkg -s "postgresql-$VERSION_POSTGRESQL" >/dev/null 2>&1; then
|
|
fancylog "ERREUR: PostgreSQL $VERSION_POSTGRESQL ne semble pas installée." >&2
|
|
exit 1
|
|
fi
|
|
|
|
# Fin des vérifications
|
|
fancylog "INFO: fin des vérifications. Lancement des opérations."
|
|
|
|
|
|
if [ "$MODE_CREATION" -eq 1 ]; then
|
|
POSTGRESQL_PASSWORD=$( dd if=/dev/random 2>/dev/null bs=1 count=10 status=noxfer | base64 | sed 's#[/=]##g' )
|
|
POSTGRESQL_REPLICATION_PASSWORD=$( dd if=/dev/random 2>/dev/null bs=1 count=20 status=noxfer | base64 | sed 's#[/=]##g' )
|
|
# Création de l'instance dédiée
|
|
fancylog "INFO: création du cluster PG primaire..."
|
|
if [ -z "$POSTGRESQL_PORT" ]; then
|
|
pg_createcluster --locale=$POSTGRESQL_LOCALE --start-conf=auto "$VERSION_POSTGRESQL" "$NOM_INSTANCE"
|
|
# Détermination du port généré
|
|
# TODO: récupérer ça via pg_lsclusters serait plus "propre"
|
|
POSTGRESQL_PORT=$( grep "^port" /etc/postgresql/$VERSION_POSTGRESQL/$NOM_INSTANCE/postgresql.conf | sed 's/^port[[:space:]]*=[[:space:]]*\([0-9]\+\).*$/\1/' )
|
|
else
|
|
pg_createcluster --locale=$POSTGRESQL_LOCALE --start-conf=auto --port "$POSTGRESQL_PORT" "$VERSION_POSTGRESQL" "$NOM_INSTANCE"
|
|
fi
|
|
fancylog "INFO: modification du pg_hba.conf..."
|
|
if ! generate_patch_postgresql_pghbaconf "$NOM_INSTANCE" | patch -s --dry-run /etc/postgresql/$VERSION_POSTGRESQL/$NOM_INSTANCE/pg_hba.conf; then
|
|
fancylog "ERREUR: modification du fichier pg_hba.conf en échec. Arrêt."
|
|
exit 1
|
|
fi
|
|
generate_patch_postgresql_pghbaconf "$NOM_INSTANCE" | patch -s /etc/postgresql/$VERSION_POSTGRESQL/$NOM_INSTANCE/pg_hba.conf
|
|
|
|
fancylog "INFO: démarrage de l'instance PostgreSQL..."
|
|
pg_ctlcluster "$VERSION_POSTGRESQL" "$NOM_INSTANCE" start
|
|
|
|
# Lancement du script fourre-tout
|
|
fancylog "INFO: création de l'utilisateur et de la base de données, et affinage des droits d'accès..."
|
|
generate_script_postgresql_creation_db_et_user "$NOM_INSTANCE" "$POSTGRESQL_PASSWORD" "$POSTGRESQL_REPLICATION_USER_NAME" "$POSTGRESQL_REPLICATION_PASSWORD" | su -c "psql -p $POSTGRESQL_PORT -v ON_ERROR_STOP=1" postgres
|
|
|
|
if [ -n "$ESCLAVE" ]; then
|
|
fancylog "INFO: création de l'utilisateur de réplication..."
|
|
generate_script_postgresql_creation_replication_user "$POSTGRESQL_REPLICATION_USER_NAME" "$POSTGRESQL_REPLICATION_PASSWORD" | su -c "psql -p $POSTGRESQL_PORT -v ON_ERROR_STOP=1" postgres
|
|
|
|
# configuration en tant que maître
|
|
fancylog "INFO: modification de la configuration BDD de l'instance primaire..."
|
|
if ! generate_patch_postgresqlconf_master "$ESCLAVE" "$VERSION_POSTGRESQL" "$NOM_INSTANCE" | patch -s --dry-run /etc/postgresql/$VERSION_POSTGRESQL/$NOM_INSTANCE/postgresql.conf; then
|
|
fancylog "ERREUR: modification du fichier postgresql.conf en échec. Arrêt."
|
|
exit 1
|
|
fi
|
|
generate_patch_postgresqlconf_master "$ESCLAVE" "$VERSION_POSTGRESQL" "$NOM_INSTANCE" | patch -s /etc/postgresql/$VERSION_POSTGRESQL/$NOM_INSTANCE/postgresql.conf
|
|
# On rajoute les lignes pour la connexion streaming replication dans le pg_hba.conf
|
|
echo "host replication $POSTGRESQL_REPLICATION_USER_NAME $ESCLAVE_WITH_MASK md5" >>/etc/postgresql/$VERSION_POSTGRESQL/$NOM_INSTANCE/pg_hba.conf
|
|
echo "host replication $POSTGRESQL_REPLICATION_USER_NAME $MAITRE_WITH_MASK md5" >>/etc/postgresql/$VERSION_POSTGRESQL/$NOM_INSTANCE/pg_hba.conf
|
|
|
|
# Création sur l'esclave
|
|
# Note: on commence par créer l'arborescence de l'esclave pour
|
|
# avoir le répertoire de destination des archives logs
|
|
# le plus tôt possible (en tout cas, avant le pg_stop_backup()
|
|
# qui envoie forcément un WAL)
|
|
fancylog "INFO: création du cluster PG secondaire..."
|
|
ssh "root@$ESCLAVE" "cd /tmp; pg_createcluster --locale='$POSTGRESQL_LOCALE' -p '$POSTGRESQL_PORT' --start-conf=auto '$VERSION_POSTGRESQL' '$NOM_INSTANCE'"
|
|
fancylog "INFO: création du dossier de réception des archives logs et arret du backup..."
|
|
su -c "mkdir '/var/lib/postgresql/$VERSION_POSTGRESQL/$NOM_INSTANCE/archives_from_master'" postgres
|
|
su -c "ssh postgres@$ESCLAVE mkdir '/var/lib/postgresql/$VERSION_POSTGRESQL/$NOM_INSTANCE/archives_from_master'" postgres
|
|
|
|
fancylog "INFO: redémarrage du serveur primaire..."
|
|
pg_ctlcluster "$VERSION_POSTGRESQL" "$NOM_INSTANCE" restart
|
|
|
|
# rsync du PGDATA vers l'esclave
|
|
fancylog "INFO: écrasement du PGDATA secondaire par celui de l'instance primaire..."
|
|
echo "SELECT pg_start_backup('script_mi_pg', true);" | su -c "psql -p $POSTGRESQL_PORT -v ON_ERROR_STOP=1" postgres
|
|
# on attend un peu, il y a parfois des fichiers WAL qui "vanished" pendant le rsync
|
|
sleep 1
|
|
# On exclut :
|
|
# - postmaster.pid : raison évidente :)
|
|
# - postmaster.opts : a priori, le contenu est identique mais par prudence...
|
|
# - server.key/server.crt : rsync génère une erreur sur la date de modification des symlinks :-/
|
|
# - recovery.* : le recovery.done du maitre référence l'esclave, et vice versa pour le recovery.conf de l'esclave
|
|
# - archives_from_master : cela écraserait tout éventuel WAL déjà envoyé
|
|
# - lost+found : au cas où la partition existe déjà (pg_createcluster se bloque mais ça permet de récupérer cette ligne de commande ailleurs :)
|
|
# A étudier : pas de --delete ?
|
|
# test -c car problème de synchro bizarre
|
|
su -c "rsync -aHc --exclude=/postmaster.pid --exclude=/postmaster.opts --exclude=/server.key --exclude=/server.crt --exclude=/recovery.conf --exclude=/recovery.done --exclude=/archives_from_master --exclude=lost+found /var/lib/postgresql/$VERSION_POSTGRESQL/$NOM_INSTANCE/ postgres@$ESCLAVE:/var/lib/postgresql/$VERSION_POSTGRESQL/$NOM_INSTANCE/" postgres
|
|
echo "SELECT pg_stop_backup();" | su -c "psql -p $POSTGRESQL_PORT -v ON_ERROR_STOP=1" postgres
|
|
|
|
# configuration de l'esclave
|
|
fancylog "INFO: configuration de l'instance PG secondaire..."
|
|
if ! ssh root@$ESCLAVE dpkg -s "postgresql-contrib-$VERSION_POSTGRESQL" >/dev/null 2>&1; then
|
|
fancylog "WARNING: Le paquet postgresql-contrib-$VERSION_POSTGRESQL ne semble pas installé sur le serveur esclave, archive_cleanup_command sera désactivé." >&2
|
|
fancylog "NOTICE: cf fichier /var/lib/postgresql/$VERSION_POSTGRESQL/$NOM_INSTANCE/recovery.conf en cas d'installation après-coup." >&2
|
|
ARCHIVE_CLEANUP_COMMAND=""
|
|
else
|
|
# TODO: à rendre plus portable ?
|
|
ARCHIVE_CLEANUP_COMMAND="/usr/lib/postgresql/$VERSION_POSTGRESQL/bin/pg_archivecleanup"
|
|
fi
|
|
generate_file_postgresqlrecoveryconf_slave "$MAITRE" "$POSTGRESQL_PORT" "$POSTGRESQL_REPLICATION_USER_NAME" "$POSTGRESQL_REPLICATION_PASSWORD" "$VERSION_POSTGRESQL" "$NOM_INSTANCE" "$ARCHIVE_CLEANUP_COMMAND" | su -c "ssh postgres@$ESCLAVE 'cat - >/var/lib/postgresql/$VERSION_POSTGRESQL/$NOM_INSTANCE/recovery.conf'" postgres
|
|
generate_file_postgresqlrecoveryconf_slave "$ESCLAVE" "$POSTGRESQL_PORT" "$POSTGRESQL_REPLICATION_USER_NAME" "$POSTGRESQL_REPLICATION_PASSWORD" "$VERSION_POSTGRESQL" "$NOM_INSTANCE" "$ARCHIVE_CLEANUP_COMMAND" | su -c "cat - >/var/lib/postgresql/$VERSION_POSTGRESQL/$NOM_INSTANCE/recovery.done" postgres
|
|
generate_patch_postgresqlconf_slave | ssh "root@$ESCLAVE" patch -s /etc/postgresql/$VERSION_POSTGRESQL/$NOM_INSTANCE/postgresql.conf
|
|
# (note: même fichier pg_hba.conf pour tout le monde, homogénéisation avec peu de risques il me semble)
|
|
scp -q /etc/postgresql/$VERSION_POSTGRESQL/$NOM_INSTANCE/pg_hba.conf root@$ESCLAVE:/etc/postgresql/$VERSION_POSTGRESQL/$NOM_INSTANCE/pg_hba.conf
|
|
|
|
# démarrage des instances maître et esclave
|
|
fancylog "INFO: démarrage de l'instance PostgreSQL esclave..."
|
|
ssh root@$ESCLAVE pg_ctlcluster "$VERSION_POSTGRESQL" "$NOM_INSTANCE" start
|
|
|
|
# Vérification de la réplication
|
|
# TODO (via numéro de transaction (requête) ? processus/connexion ?)
|
|
fi
|
|
|
|
# Fin
|
|
fancylog "INFO: Création terminée. Instance PostgreSQL allumée."
|
|
fancylog "INFO: pour mémo :"
|
|
fancylog "INFO: BDD: $NOM_INSTANCE, port: $POSTGRESQL_PORT, login: $NOM_INSTANCE, mdp: $POSTGRESQL_PASSWORD"
|
|
TMP="$MAITRE"
|
|
if [ -z "$MAITRE" ]; then
|
|
TMP="localhost"
|
|
fi
|
|
fancylog "INFO: pgpass: $TMP:$POSTGRESQL_PORT:$NOM_INSTANCE:$NOM_INSTANCE:$POSTGRESQL_PASSWORD"
|
|
fi
|
|
|
|
|
|
|
|
if [ "$MODE_DESTRUCTION" -eq 1 ]; then
|
|
fancylog "INFO: suppression de l'instance locale..."
|
|
# Note : en guise de garde-fou, on ne met pas l'option --stop
|
|
pg_dropcluster "$VERSION_POSTGRESQL" "$NOM_INSTANCE"
|
|
|
|
if [ -n "$ESCLAVE" ]; then
|
|
fancylog "INFO: suppression de l'instance esclave..."
|
|
ssh root@$ESCLAVE pg_dropcluster "$VERSION_POSTGRESQL" "$NOM_INSTANCE"
|
|
fi
|
|
fi
|
|
|
|
|