Skip to content

Instantly share code, notes, and snippets.

@x-yuri
Last active January 18, 2021 16:40
Show Gist options
  • Save x-yuri/3d52b2e70dc84f4fc7eb177a5f204ac5 to your computer and use it in GitHub Desktop.
Save x-yuri/3d52b2e70dc84f4fc7eb177a5f204ac5 to your computer and use it in GitHub Desktop.
Barman scripts #pg #barman
#!/usr/bin/env bash
set -eu
. ~/lib/barman.sh
eval set -- "$(
getopt -o h --long n-base-backups:,n-standalone-base-backups:,dry-run,help \
-n "$(basename -- "$0")" -- "$@"
)"
p_n_base_backups=
p_n_standalone_base_backups=
p_dry_run=
while true; do
case "$1" in
--n-base-backups) p_n_base_backups=$2
shift 2
;;
--n-standalone-base-backups) p_n_standalone_base_backups=$2
shift 2
;;
--dry-run) p_dry_run=1
shift
;;
-h|--help) cat <<USAGE
usage: $(basename -- "$0") [OPTIONS] SERVER
options: --n-base-backups N
--n-standalone-base-backups N
--dry-run
USAGE
exit
;;
--) shift
break
;;
esac
done
p_server=$1
# target is either wal or standalone
backup_files() {
local b=$1 target=$2
local f f2 files files2
printf '%s\n' "$basebackups_directory/$b"
nlstr2arr "$(barman list-files --target "$target" -- "$p_server" "$b")" files
for f in "${files[@]}"; do
if starts_with "$f" "$basebackups_directory"; then # standalone
continue
fi
ls -1 -- "$f"*
done
}
# get list of backups
nlstr2arr "$(barman list-backup --minimal -- "$p_server")" backups
# exit if no backups to be deleted
if (( ${#backups[@]} <= p_n_base_backups )); then
exit
fi
basebackups_directory=$(get_server_var "$p_server" basebackups_directory)
wals_directory=$(get_server_var "$p_server" wals_directory)
# what to keep
nlstr2arr "$(
set -eu
{
for (( i = 0; i < p_n_base_backups; i++ )); do
backup_files "${backups[$i]}" wal
done
for (( i = p_n_base_backups;
i < p_n_base_backups + p_n_standalone_base_backups
&& i < ${#backups[@]};
i++ )); do
backup_files "${backups[$i]}" standalone
done
} | sort | uniq # the first bunch have common WAL files
)" keep_files
# which backups to delete
nlstr2arr "$(ls -d -- "$basebackups_directory"/*)" all_base_backups
delete_base_backups=()
for f in "${all_base_backups[@]}"; do
if ! in_array "$f" "${keep_files[@]}"; then
delete_base_backups+=("$f")
fi
done
# which WALs to delete
nlstr2arr "$(ls -- "$wals_directory"/*/*)" all_wals
delete_wals=()
for f in "${all_wals[@]}"; do
if ! in_array "$f" "${keep_files[@]}"; then
delete_wals+=("$f")
fi
done
# delete
for f in "${delete_base_backups[@]}"; do
cmd=(rm -rf -- "$f")
if (( p_dry_run )); then
printf '%s\n' "${cmd[*]}"
else
"${cmd[@]}"
fi
done
for f in "${delete_wals[@]}"; do
cmd=(rm -- "$f")
if (( p_dry_run )); then
printf '%s\n' "${cmd[*]}"
else
"${cmd[@]}"
fi
done
barman rebuild-xlogdb -- "$p_server"
#!/usr/bin/env bash
set -eu
eval set -- "$(
getopt -o h --long help \
-n "$(basename -- "$0")" -- "$@"
)"
while true; do
case "$1" in
-h|--help) cat <<USAGE
usage: $(basename -- "$0") SERVER
USAGE
exit
;;
--) shift
break
;;
esac
done
p_server=$1
re='^(\s*streaming_archiver\s*=\s*)\S+(.*)'
sed -Ei -- 's/'"$re"'/# &/' /etc/barman.d/"$p_server".conf
#!/usr/bin/env bash
set -eu
eval set -- "$(
getopt -o h --long help \
-n "$(basename -- "$0")" -- "$@"
)"
while true; do
case "$1" in
-h|--help) cat <<USAGE
usage: $(basename -- "$0") SERVER
USAGE
exit
;;
--) shift
break
;;
esac
done
p_server=$1
f=/etc/barman.d/"$p_server".conf
re='^(\s*streaming_archiver\s*=\s*)\S+(.*)'
if egrep -q -- "$re" "$f"; then
sed -Ei -- 's/'"$re"'/\1on\2/' "$f"
else
re='^\s*#\s?'${re:1}
egrep -q -- "$re" "$f" \
&& sed -Ei -- 's/'"$re"'/\1on\2/' "$f" \
|| printf 'streaming_archiver = on\n' >> "$f"
fi
#!/usr/bin/env bash
set -eu
. ~/.barman-vars
. ~/lib/barman.sh
eval set -- "$(
getopt -o h --long target-immediate,restore-standby,standby-host:,standby-port:,help \
-n "$(basename -- "$0")" -- "$@"
)"
p_target_immediate=
p_restore_standby=
p_standby_host=
p_standby_port=22
while true; do
case "$1" in
--target-immediate) p_target_immediate=1
shift
;;
--restore-standby) p_restore_standby=1
shift
;;
--standby-host) p_standby_host=$2
shift 2
;;
--standby-port) p_standby_port=$2
shift 2
;;
-h|--help) cat <<USAGE
restore db, then standby
usage: $(basename -- "$0") [OPTIONS] SERVER BACKUP
options: --target-immediate
--restore-standby
--standby-host HOST
--standby-port PORT
Restoring standby is performed if --standby-host was specified. --restore-standby makes it skip restoring db.
USAGE
exit
;;
--) shift
break
;;
esac
done
p_server=$1
p_backup_id=$2
if [ "$p_restore_standby" ]; then
host=$p_standby_host
port=$p_standby_port
else
host=$p_server
port=${barman_server_port[$p_server]}
fi
if [ "$p_target_immediate" ] && [ "$p_restore_standby" ]; then
printf '%s: --target-immediate and --restore-standby are mutually exclusive\n' >&2
exit 1
fi
pg_home=${barman_server_home[$p_server]}
datadir=${barman_server_data_directory[$p_server]}
datadir_rel=${datadir:$(( ${#pg_home} + 1 ))}
verdir=$pg_home/${datadir_rel%%/*}
ssh -p "$port" -- "$host" "pg_home=${pg_home@Q} verdir=${verdir@Q} host=${host@Q} bash -lc '
set -eu
timestamp=\$(date +%Y%m%d-%H%M%S)
printf \"%s %s: stop pg\\\\n\" -- \"\$host\"
pg-stop.sh
# move data dir
if [ -e \"\$verdir\" ]; then
printf \"%s %s: move data dir\\\\n\" -- \"\$host\"
su - -c \"mv \${verdir@Q}{,-\${timestamp@Q}}\" -- postgres
fi
'"
if ! [ "$p_restore_standby" ]; then
printf "%s %s: stop streaming\\n" -- "$p_server"
barman-disable-streaming.sh -- "$p_server"
barman-stop-streaming.sh -- "$p_server"
fi
# enable get-wal
recovery_options_re='^(\s*recovery_options\s*=\s*)\S+(.*)'
disable_get_wal() {
sed -Ei -- '/'"$recovery_options_re"'/d' "/etc/barman.d/$p_server.conf"
}
if [ "$p_restore_standby" ]; then
printf "%s %s: enable get-wal\\n" -- "$p_server"
disable_get_wal
printf 'recovery_options = get-wal\n' >> "/etc/barman.d/$p_server.conf"
trap disable_get_wal EXIT
fi
# recover
printf "%s %s: recover\\n" -- "$host"
args=()
if (( p_target_immediate )); then
args+=(--target-immediate --target-action promote)
fi
if [ "$p_restore_standby" ]; then
args+=(--standby-mode)
fi
barman recover "${args[@]}" \
--remote-ssh-command "ssh -p ${port@Q} postgres@${host@Q}" \
-- "$p_server" "$p_backup_id" "${barman_server_data_directory[$p_server]}"
# disable get-wal
if [ "$p_restore_standby" ]; then
printf "%s %s: disable get-wal\\n" -- "$p_server"
disable_get_wal
fi
# copy partial wal file
if ! (( p_target_immediate )) \
&& ! [ "$p_restore_standby" ] \
&& [ -e /var/lib/barman/"$p_server"/streaming/*.partial ]; then
printf "%s %s: copy partial wal\\n" -- "$p_server"
f=$(basename -- /var/lib/barman/$p_server/streaming/*.partial .partial)
su - -c "
scp -P ${port@Q} -- /var/lib/barman/${p_server@Q}/streaming/*.partial \\
postgres@${host@Q}:${barman_server_data_directory[$p_server]@Q}/pg_wal/${f@Q}
" -- barman
fi
if [ "$p_restore_standby" ]; then
ssh -p "$port" -- "$host" "
standby_datadir=${barman_server_data_directory[$host]@Q}
# fix recovery.conf
printf \"%s %s: fix recovery.conf\\\\n\" -- ${host@Q}
sed -Ei 's/(barman-wal-restore\\s+-U\\s+\\w+\\s+)(\\w+)/\\1barman-wal-restore-\\2/' \\
\"\$standby_datadir/recovery.conf\"
# start pg
printf \"%s %s: start pg\\\\n\" -- ${host@Q}
systemctl start postgresql
"
else
if [ "$p_target_immediate" ]; then
printf "%s %s: stop streaming\\n" -- "$p_server"
barman-disable-streaming.sh -- "$p_server"
barman-stop-streaming.sh -- "$p_server"
printf "%s %s: move barman server dir\\n" -- "$p_server"
mv -- /var/lib/barman/"$p_server"{,-$(date +%Y%m%d-%H%M%S)}
fi
printf "%s %s: start pg\\n" -- "$p_server"
ssh -p "$port" -- "$host" '
set -eu
pg_home='"${pg_home@Q}"'
datadir='"${datadir@Q}"'
step=$(printf "1 * 5\\n" | bc)
start=$(date +%s)
printf "[%s] start\\n" "$(date -d @$start)"
systemctl start postgresql
IFS=: read -r today now <<< $(date +%F:%s)
midnight=$(date -d "$today 0" +%s)
t=$(( midnight + (now - midnight) * step / step ))
while true; do
(( t += step ))
sleep $(( t - $(date +%s) ))
in_recovery=$(su - -c "psql -Atc \"select pg_is_in_recovery()\"" -- postgres \
|| printf "t\\n")
if [ "$in_recovery" != t ]; then
break
fi
wal=$(ps -u postgres -o pid,comm,args | grep "startup process" | awk "{print \$NF}")
last_wal=$(find "$datadir"/pg_wal -mindepth 1 -maxdepth 1 -type f -printf "%f\\n" \
| sort \
| tail -n 1)
recovery_conf=$(basename -- "$(ls -- "$datadir"/recovery*)")
printf "\\r[%s] %s %s %s/%s" \
"$(date "+%F %T")" \
"$in_recovery" \
"$recovery_conf" \
"$wal" \
"$last_wal"
done
end=$(date +%s)
printf "[%s] end\\n" "$(date -d @$end)"
'
printf "%s %s: create replication slot\\n" -- "$p_server"
barman receive-wal --create-slot -- "$p_server" || true # create replication slot
printf "%s %s: start streaming\\n" -- "$p_server"
barman-enable-streaming.sh -- "$p_server"
barman-start-streaming.sh
if [ "$p_target_immediate" ]; then
printf "%s %s: create directory structure\\n" -- "$p_server"
barman check -- "$p_server" &> /dev/null || true # create directory structure
printf "%s %s: switch wal\\n" -- "$p_server"
barman switch-wal --force --archive -- "$p_server" # switch WAL file
printf "%s %s: backup\\n" -- "$p_server"
barman backup -- "$p_server"
fi
if [ "$p_standby_host" ]; then
printf "%s %s: recreate standby\\n" -- "$p_server"
"$0" --restore-standby --standby-host "$p_standby_host" --standby-port "$p_standby_port" \
-- "$p_server" "$p_backup_id"
fi
fi
#!/usr/bin/env bash
set -eu
eval set -- "$(
getopt -o h --long help \
-n "$(basename -- "$0")" -- "$@"
)"
while true; do
case "$1" in
-h|--help) cat <<USAGE
usage: $(basename -- "$0")
USAGE
exit
;;
--) shift
break
;;
esac
done
barman cron
#!/usr/bin/env bash
set -eu
eval set -- "$(
getopt -o h --long help \
-n "$(basename -- "$0")" -- "$@"
)"
while true; do
case "$1" in
-h|--help) cat <<USAGE
usage: $(basename -- "$0") SERVER
USAGE
exit
;;
--) shift
break
;;
esac
done
p_server=$1
barman receive-wal --stop -- "$p_server" || true
# quote for ERE
qe() {
local s=$1 delimiter=${2:-}
local re='\.|\*|\[|\^|\$|\\|\+|\?|\{|\||\(' # .*[^$\+?{|(
if [ "$delimiter" ]; then
re=$re'|\'$delimiter
fi
printf '%s\n' "$s" | sed -E -- 's/('"$re"')/\\\1/g'
}
nlstr2arr() {
local __IFS __el __r __s=$1 __a=$2
__IFS=$IFS
IFS=$'\n'
__r=($__s)
IFS=$__IFS
eval "$__a=()"
for __el in "${__r[@]}"; do
eval "$__a+=(${__el@Q})"
done
}
in_array() {
local el=$1
shift
local a=("$@")
for el2 in "${a[@]}"; do
if [ "$el2" = "$el" ]; then
return 0
fi
done
return 1
}
starts_with() {
local s=$1 prefix=$2
[[ "$s" == "$prefix"* ]]
}
get_server_var() {
local srv=$1 var=$2
local q_var=$(qe "$var")
barman show-server -- "$srv" \
| egrep -- "^\s*$q_var\s*:" \
| sed -E -- 's/^[^:]+:\s*//'
}
#!/usr/bin/env bash
set -eu
services=$(systemctl list-units 'postgresql*' \
| grep ^postgresql \
| awk '{print $1}')
main_pids() {
printf '%s' "$services" \
| xargs -rI{} -d'\n' systemctl show -p MainPID {} \
| sed -E 's/.*=//'
}
systemctl stop postgresql
while [ "$(main_pids | tr -d '\n' | sed -E 's/0//g')" ]; do :; done
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment