Files
PgBackRestWrapper/bin/pgbackrest_backup.sh

261 lines
7.8 KiB
Bash
Executable File

#!/usr/bin/env bash
# PgBackrest backup wrapper script
## FUNCTIONS
# METHOD: convert_time
# PARAMS: timestamp in seconds or with milliseconds (nnnn.nnnn)
# RETURN: formated string with human readable time (d/h/m/s)
# CALL : var=$(convert_time $timestamp);
# DESC : converts a timestamp or a timestamp with float milliseconds
# to a human readable format
# output is in days/hours/minutes/seconds
function convert_time
{
timestamp=${1};
# round to four digits for ms
timestamp=$(printf "%1.4f" "$timestamp");
# get the ms part and remove any leading 0
ms=$(echo "${timestamp}" | cut -d "." -f 2 | sed -e 's/^0*//');
timestamp=$(echo "${timestamp}" | cut -d "." -f 1);
timegroups=(86400 3600 60 1); # day, hour, min, sec
timenames=("d" "h" "m" "s"); # day, hour, min, sec
output=( );
time_string="";
for timeslice in "${timegroups[@]}"; do
# floor for the division, push to output
output[${#output[*]}]=$(awk "BEGIN {printf \"%d\", ${timestamp}/${timeslice}}");
timestamp=$(awk "BEGIN {printf \"%d\", ${timestamp}%${timeslice}}");
done;
for ((i=0; i<${#output[@]}; i++)); do
if [ "${output[$i]}" -gt 0 ] || [ -n "$time_string" ]; then
if [ -n "${time_string}" ]; then
time_string=${time_string}" ";
fi;
time_string=${time_string}${output[$i]}${timenames[$i]};
fi;
done;
if [ -n "${ms}" ] && [ "${ms}" != "nan" ] && [ "${ms}" -gt 0 ]; then
time_string=${time_string}" ${ms}ms";
fi;
# just in case the time is 0
if [ -z "${time_string}" ]; then
time_string="0s";
fi;
echo -n "${time_string}";
}
## VARIABLES
REGEX_COMMENT="^[\ \t]*#";
INI_BLOCK="^\[[A-Za-z]*\]";
BASE_FOLDER=$(dirname "$(readlink -f "$0")")"/";
CONFIG="${BASE_FOLDER}../config/";
BACKUP_TYPE="";
OVERRIDE_STANZA="";
LIST_STANZA=0;
TEST=0;
config_file="${CONFIG}pgbackrest.cfg";
stanza_file="${CONFIG}stanza.cfg";
if [ -f "${config_file}" ]; then
# shellcheck disable=SC1090
# shellcheck disable=SC2283
source <(grep = "${config_file}" | sed 's/ *= */=/g')
else
echo "Missing config file ${config_file}";
exit;
fi;
if [ -z "${sudo_user}" ]; then
echo "sudo_user not set in the config file ${config_file}";
exit;
fi;
if [ -z "${pgbackrest_config}" ] ||[ ! -f "${pgbackrest_config}" ]; then
echo "Missing pgbackrest default config file ${pgbackrest_config}";
exit;
fi;
# stanza list file
if [ ! -f "${stanza_file}" ]; then
echo "Missing stanza config file ${stanza_file}";
exit;
fi;
PRINTF_BLOCK="=== [%-8s: %19s] ==[%s]===============>\n";
## OPT PARSEIN
while getopts ":b:s:lt" opt; do
case "${opt}" in
b)
# backuptype
BACKUP_TYPE="${OPTARG}";
;;
s)
# stanza
OVERRIDE_STANZA="${OPTARG}";
;;
l)
# list
LIST_STANZA=1;
;;
t)
# test
TEST=1;
;;
:)
echo "Option -$OPTARG requires an argument."
;;
\?)
echo -e "\n Option does not exist: ${OPTARG}\n";
echo "-b (backuptype): full/diff";
echo "-s (stanza): override stanza name, must be in list"
echo "-l list available stanza"
echo "-t test run"
exit 1;
;;
esac;
done;
## check if OVERIDE_STANZA has a repo target flag set, get the name only for checks
OVERRIDE_STANZA_NAME="";
if [ -n "${OVERRIDE_STANZA}" ]; then
OVERRIDE_STANZA_NAME=$(echo "${OVERRIDE_STANZA}" | cut -d ":" -f 1);
fi;
## SCRIPT
if [ $TEST -eq 1 ]; then
echo "[..........] TEST RUN ONLY";
fi;
if [ $LIST_STANZA -eq 1 ]; then
echo "+ Stanza List:";
while read -r stanza; do
# skip empty
[ -z "${stanza}" ] && continue;
# skip starting with #
[[ "${stanza}" =~ ${REGEX_COMMENT} ]] && continue;
# skip the ini header blocks
[[ "${stanza}" =~ ${INI_BLOCK} ]] && continue;
# split the stanz int stanza and stanza repo list
stanza_name=$(echo "${stanza}" | cut -d ":" -f 1);
stanza_repo=$(echo "${stanza}" | awk -F':' '{print (NF>1) ? $2 : ""}');
# if override stanza matching
if [ "${stanza_name}" = "${OVERRIDE_STANZA_NAME}" ]; then
OVERRIDE_STANZA_REPO=$(echo "${OVERRIDE_STANZA}" | awk -F':' '{print (NF>1) ? $2 : ""}');
if [ -n "${OVERRIDE_STANZA_REPO}" ] && [ -n "${stanza_repo}" ] && [ "${stanza_repo}" = "${OVERRIDE_STANZA_REPO}" ]; then
echo "[*] ${stanza}";
elif [ -z "${OVERRIDE_STANZA_REPO}" ]; then
echo "[*] ${stanza}";
else
echo "[ ] ${stanza}";
fi;
else
echo "[ ] ${stanza}";
fi;
done <<< "$(cat "${stanza_file}")";
echo "";
echo "Entry marked with '*' is set as override stanza, and will be the only ones backed up";
echo "";
exit;
fi;
if [ -z "${BACKUP_TYPE}" ]; then
echo "[!] Backup type must be set as -b full or -b diff";
exit;
fi;
if [ "${BACKUP_TYPE}" != "full" ] && [ "${BACKUP_TYPE}" != "diff" ]; then
echo "[!] Backup type can only be 'full' or 'diff'";
exit;
fi;
echo "* PgBackrest Backup run type '${BACKUP_TYPE}' on $(date +'%F')";
# run backup
while read -r stanza; do
# skip empty
[ -z "${stanza}" ] && continue;
# skip starting with #
[[ "${stanza}" =~ ${REGEX_COMMENT} ]] && continue;
# skip the ini header blocks
[[ "${stanza}" =~ ${INI_BLOCK} ]] && continue;
# split into the name and repo list
stanza_name=$(echo "${stanza}" | cut -d ":" -f 1);
stanza_repo=$(echo "${stanza}" | awk -F':' '{print (NF>1) ? $2 : ""}');
# if we have a config
stanza_config=$(echo "${stanza}" | awk -F':' '{print (NF>1) ? $3 : ""}');
# override stanza check
if [ -n "${OVERRIDE_STANZA}" ]; then
# skip if not matching name
if [ "${stanza_name}" != "${OVERRIDE_STANZA_NAME}" ]; then
continue
fi;
# if we have repo set, check if repo is matching
OVERRIDE_STANZA_REPO=$(echo "${OVERRIDE_STANZA}" | awk -F':' '{print (NF>1) ? $2 : ""}');
if [ -n "${OVERRIDE_STANZA_REPO}" ] && [ "${stanza_repo}" != "${OVERRIDE_STANZA_REPO}" ]; then
continue
fi;
# set repo from override
stanza_repo="${OVERRIDE_STANZA_REPO}";
OVERRIDE_STANZA_CONFIG=$(echo "${OVERRIDE_STANZA}" | awk -F':' '{print (NF>2) ? $3 : ""}');
# if we have a config set in the stanza config, but none in the override, use the one from the stanza config
if [ -z "${OVERRIDE_STANZA_CONFIG}" ] && [ -n "${stanza_config}" ]; then
OVERRIDE_STANZA_CONFIG="${stanza_config}";
else
stanza_config="${OVERRIDE_STANZA_CONFIG}";
fi;
fi;
# build the call command
CALL=(
"sudo" "-u" "${sudo_user}"
"pgbackrest" "--type=${BACKUP_TYPE}" "--stanza=${stanza_name}"
);
_stanza_config="${pgbackrest_config}";
if [ -f "${stanza_config}" ]; then
_stanza_config="${stanza_config}";
fi;
stanza_check=$(grep -E "^\[${stanza_name}\]$" "${_stanza_config}");
if [ -z "${stanza_check}" ]; then
echo "[!] Stanza ${stanza_name} not found in config file ${_stanza_config}, skipping stanza";
continue;
fi;
if [ -n "${stanza_repo}" ]; then
# check if repo exists in config file with "repo<number>-"
repo_check=$(grep -E "^repo${stanza_repo}-" "${_stanza_config}");
if [ -z "${repo_check}" ]; then
echo "[!] Stanza repo ${stanza_repo} for stanza ${stanza_name} not found in config file ${_stanza_config}, skipping stanza";
continue;
fi;
CALL=("${CALL[@]}" "--repo=${stanza_repo}");
fi;
if [ -n "${stanza_config}" ]; then
if [ ! -f "${stanza_config}" ]; then
echo "[!] Stanza config file ${stanza_config} for stanza ${stanza_name} not found, skipping stanza";
continue;
fi;
CALL=("${CALL[@]}" "--config=${stanza_config}");
fi;
CALL=("${CALL[@]}" "backup");
# main backup start
START=$(date +'%s');
# shellcheck disable=SC2059
printf "${PRINTF_BLOCK}" "START" "$(date +'%F %T')" "${stanza}";
# --log-level-console=info
if [ $TEST -eq 1 ]; then
echo "${CALL[@]}";
else
# sudo -u "${sudo_user}" pgbackrest --type="${BACKUP_TYPE}" --stanza="${stanza}" ${option_repo} backup;
"${CALL[@]}";
fi;
DURATION=$(( $(date +'%s') - START ));
# shellcheck disable=SC2059
printf "${PRINTF_BLOCK}" "END" "$(convert_time ${DURATION})" "${stanza}";
done <<< "$(cat "${stanza_file}")";
echo "* PgBackrest Backup end";
if [ $TEST -eq 1 ]; then
echo "[..........] TEST RUN ONLY";
fi;
## __END__