Compare commits

...

16 Commits

Author SHA1 Message Date
Clemens Schwaighofer
924014688e Update gitignore file with backup lock files 2025-12-04 09:57:54 +09:00
Clemens Schwaighofer
f9a58171cc Bump version to v4.8.0 2025-12-04 09:35:08 +09:00
Clemens Schwaighofer
1b52af909a Update PostgreSQL module to run as normal user with sudo for PostgreSQL
also clean up all PostgreSQL command calls as array type calls
clean up binary finder for postgresql installations
and add port/host override options
2025-12-04 09:28:57 +09:00
Clemens Schwaighofer
32a75626bb Version number fixes 2025-12-03 15:49:45 +09:00
Clemens Schwaighofer
12ff648504 PostgreSQL backup hat wrong table selection 2025-12-03 15:31:55 +09:00
Clemens Schwaighofer
69be76e34c Default settings file update for BACKUP_FILE 2025-12-03 14:48:54 +09:00
Clemens Schwaighofer
4a95049d4f Default config file info update 2025-12-03 14:12:24 +09:00
Clemens Schwaighofer
d0e96a82e0 Clean up PostgreSQL call, clean up varify error block, ERR trap fixes
ERR trap is now returning last error so $? can bet used
Verify catches $? error now for INIT repository check
2025-12-03 14:00:49 +09:00
Clemens Schwaighofer
e5c5df6013 Fix error trap with return error to STD ERR 2025-12-03 13:08:35 +09:00
Clemens Schwaighofer
6023fac636 Fix trap clanup that also trapped ERR 2025-12-03 13:05:11 +09:00
Clemens Schwaighofer
9e0db8bae9 Fix the error trap with exit to stop calling it again with itself 2025-12-03 13:03:46 +09:00
Clemens Schwaighofer
8a8de773df Change borg repository verify error message collection 2025-12-03 12:47:49 +09:00
Clemens Schwaighofer
f41dd1b723 Change verify command error check 2025-12-03 12:45:56 +09:00
Clemens Schwaighofer
c5d88a64e1 Fix last command check for verify 2025-12-03 12:43:52 +09:00
Clemens Schwaighofer
943d1c551e Stop trapping errors und unset enviromant vars
On error just print error, but do not reset env vars, if this is done on verify error the init afterwards will store all settings in the wrong path
2025-12-03 12:38:01 +09:00
Clemens Schwaighofer
45e1e29d22 Update readme file with info about encryption 2025-12-02 10:01:37 +09:00
10 changed files with 208 additions and 103 deletions

2
.gitignore vendored
View File

@@ -1,5 +1,6 @@
.cache/ .cache/
.config/ .config/
# various borg files that need to be ignored
borg.backup.settings borg.backup.settings
borg.backup.*.settings borg.backup.*.settings
borg.backup.*.include borg.backup.*.include
@@ -7,3 +8,4 @@ borg.backup.*.exclude
borg.backup.*.schema-only borg.backup.*.schema-only
borg.backup.*.init borg.backup.*.init
borg.backup.*.compact borg.backup.*.compact
borg.backup.*.lock

View File

@@ -141,7 +141,7 @@ All below have default values if not set in the main settings file
* COMPRESSION: zstd * COMPRESSION: zstd
* COMPRESSION_LEVEL: 3 * COMPRESSION_LEVEL: 3
* ENCRYPTION: none * ENCRYPTION: keyfile (with no password)
* FORCE_VERIFY: false * FORCE_VERIFY: false
* COMPACT_INTERVAL: 1 * COMPACT_INTERVAL: 1
* CHECK_INTERVAL: none * CHECK_INTERVAL: none

View File

@@ -5,16 +5,24 @@ if [ -z "${MODULE}" ]; then
exit 1; exit 1;
fi; fi;
# E: inherit trap ERR
# T: DEBUG and RETURN traps are inherited
# u: unset variables ere error
set -ETu #-e -o pipefail set -ETu #-e -o pipefail
trap cleanup SIGINT SIGTERM ERR trap _catch ERR
trap _cleanup SIGINT SIGTERM
cleanup() { _cleanup() {
# script cleanup here # script cleanup here
echo "Some part of the script failed with an error: $? @LINE: $(caller)"; echo "Script abort: $? @LINE: $(caller)";
# unset exported vars # unset exported vars
unset BORG_BASE_DIR BORG_UNKNOWN_UNENCRYPTED_REPO_ACCESS_IS_OK BORG_RELOCATED_REPO_ACCESS_IS_OK; unset BORG_BASE_DIR BORG_UNKNOWN_UNENCRYPTED_REPO_ACCESS_IS_OK BORG_RELOCATED_REPO_ACCESS_IS_OK;
# end trap # end trap
trap - SIGINT SIGTERM ERR trap - SIGINT SIGTERM
}
_catch() {
local last_exit_code=$?;
echo "Some part of the script failed with ERROR: $last_exit_code @COMMAND: '$BASH_COMMAND' @LINE: $(caller)" >&2;
} }
# on exit unset any exported var # on exit unset any exported var
trap "unset BORG_BASE_DIR BORG_UNKNOWN_UNENCRYPTED_REPO_ACCESS_IS_OK BORG_RELOCATED_REPO_ACCESS_IS_OK" EXIT; trap "unset BORG_BASE_DIR BORG_UNKNOWN_UNENCRYPTED_REPO_ACCESS_IS_OK BORG_RELOCATED_REPO_ACCESS_IS_OK" EXIT;
@@ -24,7 +32,7 @@ function version {
} }
# version for all general files # version for all general files
VERSION="4.5.4"; VERSION="4.8.0";
# borg version and borg comamnd # borg version and borg comamnd
BORG_VERSION=""; BORG_VERSION="";
@@ -85,7 +93,9 @@ REGEX="";
REGEX_COMMENT="^[\ \t]*#"; REGEX_COMMENT="^[\ \t]*#";
REGEX_GLOB='\*'; REGEX_GLOB='\*';
REGEX_NUMERIC="^[0-9]{1,2}$"; REGEX_NUMERIC="^[0-9]{1,2}$";
REGEX_ERROR="^Some part of the script failed with an error:"; # port regex, but only approximately
REGEX_PORT="^[0-9]{2,5}$";
REGEX_ERROR="^Some part of the script failed with ERROR:";
PRUNE_DEBUG=""; PRUNE_DEBUG="";
INIT_REPOSITORY=0; INIT_REPOSITORY=0;
FOLDER_OK=0; FOLDER_OK=0;
@@ -148,6 +158,10 @@ SUB_BACKUP_SET="";
# for database backup only # for database backup only
DATABASE_FULL_DUMP=""; DATABASE_FULL_DUMP="";
DATABASE_USER=""; DATABASE_USER="";
DATABASE_USE_SUDO="";
DATABASE_SUDO_USER="";
DATABASE_PORT="";
DATABASE_HOST="";
# only for mysql old config file # only for mysql old config file
MYSQL_DB_CONFIG=""; MYSQL_DB_CONFIG="";
MYSQL_DB_CONFIG_PARAM=""; MYSQL_DB_CONFIG_PARAM="";
@@ -348,7 +362,7 @@ if [ -n "${ONE_TIME_TAG}" ] && ! [[ "${ONE_TIME_TAG}" =~ ^[A-Za-z0-9_-]+$ ]]; th
echo "One time tag '${ONE_TIME_TAG}' must be alphanumeric with dashes and underscore only."; echo "One time tag '${ONE_TIME_TAG}' must be alphanumeric with dashes and underscore only.";
exit 1; exit 1;
elif [ -n "${ONE_TIME_TAG}" ]; then elif [ -n "${ONE_TIME_TAG}" ]; then
# all ok, attach . at the end # all ok, attach '.' at the end
ONE_TIME_TAG=${ONE_TIME_TAG}"."; ONE_TIME_TAG=${ONE_TIME_TAG}".";
fi; fi;
# if -D, cannot be with -T, -i, -C, -I, -P # if -D, cannot be with -T, -i, -C, -I, -P
@@ -359,7 +373,7 @@ fi;
# -D also must be in valid backup set format # -D also must be in valid backup set format
# ! [[ "${DELETE_ONE_TIME_TAG}" =~ ^[A-Za-z0-9_-]+\.${MODULE},(\*-)?[0-9]{4}-[0-9]{2}-[0-9]{2}T\*$ ]] # ! [[ "${DELETE_ONE_TIME_TAG}" =~ ^[A-Za-z0-9_-]+\.${MODULE},(\*-)?[0-9]{4}-[0-9]{2}-[0-9]{2}T\*$ ]]
if [ -n "${DELETE_ONE_TIME_TAG}" ] && ! [[ "${DELETE_ONE_TIME_TAG}" =~ ^[A-Za-z0-9_-]+\.${MODULE},([A-Za-z0-9_-]+-)?[0-9]{4}-[0-9]{2}-[0-9]{2}T[0-9]{2}:[0-9]{2}:[0-9]{2}$ ]] && ! [[ "${DELETE_ONE_TIME_TAG}" =~ ^[A-Za-z0-9_-]+\.${MODULE},(\*-)?[0-9]{4}-[0-9]{2}-[0-9]{2}T\*$ ]]; then if [ -n "${DELETE_ONE_TIME_TAG}" ] && ! [[ "${DELETE_ONE_TIME_TAG}" =~ ^[A-Za-z0-9_-]+\.${MODULE},([A-Za-z0-9_-]+-)?[0-9]{4}-[0-9]{2}-[0-9]{2}T[0-9]{2}:[0-9]{2}:[0-9]{2}$ ]] && ! [[ "${DELETE_ONE_TIME_TAG}" =~ ^[A-Za-z0-9_-]+\.${MODULE},(\*-)?[0-9]{4}-[0-9]{2}-[0-9]{2}T\*$ ]]; then
echo "Delete one time tag '${DELETE_ONE_TIME_TAG}' is in an invalid format. " echo "Delete one time tag '${DELETE_ONE_TIME_TAG}' is in an invalid format."
echo "Please verify existing tags with -P option." echo "Please verify existing tags with -P option."
echo "For a globing be sure it is in the format of: TAG.MODULE,*-YYYY-MM-DDT*"; echo "For a globing be sure it is in the format of: TAG.MODULE,*-YYYY-MM-DDT*";
echo "Note the dash (-) after the first *, also time (T) is a globa (*) must." echo "Note the dash (-) after the first *, also time (T) is a globa (*) must."

View File

@@ -294,18 +294,15 @@ COMMAND_INFO="${COMMAND_EXPORT}${BORG_COMMAND} info ${OPT_REMOTE} ${REPOSITORY}"
# MARK: VERIFY / INFO # MARK: VERIFY / INFO
if [ "${VERIFY}" -eq 1 ] || [ "${INIT}" -eq 1 ]; then if [ "${VERIFY}" -eq 1 ] || [ "${INIT}" -eq 1 ]; then
printf "${PRINTF_SUB_BLOCK}" "VERIFY" "$(date +'%F %T')" "${MODULE}"; printf "${PRINTF_SUB_BLOCK}" "VERIFY" "$(date +'%F %T')" "${MODULE}";
if [ -n "${TARGET_SERVER}" ]; then if [ "${DEBUG}" -eq 1 ]; then
if [ "${DEBUG}" -eq 1 ]; then echo "${BORG_COMMAND} info ${OPT_REMOTE} ${REPOSITORY} 2>&1 ";
echo "${BORG_COMMAND} info ${OPT_REMOTE} ${REPOSITORY} 2>&1|grep \"Repository ID:\""; fi;
fi; # use borg info and verify if it returns "Repository ID:" in the first line
# use borg info and verify if it returns "Repository ID:" in the first line REPO_VERIFY=$(${BORG_COMMAND} info ${OPT_REMOTE} "${REPOSITORY}" 2>&1);
REPO_VERIFY=$(${BORG_COMMAND} info ${OPT_REMOTE} "${REPOSITORY}" 2>&1|grep "Repository ID:"); __last_error=$?;
# this is currently a hack to work round the error code in borg info # on any error in verify command force new INIT
# this checks if REPO_VERIFY holds this error message and then starts init if [[ $__last_error -ne 0 ]]; then
if [[ -z "${REPO_VERIFY}" ]] || [[ "${REPO_VERIFY}" =~ ${REGEX_ERROR} ]]; then echo "[!] Repository verify error: ${REPO_VERIFY}";
INIT_REPOSITORY=1;
fi;
elif [ ! -d "${REPOSITORY}" ]; then
INIT_REPOSITORY=1; INIT_REPOSITORY=1;
fi; fi;
# if verrify but no init and repo is there but init file is missing set it # if verrify but no init and repo is there but init file is missing set it
@@ -362,7 +359,7 @@ if [ "${INIT}" -eq 1 ] && [ "${INIT_REPOSITORY}" -eq 1 ]; then
# exit after init # exit after init
exit; exit;
elif [ "${INIT}" -eq 1 ] && [ "${INIT_REPOSITORY}" -eq 0 ]; then elif [ "${INIT}" -eq 1 ] && [ "${INIT_REPOSITORY}" -eq 0 ]; then
echo "[! $(date +'%F %T')] Repository already initialized"; echo "[!] ($(date +'%F %T')) Repository already initialized";
echo "For more information run:" echo "For more information run:"
echo "${COMMAND_INFO}"; echo "${COMMAND_INFO}";
. "${DIR}/borg.backup.functions.close.sh" 1; . "${DIR}/borg.backup.functions.close.sh" 1;
@@ -371,7 +368,7 @@ fi;
# verify for init file # verify for init file
if [ ! -f "${BASE_FOLDER}${BACKUP_INIT_FILE}" ]; then if [ ! -f "${BASE_FOLDER}${BACKUP_INIT_FILE}" ]; then
echo "[! $(date +'%F %T')] It seems the repository has never been initialized." echo "[!] ($(date +'%F %T')) It seems the repository has never been initialized."
echo "Please run -I to initialize or if already initialzed run with -C for init update." echo "Please run -I to initialize or if already initialzed run with -C for init update."
. "${DIR}/borg.backup.functions.close.sh" 1; . "${DIR}/borg.backup.functions.close.sh" 1;
exit 1; exit 1;

View File

@@ -6,7 +6,7 @@
# Backup gitea database, all git folders and gitea settings # Backup gitea database, all git folders and gitea settings
MODULE="gitea" MODULE="gitea"
MODULE_VERSION="1.2.1"; MODULE_VERSION="1.2.2";
DIR="${BASH_SOURCE%/*}" DIR="${BASH_SOURCE%/*}"
if [[ ! -d "$DIR" ]]; then DIR="$PWD"; fi if [[ ! -d "$DIR" ]]; then DIR="$PWD"; fi

View File

@@ -10,7 +10,7 @@
# set last edit date + time # set last edit date + time
MODULE="mysql" MODULE="mysql"
MODULE_VERSION="1.1.4"; MODULE_VERSION="1.1.5";
DIR="${BASH_SOURCE%/*}" DIR="${BASH_SOURCE%/*}"
if [[ ! -d "$DIR" ]]; then DIR="$PWD"; fi if [[ ! -d "$DIR" ]]; then DIR="$PWD"; fi

View File

@@ -9,5 +9,15 @@
# note that with this databases that have been dropped need to be pruned manually # note that with this databases that have been dropped need to be pruned manually
# if 'schema' word is used, only schema data is dumped # if 'schema' word is used, only schema data is dumped
DATABASE_FULL_DUMP=""; DATABASE_FULL_DUMP="";
# override default postgres user # override default postgres user and sudo user for all postgres commands
# All commands must be run as the postgres admin user
DATABASE_USER=""; DATABASE_USER="";
# disable sudo usage by setting to "0", default is to use sudo
DATABASE_USE_SUDO="";
# set the sudo user, if not set postgres or DATABASE_USER is used
DATABASE_SUDO_USER="";
# override port
DATABASE_PORT="";
# override database host, if set to local, localhost or 127.0.0.1 it will use sockets to connect
# for socket connection ident or sudo has to be used
DATABASE_HOST="";

View File

@@ -1,5 +1,8 @@
#!/usr/bin/env bash #!/usr/bin/env bash
# allow variables in printf format string
# shellcheck disable=SC2059
# Backup PostgreSQL # Backup PostgreSQL
# default is per table dump, can be set to one full dump # default is per table dump, can be set to one full dump
# config override set in borg.backup.pgsql.settings # config override set in borg.backup.pgsql.settings
@@ -7,11 +10,13 @@
# set last edit date + time # set last edit date + time
MODULE="pgsql" MODULE="pgsql"
MODULE_VERSION="1.2.7"; MODULE_VERSION="1.3.0";
DIR="${BASH_SOURCE%/*}" DIR="${BASH_SOURCE%/*}"
if [[ ! -d "$DIR" ]]; then DIR="$PWD"; fi if [[ ! -d "$DIR" ]]; then DIR="$PWD"; fi
DEFAULT_DATABASE_USE_SUDO="1";
DEFAULT_DATABASE_USER="postgres";
# init system # init system
. "${DIR}/borg.backup.functions.init.sh"; . "${DIR}/borg.backup.functions.init.sh";
@@ -32,15 +37,41 @@ BACKUP_LOCK_FILE="borg.backup.${MODULE}.lock";
# if info print info and then abort run # if info print info and then abort run
. "${DIR}/borg.backup.functions.info.sh"; . "${DIR}/borg.backup.functions.info.sh";
if [ ! -z "${DATABASE_USER}" ]; then # set db and sudo user
DB_USER=${DATABASE_USER}; if [ -n "${DATABASE_USER}" ]; then
DB_USER="${DATABASE_USER}";
else else
DB_USER='postgres'; DB_USER="${DEFAULT_DATABASE_USER}";
fi; fi;
if [ -n "${DATABASE_SUDO_USER}" ]; then
DB_SUDO_USER="${DATABASE_SUDO_USER}";
else
DB_SUDO_USER="${DB_USER}";
fi;
# set flag if we should use sudo
if [ -n "${DATABASE_USE_SUDO}" ]; then
USE_SUDO="${DATABASE_USE_SUDO}";
else
USE_SUDO="${DEFAULT_DATABASE_USE_SUDO}";
fi;
# sudo command, or none if not requested
SUDO_COMMAND_A=("sudo" "-u" "${DB_SUDO_USER}");
if [ "${USE_SUDO}" -eq "0" ]; then
SUDO_COMMAND_A=()
fi;
# get current pgsql version first # get current pgsql version first
# if first part <10 then user full, else only first part # if first part <10 then user full, else only first part
# eg 9.4 -> 9.4, 12.5 -> 12 # eg 9.4 -> 9.4, 12.5 -> 12
PG_VERSION=$(pgv=$(psql -U ${DB_USER} -d template1 -t -A -F "," -X -q -c 'select version();' | sed -e 's/^PostgreSQL \([0-9]\{1,\}\.[0-9]\{1,\}\).*/\1/'); if [[ $(echo "${pgv}" | cut -d "." -f 1) -ge 10 ]]; then echo "${pgv}" | cut -d "." -f 1; else echo "${pgv}" | cut -d "." -f 1,2; fi ); PG_VERSION_CMD=("${SUDO_COMMAND_A[@]}" "psql" "-U" "${DB_USER}" "-d" "template1" "-t" "-A" "-F" "," "-X" "-q" "-c" "select version();");
PG_VERSION=$(
pgv=$("${PG_VERSION_CMD[@]}" | sed -e 's/^PostgreSQL \([0-9]\{1,\}\.[0-9]\{1,\}\).*/\1/');
if [[ $(echo "${pgv}" | cut -d "." -f 1) -ge 10 ]]; then
echo "${pgv}" | cut -d "." -f 1;
else
echo "${pgv}" | cut -d "." -f 1,2;
fi;
);
_PATH_PG_VERSION=${PG_VERSION}; _PATH_PG_VERSION=${PG_VERSION};
_backup_error=$?; _backup_error=$?;
if [ $_backup_error -ne 0 ] || [ -z "${PG_VERSION}" ]; then if [ $_backup_error -ne 0 ] || [ -z "${PG_VERSION}" ]; then
@@ -50,52 +81,78 @@ if [ $_backup_error -ne 0 ] || [ -z "${PG_VERSION}" ]; then
fi; fi;
# path set per Distribution type and current running DB version # path set per Distribution type and current running DB version
# Debian/Ubuntu: PG_BASE_PATH='/usr/lib/postgresql/';
# Redhat: PG_BASE_PATH='/usr/pgsql-'; # Redhat: PG_BASE_PATH='/usr/pgsql-';
# AWS 1: PG_BASE_PATH='/usr/lib64/pgsql'; PG_BASE_PATH_LIST=("/usr/lib/postgresql" "/usr/lib64/pgsql");
# Debian: PG_BASE_PATH='/usr/lib/postgresql/'; PG_BASE_PATH="";
PG_BASE_PATH='/usr/lib/postgresql/'; for path in "${PG_BASE_PATH_LIST[@]}"; do
if [ ! -f "${PG_BASE_PATH}${_PATH_PG_VERSION}/bin/psql" ]; then if [ -f "${path}/${_PATH_PG_VERSION}/bin/psql" ]; then
PG_BASE_PATH='/usr/pgsql-'; PG_BASE_PATH="${path}/";
if [ ! -f "${PG_BASE_PATH}${_PATH_PG_VERSION}/bin/psql" ]; then break;
PG_BASE_PATH='/usr/lib64/pgsql';
_PATH_PG_VERSION=$(echo "${PG_VERSION}" | sed -e 's/\.//');
if [ ! -f "${PG_BASE_PATH}${_PATH_PG_VERSION}/bin/psql" ]; then
echo "[! $(date +'%F %T')] PostgreSQL not found in any paths";
. "${DIR}/borg.backup.functions.close.sh" 1;
exit 1;
fi;
fi; fi;
done;
if [ -z "${PG_BASE_PATH}" ]; then
echo "[! $(date +'%F %T')] PostgreSQL not found in any paths";
. "${DIR}/borg.backup.functions.close.sh" 1;
exit 1;
fi; fi;
PG_PATH=${PG_BASE_PATH}${_PATH_PG_VERSION}'/bin/'; PG_PATH="${PG_BASE_PATH}${_PATH_PG_VERSION}/bin/";
PG_PSQL=${PG_PATH}'psql'; PG_PSQL=("${PG_PATH}psql");
PG_DUMP=${PG_PATH}'pg_dump'; PG_DUMP=("${PG_PATH}pg_dump");
PG_DUMPALL=${PG_PATH}'pg_dumpall'; PG_DUMPALL=("${PG_PATH}pg_dumpall");
PG_ERROR=0
# check that command are here # check that command are here
if [ ! -f "${PG_PSQL}" ]; then if [ ! -f "${PG_PSQL[0]}" ]; then
echo "[! $(date +'%F %T')] psql binary not found in ${PG_PATH}"; echo "[!] ($(date +'%F %T')) psql binary not found in ${PG_PATH}";
. "${DIR}/borg.backup.functions.close.sh" 1; PG_ERROR=1;
exit 1;
fi; fi;
if [ ! -f "${PG_DUMP}" ]; then if [ ! -f "${PG_DUMP[0]}" ]; then
echo "[! $(date +'%F %T')] pg_dump binary not found in ${PG_PATH}"; echo "[!] ($(date +'%F %T')) pg_dump binary not found in ${PG_PATH}";
. "${DIR}/borg.backup.functions.close.sh" 1; PG_ERROR=1;
exit 1;
fi; fi;
if [ ! -f "${PG_DUMPALL}" ]; then if [ ! -f "${PG_DUMPALL[0]}" ]; then
echo "[! $(date +'%F %T')] pg_dumpall binary not found in ${PG_PATH}"; echo "[!] ($(date +'%F %T')) pg_dumpall binary not found in ${PG_PATH}";
PG_ERROR=1;
fi;
if [ ${PG_ERROR} -ne 0 ]; then
. "${DIR}/borg.backup.functions.close.sh" 1; . "${DIR}/borg.backup.functions.close.sh" 1;
exit 1; exit ${PG_ERROR};
fi;
# prefix with sudo, if sudo command is requested
if [ "${USE_SUDO}" -ne "0" ]; then
PG_PSQL=("${SUDO_COMMAND_A[@]}" "${PG_PSQL[@]}");
PG_DUMP=("${SUDO_COMMAND_A[@]}" "${PG_DUMP[@]}");
PG_DUMPALL=("${SUDO_COMMAND_A[@]}" "${PG_DUMPALL[@]}");
fi; fi;
DB_VERSION=${PG_VERSION}; DB_VERSION=${PG_VERSION};
# TODO override port/host info # override for port or host name
DB_PORT='5432'; if [ -n "${DATABASE_PORT}" ] && [[ "${DATABASE_PORT}" =~ ${REGEX_PORT} ]]; then
DB_HOST='local'; # or <host> DB_PORT="${DATABASE_PORT}";
CONN_DB_HOST=''; # -h <host> else
CONN_DB_PORT=''; # -p <port> DB_PORT="5432";
fi;
if [ -n "${DATABASE_HOST}" ]; then
DB_HOST="${DATABASE_HOST}";
else
DB_HOST="local";
fi;
# use socket for local
if [ "${DB_HOST}" = "local" ] || [ "${DB_HOST}" = "localhost" ] || [ "${DB_HOST}" = "127.0.0.1" ]; then
DB_HOST='local';
CONN_DB_HOST=();
CONN_DB_PORT=();
else
CONN_DB_HOST=("-p" "${DB_HOST}"); # -h <host>
CONN_DB_PORT=("-h" "${DB_HOSTNAME}"); # -p <port>
fi;
# now add user, con, host to all commands
PG_PSQL=("${PG_PSQL[@]}" "-U" "${DB_USER}" "${CONN_DB_HOST[@]}" "${CONN_DB_PORT[@]}");
PG_DUMP=("${PG_DUMP[@]}" "-U" "${DB_USER}" "${CONN_DB_HOST[@]}" "${CONN_DB_PORT[@]}");
PG_DUMPALL=("${PG_DUMPALL[@]}" "-U" "${DB_USER}" "${CONN_DB_HOST[@]}" "${CONN_DB_PORT[@]}");
# ALL IN ONE FILE or PER DATABASE FLAG # ALL IN ONE FILE or PER DATABASE FLAG
if [ ! -z "${DATABASE_FULL_DUMP}" ]; then if [ -n "${DATABASE_FULL_DUMP}" ]; then
SCHEMA_ONLY=''; SCHEMA_ONLY='';
schema_flag='data'; schema_flag='data';
if [ "${DATABASE_FULL_DUMP}" = "schema" ]; then if [ "${DATABASE_FULL_DUMP}" = "schema" ]; then
@@ -110,17 +167,25 @@ if [ ! -z "${DATABASE_FULL_DUMP}" ]; then
BACKUP_SET_PREFIX="${MODULE},all-"; BACKUP_SET_PREFIX="${MODULE},all-";
BACKUP_SET_NAME="${ONE_TIME_TAG}${BACKUP_SET_PREFIX}${schema_flag}-${BACKUP_SET}"; BACKUP_SET_NAME="${ONE_TIME_TAG}${BACKUP_SET_PREFIX}${schema_flag}-${BACKUP_SET}";
# borg call # borg call
BORG_CALL=$(echo "${_BORG_CALL}" | sed -e "s/##FILENAME##/${FILENAME}/" | sed -e "s/##BACKUP_SET##/${BACKUP_SET_NAME}/"); BORG_CALL=$(
BORG_PRUNE=$(echo "${_BORG_PRUNE}" | sed -e "s/##BACKUP_SET_PREFIX##/${BACKUP_SET_PREFIX}/"); echo "${_BORG_CALL}" |
sed -e "s/##FILENAME##/${FILENAME}/" |
sed -e "s/##BACKUP_SET##/${BACKUP_SET_NAME}/"
);
BORG_PRUNE=$(
echo "${_BORG_PRUNE}" |
sed -e "s/##BACKUP_SET_PREFIX##/${BACKUP_SET_PREFIX}/"
);
PG_DUMPALL_CMD=("${PG_DUMPALL[@]}" "${SCHEMA_ONLY}" "-c");
if [ ${DEBUG} -eq 1 ] || [ ${DRYRUN} -eq 1 ]; then if [ ${DEBUG} -eq 1 ] || [ ${DRYRUN} -eq 1 ]; then
echo "export BORG_BASE_DIR=\"${BASE_FOLDER}\";"; echo "export BORG_BASE_DIR=\"${BASE_FOLDER}\";";
echo "${PG_DUMPALL} -U ${DB_USER} ${CONN_DB_HOST} ${CONN_DB_PORT} ${SCHEMA_ONLY} -c | ${BORG_CALL}"; echo "${PG_DUMPALL_CMD[*]} | ${BORG_CALL}";
if [ -z "${ONE_TIME_TAG}" ]; then if [ -z "${ONE_TIME_TAG}" ]; then
echo "${BORG_PRUNE}"; echo "${BORG_PRUNE}";
fi; fi;
fi; fi;
if [ ${DRYRUN} -eq 0 ]; then if [ ${DRYRUN} -eq 0 ]; then
$(${PG_DUMPALL} -U ${DB_USER} ${CONN_DB_HOST} ${CONN_DB_PORT} ${SCHEMA_ONLY} -c | ${BORG_CALL}); "${PG_DUMPALL_CMD[@]}" | ${BORG_CALL};
_backup_error=$?; _backup_error=$?;
if [ $_backup_error -ne 0 ]; then if [ $_backup_error -ne 0 ]; then
echo "[! $(date +'%F %T')] Backup creation failed for full dump with error code: ${_backup_error}"; echo "[! $(date +'%F %T')] Backup creation failed for full dump with error code: ${_backup_error}";
@@ -133,7 +198,7 @@ if [ ! -z "${DATABASE_FULL_DUMP}" ]; then
echo "Prune repository with keep${KEEP_INFO:1}"; echo "Prune repository with keep${KEEP_INFO:1}";
${BORG_PRUNE}; ${BORG_PRUNE};
fi; fi;
DURATION=$[ $(date +'%s')-$LOCAL_START ]; DURATION=$(( $(date +'%s') - LOCAL_START ));
printf "${PRINTF_DB_RUN_TIME_SUB_BLOCK}" "DONE" "all databases" "${MODULE}" "$(convert_time ${DURATION})"; printf "${PRINTF_DB_RUN_TIME_SUB_BLOCK}" "DONE" "all databases" "${MODULE}" "$(convert_time ${DURATION})";
else else
# dump globals first # dump globals first
@@ -147,17 +212,25 @@ else
BACKUP_SET_PREFIX="${MODULE},${db}-"; BACKUP_SET_PREFIX="${MODULE},${db}-";
BACKUP_SET_NAME="${ONE_TIME_TAG}${BACKUP_SET_PREFIX}${schema_flag}-${BACKUP_SET}"; BACKUP_SET_NAME="${ONE_TIME_TAG}${BACKUP_SET_PREFIX}${schema_flag}-${BACKUP_SET}";
# borg call # borg call
BORG_CALL=$(echo "${_BORG_CALL}" | sed -e "s/##FILENAME##/${FILENAME}/" | sed -e "s/##BACKUP_SET##/${BACKUP_SET_NAME}/"); BORG_CALL=$(
BORG_PRUNE=$(echo "${_BORG_PRUNE}" | sed -e "s/##BACKUP_SET_PREFIX##/${BACKUP_SET_PREFIX}/"); echo "${_BORG_CALL}" |
sed -e "s/##FILENAME##/${FILENAME}/" |
sed -e "s/##BACKUP_SET##/${BACKUP_SET_NAME}/"
);
BORG_PRUNE=$(
echo "${_BORG_PRUNE}" |
sed -e "s/##BACKUP_SET_PREFIX##/${BACKUP_SET_PREFIX}/"
);
PG_DUMPALL_CMD=("${PG_DUMPALL[@]}" "--globals-only");
if [ ${DEBUG} -eq 1 ] || [ ${DRYRUN} -eq 1 ]; then if [ ${DEBUG} -eq 1 ] || [ ${DRYRUN} -eq 1 ]; then
echo "export BORG_BASE_DIR=\"${BASE_FOLDER}\";"; echo "export BORG_BASE_DIR=\"${BASE_FOLDER}\";";
echo "${PG_DUMPALL} -U ${DB_USER} ${CONN_DB_HOST} ${CONN_DB_PORT} --globals-only | ${BORG_CALL}"; echo "${PG_DUMPALL_CMD[*]} | ${BORG_CALL}";
if [ -z "${ONE_TIME_TAG}" ]; then if [ -z "${ONE_TIME_TAG}" ]; then
echo "${BORG_PRUNE}"; echo "${BORG_PRUNE}";
fi; fi;
fi; fi;
if [ ${DRYRUN} -eq 0 ]; then if [ ${DRYRUN} -eq 0 ]; then
${PG_DUMPALL} -U ${DB_USER} ${CONN_DB_HOST} ${CONN_DB_PORT} --globals-only | ${BORG_CALL}; "${PG_DUMPALL_CMD[@]}" | ${BORG_CALL};
_backup_error=$?; _backup_error=$?;
if [ $_backup_error -ne 0 ]; then if [ $_backup_error -ne 0 ]; then
echo "[! $(date +'%F %T')] Backup creation failed for ${db} dump with error code: ${_backup_error}"; echo "[! $(date +'%F %T')] Backup creation failed for ${db} dump with error code: ${_backup_error}";
@@ -170,21 +243,25 @@ else
echo "Prune repository with keep${KEEP_INFO:1}"; echo "Prune repository with keep${KEEP_INFO:1}";
${BORG_PRUNE}; ${BORG_PRUNE};
fi; fi;
DURATION=$[ $(date +'%s')-$LOCAL_START ]; DURATION=$(( $(date +'%s') - LOCAL_START ));
printf "${PRINTF_DB_RUN_TIME_SUB_BLOCK}" "DONE" "${db}" "${MODULE}" "$(convert_time ${DURATION})"; printf "${PRINTF_DB_RUN_TIME_SUB_BLOCK}" "DONE" "${db}" "${MODULE}" "$(convert_time ${DURATION})";
# get list of tables # get list of tables
for owner_db in $(${PG_PSQL} -U ${DB_USER} ${CONN_DB_HOST} ${CONN_DB_PORT} -d template1 -t -A -F "," -X -q -c "SELECT pg_catalog.pg_get_userbyid(datdba) AS owner, datname, pg_catalog.pg_encoding_to_char(encoding) AS encoding FROM pg_catalog.pg_database WHERE datname "\!"~ 'template(0|1)' ORDER BY datname;"); do GET_DB_CMD=(
"${PG_PSQL[@]}" "-d" "template1" "-t" "-A" "-F" "," "-X" "-q" "-c"
"SELECT pg_catalog.pg_get_userbyid(datdba) AS owner, datname, pg_catalog.pg_encoding_to_char(encoding) AS encoding FROM pg_catalog.pg_database WHERE datname !~ 'template(0|1)' ORDER BY datname;"
);
for owner_db in $("${GET_DB_CMD[@]}"); do
LOCAL_START=$(date +'%s'); LOCAL_START=$(date +'%s');
# get the user who owns the DB too # get the user who owns the DB too
owner=$(echo ${owner_db} | cut -d "," -f 1); owner=$(echo "${owner_db}" | cut -d "," -f 1);
db=$(echo ${owner_db} | cut -d "," -f 2); db=$(echo "${owner_db}" | cut -d "," -f 2);
encoding=$(echo ${owner_db} | cut -d "," -f 3); encoding=$(echo "${owner_db}" | cut -d "," -f 3);
printf "${PRINTF_DB_SUB_BLOCK}" "DB" "${db}" "${MODULE}"; printf "${PRINTF_DB_SUB_BLOCK}" "DB" "${db}" "${MODULE}";
printf "${PRINTF_SUBEXT_BLOCK}" "BACKUP" "${db}" "$(date +'%F %T')" "${MODULE}"; printf "${PRINTF_SUBEXT_BLOCK}" "BACKUP" "${db}" "$(date +'%F %T')" "${MODULE}";
include=0; include=0;
if [ -s "${BASE_FOLDER}${INCLUDE_FILE}" ]; then if [ -s "${BASE_FOLDER}${INCLUDE_FILE}" ]; then
while read incl_db; do while read -r incl_db; do
if [ "${db}" = "${incl_db}" ]; then if [ "${db}" = "${incl_db}" ]; then
include=1; include=1;
break; break;
@@ -195,7 +272,7 @@ else
fi; fi;
exclude=0; exclude=0;
if [ -f "${BASE_FOLDER}${EXCLUDE_FILE}" ]; then if [ -f "${BASE_FOLDER}${EXCLUDE_FILE}" ]; then
while read excl_db; do while read -r excl_db; do
if [ "${db}" = "${excl_db}" ]; then if [ "${db}" = "${excl_db}" ]; then
exclude=1; exclude=1;
break; break;
@@ -203,17 +280,15 @@ else
done<"${BASE_FOLDER}${EXCLUDE_FILE}"; done<"${BASE_FOLDER}${EXCLUDE_FILE}";
fi; fi;
if [ ${include} -eq 1 ] && [ ${exclude} -eq 0 ]; then if [ ${include} -eq 1 ] && [ ${exclude} -eq 0 ]; then
PG_DUMP_CMD=("${PG_DUMP[@]}" "-c" "--format=c");
# set dump type # set dump type
SCHEMA_ONLY='';
schema_flag=''; # schema or data schema_flag=''; # schema or data
# schema exclude over data exclude, can't have both # schema exclude over data exclude, can't have both
if [ -s "${BASE_FOLDER}${SCHEMA_ONLY_FILE}" ]; then if [ -s "${BASE_FOLDER}${SCHEMA_ONLY_FILE}" ]; then
# default is data dump # default is data dump
SCHEMA_ONLY='';
schema_flag='data'; schema_flag='data';
while read schema_db; do while read -r schema_db; do
if [ "${db}" = "${schema_db}" ]; then if [ "${db}" = "${schema_db}" ]; then
SCHEMA_ONLY='-s';
schema_flag='schema'; schema_flag='schema';
# skip out # skip out
break; break;
@@ -221,11 +296,9 @@ else
done<"${BASE_FOLDER}${SCHEMA_ONLY_FILE}"; done<"${BASE_FOLDER}${SCHEMA_ONLY_FILE}";
elif [ -s "${BASE_FOLDER}${DATA_ONLY_FILE}" ]; then elif [ -s "${BASE_FOLDER}${DATA_ONLY_FILE}" ]; then
# default to schema, unless in data list # default to schema, unless in data list
SCHEMA_ONLY='-s';
schema_flag='schema'; schema_flag='schema';
while read data_db; do while read -r data_db; do
if [ "${db}" = "${data_db}" ]; then if [ "${db}" = "${data_db}" ]; then
SCHEMA_ONLY='';
schema_flag='data'; schema_flag='data';
# skip out # skip out
break; break;
@@ -234,9 +307,13 @@ else
fi; fi;
# if nothing is set, default to data # if nothing is set, default to data
if [ -z "${schema_flag}" ]; then if [ -z "${schema_flag}" ]; then
SCHEMA_ONLY=''
schema_flag="data"; schema_flag="data";
fi; fi;
# set schema flag if schmea only is requested
if [ $schema_flag = "schema" ]; then
PG_DUMP_CMD+=("-s");
fi;
PG_DUMP_CMD+=("${db}");
# Filename # Filename
# Database.User.Encoding.pgsql|data|schema-Version_Host_Port_YearMonthDay_HourMinute_Counter.Fromat(c).sql # Database.User.Encoding.pgsql|data|schema-Version_Host_Port_YearMonthDay_HourMinute_Counter.Fromat(c).sql
FILENAME="${db}.${owner}.${encoding}.${schema_flag}-${DB_VERSION}_${DB_HOST}_${DB_PORT}.c.sql" FILENAME="${db}.${owner}.${encoding}.${schema_flag}-${DB_VERSION}_${DB_HOST}_${DB_PORT}.c.sql"
@@ -245,18 +322,25 @@ else
# backup set: # backup set:
BACKUP_SET_NAME="${ONE_TIME_TAG}${BACKUP_SET_PREFIX}${schema_flag}-${BACKUP_SET}"; BACKUP_SET_NAME="${ONE_TIME_TAG}${BACKUP_SET_PREFIX}${schema_flag}-${BACKUP_SET}";
# borg call # borg call
BORG_CALL=$(echo "${_BORG_CALL}" | sed -e "s/##FILENAME##/${FILENAME}/" | sed -e "s/##BACKUP_SET##/${BACKUP_SET_NAME}/"); BORG_CALL=$(
echo "${_BORG_CALL}" |
sed -e "s/##FILENAME##/${FILENAME}/" |
sed -e "s/##BACKUP_SET##/${BACKUP_SET_NAME}/"
);
# borg prune # borg prune
BORG_PRUNE=$(echo "${_BORG_PRUNE}" | sed -e "s/##BACKUP_SET_PREFIX##/${BACKUP_SET_PREFIX}/"); BORG_PRUNE=$(
echo "${_BORG_PRUNE}" |
sed -e "s/##BACKUP_SET_PREFIX##/${BACKUP_SET_PREFIX}/"
);
if [ ${DEBUG} -eq 1 ] || [ ${DRYRUN} -eq 1 ]; then if [ ${DEBUG} -eq 1 ] || [ ${DRYRUN} -eq 1 ]; then
echo "export BORG_BASE_DIR=\"${BASE_FOLDER}\";"; echo "export BORG_BASE_DIR=\"${BASE_FOLDER}\";";
echo "${PG_DUMP} -U ${DB_USER} ${CONN_DB_HOST} ${CONN_DB_PORT} -c ${SCHEMA_ONLY} --format=c ${db} | ${BORG_CALL}"; echo "${PG_DUMP_CMD[*]} | ${BORG_CALL}";
if [ -z "${ONE_TIME_TAG}" ]; then if [ -z "${ONE_TIME_TAG}" ]; then
echo "${BORG_PRUNE}"; echo "${BORG_PRUNE}";
fi; fi;
fi; fi;
if [ ${DRYRUN} -eq 0 ]; then if [ ${DRYRUN} -eq 0 ]; then
${PG_DUMP} -U ${DB_USER} ${CONN_DB_HOST} ${CONN_DB_PORT} -c ${SCHEMA_ONLY} --format=c ${db} | ${BORG_CALL}; "${PG_DUMP_CMD[@]}" | ${BORG_CALL};
_backup_error=$?; _backup_error=$?;
if [ $_backup_error -ne 0 ]; then if [ $_backup_error -ne 0 ]; then
echo "[! $(date +'%F %T')] Backup creation failed for ${db} dump with error code: ${_backup_error}"; echo "[! $(date +'%F %T')] Backup creation failed for ${db} dump with error code: ${_backup_error}";
@@ -272,7 +356,7 @@ else
else else
echo "- [E] ${db}"; echo "- [E] ${db}";
fi; fi;
DURATION=$[ $(date +'%s')-$LOCAL_START ]; DURATION=$(( $(date +'%s') - LOCAL_START ));
printf "${PRINTF_DB_RUN_TIME_SUB_BLOCK}" "DONE" "${db}" "${MODULE}" "$(convert_time ${DURATION})"; printf "${PRINTF_DB_RUN_TIME_SUB_BLOCK}" "DONE" "${db}" "${MODULE}" "$(convert_time ${DURATION})";
done; done;
fi; fi;

View File

@@ -13,21 +13,19 @@ TARGET_PORT="";
TARGET_BORG_PATH=""; TARGET_BORG_PATH="";
# folder where the backup folder will be created # folder where the backup folder will be created
TARGET_FOLDER=""; TARGET_FOLDER="";
# the backup file (folder) for this host $(hostname), must end with .borg # the backup file (folder) for this backup, avoid dynamic variables in here, must end with .borg
BACKUP_FILE=""; BACKUP_FILE="";
# compression settings (empty for none, lz4, zstd, zlib, lzma) # compression settings (none, lz4, zstd, zlib, lzma)
# level, if empty then default, else number between 0 and 9, or 1 to 22 for zstd # empty is default zstd
# default is zstd, 3
COMPRESSION=""; COMPRESSION="";
# compression level, if empty then default 3, else number between 0 and 9, or 1 to 22 for zstd
COMPRESSION_LEVEL=""; COMPRESSION_LEVEL="";
# encryption settings: # encryption settings:
# SHA-256: 'none', 'authenticated', 'repokey', 'keyfile' # SHA-256: 'none', 'authenticated', 'repokey', 'keyfile'
# BLAKE2b: 'authenticated-blake2', 'repokey-blake2', 'keyfile-blake2' # BLAKE2b: 'authenticated-blake2', 'repokey-blake2', 'keyfile-blake2'
# Note: none does not encrypt # Note: none does not encrypt and is not recommended
# Blank passwords allowed for only key (if used, use keyfile)
# Default is keyfile # Default is keyfile
# passwords have to be set via BORG_PASSPHRASE or BORG_PASSCOMMAND # Blank passwords allowed for only keyfile, else passwords have to be set via BORG_PASSPHRASE or BORG_PASSCOMMAND
# keyfile can have blank passwords
# See: http://borgbackup.readthedocs.io/en/stable/faq.html#how-can-i-specify-the-encryption-passphrase-programmatically # See: http://borgbackup.readthedocs.io/en/stable/faq.html#how-can-i-specify-the-encryption-passphrase-programmatically
ENCRYPTION="" ENCRYPTION=""
# force repository verify, default is off, set to true for verify on every run # force repository verify, default is off, set to true for verify on every run

View File

@@ -6,7 +6,7 @@
# Backup zabbix config and settings only # Backup zabbix config and settings only
MODULE="zabbix" MODULE="zabbix"
MODULE_VERSION="1.1.3"; MODULE_VERSION="1.1.4";
DIR="${BASH_SOURCE%/*}" DIR="${BASH_SOURCE%/*}"
if [[ ! -d "$DIR" ]]; then DIR="$PWD"; fi if [[ ! -d "$DIR" ]]; then DIR="$PWD"; fi