Skip to content

Commit

Permalink
feat: logging for PostgreSQL wal-g scripts (#1120)
Browse files Browse the repository at this point in the history
  • Loading branch information
dingshun-cmss authored Oct 25, 2024
1 parent cfe6878 commit 81459e5
Show file tree
Hide file tree
Showing 10 changed files with 257 additions and 67 deletions.
46 changes: 46 additions & 0 deletions addons/kblib/templates/_liblogs.tpl
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
{{/*
This function is used to format a line to the log format, so that it can be saved into a log file.
Usage:
format_log_content SOME_TYPE SOME_COMPONENT
Result:
The line to be logged will be formatted with some logging information, and be printed to the stdout
Example:
echo "some line content from stdout" | format_log_content STDOUT SOME_COMPONENT > /path/to/logfile
echo "some line content from stderr" | format_log_content STDERR SOME_COMPONENT > /path/to/logfile
*/}}
{{- define "kblib.logs.format_log_content" }}
format_log_content() {
local content_type #STDOUT or STDERR
local component
content_type=$1
component=$2
while IFS= read -r line; do
echo "$(date -u '+%Y-%m-%dT%H:%M:%SZ') [$content_type] [$component] $line"
done
}
{{- end }}

{{/*
This function is used to setup the logging of the script,
so that the STDOUT/STDERR of the scripts can be recorded into a dedicated file.
Usage:
setup_logging LOG_COMPONENT LOG_FILE
Result:
The stdout / stderr of the script will be saved into a dedicated file
Example:
setup_logging SOME_COMPONENT dummy.log
*/}}
{{- define "kblib.logs.setup_logging" }}
setup_logging() {
local component
local log_file
component=$1
log_file=$2
# redirect all the stdout and stderr to files
exec > >( tee >( format_log_content STDOUT "${component}" | stdbuf -oL cat >> "${log_file}" ) ) \
2> >( tee >( format_log_content STDERR "${component}" | stdbuf -oL cat >> "${log_file}" ) >&2 )
}
{{- end }}
30 changes: 21 additions & 9 deletions addons/postgresql/dataprotection/wal-g-backup.sh
Original file line number Diff line number Diff line change
@@ -1,4 +1,10 @@
backup_base_path="$(dirname $DP_BACKUP_BASE_PATH)/wal-g"
# shellcheck disable=SC2148

postgres_log_dir="${VOLUME_DATA_DIR}/logs"
postgres_scripts_log_file="${postgres_log_dir}/scripts.log"
setup_logging WALG_BACKUP "${postgres_scripts_log_file}"

backup_base_path="$(dirname "$DP_BACKUP_BASE_PATH")/wal-g"
export WALG_DATASAFED_CONFIG=""
export PATH="$PATH:$DP_DATASAFED_BIN_PATH"
export WALG_COMPRESSION_METHOD=zstd
Expand All @@ -19,9 +25,9 @@ function handle_exit() {
}

function get_backup_name() {
line=$(cat result.txt | tail -n 1)
line=$(tail -n 1 result.txt)
if [[ $line == *"Wrote backup with name"* ]]; then
echo ${line##* }
echo "${line##* }"
fi
}

Expand All @@ -37,7 +43,9 @@ trap handle_exit EXIT
set -e
# 1. do full backup
writeSentinelInBaseBackupPath "${backup_base_path}" "wal-g-backup-repo.path"
PGHOST=${DP_DB_HOST} PGUSER=${DP_DB_USER} PGPORT=5432 wal-g backup-push ${DATA_DIR} 2>&1 | tee result.txt
echo "Full backup using WAL-G: BEGIN"
PGHOST=${DP_DB_HOST} PGUSER=${DP_DB_USER} PGPORT=5432 wal-g backup-push "${DATA_DIR}" 2>&1 | tee result.txt
echo "Full backup using WAL-G: DONE"

set +e
echo "switch wal log"
Expand All @@ -52,16 +60,20 @@ if [[ -z ${backupName} ]] || [[ ${backupName} != "base_"* ]];then
fi

# 3. add sentinel file for this backup CR
echo "add sentinel file for backup"
echo "" | datasafed push - "/basebackups_005/${backupName}_dp_${DP_BACKUP_NAME}"
writeSentinelInBaseBackupPath "${backupName}" "wal-g-backup-name"

# 4. stat startTime,stopTime,totalSize for this backup
sentinel_file="/basebackups_005/${backupName}_backup_stop_sentinel.json"
datasafed pull ${sentinel_file} backup_stop_sentinel.json
datasafed pull "${sentinel_file}" backup_stop_sentinel.json
result_json=$(cat backup_stop_sentinel.json)
STOP_TIME=$(echo $result_json | jq -r ".FinishTime")
START_TIME=$(echo $result_json | jq -r ".StartTime")
TOTAL_SIZE=$(echo $result_json | jq -r ".CompressedSize")
STOP_TIME=$(echo "${result_json}" | jq -r ".FinishTime")
START_TIME=$(echo "${result_json}" | jq -r ".StartTime")
TOTAL_SIZE=$(echo "${result_json}" | jq -r ".CompressedSize")

# 5. update backup status
echo "{\"totalSize\":\"$TOTAL_SIZE\",\"timeRange\":{\"start\":\"${START_TIME}\",\"end\":\"${STOP_TIME}\"}}" >"${DP_BACKUP_INFO_FILE}"
echo "write backup result"
echo "{\"totalSize\":\"$TOTAL_SIZE\",\"timeRange\":{\"start\":\"${START_TIME}\",\"end\":\"${STOP_TIME}\"}}" >"${DP_BACKUP_INFO_FILE}"
echo "full backup DONE"
sync
34 changes: 21 additions & 13 deletions addons/postgresql/dataprotection/wal-g-config.sh
Original file line number Diff line number Diff line change
@@ -1,26 +1,34 @@
# shellcheck disable=SC2148
set -e

postgres_log_dir="${VOLUME_DATA_DIR}/logs"
postgres_scripts_log_file="${postgres_log_dir}/scripts.log"
setup_logging WALG_CONFIG "${postgres_scripts_log_file}"

if [[ ! -f /etc/datasafed/datasafed.conf ]]; then
echo "ERROR: backupRepo should use Tool accessMode"
exit 1
echo "ERROR: backupRepo should use Tool accessMode"
exit 1
fi

function config_wal_g() {
walg_dir=${VOLUME_DATA_DIR}/wal-g
walg_env=${walg_dir}/env
mkdir -p ${walg_dir}/env
cp /etc/datasafed/datasafed.conf ${walg_dir}/datasafed.conf
cp /usr/bin/wal-g ${walg_dir}/wal-g
walg_dir="${VOLUME_DATA_DIR}/wal-g"
walg_env="${walg_dir}/env"
mkdir -p "${walg_env}"
cp /etc/datasafed/datasafed.conf "${walg_dir}/datasafed.conf"
cp /usr/bin/wal-g "${walg_dir}/wal-g"
datasafed_base_path=${1:?missing datasafed_base_path}
# config wal-g env
# config WALG_PG_WAL_SIZE with wal_segment_size which fetched by psql
# echo "" > ${walg_env}/WALG_PG_WAL_SIZE
echo "${walg_dir}/datasafed.conf" > ${walg_env}/WALG_DATASAFED_CONFIG
echo "${datasafed_base_path}" > ${walg_env}/DATASAFED_BACKEND_BASE_PATH
echo "true" > ${walg_env}/PG_READY_RENAME
echo "zstd" > ${walg_env}/WALG_COMPRESSION_METHOD
echo "${walg_dir}/datasafed.conf" > "${walg_env}/WALG_DATASAFED_CONFIG"
echo "${datasafed_base_path}" > "${walg_env}/DATASAFED_BACKEND_BASE_PATH"
echo "true" > "${walg_env}/PG_READY_RENAME"
echo "zstd" > "${walg_env}/WALG_COMPRESSION_METHOD"
}

config_wal_g "$(dirname $(dirname $DP_BACKUP_BASE_PATH))/wal-g"
echo "Configure WAL-G : BEGIN"
config_wal_g "$(dirname "$(dirname "${DP_BACKUP_BASE_PATH}")")/wal-g"
echo "Configure WAL-G : DONE"

echo "{}" >"${DP_BACKUP_INFO_FILE}"
sync
sync
34 changes: 22 additions & 12 deletions addons/postgresql/dataprotection/wal-g-delete.sh
Original file line number Diff line number Diff line change
@@ -1,44 +1,54 @@
# shellcheck disable=SC2148

postgres_log_dir="${VOLUME_DATA_DIR}/logs"
postgres_scripts_log_file="${postgres_log_dir}/scripts.log"
setup_logging WALG_DELETE "${postgres_scripts_log_file}"

export WALG_DATASAFED_CONFIG=""
export PATH="$PATH:$DP_DATASAFED_BIN_PATH"
export DATASAFED_BACKEND_BASE_PATH="$DP_BACKUP_BASE_PATH"

function getWalGSentinelInfo() {
local sentinelFile=${1}
local out=$(datasafed list ${sentinelFile})
local sentinelFile
local out
sentinelFile=${1}
out=$(datasafed list "${sentinelFile}")
if [ "${out}" == "${sentinelFile}" ]; then
datasafed pull "${sentinelFile}" ${sentinelFile}
echo "$(cat ${sentinelFile})"
datasafed pull "${sentinelFile}" "${sentinelFile}"
cat "${sentinelFile}"
return
fi
}

# 1. get backup repo path of wal-g
backupRepoPath=$(getWalGSentinelInfo "wal-g-backup-repo.path")
if [[ -z ${backupRepoPath} ]]; then
if [[ -z "${backupRepoPath}" ]]; then
echo "INFO: nothing to delete."
exit 0
fi

# 2. get backup name of this backup
backupName=$(getWalGSentinelInfo "wal-g-backup-name")
if [[ -z ${backupName} ]]; then
if [[ -z "${backupName}" ]]; then
echo "INFO: delete unsuccessfully backup files and outdated WAL archive."
export DATASAFED_BACKEND_BASE_PATH=${backupRepoPath}
wal-g delete garbage --confirm
exit 0
fi

# 3. cleanup outdated wal logs, only effective when existing at least one full backup
export DATASAFED_BACKEND_BASE_PATH=${backupRepoPath}
echo "cleanup garbage archives in backup repo"
export DATASAFED_BACKEND_BASE_PATH="${backupRepoPath}"
wal-g delete garbage ARCHIVES

# 4. delete wal-g
echo "cleanup garbage full backups in backup repo"
dpBackupFilesCount=$(datasafed list --name "${backupName}_dp_*" /basebackups_005 | wc -l)
if [[ ${dpBackupFilesCount} -le 1 ]]; then
if [[ "${dpBackupFilesCount}" -le 1 ]]; then
# if this base backup only belongs to a backup CR, delete it.
echo "INFO: delete ${backupName}, backupRepo: ${backupRepo}"
wal-g delete target ${backupName} --confirm && wal-g delete garbage ARCHIVES --confirm
echo "INFO: delete ${backupName}"
wal-g delete target "${backupName}" --confirm && wal-g delete garbage ARCHIVES --confirm
fi
datasafed rm "/basebackups_005/${backupName}_dp_${DP_BACKUP_NAME}"


echo "backup cleanup DONE"
sync
78 changes: 50 additions & 28 deletions addons/postgresql/dataprotection/wal-g-restore.sh
Original file line number Diff line number Diff line change
@@ -1,3 +1,14 @@
# shellcheck disable=SC2148

postgres_log_dir="${VOLUME_DATA_DIR}/logs"
postgres_scripts_log_file="${postgres_log_dir}/scripts.log"
mkdir -p "$postgres_log_dir"
chmod -R +777 "$postgres_log_dir"
touch "$postgres_scripts_log_file"
chmod 666 "$postgres_scripts_log_file"

setup_logging WALG_RESTORE "${postgres_scripts_log_file}"

set -e
export WALG_DATASAFED_CONFIG=""
export WALG_COMPRESSION_METHOD=zstd
Expand All @@ -7,28 +18,35 @@ export WALG_TAR_SIZE_THRESHOLD=21474836480
export DATASAFED_BACKEND_BASE_PATH="$DP_BACKUP_BASE_PATH"

function getWalGSentinelInfo() {
local sentinelFile=${1}
local out=$(datasafed list ${sentinelFile})
if [ "${out}" == "${sentinelFile}" ]; then
datasafed pull "${sentinelFile}" ${sentinelFile}
echo "$(cat ${sentinelFile})"
return
fi
local sentinelFile
local out

sentinelFile=$1
out=$(datasafed list "${sentinelFile}")
if [ "${out}" == "${sentinelFile}" ]; then
datasafed pull "${sentinelFile}" "${sentinelFile}"
cat "${sentinelFile}"
return
fi
}

function config_wal_g_for_fetch_wal_log() {
walg_dir=${VOLUME_DATA_DIR}/wal-g
walg_env=${walg_dir}/restore-env
mkdir -p ${walg_dir}/restore-env
cp /etc/datasafed/datasafed.conf ${walg_dir}/datasafed.conf
cp /usr/bin/wal-g ${walg_dir}/wal-g
local walg_dir
local walg_env
local datasafed_base_path

walg_dir="${VOLUME_DATA_DIR}/wal-g"
walg_env="${walg_dir}/restore-env"
mkdir -p "${walg_env}"
cp /etc/datasafed/datasafed.conf "${walg_dir}/datasafed.conf"
cp /usr/bin/wal-g "${walg_dir}/wal-g"
datasafed_base_path=${1:?missing datasafed_base_path}
# config wal-g env
# config WALG_PG_WAL_SIZE with wal_segment_size which fetched by psql
# echo "" > ${walg_env}/WALG_PG_WAL_SIZE
echo "${walg_dir}/datasafed.conf" > ${walg_env}/WALG_DATASAFED_CONFIG
echo "${datasafed_base_path}" > ${walg_env}/DATASAFED_BACKEND_BASE_PATH
echo "zstd" > ${walg_env}/WALG_COMPRESSION_METHOD
echo "${walg_dir}/datasafed.conf" > "${walg_env}/WALG_DATASAFED_CONFIG"
echo "${datasafed_base_path}" > "${walg_env}/DATASAFED_BACKEND_BASE_PATH"
echo "zstd" > "${walg_env}/WALG_COMPRESSION_METHOD"
}

# 1. get restore info
Expand All @@ -37,26 +55,29 @@ backupName=$(getWalGSentinelInfo "wal-g-backup-name")

# 2. fetch base backup
export DATASAFED_BACKEND_BASE_PATH="${backupRepoPath}"
mkdir -p ${DATA_DIR};
wal-g backup-fetch ${DATA_DIR} ${backupName}
mkdir -p "${DATA_DIR}";
echo "WAL-G fetching full backup '${backupName}': BEGIN"
wal-g backup-fetch "${DATA_DIR}" "${backupName}"
echo "WAL-G fetching full backup '${backupName}': DONE"

# 3. config restore script
touch ${DATA_DIR}/recovery.signal;
mkdir -p ${RESTORE_SCRIPT_DIR} && chmod 777 -R ${RESTORE_SCRIPT_DIR};
echo "#!/bin/bash" > ${RESTORE_SCRIPT_DIR}/kb_restore.sh;
echo "[[ -d '${DATA_DIR}.old' ]] && mv -f ${DATA_DIR}.old/* ${DATA_DIR}/;" >> ${RESTORE_SCRIPT_DIR}/kb_restore.sh;
echo "sync;" >> ${RESTORE_SCRIPT_DIR}/kb_restore.sh;
chmod +x ${RESTORE_SCRIPT_DIR}/kb_restore.sh;
echo "configure restore script"
touch "${DATA_DIR}/recovery.signal";
mkdir -p "${RESTORE_SCRIPT_DIR}" && chmod 777 -R "${RESTORE_SCRIPT_DIR}";
echo "#!/bin/bash" > "${RESTORE_SCRIPT_DIR}/kb_restore.sh";
echo "[[ -d '${DATA_DIR}.old' ]] && mv -f ${DATA_DIR}.old/* ${DATA_DIR}/;" >> "${RESTORE_SCRIPT_DIR}/kb_restore.sh";
echo "sync;" >> "${RESTORE_SCRIPT_DIR}/kb_restore.sh";
chmod +x "${RESTORE_SCRIPT_DIR}/kb_restore.sh";

# 4. config wal-g to fetch wal logs
echo "configure wal-g to fetch WAL log"
config_wal_g_for_fetch_wal_log "${backupRepoPath}"

# 5. config restore command
mkdir -p ${CONF_DIR} && chmod 777 -R ${CONF_DIR};
WALG_DIR=/home/postgres/pgdata/wal-g
mkdir -p "${CONF_DIR}" && chmod 777 -R "${CONF_DIR}";

restore_command_str="envdir ${WALG_DIR}/restore-env ${WALG_DIR}/wal-g wal-fetch %f %p >> ${RESTORE_SCRIPT_DIR}/wal-g.log 2>&1"
if [[ ! -z "${DP_RESTORE_TIMESTAMP}" ]]; then
restore_command_str="/kb-scripts/wal-g-wal-restore.sh %f %p"
if [[ -n "${DP_RESTORE_TIMESTAMP}" ]]; then
cat << EOF > "${CONF_DIR}/recovery.conf"
restore_command='${restore_command_str}'
recovery_target_time='$( date -d "@${DP_RESTORE_TIMESTAMP}" '+%F %T%::z' )'
Expand All @@ -71,5 +92,6 @@ recovery_target_action='promote'
EOF
fi
# this step is necessary, data dir must be empty for patroni
mv ${DATA_DIR} ${DATA_DIR}.old
mv "${DATA_DIR}" "${DATA_DIR}.old"
echo "restore data from full backup DONE"
sync
18 changes: 14 additions & 4 deletions addons/postgresql/scripts/postgres-pre-setup.sh
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,21 @@
postgres_template_conf_file="/home/postgres/conf/postgresql.conf"
postgres_conf_dir="/home/postgres/pgdata/conf/"
postgres_conf_file="/home/postgres/pgdata/conf/postgresql.conf"
postgres_log_dir="/home/postgres/pgdata/logs/"
postgres_scripts_log_file="${postgres_log_dir}/scripts.log"

build_real_postgres_conf() {
mkdir -p $postgres_conf_dir
chmod -R 777 $postgres_conf_dir
cp $postgres_template_conf_file $postgres_conf_dir
chmod 777 $postgres_conf_file
mkdir -p "$postgres_conf_dir"
chmod -R 777 "$postgres_conf_dir"
cp "$postgres_template_conf_file" "$postgres_conf_dir"
chmod 777 "$postgres_conf_file"
}

init_postgres_log() {
mkdir -p "$postgres_log_dir"
chmod -R 777 "$postgres_log_dir"
touch "$postgres_scripts_log_file"
chmod 666 "$postgres_scripts_log_file"
}

# This is magic for shellspec ut framework.
Expand All @@ -20,3 +29,4 @@ ${__SOURCED__:+false} : || return 0

# main
build_real_postgres_conf
init_postgres_log
Loading

0 comments on commit 81459e5

Please sign in to comment.