#!/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