Compare commits

..

No commits in common. "97f4875aee5262c14c77c01475f8e52113252ce6" and "747331a9ecbb15baa2b5a47d195a2a57bfff3696" have entirely different histories.

3 changed files with 122 additions and 109 deletions

View file

@ -1,14 +0,0 @@
---
name: Run tests
on: [push]
jobs:
tests:
runs-on: docker
container:
image: docker.io/brenard/python-pre-commit:latest
options: "--workdir /src"
steps:
- name: Check out repository code
uses: actions/checkout@v4
- name: Run pre-commit
run: pre-commit run --all-files

View file

@ -13,17 +13,13 @@ repos:
- --ignore-regex=.*codespell-ignore$ - --ignore-regex=.*codespell-ignore$
# - --write-changes # Uncomment to write changes # - --write-changes # Uncomment to write changes
exclude_types: [csv, json] exclude_types: [csv, json]
- repo: https://github.com/pre-commit/mirrors-prettier
rev: v2.7.1
hooks:
- id: prettier
args: ["--print-width", "100"]
- repo: https://github.com/adrienverge/yamllint - repo: https://github.com/adrienverge/yamllint
rev: v1.32.0 rev: v1.32.0
hooks: hooks:
- id: yamllint - id: yamllint
ignore: .github/ ignore: .github/
- repo: https://github.com/shellcheck-py/shellcheck-py - repo: https://github.com/pre-commit/mirrors-prettier
rev: v0.10.0.1 rev: v2.7.1
hooks: hooks:
- id: shellcheck - id: prettier
args: ["--print-width", "100"]

View file

@ -49,7 +49,7 @@ DEBUG=0
function usage () { function usage () {
ERROR="$1" ERROR="$1"
[[ -n "$ERROR" ]] && echo -e "$ERROR\n" [ -n "$ERROR" ] && echo -e "$ERROR\n"
cat << EOF cat << EOF
Usage: $0 [-d] [-h] [options] Usage: $0 [-d] [-h] [options]
-u pg_user Specify local Postgres user (Default: try to auto-detect or use $DEFAULT_PG_USER) -u pg_user Specify local Postgres user (Default: try to auto-detect or use $DEFAULT_PG_USER)
@ -59,7 +59,7 @@ Usage: $0 [-d] [-h] [options]
-m pg_main Specify Postgres main directory path (Default: try to auto-detect or use -m pg_main Specify Postgres main directory path (Default: try to auto-detect or use
$DEFAULT_PG_MAIN) $DEFAULT_PG_MAIN)
-r recovery_conf Specify Postgres recovery configuration file path -r recovery_conf Specify Postgres recovery configuration file path
(Default: [PG_MAIN]/recovery.conf on PG <= 11, [PG_MAIN]/postgresql.auto.conf on PG >= 12) ( Default: [PG_MAIN]/recovery.conf on PG <= 11, [PG_MAIN]/postgresql.auto.conf on PG >= 12)
-U pg_master_user Specify Postgres user to use on master (Default: user from recovery.conf file) -U pg_master_user Specify Postgres user to use on master (Default: user from recovery.conf file)
-p pg_port Specify default Postgres master TCP port (Default: same as local PostgreSQL -p pg_port Specify default Postgres master TCP port (Default: same as local PostgreSQL
port if detected or use $DEFAULT_PG_PORT) port if detected or use $DEFAULT_PG_PORT)
@ -74,10 +74,11 @@ Usage: $0 [-d] [-h] [options]
-d Debug mode -d Debug mode
-h Show this message -h Show this message
EOF EOF
[[ -n "$ERROR" ]] && exit 1 || exit 0 [ -n "$ERROR" ] && exit 1 || exit 0
} }
while getopts "hu:b:B:V:m:r:U:p:D:C:w:c:e:E:d" OPTION; do while getopts "hu:b:B:V:m:r:U:p:D:C:w:c:e:E:d" OPTION
do
case $OPTION in case $OPTION in
u) u)
PG_USER=$OPTARG PG_USER=$OPTARG
@ -116,12 +117,12 @@ while getopts "hu:b:B:V:m:r:U:p:D:C:w:c:e:E:d" OPTION; do
REPLAY_CRITICAL_DELAY=$OPTARG REPLAY_CRITICAL_DELAY=$OPTARG
;; ;;
e) e)
[[ "$OPTARG" != "sync" ]] && [[ "$OPTARG" != "async" ]] && \ [ "$OPTARG" != "sync" -a "$OPTARG" != "async" ] && \
usage "Invalid expected replication state '$OPTARG'. Possible values: sync or async." usage "Invalid expected replication state '$OPTARG'. Possible values: sync or async."
EXPECTED_SYNC_STATE=$OPTARG EXPECTED_SYNC_STATE=$OPTARG
;; ;;
E) E)
[[ "$OPTARG" != "master" ]] && [[ "$OPTARG" != "hot-standby" ]] && [[ "$OPTARG" != "auto" ]] && \ [ "$OPTARG" != "master" -a "$OPTARG" != "hot-standby" -a "$OPTARG" != "auto" ] && \
usage "Invalid expected mode '$OPTARG'. Possible values: master, hot-standby or auto." usage "Invalid expected mode '$OPTARG'. Possible values: master, hot-standby or auto."
EXPECTED_MODE=$OPTARG EXPECTED_MODE=$OPTARG
;; ;;
@ -138,7 +139,8 @@ while getopts "hu:b:B:V:m:r:U:p:D:C:w:c:e:E:d" OPTION; do
done done
function debug() { function debug() {
if [[ $DEBUG -eq 1 ]]; then if [ $DEBUG -eq 1 ]
then
>&2 echo -e "[DEBUG] $1" >&2 echo -e "[DEBUG] $1"
fi fi
} }
@ -161,62 +163,64 @@ EXPECTED_MODE = $EXPECTED_MODE
" "
# Auto-detect PostgreSQL information using pg_lsclusters # Auto-detect PostgreSQL information using pg_lsclusters
if [[ -x "$PG_LSCLUSTER_BIN" ]]; then if [ -x "$PG_LSCLUSTER_BIN" ]
then
PG_CLUSTER=$( $PG_LSCLUSTER_BIN -h 2>/dev/null|head -n1 ) PG_CLUSTER=$( $PG_LSCLUSTER_BIN -h 2>/dev/null|head -n1 )
if [[ -n "$PG_CLUSTER" ]]; then if [ -n "$PG_CLUSTER" ]
then
debug "pg_lsclusters output:\n\t$PG_CLUSTER" debug "pg_lsclusters output:\n\t$PG_CLUSTER"
# Output example: # Output example:
# 9.6 main 5432 online,recovery postgres /var/lib/postgresql/9.6/main /var/log/postgresql/postgresql-9.6-main.log # 9.6 main 5432 online,recovery postgres /var/lib/postgresql/9.6/main /var/log/postgresql/postgresql-9.6-main.log
[[ -z "$PG_VERSION" ]] && PG_VERSION=$( echo "$PG_CLUSTER"|awk -F ' +' '{print $1}' ) [ -z "$PG_VERSION" ] && PG_VERSION=$( echo "$PG_CLUSTER"|awk -F ' +' '{print $1}' )
[[ -z "$PG_DEFAULT_PORT" ]] && PG_DEFAULT_PORT=$( echo "$PG_CLUSTER"|awk -F ' +' '{print $3}' ) [ -z "$PG_DEFAULT_PORT" ] && PG_DEFAULT_PORT=$( echo "$PG_CLUSTER"|awk -F ' +' '{print $3}' )
[[ -z "$PG_USER" ]] && PG_USER=$( echo "$PG_CLUSTER"|awk -F ' +' '{print $5}' ) [ -z "$PG_USER" ] && PG_USER=$( echo "$PG_CLUSTER"|awk -F ' +' '{print $5}' )
[[ -z "$PG_MAIN" ]] && PG_MAIN=$( echo "$PG_CLUSTER"|awk -F ' +' '{print $6}' ) [ -z "$PG_MAIN" ] && PG_MAIN=$( echo "$PG_CLUSTER"|awk -F ' +' '{print $6}' )
fi fi
else else
debug "pg_lsclusters not found ($PG_LSCLUSTER_BIN): parameters auto-detection disabled" debug "pg_lsclusters not found ($PG_LSCLUSTER_BIN): parameters auto-detection disabled"
fi fi
# If auto-detection failed, use default values # If auto-detection failed, use default values
[[ -z "$PG_USER" ]] && PG_USER="$DEFAULT_PG_USER" [ -z "$PG_USER" ] && PG_USER="$DEFAULT_PG_USER"
[[ -z "$PG_VERSION" ]] && PG_VERSION="$DEFAULT_PG_VERSION" [ -z "$PG_VERSION" ] && PG_VERSION="$DEFAULT_PG_VERSION"
[[ -z "$PG_MAIN" ]] && PG_MAIN="$DEFAULT_PG_MAIN" [ -z "$PG_MAIN" ] && PG_MAIN="$DEFAULT_PG_MAIN"
[[ -z "$PG_DEFAULT_PORT" ]] && PG_DEFAULT_PORT="$DEFAULT_PG_PORT" [ -z "$PG_DEFAULT_PORT" ] && PG_DEFAULT_PORT="$DEFAULT_PG_PORT"
# Check PG_USER # Check PG_USER
[[ -z "$PG_USER" ]] && echo "UNKNOWN: Postgres user not specified" && exit 3 [ -z "$PG_USER" ] && echo "UNKNOWN: Postgres user not specified" && exit 3
id "$PG_USER" > /dev/null 2>&1 || { echo "UNKNOWN: Invalid Postgres user ($PG_USER)"; exit 3; } id "$PG_USER" > /dev/null 2>&1
[ $? -ne 0 ] && echo "UNKNOWN: Invalid Postgres user ($PG_USER)" && exit 3
# Check PSQL_BIN # Check PSQL_BIN
[[ ! -x "$PSQL_BIN" ]] && echo "UNKNOWN: Invalid psql bin path ($PSQL_BIN)" && exit 3 [ ! -x "$PSQL_BIN" ] && echo "UNKNOWN: Invalid psql bin path ($PSQL_BIN)" && exit 3
# Check PG_MAIN # Check PG_MAIN
[[ ! -d "$PG_MAIN/" ]] && echo "UNKNOWN: Invalid Postgres main directory path ($PG_MAIN)" && exit 3 [ ! -d "$PG_MAIN/" ] && echo "UNKNOWN: Invalid Postgres main directory path ($PG_MAIN)" && exit 3
# Check RECOVERY_CONF # Check RECOVERY_CONF
if [[ -z "$RECOVERY_CONF" ]]; then if [ -z "$RECOVERY_CONF" ]; then
[[ $PG_VERSION -le 11 ]] && RECOVERY_CONF_FILENAME="recovery.conf" || RECOVERY_CONF_FILENAME="postgresql.auto.conf" [ $PG_VERSION -le 11 ] && RECOVERY_CONF_FILENAME="recovery.conf" || RECOVERY_CONF_FILENAME="postgresql.auto.conf"
RECOVERY_CONF="$PG_MAIN/$RECOVERY_CONF_FILENAME" RECOVERY_CONF="$PG_MAIN/$RECOVERY_CONF_FILENAME"
else else
RECOVERY_CONF_FILENAME=$( basename "$RECOVERY_CONF" ) RECOVERY_CONF_FILENAME=$( basename "$RECOVERY_CONF" )
fi fi
# Check PG_DEFAULT_PORT # Check PG_DEFAULT_PORT
[[ $( grep -c -E '^[0-9]*$' <<< "$PG_DEFAULT_PORT" ) -ne 1 ]] && \ [ $( echo "$PG_DEFAULT_PORT"|grep -c -E '^[0-9]*$' ) -ne 1 ] && "UNKNOWN: Postgres default master TCP port must be an integer." && exit 3
echo "UNKNOWN: Postgres default master TCP port must be an integer." && exit 3
# If PG_DB is not provided with -D parameter, use PG_USER as default value # If PG_DB is not provided with -D parameter, use PG_USER as default value
[[ -z "$PG_DB" ]] && PG_DB="$PG_USER" [ -z "$PG_DB" ] && PG_DB="$PG_USER"
function psql_get () { function psql_get () {
sql="$1" sql="$1"
debug "Exec 'echo \"$sql\"|sudo -u $PG_USER $PSQL_BIN -d \"$PG_DB\" -w -t -P format=unaligned" debug "Exec 'echo \"$sql\"|sudo -u $PG_USER $PSQL_BIN -d \"$PG_DB\" -w -t -P format=unaligned"
sudo -u "$PG_USER" "$PSQL_BIN" -d "$PG_DB" -w -t -P format=unaligned <<< "$sql" echo "$sql"|sudo -u $PG_USER $PSQL_BIN -d "$PG_DB" -w -t -P format=unaligned
} }
function psql_master_get () { function psql_master_get () {
sql="$1" sql="$1"
debug "Exec 'echo \"$sql\"|sudo -u $PG_USER $PSQL_BIN -U $M_USER -h $M_HOST -w -p $M_PORT -d $PG_DB -t -P format=unaligned" debug "Exec 'echo \"$sql\"|sudo -u $PG_USER $PSQL_BIN -U $M_USER -h $M_HOST -w -p $M_PORT -d $PG_DB -t -P format=unaligned"
sudo -u "$PG_USER" "$PSQL_BIN" -U "$M_USER" -h "$M_HOST" -w -p "$M_PORT" -d "$PG_DB" -t -P format=unaligned <<< "$sql" echo "$sql"|sudo -u $PG_USER $PSQL_BIN -U $M_USER -h $M_HOST -w -p $M_PORT -d $PG_DB -t -P format=unaligned
} }
debug "Running options: debug "Running options:
@ -235,7 +239,8 @@ REPLAY_CRITICAL_DELAY = $REPLAY_CRITICAL_DELAY
" "
# Set some stuff to PostgreSQL version # Set some stuff to PostgreSQL version
if [[ $( bc -l <<< "$PG_VERSION < 10" ) -eq 1 ]]; then if [ $( echo "$PG_VERSION < 10" |bc -l ) -eq 1 ]
then
pg_last_wal_receive_lsn='pg_last_xlog_receive_location()' pg_last_wal_receive_lsn='pg_last_xlog_receive_location()'
pg_last_wal_replay_lsn='pg_last_xlog_replay_location()' pg_last_wal_replay_lsn='pg_last_xlog_replay_location()'
pg_current_wal_lsn='pg_current_xlog_location()' pg_current_wal_lsn='pg_current_xlog_location()'
@ -252,28 +257,28 @@ else
fi fi
# Postgres is running ? # Postgres is running ?
if [[ $DEBUG -eq 0 ]]; then if [ $DEBUG -eq 0 ]
then
psql_get '\q' 2> /dev/null psql_get '\q' 2> /dev/null
is_running=$?
else else
psql_get '\q' psql_get '\q'
is_running=$?
fi fi
if [[ $is_running -ne 0 ]]; then if [ $? -ne 0 ]
then
echo "CRITICAL: Postgres is not running !" echo "CRITICAL: Postgres is not running !"
exit 2 exit 2
fi fi
debug "Postgres is running" debug "Postgres is running"
RECOVERY_MODE=0 RECOVERY_MODE=0
[[ "$( psql_get 'SELECT pg_is_in_recovery();' )" == "t" ]] && RECOVERY_MODE=1 [ "$( psql_get 'SELECT pg_is_in_recovery();' )" == "t" ] && RECOVERY_MODE=1
if [[ "$EXPECTED_MODE" == "auto" ]]; then if [ "$EXPECTED_MODE" == "auto" ]; then
debug "Auto-detect mode" debug "Auto-detect mode"
if [[ $RECOVERY_MODE -eq 1 ]]; then if [[ $RECOVERY_MODE -eq 1 ]]; then
debug "Postgres is in recovery mode. Hot-standby mode." debug "Postgres is in recovery mode. Hot-standby mode."
EXPECTED_MODE="hot-standby" EXPECTED_MODE="hot-standby"
elif [[ -f $RECOVERY_CONF ]] && [[ $( grep -cE '^\s*primary_conninfo' "$RECOVERY_CONF" ) -gt 0 ]]; then elif [ -f $RECOVERY_CONF -a $( grep -cE '^\s*primary_conninfo' $RECOVERY_CONF ) -gt 0 ]; then
debug "File $RECOVERY_CONF_FILENAME found and contain primary_conninfo. Hot-standby mode." debug "File $RECOVERY_CONF_FILENAME found and contain primary_conninfo. Hot-standby mode."
EXPECTED_MODE="hot-standby" EXPECTED_MODE="hot-standby"
else else
@ -283,10 +288,12 @@ if [[ "$EXPECTED_MODE" == "auto" ]]; then
fi fi
fi fi
if [[ "$EXPECTED_MODE" == "hot-standby" ]]; then if [ "$EXPECTED_MODE" == "hot-standby" ]
then
# Check recovery mode # Check recovery mode
if [[ $RECOVERY_MODE -ne 1 ]]; then if [ $RECOVERY_MODE -ne 1 ]
echo "CRITICAL: Not in recovery mode while $RECOVERY_CONF_FILENAME file found !" then
echo "CRITICAL: Not in recovery mode while recovery.conf file found !"
exit 2 exit 2
fi fi
debug "Postgres is in recovery mode" debug "Postgres is in recovery mode"
@ -298,35 +305,40 @@ if [[ "$EXPECTED_MODE" == "hot-standby" ]]; then
debug "Last replayed LSN: $LAST_REPLAYED_LSN" debug "Last replayed LSN: $LAST_REPLAYED_LSN"
# Get master connection information from primary_conninfo configuration parameter # Get master connection information from recovery.conf file
MASTER_CONN_INFOS=$( psql_get "SHOW primary_conninfo" ) MASTER_CONN_INFOS=$( egrep '^ *primary_conninfo' $RECOVERY_CONF|sed "s/^ *primary_conninfo *= *\(.\+\) *$/\1/" )
if [[ -z "$MASTER_CONN_INFOS" ]]; then if [ ! -n "$MASTER_CONN_INFOS" ]
echo "UNKNOWN: Can't retrieve master connection information from primary_conninfo configuration parameter" then
echo "UNKNOWN: Can't retrieve master connection information form recovery.conf file"
exit 3 exit 3
fi fi
debug "Master connection information: $MASTER_CONN_INFOS" debug "Master connection information: $MASTER_CONN_INFOS"
M_HOST=$( grep 'host=' <<< "$MASTER_CONN_INFOS" | sed 's/^.*host= *\([0-9a-zA-Z.-]\+\) *.*$/\1/' ) M_HOST=$( echo "$MASTER_CONN_INFOS"| grep 'host=' | sed 's/^.*host= *\([0-9a-zA-Z.-]\+\) *.*$/\1/' )
if [[ -z "$M_HOST" ]]; then if [ ! -n "$M_HOST" ]
echo "UNKNOWN: Can't retrieve master host from primary_conninfo configuration parameter" then
echo "UNKNOWN: Can't retrieve master host from recovery.conf file"
exit 3 exit 3
fi fi
debug "Master host: $M_HOST" debug "Master host: $M_HOST"
M_PORT=$( grep 'port=' <<< "$MASTER_CONN_INFOS" | sed 's/^.*port= *\([0-9a-zA-Z.-]\+\) *.*$/\1/' ) M_PORT=$( echo "$MASTER_CONN_INFOS"| grep 'port=' | sed 's/^.*port= *\([0-9a-zA-Z.-]\+\) *.*$/\1/' )
if [[ -z "$M_PORT" ]]; then if [ ! -n "$M_PORT" ]
then
debug "Master port not specified, use default: $PG_DEFAULT_PORT" debug "Master port not specified, use default: $PG_DEFAULT_PORT"
M_PORT=$PG_DEFAULT_PORT M_PORT=$PG_DEFAULT_PORT
else else
debug "Master port: $M_PORT" debug "Master port: $M_PORT"
fi fi
if [[ -n "$PG_MASTER_USER" ]]; then if [ -n "$PG_MASTER_USER" ]
then
debug "Master user provided by command-line, use it: $PG_MASTER_USER" debug "Master user provided by command-line, use it: $PG_MASTER_USER"
M_USER="$PG_MASTER_USER" M_USER="$PG_MASTER_USER"
else else
M_USER=$( grep 'user=' <<< "$MASTER_CONN_INFOS" | sed 's/^.*user= *\([0-9a-zA-Z.-]\+\) *.*$/\1/' ) M_USER=$( echo "$MASTER_CONN_INFOS"| grep 'user=' | sed 's/^.*user= *\([0-9a-zA-Z.-]\+\) *.*$/\1/' )
if [[ -z "$M_USER" ]]; then if [ ! -n "$M_USER" ]
then
debug "Master user not specified, use default: $PG_USER" debug "Master user not specified, use default: $PG_USER"
M_USER=$PG_USER M_USER=$PG_USER
else else
@ -334,13 +346,16 @@ if [[ "$EXPECTED_MODE" == "hot-standby" ]]; then
fi fi
fi fi
M_APP_NAME=$( grep 'application_name=' <<< "$MASTER_CONN_INFOS" | sed "s/^.*application_name=[ \'\"]*\([^ \'\"]\+\)[ \'\"]*.*$/\1/" ) M_APP_NAME=$( echo "$MASTER_CONN_INFOS"| grep 'application_name=' | sed "s/^.*application_name=[ \'\"]*\([^ \'\"]\+\)[ \'\"]*.*$/\1/" )
if [[ -z "$M_APP_NAME" ]]; then if [ ! -n "$M_APP_NAME" ]
if [[ $PG_VERSION -ge 12 ]]; then then
if [ $PG_VERSION -ge 12 ]
then
debug "Master application name not specified, use cluster_name if defined" debug "Master application name not specified, use cluster_name if defined"
CLUSTER_NAME=$( psql_get "SELECT current_setting('cluster_name')" ) CLUSTER_NAME=$( psql_get "SELECT current_setting('cluster_name')" )
debug "Cluster name: $CLUSTER_NAME" debug "Cluster name: $CLUSTER_NAME"
if [[ -n "$CLUSTER_NAME" ]]; then if [ -n "$CLUSTER_NAME" ]
then
M_APP_NAME=$CLUSTER_NAME M_APP_NAME=$CLUSTER_NAME
else else
debug "Cluster name not defined, use default: $PG_DEFAULT_APP_NAME" debug "Cluster name not defined, use default: $PG_DEFAULT_APP_NAME"
@ -356,42 +371,48 @@ if [[ "$EXPECTED_MODE" == "hot-standby" ]]; then
# Get current replication state information from master # Get current replication state information from master
M_CUR_REPL_STATE_INFO="$( psql_master_get "SELECT state, sync_state, $sent_lsn AS sent_lsn, $write_lsn AS write_lsn FROM pg_stat_replication WHERE application_name='$M_APP_NAME';" )" M_CUR_REPL_STATE_INFO="$( psql_master_get "SELECT state, sync_state, $sent_lsn AS sent_lsn, $write_lsn AS write_lsn FROM pg_stat_replication WHERE application_name='$M_APP_NAME';" )"
if [[ -z "$M_CUR_REPL_STATE_INFO" ]]; then if [ ! -n "$M_CUR_REPL_STATE_INFO" ]
then
echo "UNKNOWN: Can't retrieve current replication state information from master server" echo "UNKNOWN: Can't retrieve current replication state information from master server"
exit 3 exit 3
fi fi
debug "Master current replication state:\n\tstate|sync_state|sent_lsn|write_lsn\n\t$M_CUR_REPL_STATE_INFO" debug "Master current replication state:\n\tstate|sync_state|sent_lsn|write_lsn\n\t$M_CUR_REPL_STATE_INFO"
M_CUR_STATE=$( cut -d'|' -f1 <<< "$M_CUR_REPL_STATE_INFO" ) M_CUR_STATE=$( echo "$M_CUR_REPL_STATE_INFO"|cut -d'|' -f1 )
debug "Master current state: $M_CUR_STATE" debug "Master current state: $M_CUR_STATE"
if [[ "$M_CUR_STATE" != "streaming" ]]; then if [ "$M_CUR_STATE" != "streaming" ]
then
echo "CRITICAL: this host is not in streaming state according to master host (current state = '$M_CUR_STATE')" echo "CRITICAL: this host is not in streaming state according to master host (current state = '$M_CUR_STATE')"
exit 2 exit 2
fi fi
M_CUR_SYNC_STATE=$( cut -d'|' -f2 <<< "$M_CUR_REPL_STATE_INFO" ) M_CUR_SYNC_STATE=$( echo "$M_CUR_REPL_STATE_INFO"|cut -d'|' -f2 )
debug "Master current sync state: $M_CUR_SYNC_STATE" debug "Master current sync state: $M_CUR_SYNC_STATE"
if [[ "$M_CUR_SYNC_STATE" != "$EXPECTED_SYNC_STATE" ]]; then if [ "$M_CUR_SYNC_STATE" != "$EXPECTED_SYNC_STATE" ]
then
echo "CRITICAL: unexpected replication state '$M_CUR_SYNC_STATE' (expected state = '$EXPECTED_SYNC_STATE')" echo "CRITICAL: unexpected replication state '$M_CUR_SYNC_STATE' (expected state = '$EXPECTED_SYNC_STATE')"
exit 2 exit 2
fi fi
M_CUR_SENT_LSN=$( cut -d'|' -f3 <<< "$M_CUR_REPL_STATE_INFO" ) M_CUR_SENT_LSN=$( echo "$M_CUR_REPL_STATE_INFO"|cut -d'|' -f3 )
M_CUR_WRITED_LSN=$( cut -d'|' -f4 <<< "$M_CUR_REPL_STATE_INFO" ) M_CUR_WRITED_LSN=$( echo "$M_CUR_REPL_STATE_INFO"|cut -d'|' -f4 )
debug "Master current last sent/writed LSN: '$M_CUR_SENT_LSN' / '$M_CUR_WRITED_LSN'" debug "Master current last sent/writed LSN: '$M_CUR_SENT_LSN' / '$M_CUR_WRITED_LSN'"
# Check current master LSN vs last received LSN # Check current master LSN vs last received LSN
if [[ "$CHECK_CUR_MASTER_LSN" == "1" ]]; then if [ "$CHECK_CUR_MASTER_LSN" == "1" ]
then
# Get current LSN from master # Get current LSN from master
M_CUR_LSN="$( psql_master_get "SELECT $pg_current_wal_lsn" )" M_CUR_LSN="$( psql_master_get "SELECT $pg_current_wal_lsn" )"
if [[ -z "$M_CUR_LSN" ]]; then if [ ! -n "$M_CUR_LSN" ]
then
echo "UNKNOWN: Can't retrieve current LSN from master server" echo "UNKNOWN: Can't retrieve current LSN from master server"
exit 3 exit 3
fi fi
debug "Master current LSN: $M_CUR_LSN" debug "Master current LSN: $M_CUR_LSN"
# Master current LSN is the last received LSN ? # Master current LSN is the last received LSN ?
if [[ "$M_CUR_LSN" != "$LAST_RECEIVED_LSN" ]]; then if [ "$M_CUR_LSN" != "$LAST_RECEIVED_LSN" ]
then
echo "CRITICAL: Master current LSN is not the last received LSN" echo "CRITICAL: Master current LSN is not the last received LSN"
exit 2 exit 2
fi fi
@ -399,15 +420,18 @@ if [[ "$EXPECTED_MODE" == "hot-standby" ]]; then
fi fi
# The last received LSN is the last replayed ? # The last received LSN is the last replayed ?
if [[ "$LAST_RECEIVED_LSN" != "$LAST_REPLAYED_LSN" ]]; then if [ "$LAST_RECEIVED_LSN" != "$LAST_REPLAYED_LSN" ]
then
debug "/!\ The last received LSN is NOT the last replayed LSN ('$M_CUR_LSN' / '$LAST_REPLAYED_LSN')" debug "/!\ The last received LSN is NOT the last replayed LSN ('$M_CUR_LSN' / '$LAST_REPLAYED_LSN')"
REPLAY_DELAY="$( psql_get 'SELECT EXTRACT(EPOCH FROM now() - pg_last_xact_replay_timestamp());' )" REPLAY_DELAY="$( psql_get 'SELECT EXTRACT(EPOCH FROM now() - pg_last_xact_replay_timestamp());' )"
debug "Replay delay is $REPLAY_DELAY second(s)" debug "Replay delay is $REPLAY_DELAY second(s)"
if [[ $( bc -l <<< "$REPLAY_DELAY >= $REPLAY_CRITICAL_DELAY" ) -gt 0 ]]; then if [ $( echo "$REPLAY_DELAY >= $REPLAY_CRITICAL_DELAY"|bc -l ) -gt 0 ]
then
echo "CRITICAL: last received LSN is not the last replayed ('$LAST_RECEIVED_LSN' / '$LAST_REPLAYED_LSN') and replay delay is $REPLAY_DELAY second(s)" echo "CRITICAL: last received LSN is not the last replayed ('$LAST_RECEIVED_LSN' / '$LAST_REPLAYED_LSN') and replay delay is $REPLAY_DELAY second(s)"
exit 2 exit 2
fi fi
if [[ $( bc -l <<< "$REPLAY_DELAY >= $REPLAY_WARNING_DELAY" ) -gt 0 ]]; then if [ $( echo "$REPLAY_DELAY >= $REPLAY_WARNING_DELAY"|bc -l ) -gt 0 ]
then
echo "WARNING: last received LSN is not the last replay file ('$LAST_RECEIVED_LSN' / '$LAST_REPLAYED_LSN') and replay delay is $REPLAY_DELAY second(s)" echo "WARNING: last received LSN is not the last replay file ('$LAST_RECEIVED_LSN' / '$LAST_REPLAYED_LSN') and replay delay is $REPLAY_DELAY second(s)"
exit 1 exit 1
fi fi
@ -416,7 +440,8 @@ if [[ "$EXPECTED_MODE" == "hot-standby" ]]; then
debug "Last received LSN is the last replayed file" debug "Last received LSN is the last replayed file"
# The master last sent LSN is the last received (and synced) ? # The master last sent LSN is the last received (and synced) ?
if [[ "$M_CUR_SENT_LSN" != "$LAST_RECEIVED_LSN" ]]; then if [ "$M_CUR_SENT_LSN" != "$LAST_RECEIVED_LSN" ]
then
echo "WARNING: master last sent LSN is not already received (and synced to disk) by slave. May be we have some network delay or load on slave" echo "WARNING: master last sent LSN is not already received (and synced to disk) by slave. May be we have some network delay or load on slave"
echo "Master last sent LSN: $M_CUR_SENT_LSN" echo "Master last sent LSN: $M_CUR_SENT_LSN"
echo "Slave last received (and synced to disk) LSN: $LAST_RECEIVED_LSN" echo "Slave last received (and synced to disk) LSN: $LAST_RECEIVED_LSN"
@ -426,19 +451,22 @@ if [[ "$EXPECTED_MODE" == "hot-standby" ]]; then
echo "OK: Hot-standby server is up-to-date" echo "OK: Hot-standby server is up-to-date"
echo "Replication state: $M_CUR_SYNC_STATE" echo "Replication state: $M_CUR_SYNC_STATE"
echo "Last sent/writed LSN: '$M_CUR_SENT_LSN' / '$M_CUR_WRITED_LSN'" echo "Last sent/writed LSN: '$M_CUR_SENT_LSN' / '$M_CUR_WRITED_LSN'"
[[ "$LAST_RECEIVED_LSN" != "$LAST_REPLAYED_LSN" ]] && echo "Replay delay: ${REPLAY_DELAY}s" [ "$LAST_RECEIVED_LSN" != "$LAST_REPLAYED_LSN" ] && echo "Replay delay: ${REPLAY_DELAY}s"
exit 0 exit 0
elif [[ "$EXPECTED_MODE" == "master" ]]; then elif [ "$EXPECTED_MODE" == "master" ]
then
# Check recovery mode # Check recovery mode
if [[ $RECOVERY_MODE -eq 1 ]]; then if [ $RECOVERY_MODE -eq 1 ]
echo "CRITICAL: In recovery mode while expected mode is master!" then
echo "CRITICAL: In recovery mode while recovery.conf file not found !"
exit 2 exit 2
fi fi
debug "Postgres is not in recovery mode" debug "Postgres is not in recovery mode"
# Retrieve current lsn # Retrieve current lsn
CURRENT_LSN=$( psql_get "SELECT $pg_current_wal_lsn" ) CURRENT_LSN=$( psql_get "SELECT $pg_current_wal_lsn" )
if [[ -z "$CURRENT_LSN" ]]; then if [ -z "$CURRENT_LSN" ]
then
echo "UNKNOWN: Fail to retrieve current LSN (Log Sequence Number)" echo "UNKNOWN: Fail to retrieve current LSN (Log Sequence Number)"
exit 3 exit 3
fi fi
@ -454,30 +482,33 @@ elif [[ "$EXPECTED_MODE" == "master" ]]; then
FROM pg_stat_replication FROM pg_stat_replication
) AS s2 ) AS s2
) AS s1" ) ) AS s1" )
if [[ -z "$STANDBY_CLIENTS" ]]; then if [ ! -n "$STANDBY_CLIENTS" ]
then
echo "WARNING: no stand-by client connected" echo "WARNING: no stand-by client connected"
exit 1 exit 1
fi fi
debug "Stand-by client(s):\n\t${STANDBY_CLIENTS//$'\n'/\\n\\t}" debug "Stand-by client(s):\n\t$( echo -e "$STANDBY_CLIENTS"|sed 's/\n/\n\t/' )"
STANDBY_CLIENTS_TXT="" STANDBY_CLIENTS_TXT=""
STANDBY_CLIENTS_COUNT=0 STANDBY_CLIENTS_COUNT=0
CURRENT_LSN_IS_LAST_SENT=1 CURRENT_LSN_IS_LAST_SENT=1
for line in $STANDBY_CLIENTS; do for line in $STANDBY_CLIENTS
(( STANDBY_CLIENTS_COUNT+=1 )) do
let STANDBY_CLIENTS_COUNT=STANDBY_CLIENTS_COUNT+1
NAME=$( cut -d '|' -f 1 <<< "$line" ) NAME=$( echo $line|cut -d '|' -f 1 )
IP=$( cut -d '|' -f 2 <<< "$line" ) IP=$( echo $line|cut -d '|' -f 2 )
SENT_LSN=$( cut -d '|' -f 3 <<< "$line" ) SENT_LSN=$( echo $line|cut -d '|' -f 3 )
WRITED_LSN=$( cut -d '|' -f 4 <<< "$line" ) WRITED_LSN=$( echo $line|cut -d '|' -f 4 )
STATE=$( cut -d '|' -f 5 <<< "$line" ) STATE=$( echo $line|cut -d '|' -f 5 )
SYNC_STATE=$( cut -d '|' -f 6 <<< "$line" ) SYNC_STATE=$( echo $line|cut -d '|' -f 6 )
LAG=$( cut -d '|' -f 7 <<< "$line" ) LAG=$( echo $line|cut -d '|' -f 7 )
STANDBY_CLIENTS_TXT="$STANDBY_CLIENTS_TXT\n$NAME ($IP): $STATE/$SYNC_STATE (LSN: sent='$SENT_LSN' / writed='$WRITED_LSN', Lag: ${LAG}b)" STANDBY_CLIENTS_TXT="$STANDBY_CLIENTS_TXT\n$NAME ($IP): $STATE/$SYNC_STATE (LSN: sent='$SENT_LSN' / writed='$WRITED_LSN', Lag: ${LAG}b)"
[[ "$SENT_LSN" != "$CURRENT_LSN" ]] && CURRENT_LSN_IS_LAST_SENT=0 [ "$SENT_LSN" != "$CURRENT_LSN" ] && CURRENT_LSN_IS_LAST_SENT=0
done done
if [[ $CURRENT_LSN_IS_LAST_SENT -eq 1 ]]; then if [ $CURRENT_LSN_IS_LAST_SENT -eq 1 ]
then
echo "OK: $STANDBY_CLIENTS_COUNT stand-by client(s) connected" echo "OK: $STANDBY_CLIENTS_COUNT stand-by client(s) connected"
EXIT_CODE=0 EXIT_CODE=0
else else