Compare commits

...

26 Commits

Author SHA1 Message Date
Clemens Schwaighofer
86b0fa122a Add empty KEEP option for error with -T 2022-03-30 20:27:46 +09:00
Clemens Schwaighofer
32c320be27 Fix close call int compare 2022-03-30 14:48:52 +09:00
Clemens Schwaighofer
500ab01790 Bug fix for unset var in close call 2022-03-30 11:35:19 +09:00
Clemens Schwaighofer
ab58ab3ad0 Update postgresql module version 2022-03-30 09:48:37 +09:00
Clemens Schwaighofer
7767eb58df Override sudo for postgresql in upgrade script 2022-03-30 09:32:57 +09:00
Clemens Schwaighofer
38f467de96 PostgreSQL backup add schema or data dump in either default direction 2022-03-29 11:21:06 +09:00
Clemens Schwaighofer
8f91690f6a Upgrade script for zabbix fix if no zabbix prefix set at all 2022-03-29 10:53:59 +09:00
Clemens Schwaighofer
e860573e0c Fix upgrade script gitea module rename check 2022-03-29 10:28:26 +09:00
Clemens Schwaighofer
f990e86949 update script gitea block fix for missing module name 2022-03-29 10:25:12 +09:00
Clemens Schwaighofer
c929987900 variable name wrong for module check in upgrade script 2022-03-29 10:20:52 +09:00
Clemens Schwaighofer
6cb941818c Repository ID via config only works with local repos, drop that and keep repo ID in -i option only 2022-03-29 10:01:00 +09:00
Clemens Schwaighofer
edaf41f1af Repository ID info, borg command call via variable
The main info block gets Repository ID as info too (for cache/etc
folders check)

Missing borg command as variable for borg list command.
2022-03-29 09:57:12 +09:00
Clemens Schwaighofer
c7f2197614 add -E to sudo for upgrade script to keep enviroment variables for postgres run 2022-03-29 09:16:03 +09:00
Clemens Schwaighofer
88ea600e1d Mising remote path option in update script 2022-03-29 08:55:19 +09:00
Clemens Schwaighofer
f396032728 Add remote override path for borg backup in update script 2022-03-29 08:53:37 +09:00
Clemens Schwaighofer
18cbcea2b0 Archive print page make archive space 45 chars wide 2022-03-29 07:01:31 +09:00
Clemens Schwaighofer
a0537a24d3 PostgreSQL sudo for upgrade script 2022-03-29 06:46:23 +09:00
Clemens Schwaighofer
89897eb676 Add base BORG export variables in upgrade script 2022-03-29 06:36:06 +09:00
Clemens Schwaighofer
e1787fcfb3 Add missing DEBUG var setting for borg update wrapper script 2022-03-28 12:37:33 +09:00
Clemens Schwaighofer
0ce5442bcf Bug fix for update fix script
Add missing / for BASE_FOLDER if not set.

Dropped old file module borg name
2022-03-28 11:54:21 +09:00
Clemens Schwaighofer
d9346c84a7 Borg Backup wrapper Version 4.0 update
* file backup borg folder has now -file name inside. Old folder must be
  manuall renamed
* All modules have the module id name as prefix in the backup set,
  _borg_backup_set_prefix_cleanup.sh needs to be run before to clean up
  all names or prune will not correctly delete old entries

New -T for one time target backup with custom prefix to have backups
outside the automated prune. -D option to delete this set

Add borg 1.2 support for compact which is called after delete and prune
to actually clean up the space.

-b borg executable and BORG_EXECUTEABLE override setting if borg is not
in path or another borg executable should be used
2022-03-28 11:27:35 +09:00
Clemens Schwaighofer
828a59c984 Set proper default values for core settings.
If nothing set in the settings file some entries need to be default set:
COMPRESSION
COMPRESSION_LEVEL
ENCRYPTION
FORCE_CHECK
KEEP_LAST
KEEP_HOURS
KEEP_DAYS
KEEP_WEEKS
KEEP_MONTHS
KEEP_YEARS

If these variables are empty after settings file is ready they are set
to the default value. After that the sub configs override those settings
2022-03-08 13:56:16 +09:00
Clemens Schwaighofer
ee1b3b23ab Fixed missing init for OPT_COMPRESSION variable in functions check 2022-03-03 10:23:39 +09:00
Clemens Schwaighofer
fd5ee4be04 Just Version number adjustments in scripts 2022-01-06 09:42:16 +09:00
Clemens Schwaighofer
6dbf3497ea Fix all BACKUP_SET_NAME call order
Set PREFIX before name so we can use the prefix in the db name to
always lock them.
Also fix BACKUP_SET_NAME for gitea backup
2021-12-20 15:38:50 +09:00
Clemens Schwaighofer
9d184f09f4 Bug fix for missing KEEP_MONTHS override check and double KEEP_LAST
No SUB_KEEP_MONTHS was ever set, but SUB_KEEP_LAST was checked twice
2021-12-16 13:59:05 +09:00
13 changed files with 707 additions and 167 deletions

View File

@@ -4,6 +4,29 @@ These scripts are wrappers around the main borg backup scripts.
Modules for plain file backup, mysql and postgresql backup exists. Modules for plain file backup, mysql and postgresql backup exists.
## IMPORTANT NOTICE FOR UPGRADE TO VERSION 4.0 OR HIGHER
*VERSION 4.0* CHANGE
Version 4.0 introduces default borg repository name with `-file` for the `file` module. The repository has to be renamed manual before the next backup or the backup will fail.
*Example:*
Old backup name
```sh
BACKUP_FILE="some-backup-data.borg"
```
Then the file need to be renamed the following way:
`mv some-backup-data.borg some-backup-data-file.borg`
Below changes have to be done after the `file` module backup has been renamed.
With Version 4.0 all backup sets are prefixed with the module name and a comma. For exmaple the files backup will have backup set "file,YYYY-MM-DD" as base name.
To make sure prune of archives will work the `_borg_backup_set_prefix_cleanup.sh` script has to be run once. It has the same config (-c), debug (-d) and dry run (-n) options like the main scripts. It is recommended to run with the dry-run script first and see that the list of chagnes matches the expectation.
The zabbix module has the prefix changed from `zabbix-settings-` to `zabbix,settings-` to match the new archive set rules
## Recommended setup ## Recommended setup
git clone this repostory into the target folder: git clone this repostory into the target folder:
@@ -16,6 +39,53 @@ Now the core scripts can be updated with a simple
No settings files will be overwritten No settings files will be overwritten
## Possible command line options
### `-c <config folder>`
if this is not given, /usr/local/scripts/borg/ is used
### `-L <log folder>`
override config set and default log folder
### `-T <tag>`
create one time stand alone backup prefixed with tag name
### `-D <tag backup set>`
remove a tagged backup set, full name must be given
### `-b <borg executable>`
override the default borg executable found in path
### `-P`
print list of archives created
### `-C`
check if repository exists, if not abort
### `-E`
exit after check
### `-I`
init repository (must be run first)
### `-i`
print out only info
### `-l`
list files during backup
### `-v`
be verbose
### `-d`
debug output all commands
### `-n`
only do dry run
### `-h`
this help page
## Basic Settings ## Basic Settings
`borg.backup.settings` `borg.backup.settings`
@@ -35,6 +105,18 @@ eg:
If `FILE_REPOSITORY_COMPATIBLE` is set to `false` in the borg.backup.file.settings then the file borg name will have `-file` added too. Currently this is not added to stay compatible with older scripts If `FILE_REPOSITORY_COMPATIBLE` is set to `false` in the borg.backup.file.settings then the file borg name will have `-file` added too. Currently this is not added to stay compatible with older scripts
All below have default values if not set in the main settings file
* COMPRESSION: zstd
* COMPRESSION_LEVEL: 3
* ENCRYPTION: none
* FORCE_CHECK: false
* KEEP_LAST: 0
* KEEP_HOURS: 0
* KEEP_DAYS: 7
* KEEP_WEEKS: 4
* KEEP_MONTHS: 6
* KEEP_YEARS: 1
All module settings files can have the following prefixed with `SUB_` to override master settings: All module settings files can have the following prefixed with `SUB_` to override master settings:
* SUB_BACKUP_FILE * SUB_BACKUP_FILE
* SUB_COMPRESSION * SUB_COMPRESSION
@@ -48,7 +130,7 @@ All module settings files can have the following prefixed with `SUB_` to overrid
* SUB_KEEP_YEARS * SUB_KEEP_YEARS
* SUB_KEEP_WITHIN * SUB_KEEP_WITHIN
## Setup backup via SSH to remote host ## Setup backup via SSH to remote host on `borg.backup.settings`
For this the following settings are from interest For this the following settings are from interest
@@ -62,8 +144,16 @@ Note that if `.ssh/config` is used only `TARGET_HOST` needs to be set. Recommene
and `TARGET_BORG_PATH="";` if the target borg is in a non default path and `TARGET_BORG_PATH="";` if the target borg is in a non default path
## Override borg executable in `borg.backup.settings`
`BORG_EXECUTABLE="<full path to borg>"`
## File backup settings ## File backup settings
On new setups it is recommended to use the `borg.backup.file.setings` and set
`FILE_REPOSITORY_COMPATIBLE`
to `true`
### Config variables ### Config variables

View File

@@ -0,0 +1,140 @@
#!/usr/bin/env bash
# this will fix backup sets name
# must have a target call for
# file
# gitea
# mysql
# pgsql
# zabbix-settings-
# debug and dry run
DEBUG=0;
DRYRUN=0;
PGSQL_SUDO=1;
# options
OPT_REMOTE="";
PGSQL_SUDO_USER="postgres";
# basic settings needed
TARGET_USER="";
TARGET_HOST="";
TARGET_PORT="";
TARGET_BORG_PATH="";
TARGET_FOLDER="";
# base folder
BASE_FOLDER="/usr/local/scripts/borg/";
# those are the valid modules
MODULE_LIST="file gitea mysql pgsql zabbix"
# basic options
# -c for config file override
# -n for dry run test
while getopts ":c:snd" opt; do
case "${opt}" in
c|config)
BASE_FOLDER=${OPTARG};
;;
s|nosudo)
PGSQL_SUDO=0;
;;
d|debug)
DEBUG=1;
;;
n|dryrun)
DRYRUN=1;
;;
:)
echo "Option -$OPTARG requires an argument."
;;
\?)
echo -e "\n Option does not exist: ${OPTARG}\n";
usage;
exit 1;
;;
esac;
done;
[[ "${BASE_FOLDER}" != */ ]] && BASE_FOLDER=${BASE_FOLDER}"/";
if [ ! -d "${BASE_FOLDER}" ]; then
echo "Base folder not found: ${BASE_FOLDER}";
exit 1;
fi;
SETTINGS_FILE="borg.backup.settings";
if [ ! -f "${BASE_FOLDER}${SETTINGS_FILE}" ]; then
echo "Could not find: ${BASE_FOLDER}${SETTINGS_FILE}";
exit;
fi;
. "${BASE_FOLDER}${SETTINGS_FILE}";
if [ ! -z "${TARGET_BORG_PATH}" ]; then
OPT_REMOTE="--remote-path="$(printf "%q" "${TARGET_BORG_PATH}");
fi;
export BORG_BASE_DIR="${BASE_FOLDER}";
export BORG_UNKNOWN_UNENCRYPTED_REPO_ACCESS_IS_OK="yes";
export BORG_RELOCATED_REPO_ACCESS_IS_OK="yes";
ORIG_BACKUPFILE=${BACKUP_FILE};
for MODULE in ${MODULE_LIST}; do
echo "************* MODULE: ${MODULE}";
BACKUP_FILE=${ORIG_BACKUPFILE};
BACKUP_FILE=${BACKUP_FILE/.borg/-${MODULE,,}.borg};
TARGET_FOLDER=${TARGET_FOLDER%/}
TARGET_FOLDER=${TARGET_FOLDER#/}
# and add slash front and back and escape the path
TARGET_FOLDER=$(printf "%q" "/${TARGET_FOLDER}/");
if [ ! -z "${TARGET_USER}" ] && [ ! -z "${TARGET_HOST}" ] && [ ! -z "${TARGET_PORT}" ]; then
TARGET_SERVER="ssh://${TARGET_USER}@${TARGET_HOST}:${TARGET_PORT}/";
# host/port
elif [ ! -z "${TARGET_HOST}" ] && [ ! -z "${TARGET_PORT}" ]; then
TARGET_SERVER="ssh://${TARGET_HOST}:${TARGET_PORT}/";
# user/host
elif [ ! -z "${TARGET_USER}" ] && [ ! -z "${TARGET_HOST}" ]; then
TARGET_SERVER="${TARGET_USER}@${TARGET_HOST}:";
# host
elif [ ! -z "${TARGET_HOST}" ]; then
TARGET_SERVER="${TARGET_HOST}:";
fi;
# we dont allow special characters, so we don't need to special escape it
REPOSITORY="${TARGET_SERVER}${TARGET_FOLDER}${BACKUP_FILE}";
# set sudo prefix for postgres so the cache folder stays the same
# if run as root then the foloders below have to have the user set to postgres again
# .config/borg/security/<postgresql repo id>
# .cache/borg/<postgresql repo id>
CMD_PREFIX="";
# only sudo to pgsql if sudo is set to true
if [ "${MODULE}" = "pgsql" ] && [ "${PGSQL_SUDO}" = "1" ]; then
CMD_PREFIX="sudo -E -u ${PGSQL_SUDO_USER} ";
fi;
echo "==== REPOSITORY: ${REPOSITORY}";
borg list ${OPT_REMOTE} --format '{archive}{NL}' ${REPOSITORY}|grep -v "${MODULE},"|
while read i; do
# for gitea, zabbix we do not ADD we RENAME
if [ "${MODULE}" = "gitea" ]; then
# if just date, add gitea,
# else rename
if [ ! -z "${i##gitea*}" ]; then
target_name="${MODULE},${i}";
else
target_name=$(echo $i | sed -e 's/gitea-/gitea,/');
fi;
elif [ "${MODULE}" = "zabbix" ]; then
# if zabbix is missing, prefix
if [ ! -z "${i##zabbix*}" ]; then
target_name="${MODULE},${i}";
else
target_name=$(echo $i | sed -e 's/zabbix-settings-/zabbix,settings-/');
fi;
else
target_name="${MODULE},${i}";
fi;
echo "- Rename from: ${i} to: ${target_name}";
if [ ${DEBUG} -eq 1 ]; then
echo "${CMD_PREFIX}borg rename ${OPT_REMOTE} -p -v ${REPOSITORY}::${i} ${target_name}";
fi;
if [ ${DRYRUN} -eq 0 ]; then
${CMD_PREFIX}borg rename ${OPT_REMOTE} -p -v ${REPOSITORY}::${i} ${target_name};
fi;
done;
done;
# __END__

View File

@@ -2,8 +2,8 @@
# rename to borg.backup.file.settings to use # rename to borg.backup.file.settings to use
# set to false to use -file, current default is "true" # set to true to use old setting without -file in backup name
#FILE_REPOSITORY_COMPATIBLE="false" #FILE_REPOSITORY_COMPATIBLE="true"
# override settings in borg.backup.settings with SUB_ prefix # override settings in borg.backup.settings with SUB_ prefix
# valid for BACKUP_FILE, BACKUP_SET, COMPRESSION*, KEEP_* # valid for BACKUP_FILE, BACKUP_SET, COMPRESSION*, KEEP_*

View File

@@ -5,7 +5,7 @@
# set last edit date + time # set last edit date + time
MODULE="file"; MODULE="file";
MODULE_VERSION="1.0.0"; MODULE_VERSION="1.2.0";
DIR="${BASH_SOURCE%/*}" DIR="${BASH_SOURCE%/*}"
if [[ ! -d "$DIR" ]]; then DIR="$PWD"; fi if [[ ! -d "$DIR" ]]; then DIR="$PWD"; fi
@@ -22,6 +22,7 @@ BACKUP_INIT_CHECK="borg.backup.file.init";
# exit if include file is missing # exit if include file is missing
if [ ! -f "${BASE_FOLDER}${INCLUDE_FILE}" ]; then if [ ! -f "${BASE_FOLDER}${INCLUDE_FILE}" ]; then
echo "[! $(date +'%F %T')] The include folder file ${INCLUDE_FILE} is missing"; echo "[! $(date +'%F %T')] The include folder file ${INCLUDE_FILE} is missing";
. "${DIR}/borg.backup.functions.close.sh" 1;
exit 1; exit 1;
fi; fi;
echo "--- [INCLUDE: $(date +'%F %T')] --[${MODULE}]------------------------------------>"; echo "--- [INCLUDE: $(date +'%F %T')] --[${MODULE}]------------------------------------>";
@@ -146,11 +147,14 @@ if [ -f "${BASE_FOLDER}${EXCLUDE_FILE}" ]; then
OPT_EXCLUDE="--exclude-from=${TMP_EXCLUDE_FILE}"; OPT_EXCLUDE="--exclude-from=${TMP_EXCLUDE_FILE}";
fi; fi;
fi; fi;
# set a special file prefix
BACKUP_SET_PREFIX="${MODULE},";
# add the repository set before we add the folders # add the repository set before we add the folders
# base command # base command
COMMAND="borg create -v ${OPT_LIST} ${OPT_PROGRESS} ${OPT_COMPRESSION} -s ${OPT_REMOTE} ${OPT_EXCLUDE} "; COMMAND="${BORG_COMMAND} create -v ${OPT_LIST} ${OPT_PROGRESS} ${OPT_COMPRESSION} -s ${OPT_REMOTE} ${OPT_EXCLUDE} ";
# add repoistory, after that the folders will be added on call # add repoistory, after that the folders will be added on call
COMMAND=${COMMAND}${REPOSITORY}::${BACKUP_SET}; COMMAND=${COMMAND}${REPOSITORY}::${ONE_TIME_TAG}${BACKUP_SET_PREFIX}${BACKUP_SET};
# 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";
@@ -172,19 +176,26 @@ if [ $FOLDER_OK -eq 1 ]; then
fi; fi;
else else
echo "[! $(date +'%F %T')] No folders where set for the backup"; echo "[! $(date +'%F %T')] No folders where set for the backup";
. "${DIR}/borg.backup.functions.close.sh" 1;
exit 1; exit 1;
fi; fi;
# clean up, always verbose # clean up, always verbose, but only if we do not run one time tag
echo "--- [PRUNE : $(date +'%F %T')] --[${MODULE}]------------------------------------>"; if [ -z "${ONE_TIME_TAG}" ]; then
# build command echo "--- [PRUNE : $(date +'%F %T')] --[${MODULE}]------------------------------------>";
COMMAND="borg prune ${OPT_REMOTE} -v -s --list ${PRUNE_DEBUG} ${KEEP_OPTIONS[*]} ${REPOSITORY}"; # build command
echo "Prune repository with keep${KEEP_INFO:1}"; COMMAND="${BORG_COMMAND} prune ${OPT_REMOTE} -v --list ${OPT_PROGRESS} ${DRY_RUN_STATS} -P ${BACKUP_SET_PREFIX} ${KEEP_OPTIONS[*]} ${REPOSITORY}";
if [ ${DEBUG} -eq 1 ]; then echo "Prune repository with keep${KEEP_INFO:1}";
echo "${COMMAND//#/ }" | sed -e 's/[ ][ ]*/ /g'; if [ ${DEBUG} -eq 1 ]; then
echo "${COMMAND//#/ }" | sed -e 's/[ ][ ]*/ /g';
fi;
# for the IFS="#" to work we need to replace options spaces with exactly ONE #
$(echo "${COMMAND}" | sed -e 's/[ ][ ]*/#/g') 2>&1 || echo "[!] Borg prune aborted";
# if this is borg version >1.2 we need to run compact after prune
. "${DIR}/borg.backup.functions.compact.sh";
else
echo "[#] No prune with tagged backup";
fi; fi;
# for the IFS="#" to work we need to replace options spaces with exactly ONE #
$(echo "${COMMAND}" | sed -e 's/[ ][ ]*/#/g') 2>&1 || echo "[!] Borg prune aborted";
. "${DIR}/borg.backup.functions.close.sh"; . "${DIR}/borg.backup.functions.close.sh";

View File

@@ -10,6 +10,8 @@ echo "Script version: ${VERSION}";
# show type # show type
echo "Backup module : ${MODULE}"; echo "Backup module : ${MODULE}";
echo "Module version: ${MODULE_VERSION}"; echo "Module version: ${MODULE_VERSION}";
# borg version
echo "Borg version : ${BORG_VERSION}";
# show base folder always # show base folder always
echo "Base folder : ${BASE_FOLDER}"; echo "Base folder : ${BASE_FOLDER}";
@@ -77,6 +79,7 @@ REPOSITORY="${TARGET_SERVER}${TARGET_FOLDER}${BACKUP_FILE}";
echo "Repository : ${REPOSITORY}"; echo "Repository : ${REPOSITORY}";
# check compression if given is valid and check compression level is valid if given # check compression if given is valid and check compression level is valid if given
OPT_COMPRESSION='';
if [ ! -z "${COMPRESSION}" ]; then if [ ! -z "${COMPRESSION}" ]; then
# valid compression # valid compression
if [ "${COMPRESSION}" = "lz4" ] || [ "${COMPRESSION}" = "zlib" ] || [ "${COMPRESSION}" = "lzma" ] || [ "${COMPRESSION}" = "zstd" ]; then if [ "${COMPRESSION}" = "lz4" ] || [ "${COMPRESSION}" = "zlib" ] || [ "${COMPRESSION}" = "lzma" ] || [ "${COMPRESSION}" = "zstd" ]; then
@@ -129,63 +132,71 @@ if [ ! -w "${HOME}" ] || [ "${HOME}" = '/' ]; then
HOME=$(eval echo "$(whoami)"); HOME=$(eval echo "$(whoami)");
fi; fi;
# build options and info string, # keep optionfs (for files)
# also flag BACKUP_SET check if hourly is set KEEP_OPTIONS=("");
KEEP_OPTIONS=(); # keep info string (for files)
KEEP_INFO=""; KEEP_INFO="";
BACKUP_SET_CHECK=0; # override standard keep for tagged backups
if [ ${KEEP_LAST} -gt 0 ]; then if [ ! -z "${ONE_TIME_TAG}" ]; then
KEEP_OPTIONS+=("--keep-last=${KEEP_LAST}"); BACKUP_SET="{now:%Y-%m-%dT%H:%M:%S}";
KEEP_INFO="${KEEP_INFO}, last: ${KEEP_LAST}"; else
fi; # build options and info string,
if [ ${KEEP_HOURS} -gt 0 ]; then # also flag BACKUP_SET check if hourly is set
KEEP_OPTIONS+=("--keep-hourly=${KEEP_HOURS}"); BACKUP_SET_CHECK=0;
KEEP_INFO="${KEEP_INFO}, hourly: ${KEEP_HOURS}"; if [ ${KEEP_LAST} -gt 0 ]; then
BACKUP_SET_CHECK=1; KEEP_OPTIONS+=("--keep-last=${KEEP_LAST}");
fi; KEEP_INFO="${KEEP_INFO}, last: ${KEEP_LAST}";
if [ ${KEEP_DAYS} -gt 0 ]; then fi;
KEEP_OPTIONS+=("--keep-daily=${KEEP_DAYS}"); if [ ${KEEP_HOURS} -gt 0 ]; then
KEEP_INFO="${KEEP_INFO}, daily: ${KEEP_DAYS}"; KEEP_OPTIONS+=("--keep-hourly=${KEEP_HOURS}");
fi; KEEP_INFO="${KEEP_INFO}, hourly: ${KEEP_HOURS}";
if [ ${KEEP_WEEKS} -gt 0 ]; then BACKUP_SET_CHECK=1;
KEEP_OPTIONS+=("--keep-weekly=${KEEP_WEEKS}"); fi;
KEEP_INFO="${KEEP_INFO}, weekly: ${KEEP_WEEKS}"; if [ ${KEEP_DAYS} -gt 0 ]; then
fi; KEEP_OPTIONS+=("--keep-daily=${KEEP_DAYS}");
if [ ${KEEP_MONTHS} -gt 0 ]; then KEEP_INFO="${KEEP_INFO}, daily: ${KEEP_DAYS}";
KEEP_OPTIONS+=("--keep-monthly=${KEEP_MONTHS}"); fi;
KEEP_INFO="${KEEP_INFO}, monthly: ${KEEP_MONTHS}"; if [ ${KEEP_WEEKS} -gt 0 ]; then
fi; KEEP_OPTIONS+=("--keep-weekly=${KEEP_WEEKS}");
if [ ${KEEP_YEARS} -gt 0 ]; then KEEP_INFO="${KEEP_INFO}, weekly: ${KEEP_WEEKS}";
KEEP_OPTIONS+=("--keep-yearly=${KEEP_YEARS}"); fi;
KEEP_INFO="${KEEP_INFO}, yearly: ${KEEP_YEARS}"; if [ ${KEEP_MONTHS} -gt 0 ]; then
fi; KEEP_OPTIONS+=("--keep-monthly=${KEEP_MONTHS}");
if [ ! -z "${KEEP_WITHIN}" ]; then KEEP_INFO="${KEEP_INFO}, monthly: ${KEEP_MONTHS}";
# check for invalid string. can only be number + H|d|w|m|y fi;
if [[ "${KEEP_WITHIN}" =~ ^[0-9]+[Hdwmy]{1}$ ]]; then if [ ${KEEP_YEARS} -gt 0 ]; then
KEEP_OPTIONS+=("--keep-within=${KEEP_WITHIN}"); KEEP_OPTIONS+=("--keep-yearly=${KEEP_YEARS}");
KEEP_INFO="${KEEP_INFO}, within: ${KEEP_WITHIN}"; KEEP_INFO="${KEEP_INFO}, yearly: ${KEEP_YEARS}";
if [[ "${KEEP_WITHIN}" == *"H"* ]]; then fi;
BACKUP_SET_CHECK=1; if [ ! -z "${KEEP_WITHIN}" ]; then
# check for invalid string. can only be number + H|d|w|m|y
if [[ "${KEEP_WITHIN}" =~ ^[0-9]+[Hdwmy]{1}$ ]]; then
KEEP_OPTIONS+=("--keep-within=${KEEP_WITHIN}");
KEEP_INFO="${KEEP_INFO}, within: ${KEEP_WITHIN}";
if [[ "${KEEP_WITHIN}" == *"H"* ]]; then
BACKUP_SET_CHECK=1;
fi;
else
echo "[! $(date +'%F %T')] KEEP_WITHIN has invalid string.";
exit 1;
fi; fi;
else fi;
echo "[! $(date +'%F %T')] KEEP_WITHIN has invalid string."; # abort if KEEP_OPTIONS is empty
if [ -z "${KEEP_OPTIONS}" ]; then
echo "[! $(date +'%F %T')] It seems no KEEP_* entries where set in a valid format.";
exit 1; exit 1;
fi; fi;
# set BACKUP_SET if empty, set to Year-month-day
if [ -z "${BACKUP_SET}" ]; then
BACKUP_SET="{now:%Y-%m-%d}";
fi;
# backup set check, and there is no hour entry (%H) in the archive string
# we add T%H:%M:%S in this case, before the last }
if [ ${BACKUP_SET_CHECK} -eq 1 ] && [[ "${BACKUP_SET}" != *"%H"* ]]; then
BACKUP_SET=$(echo "${BACKUP_SET}" | sed -e "s/}/T%H:%M:%S}/");
fi;
fi; fi;
# abort if KEEP_OPTIONS is empty
if [ -z "${KEEP_OPTIONS}" ]; then
echo "[! $(date +'%F %T')] It seems no KEEP_* entries where set in a valid format.";
exit 1;
fi;
# set BACKUP_SET if empty, set to Year-month-day
if [ -z "${BACKUP_SET}" ]; then
BACKUP_SET="{now:%Y-%m-%d}";
fi;
# backup set check, and there is no hour entry (%H) in the archive string
# we add T%H:%M:%S in this case, before the last }
if [ ${BACKUP_SET_CHECK} -eq 1 ] && [[ "${BACKUP_SET}" != *"%H"* ]]; then
BACKUP_SET=$(echo "${BACKUP_SET}" | sed -e "s/}/T%H:%M:%S}/");
fi;
# for folders list split set to "#" and keep the old setting as is # for folders list split set to "#" and keep the old setting as is
_IFS=${IFS}; _IFS=${IFS};
@@ -197,8 +208,8 @@ fi;
# borg call, replace ##...## parts during run # borg call, replace ##...## parts during run
# used in all modules, except 'file' # used in all modules, except 'file'
_BORG_CALL="borg create ${OPT_REMOTE} -v ${OPT_LIST} ${OPT_PROGRESS} ${OPT_COMPRESSION} -s --stdin-name ##FILENAME## ${REPOSITORY}::##BACKUP_SET## -"; _BORG_CALL="${BORG_COMMAND} create ${OPT_REMOTE} -v ${OPT_LIST} ${OPT_PROGRESS} ${OPT_COMPRESSION} -s --stdin-name ##FILENAME## ${REPOSITORY}::##BACKUP_SET## -";
_BORG_PRUNE="borg prune ${OPT_REMOTE} -v -s --list ${PRUNE_DEBUG} -P ##BACKUP_SET_PREFIX## ${KEEP_OPTIONS[*]} ${REPOSITORY}"; _BORG_PRUNE="${BORG_COMMAND} prune ${OPT_REMOTE} -v --list ${OPT_PROGRESS} ${DRY_RUN_STATS} -P ##BACKUP_SET_PREFIX## ${KEEP_OPTIONS[*]} ${REPOSITORY}";
# general borg settings # general borg settings
# set base path to config directory to keep cache/config separated # set base path to config directory to keep cache/config separated
@@ -215,7 +226,7 @@ if [ ${DEBUG} -eq 1 ]; then
fi; fi;
# prepare debug commands only # prepare debug commands only
COMMAND_EXPORT="export BORG_BASE_DIR=\"${BASE_FOLDER}\";" COMMAND_EXPORT="export BORG_BASE_DIR=\"${BASE_FOLDER}\";"
COMMAND_INFO="${COMMAND_EXPORT}borg info ${OPT_REMOTE} ${REPOSITORY}"; COMMAND_INFO="${COMMAND_EXPORT}${BORG_COMMAND} info ${OPT_REMOTE} ${REPOSITORY}";
# if the is not there, call init to create it # if the is not there, call init to create it
# if this is user@host, we need to use ssh command to check if the file is there # if this is user@host, we need to use ssh command to check if the file is there
# else a normal check is ok # else a normal check is ok
@@ -224,14 +235,13 @@ if [ ${CHECK} -eq 1 ] || [ ${INIT} -eq 1 ]; then
echo "--- [CHECK : $(date +'%F %T')] --[${MODULE}]------------------------------------>"; echo "--- [CHECK : $(date +'%F %T')] --[${MODULE}]------------------------------------>";
if [ ! -z "${TARGET_SERVER}" ]; then if [ ! -z "${TARGET_SERVER}" ]; then
if [ ${DEBUG} -eq 1 ]; then if [ ${DEBUG} -eq 1 ]; then
echo "borg info ${OPT_REMOTE} ${REPOSITORY} 2>&1|grep \"Repository ID:\""; echo "${BORG_COMMAND} info ${OPT_REMOTE} ${REPOSITORY} 2>&1|grep \"Repository ID:\"";
fi; fi;
# use borg info and check if it returns "Repository ID:" in the first line # use borg info and check if it returns "Repository ID:" in the first line
REPO_CHECK=$(borg info ${OPT_REMOTE} ${REPOSITORY} 2>&1|grep "Repository ID:"); REPO_CHECK=$(${BORG_COMMAND} info ${OPT_REMOTE} ${REPOSITORY} 2>&1|grep "Repository ID:");
# this is currently a hack to work round the error code in borg info # this is currently a hack to work round the error code in borg info
# this checks if REPO_CHECK holds this error message and then starts init # this checks if REPO_CHECK holds this error message and then starts init
regex="^Some part of the script failed with an error:"; if [[ -z "${REPO_CHECK}" ]] || [[ "${REPO_CHECK}" =~ ${REGEX_ERROR} ]]; then
if [[ -z "${REPO_CHECK}" ]] || [[ "${REPO_CHECK}" =~ ${regex} ]]; then
INIT_REPOSITORY=1; INIT_REPOSITORY=1;
fi; fi;
elif [ ! -d "${REPOSITORY}" ]; then elif [ ! -d "${REPOSITORY}" ]; then
@@ -247,37 +257,39 @@ if [ ${CHECK} -eq 1 ] || [ ${INIT} -eq 1 ]; then
# end if checked but repository is not here # end if checked but repository is not here
if [ ${CHECK} -eq 1 ] && [ ${INIT} -eq 0 ] && [ ${INIT_REPOSITORY} -eq 1 ]; then if [ ${CHECK} -eq 1 ] && [ ${INIT} -eq 0 ] && [ ${INIT_REPOSITORY} -eq 1 ]; then
echo "[! $(date +'%F %T')] No repository. Please run with -I flag to initialze repository"; echo "[! $(date +'%F %T')] No repository. Please run with -I flag to initialze repository";
. "${DIR}/borg.backup.functions.close.sh" 1;
exit 1; exit 1;
fi; fi;
if [ ${EXIT} -eq 1 ] && [ ${CHECK} -eq 1 ] && [ ${INIT} -eq 0 ]; then if [ ${EXIT} -eq 1 ] && [ ${CHECK} -eq 1 ] && [ ${INIT} -eq 0 ]; then
echo "Repository exists"; echo "Repository exists";
echo "For more information run:" echo "For more information run:"
echo "${COMMAND_INFO}"; echo "${COMMAND_INFO}";
echo "=== [END : $(date +'%F %T')] ==[${MODULE}]====================================>"; . "${DIR}/borg.backup.functions.close.sh";
exit; exit;
fi; fi;
fi; fi;
if [ ${INIT} -eq 1 ] && [ ${INIT_REPOSITORY} -eq 1 ]; then if [ ${INIT} -eq 1 ] && [ ${INIT_REPOSITORY} -eq 1 ]; then
echo "--- [INIT : $(date +'%F %T')] --[${MODULE}]------------------------------------>"; echo "--- [INIT : $(date +'%F %T')] --[${MODULE}]------------------------------------>";
if [ ${DEBUG} -eq 1 ] || [ ${DRYRUN} -eq 1 ]; then if [ ${DEBUG} -eq 1 ] || [ ${DRYRUN} -eq 1 ]; then
echo "borg init ${OPT_REMOTE} -e ${ENCRYPTION} ${OPT_VERBOSE} ${REPOSITORY}"; echo "${BORG_COMMAND} init ${OPT_REMOTE} -e ${ENCRYPTION} ${OPT_VERBOSE} ${REPOSITORY}";
fi fi
if [ ${DRYRUN} -eq 0 ]; then if [ ${DRYRUN} -eq 0 ]; then
# should trap and exit properly here # should trap and exit properly here
borg init ${OPT_REMOTE} -e ${ENCRYPTION} ${OPT_VERBOSE} ${REPOSITORY}; ${BORG_COMMAND} init ${OPT_REMOTE} -e ${ENCRYPTION} ${OPT_VERBOSE} ${REPOSITORY};
# write init file # write init file
echo "$(date +%s)" > "${BASE_FOLDER}${BACKUP_INIT_CHECK}"; echo "$(date +%s)" > "${BASE_FOLDER}${BACKUP_INIT_CHECK}";
echo "Repository initialized"; echo "Repository initialized";
echo "For more information run:" echo "For more information run:"
echo "${COMMAND_INFO}"; echo "${COMMAND_INFO}";
fi fi
echo "=== [END : $(date +'%F %T')] ==[${MODULE}]====================================>"; . "${DIR}/borg.backup.functions.close.sh";
# 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;
exit 1; exit 1;
fi; fi;
@@ -285,35 +297,79 @@ fi;
if [ ! -f "${BASE_FOLDER}${BACKUP_INIT_CHECK}" ]; then if [ ! -f "${BASE_FOLDER}${BACKUP_INIT_CHECK}" ]; 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;
exit 1; exit 1;
fi; fi;
# PRINT OUT current data, only do this if REPO exists # PRINT OUT current data, only do this if REPO exists
if [ ${PRINT} -eq 1 ]; then if [ ${PRINT} -eq 1 ]; then
echo "--- [PRINT : $(date +'%F %T')] --[${MODULE}]------------------------------------>"; echo "--- [PRINT : $(date +'%F %T')] --[${MODULE}]------------------------------------>";
FORMAT="{archive} {comment:6} {start} - {end} [{id}] ({username}@{hostname}){NL}" FORMAT="{archive:<45} {comment:6} {start} - {end} [{id}] ({username}@{hostname}){NL}"
# show command on debug or dry run # show command on debug or dry run
if [ ${DEBUG} -eq 1 ] || [ ${DRYRUN} -eq 1 ]; then if [ ${DEBUG} -eq 1 ] || [ ${DRYRUN} -eq 1 ]; then
echo "export BORG_BASE_DIR=\"${BASE_FOLDER}\";borg list ${OPT_REMOTE} --format ${FORMAT} ${REPOSITORY}"; echo "export BORG_BASE_DIR=\"${BASE_FOLDER}\";${BORG_COMMAND} list ${OPT_REMOTE} --format ${FORMAT} ${REPOSITORY}";
fi; fi;
# run info command if not a dry drun # run info command if not a dry drun
if [ ${DRYRUN} -eq 0 ]; then if [ ${DRYRUN} -eq 0 ]; then
borg list ${OPT_REMOTE} --format "${FORMAT}" ${REPOSITORY} ; ${BORG_COMMAND} list ${OPT_REMOTE} --format "${FORMAT}" ${REPOSITORY} ;
fi; fi;
if [ ${VERBOSE} -eq 1 ]; then if [ ${VERBOSE} -eq 1 ]; then
echo ""; echo "";
echo "Base command info:" echo "Base command info:"
echo "export BORG_BASE_DIR=\"${BASE_FOLDER}\";borg [COMMAND] ${OPT_REMOTE} ${REPOSITORY}::[BACKUP] [PATH]"; echo "export BORG_BASE_DIR=\"${BASE_FOLDER}\";${BORG_COMMAND} [COMMAND] ${OPT_REMOTE} ${REPOSITORY}::[BACKUP] [PATH]";
echo "Replace [COMMAND] with list for listing or extract for restoring backup data." echo "Replace [COMMAND] with list for listing or extract for restoring backup data."
echo "Replace [BACKUP] with archive name." echo "Replace [BACKUP] with archive name."
echo "If no [PATH] is given then all files will be restored." echo "If no [PATH] is given then all files will be restored."
echo "Before extracting -n (dry run) is recommended to use." echo "Before extracting -n (dry run) is recommended to use."
echo "If archive size is needed the info command with archive name has to be used." echo "If archive size is needed the info command with archive name has to be used."
echo "When listing (list) data the --format command can be used." echo "When listing files in an archive set (::SET) the --format command can be used."
echo "Example: \"{mode} {user:6} {group:6} {size:8d} {csize:8d} {dsize:8d} {dcsize:8d} {mtime} {path}{extra} [{health}]{NL}\"" echo "Example: \"{mode} {user:6} {group:6} {size:8d} {csize:8d} {dsize:8d} {dcsize:8d} {mtime} {path}{extra} [{health}]{NL}\""
else else
echo "export BORG_BASE_DIR=\"${BASE_FOLDER}\";borg [COMMAND] ${OPT_REMOTE} [FORMAT] ${REPOSITORY}::[BACKUP] [PATH]"; echo "export BORG_BASE_DIR=\"${BASE_FOLDER}\";${BORG_COMMAND} [COMMAND] ${OPT_REMOTE} [FORMAT] ${REPOSITORY}::[BACKUP] [PATH]";
fi; fi;
. "${DIR}/borg.backup.functions.close.sh";
exit;
fi;
# DELETE ONE TIME TAG
if [ ! -z "${DELETE_ONE_TIME_TAG}" ]; then
echo "--- [DELETE: $(date +'%F %T')] --[${MODULE}]------------------------------------>";
# if a "*" is inside we don't do ONE archive, but globbing via -a option
DELETE_ARCHIVE=""
OPT_GLOB="";
# this is more or less for debug only
if [[ "${DELETE_ONE_TIME_TAG}" =~ $REGEX_GLOB ]]; then
OPT_GLOB="-a '${DELETE_ONE_TIME_TAG}'"
else
DELETE_ARCHIVE="::"${DELETE_ONE_TIME_TAG};
fi
# if this is borg <1.2 OPT_LIST does not work
if [ $(version $BORG_VERSION) -lt $(version "1.2.0") ]; then
OPT_LIST="";
fi;
# if exists, delete and exit
# show command on debug or dry run
if [ ${DEBUG} -eq 1 ]; then
echo "${BORG_COMMAND} delete ${OPT_REMOTE} ${OPT_LIST} -s ${OPT_GLOB} ${REPOSITORY}${DELETE_ARCHIVE}";
fi;
# run delete command if not a dry drun
# NOTE seems to be glob is not working if wrapped into another variable
if [[ "${DELETE_ONE_TIME_TAG}" =~ $REGEX_GLOB ]]; then
${BORG_COMMAND} delete ${OPT_REMOTE} ${OPT_LIST} ${DRY_RUN_STATS} -a "${DELETE_ONE_TIME_TAG}" ${REPOSITORY};
else
${BORG_COMMAND} delete ${OPT_REMOTE} ${OPT_LIST} ${DRY_RUN_STATS} ${REPOSITORY}${DELETE_ARCHIVE};
fi;
# if not a dry run, compact repository after delete
# not that compact only works on borg 1.2
if [ $(version $BORG_VERSION) -ge $(version "1.2.0") ]; then
if [ ${DRYRUN} -eq 0 ]; then
${BORG_COMMAND} compact ${REPOSITORY};
fi;
if [ ${DEBUG} -eq 1 ]; then
echo "${BORG_COMMAND} compact ${REPOSITORY}";
fi;
fi;
. "${DIR}/borg.backup.functions.close.sh";
exit; exit;
fi; fi;

View File

@@ -2,8 +2,13 @@
# unset borg settings # unset borg settings
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
DURATION=$[ $(date +'%s')-$START ]; # error abort without duration and error notice
echo "=== [Run time: $(convert_time ${DURATION})]"; if [ $# -ge 1 ] && [ $1 -eq 1 ]; then
echo "=== [END : $(date +'%F %T')] ==[${MODULE}]===================>"; echo "=== [ERROR: $(date +'%F %T')] ==[${MODULE}]====================================>";
else
DURATION=$[ $(date +'%s')-$START ];
echo "=== [Run time: $(convert_time ${DURATION})]";
echo "=== [END : $(date +'%F %T')] ==[${MODULE}]====================================>";
fi;
# __END__ # __END__

View File

@@ -0,0 +1,19 @@
#!/usr/bin/env bash
# compact (only if BORG COMPACT is set)
# only for borg 1.2
# reset to normal IFS, so command works here
IFS=${_IFS};
if [ $(version $BORG_VERSION) -ge $(version "1.2.0") ]; then
echo "--- [COMPACT:$(date +'%F %T')] --[${MODULE}]------------------------------------>";
BORG_COMPACT="${BORG_COMMAND} compact -v ${OPT_PROGRESS} ${REPOSITORY}";
if [ ${DEBUG} -eq 1 ]; then
echo "${BORG_COMPACT}";
fi;
if [ ${DRYRUN} -eq 0 ]; then
${BORG_COMPACT};
fi;
fi;
# __END__

View File

@@ -4,11 +4,11 @@ if [ ${INFO} -eq 1 ]; then
echo "--- [INFO : $(date +'%F %T')] --[${MODULE}]------------------------------------>"; echo "--- [INFO : $(date +'%F %T')] --[${MODULE}]------------------------------------>";
# show command on debug or dry run # show command on debug or dry run
if [ ${DEBUG} -eq 1 ] || [ ${DRYRUN} -eq 1 ]; then if [ ${DEBUG} -eq 1 ] || [ ${DRYRUN} -eq 1 ]; then
echo "export BORG_BASE_DIR=\"${BASE_FOLDER}\";borg info ${OPT_REMOTE} ${REPOSITORY}"; echo "export BORG_BASE_DIR=\"${BASE_FOLDER}\";${BORG_COMMAND} info ${OPT_REMOTE} ${REPOSITORY}";
fi; fi;
# run info command if not a dry drun # run info command if not a dry drun
if [ ${DRYRUN} -eq 0 ]; then if [ ${DRYRUN} -eq 0 ]; then
borg info ${OPT_REMOTE} ${REPOSITORY}; ${BORG_COMMAND} info ${OPT_REMOTE} ${REPOSITORY};
fi; fi;
if [ "${MODULE}" = "files" ]; then if [ "${MODULE}" = "files" ]; then
if [ $FOLDER_OK -eq 1 ]; then if [ $FOLDER_OK -eq 1 ]; then
@@ -23,7 +23,7 @@ if [ ${INFO} -eq 1 ]; then
rm -f "${TMP_EXCLUDE_FILE}"; rm -f "${TMP_EXCLUDE_FILE}";
fi; fi;
fi; fi;
echo "=== [END : $(date +'%F %T')] ==[${MODULE}]====================================>"; . "${DIR}/borg.backup.functions.close.sh";
exit; exit;
fi; fi;

View File

@@ -13,10 +13,17 @@ cleanup() {
} }
# 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;
# for version compare
function version {
echo "$@" | awk -F. '{ printf("%d%03d%03d%03d\n", $1,$2,$3,$4); }';
}
# version for all general files # version for all general files
VERSION="3.0.0"; VERSION="4.2.3";
# borg version and borg comamnd
BORG_VERSION="";
BORG_COMMAND="borg";
# default log folder if none are set in config or option # default log folder if none are set in config or option
_LOG_FOLDER="/var/log/borg.backup/"; _LOG_FOLDER="/var/log/borg.backup/";
# log file name is set based on BACKUP_FILE, .log is added # log file name is set based on BACKUP_FILE, .log is added
@@ -34,6 +41,9 @@ INCLUDE_FILE="";
EXCLUDE_FILE=""; EXCLUDE_FILE="";
# backup folder initialzed check # backup folder initialzed check
BACKUP_INIT_CHECK=""; BACKUP_INIT_CHECK="";
# one time backup prefix tag, if set will use <tag>.<prefix>-Y-M-DTh:m:s type backup prefix
ONE_TIME_TAG="";
DELETE_ONE_TIME_TAG="";
# debug/verbose # debug/verbose
VERBOSE=0; VERBOSE=0;
LIST=0; LIST=0;
@@ -51,13 +61,14 @@ _BORG_RELOCATED_REPO_ACCESS_IS_OK="yes";
# NOTE: to keep the old .borg repository name for file module set this to true # NOTE: to keep the old .borg repository name for file module set this to true
# if set to false (future) it will add -file to the repository name like for other # if set to false (future) it will add -file to the repository name like for other
# modules # modules
FILE_REPOSITORY_COMPATIBLE="true"; FILE_REPOSITORY_COMPATIBLE="false";
# other variables # other variables
TARGET_SERVER=""; TARGET_SERVER="";
REGEX=""; 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:";
PRUNE_DEBUG=""; PRUNE_DEBUG="";
INIT_REPOSITORY=0; INIT_REPOSITORY=0;
FOLDER_OK=0; FOLDER_OK=0;
@@ -77,15 +88,23 @@ TARGET_BORG_PATH="";
TARGET_FOLDER=""; TARGET_FOLDER="";
BACKUP_FILE=""; BACKUP_FILE="";
SUB_BACKUP_FILE=""; SUB_BACKUP_FILE="";
# OPT is for options set
OPT_BORG_EXECUTEABLE="";
# which overrides BORG_EXECUTABLE that can be set in the settings file
BORG_EXECUTEABLE="";
# lz4, zstd 1-22 (3), zlib 0-9 (6), lzma 0-9 (6) # lz4, zstd 1-22 (3), zlib 0-9 (6), lzma 0-9 (6)
COMPRESSION="zstd"; DEFAULT_COMPRESSION="zstd";
COMPRESSION_LEVEL=3; DEFAULT_COMPRESSION_LEVEL=3;
COMPRESSION="";
COMPRESSION_LEVEL="";
SUB_COMPRESSION=""; SUB_COMPRESSION="";
SUB_COMPRESSION_LEVEL=""; SUB_COMPRESSION_LEVEL="";
# encryption settings # encryption settings
ENCRYPTION="none"; DEFAULT_ENCRYPTION="none";
ENCRYPTION="";
# force check always # force check always
FORCE_CHECK="false"; DEFAULT_FORCE_CHECK="false";
FORCE_CHECK="";
BACKUP_SET=""; BACKUP_SET="";
SUB_BACKUP_SET=""; SUB_BACKUP_SET="";
# for database backup only # for database backup only
@@ -113,12 +132,18 @@ OPT_ZABBIX_UNKNOWN_TABLES="";
# BACKUP SET that includes hour and minute information # BACKUP SET that includes hour and minute information
# IF BACKUP_SET is empty, this is automatically added # IF BACKUP_SET is empty, this is automatically added
# general keep last, if only this is set only last n will be kept # general keep last, if only this is set only last n will be kept
KEEP_LAST=0; DEFAULT_KEEP_LAST=0;
KEEP_HOURS=0; DEFAULT_KEEP_HOURS=0;
KEEP_DAYS=7; DEFAULT_KEEP_DAYS=7;
KEEP_WEEKS=4; DEFAULT_KEEP_WEEKS=4;
KEEP_MONTHS=6; DEFAULT_KEEP_MONTHS=6;
KEEP_YEARS=1; DEFAULT_KEEP_YEARS=1;
KEEP_LAST="";
KEEP_HOURS="";
KEEP_DAYS="";
KEEP_WEEKS="";
KEEP_MONTHS="";
KEEP_YEARS="";
# in the format of nY|M|d|h|m|s # in the format of nY|M|d|h|m|s
KEEP_WITHIN=""; KEEP_WITHIN="";
# sub override init to empty # sub override init to empty
@@ -137,13 +162,16 @@ function usage()
-c <config folder>: if this is not given, ${BASE_FOLDER} is used -c <config folder>: if this is not given, ${BASE_FOLDER} is used
-L <log folder>: override config set and default log folder -L <log folder>: override config set and default log folder
-T <tag>: create one time stand alone backup prefixed with tag name
-D <tag backup set>: remove a tagged backup set, full name must be given
-b <borg executable>: override default path
-P: print list of archives created -P: print list of archives created
-C: check if repository exists, if not abort -C: check if repository exists, if not abort
-E: exit after check -E: exit after check
-I: init repository (must be run first) -I: init repository (must be run first)
-v: be verbose
-i: print out only info -i: print out only info
-l: list files during backup -l: list files during backup
-v: be verbose
-d: debug output all commands -d: debug output all commands
-n: only do dry run -n: only do dry run
-h: this help page -h: this help page
@@ -155,14 +183,23 @@ function usage()
} }
# set options # set options
while getopts ":c:L:vldniCEIPh" opt; do while getopts ":c:L:T:D:b:vldniCEIPh" opt; do
case "${opt}" in case "${opt}" in
c|config) c|config)
BASE_FOLDER=${OPTARG}; BASE_FOLDER=${OPTARG};
;; ;;
L|log) L|Log)
OPT_LOG_FOLDER=${OPTARG}; OPT_LOG_FOLDER=${OPTARG};
;; ;;
T|Tag)
ONE_TIME_TAG=${OPTARG};
;;
D|Delete)
DELETE_ONE_TIME_TAG=${OPTARG};
;;
b|borg)
OPT_BORG_EXECUTEABLE=${OPTARG};
;;
C|Check) C|Check)
# will check if repo is there and abort if not # will check if repo is there and abort if not
CHECK=1; CHECK=1;
@@ -234,10 +271,36 @@ if [ ${CHECK} -eq 1 ] || [ ${INIT} -eq 1 ] && [ ${INFO} -eq 1 ]; then
exit 1; exit 1;
fi; fi;
# print -P cannot be run with -i/-C/-I together # print -P cannot be run with -i/-C/-I together
if [ ${PRINT} -eq 1 ] || [ ${INIT} -eq 1 ] && [ ${CHECK} -eq 1 ] && [ ${INFO} -eq 1 ]; then if [ ${PRINT} -eq 1 ] && ([ ${INIT} -eq 1 ] || [ ${CHECK} -eq 1 ] || [ ${INFO} -eq 1 ]); then
echo "Cannot have -P print option and -i info, -C check or -I initizalize option at the same time"; echo "Cannot have -P print option and -i info, -C check or -I initizalize option at the same time";
exit 1; exit 1;
fi; fi;
# if tag is set, you can't have init, check, info, etc
if [ ! -z "${ONE_TIME_TAG}" ] && ([ ${PRINT} -eq 1 ] || [ ${INIT} -eq 1 ] || [ ${CHECK} -eq 1 ] || [ ${INFO} -eq 1 ]); then
echo "Cannot have -T '${ONE_TIME_TAG}' option with -i info, -C check, -I initialize or -P print option at the same time";
exit 1;
fi;
# check only alphanumeric, no spaces, only underscore and dash
if [ ! -z "${ONE_TIME_TAG}" ] && ! [[ "${ONE_TIME_TAG}" =~ ^[A-Za-z0-9_-]+$ ]]; then
echo "One time tag '${ONE_TIME_TAG}' must be alphanumeric with dashes and underscore only.";
exit 1;
elif [ ! -z "${ONE_TIME_TAG}" ]; then
# all ok, attach . at the end
ONE_TIME_TAG=${ONE_TIME_TAG}".";
fi;
# if -D, cannot be with -T, -i, -C, -I, -P
if [ ! -z "${DELETE_ONE_TIME_TAG}" ] && ([ ! -z "${ONE_TIME_TAG}" ] || [ ${PRINT} -eq 1 ] || [ ${INIT} -eq 1 ] || [ ${CHECK} -eq 1 ] || [ ${INFO} -eq 1 ]); then
echo "Cannot have -D delete tag option with -T one time tag, -i info, -C check, -I initialize or -P print option at the same time";
exit 1;
fi;
# -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\*$ ]]
if [ ! -z "${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. Please check existing tags with -P option."
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."
exit 1;
fi;
# verbose & progress # verbose & progress
if [ ${VERBOSE} -eq 1 ]; then if [ ${VERBOSE} -eq 1 ]; then
@@ -248,12 +311,76 @@ fi;
if [ ${LIST} -eq 1 ]; then if [ ${LIST} -eq 1 ]; then
OPT_LIST="--list"; OPT_LIST="--list";
fi; fi;
# If dry run, the stats (-s) option cannot be used
if [ ${DRYRUN} -eq 1 ]; then if [ ${DRYRUN} -eq 1 ]; then
PRUNE_DEBUG="--dry-run"; DRY_RUN_STATS="-n";
else
DRY_RUN_STATS="-s";
fi; fi;
# read config file # read config file
. "${BASE_FOLDER}${SETTINGS_FILE}"; . "${BASE_FOLDER}${SETTINGS_FILE}";
# if OPTION SET overrides ALL others
if [ ! -z "${OPT_BORG_EXECUTEABLE}" ]; then
BORG_COMMAND="${OPT_BORG_EXECUTEABLE}";
if [ ! -f "${BORG_COMMAND}" ]; then
echo "borg command not found with option -b: ${BORG_COMMAND}";
exit;
fi;
# if in setting file, use this
elif [ ! -z "${BORG_EXECUTEABLE}" ]; then
BORG_COMMAND="${BORG_EXECUTEABLE}";
if [ ! -f "${BORG_COMMAND}" ]; then
echo "borg command not found with setting: ${BORG_COMMAND}";
exit;
fi;
elif ! command -v borg &> /dev/null; then
echo "borg backup seems not to be installed, please check paths";
exit;
fi;
# check that this is a borg executable, no detail check
_BORG_COMMAND_CHECK=$(${BORG_COMMAND} -V | grep "borg");
if [[ "${_BORG_COMMAND_CHECK}" =~ ${REGEX_ERROR} ]]; then
echo "Cannot extract borg info from command, is this a valid borg executable?: ${BORG_COMMAND}";
exit;
fi;
# extract actually borg version from here
# alt sed to get only numbes: sed -e 's/.* \([0-9]*\.[0-9]*\.[0-9]*\)$/\1/g'
# or use cut -d " " -f 2 and assume NO space in the first part
BORG_VERSION=$(${BORG_COMMAND} -V | sed -e 's/borg.* //') 2>&1 || echo "[!] Borg version not estable";
# load default settings for fileds not set
if [ -z "${COMPRESSION}" ]; then
COMPRESSION="${DEFAULT_COMPRESSION}";
fi;
if [ -z "${COMPRESSION_LEVEL}" ]; then
COMPRESSION_LEVEL="${DEFAULT_COMPRESSION_LEVEL}";
fi;
if [ -z "${ENCRYPTION}" ]; then
ENCRYPTION="${DEFAULT_ENCRYPTION}";
fi;
if [ -z "${FORCE_CHECK}" ]; then
FORCE_CHECK="${DEFAULT_FORCE_CHECK}";
fi;
if [ -z "${KEEP_LAST}" ]; then
KEEP_LAST="${DEFAULT_KEEP_LAST}";
fi;
if [ -z "${KEEP_HOURS}" ]; then
KEEP_HOURS="${DEFAULT_KEEP_HOURS}";
fi;
if [ -z "${KEEP_DAYS}" ]; then
KEEP_DAYS="${DEFAULT_KEEP_DAYS}";
fi;
if [ -z "${KEEP_WEEKS}" ]; then
KEEP_WEEKS="${DEFAULT_KEEP_WEEKS}";
fi;
if [ -z "${KEEP_MONTHS}" ]; then
KEEP_MONTHS="${DEFAULT_KEEP_MONTHS}";
fi;
if [ -z "${KEEP_YEARS}" ]; then
KEEP_YEARS="${DEFAULT_KEEP_YEARS}";
fi;
# ** SUB LOAD # ** SUB LOAD
# a settings file always end in .settings, replace that with lower case MODULE.settings # a settings file always end in .settings, replace that with lower case MODULE.settings
SETTINGS_FILE_SUB=$(echo "${SETTINGS_FILE}" | sed -e "s/\.settings/\.${MODULE,,}\.settings/"); SETTINGS_FILE_SUB=$(echo "${SETTINGS_FILE}" | sed -e "s/\.settings/\.${MODULE,,}\.settings/");
@@ -288,19 +415,19 @@ if [ -f "${BASE_FOLDER}${SETTINGS_FILE_SUB}" ]; then
if [ ! -z "${SUB_KEEP_WEEKS}" ]; then if [ ! -z "${SUB_KEEP_WEEKS}" ]; then
KEEP_WEEKS=${SUB_KEEP_WEEKS}; KEEP_WEEKS=${SUB_KEEP_WEEKS};
fi; fi;
if [ ! -z "${SUB_KEEP_MONTHS}" ]; then
KEEP_MONTHS=${SUB_KEEP_MONTHS};
fi;
if [ ! -z "${SUB_KEEP_YEARS}" ]; then if [ ! -z "${SUB_KEEP_YEARS}" ]; then
KEEP_YEARS=${SUB_KEEP_YEARS}; KEEP_YEARS=${SUB_KEEP_YEARS};
fi; fi;
if [ ! -z "${SUB_KEEP_LAST}" ]; then
KEEP_LAST=${SUB_KEEP_LAST};
fi;
if [ ! -z "${SUB_KEEP_WITHIN}" ]; then if [ ! -z "${SUB_KEEP_WITHIN}" ]; then
KEEP_WITHIN=${SUB_KEEP_WITHIN}; KEEP_WITHIN=${SUB_KEEP_WITHIN};
fi; fi;
fi; fi;
# add module name to backup file, always # add module name to backup file, always
# except if FILE module and FILE_REPOSITORY_COMPATIBLE="true" # except if FILE module and FILE_REPOSITORY_COMPATIBLE="true"
if ([ "${FILE_REPOSITORY_COMPATIBLE}" = "false" ] && [ "${MODULE,,}" = "file" ]) || [ "${MODULE,,}" != "file" ]; then if [ "${FILE_REPOSITORY_COMPATIBLE}" != "true" ] || [ "${MODULE,,}" != "file" ]; then
BACKUP_FILE=${BACKUP_FILE/.borg/-${MODULE,,}.borg}; BACKUP_FILE=${BACKUP_FILE/.borg/-${MODULE,,}.borg};
fi; fi;
# backup file must be set # backup file must be set
@@ -365,11 +492,13 @@ if [[ -f "${LOG}" && ! -w "${LOG}" ]] || [[ ! -f "${LOG}" && ! -w "${LOG_FOLDER}
fi; fi;
# if ENCRYPTION is empty or not in the valid list fall back to none # if ENCRYPTION is empty or not in the valid list fall back to none
if [ -z "${ENCRYPTION}" ]; then # NOTE This is currently set in default and doesn't need to be set on empty
ENCRYPTION="none"; # only ivalid should be checked
#if [ -z "${ENCRYPTION}" ]; then
# ENCRYPTION="none";
#else #else
# TODO check for invalid encryption string # TODO check for invalid encryption string
fi; #fi;
## FUNCTIONS ## FUNCTIONS

View File

@@ -1,7 +1,7 @@
#!/usr/bin/env bash #!/usr/bin/env bash
MODULE="gitea" MODULE="gitea"
MODULE_VERSION="1.0.0"; MODULE_VERSION="1.1.1";
DIR="${BASH_SOURCE%/*}" DIR="${BASH_SOURCE%/*}"
if [[ ! -d "$DIR" ]]; then DIR="$PWD"; fi if [[ ! -d "$DIR" ]]; then DIR="$PWD"; fi
@@ -35,27 +35,29 @@ if [ -z "${GITEA_CONFIG}" ]; then
fi; fi;
if [ ! -f "${GITEA_BIN}" ]; then if [ ! -f "${GITEA_BIN}" ]; then
echo "[! $(date +'%F %T')] Cannot find gitea binary"; echo "[! $(date +'%F %T')] Cannot find gitea binary";
. "${DIR}/borg.backup.functions.close.sh" 1;
exit 1; exit 1;
fi; fi;
if [ ! -f "${GITEA_CONFIG}" ]; then if [ ! -f "${GITEA_CONFIG}" ]; then
echo "[! $(date +'%F %T')] Cannot find gitea config"; echo "[! $(date +'%F %T')] Cannot find gitea config";
. "${DIR}/borg.backup.functions.close.sh" 1;
exit 1; exit 1;
fi; fi;
# Filename # Filename
FILENAME="gitea.backup.zip"; FILENAME="gitea.backup.zip";
# backup set and prefix # backup set and prefix
BACKUP_SET_NAME="gitea-${BACKUP_SET}"; BACKUP_SET_PREFIX="${MODULE},";
BACKUP_SET_PREFIX="gitea-"; BACKUP_SET_NAME="${ONE_TIME_TAG}${BACKUP_SET_PREFIX}${BACKUP_SET}";
# borg call # borg call
# BORG_CALL=$(echo "${_BORG_CALL}" | sed -e "s/##FILENAME##/${FILENAME}/" | sed -e "s|##REPOSITORY##|${REPOSITORY}|" | sed -e "s/##BACKUP_SET##/${BACKUP_SET}/"); 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}/");
# BORG_PRUNE=$(echo "${_BORG_PRUNE}" | sed -e "s|##REPOSITORY##|${REPOSITORY}|" | sed -e "s/##BACKUP_SET_PREFIX##/${BACKUP_SET_PREFIX}/");
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}/");
echo "--- [git data and database: $(date +'%F %T')] --[${MODULE}]------------------------------------>"; echo "--- [git data and database: $(date +'%F %T')] --[${MODULE}]------------------------------------>";
if [ ${DEBUG} -eq 1 ] || [ ${DRYRUN} -eq 1 ]; then if [ ${DEBUG} -eq 1 ] || [ ${DRYRUN} -eq 1 ]; then
echo "sudo -u ${GIT_USER} ${GITEA_BIN} dump -c ${GITEA_CONFIG} -w ${GITEA_TMP} -L -f - | ${BORG_CALL}"; echo "sudo -u ${GIT_USER} ${GITEA_BIN} dump -c ${GITEA_CONFIG} -w ${GITEA_TMP} -L -f - | ${BORG_CALL}";
echo "${BORG_PRUNE}"; if [ -z "${ONE_TIME_TAG}" ]; then
echo "${BORG_PRUNE}";
fi;
fi; fi;
if [ ${DRYRUN} -eq 0 ]; then if [ ${DRYRUN} -eq 0 ]; then
( (
@@ -69,10 +71,15 @@ if [ ${DRYRUN} -eq 0 ]; then
# this needs to be run in a folder that can be stat by git user # this needs to be run in a folder that can be stat by git user
cd "${GITEA_TMP}"; cd "${GITEA_TMP}";
sudo -u ${GIT_USER} ${GITEA_BIN} dump -c ${GITEA_CONFIG} -w ${GITEA_TMP} -L -f - | ${BORG_CALL}; sudo -u ${GIT_USER} ${GITEA_BIN} dump -c ${GITEA_CONFIG} -w ${GITEA_TMP} -L -f - | ${BORG_CALL};
) ) | sed 's/\x1B\[[0-9;]\{1,\}[A-Za-z]//g' # remove all ESC strings
fi;
if [ -z "${ONE_TIME_TAG}" ]; then
echo "--- [PRUNE : $(date +'%F %T')] --[${MODULE}]------------------------------------>";
echo "Prune repository with keep${KEEP_INFO:1}";
${BORG_PRUNE};
# if this is borg version >1.2 we need to run compact after prune
. "${DIR}/borg.backup.functions.compact.sh";
fi; fi;
echo "Prune repository with keep${KEEP_INFO:1}";
${BORG_PRUNE};
. "${DIR}/borg.backup.functions.close.sh"; . "${DIR}/borg.backup.functions.close.sh";

View File

@@ -10,7 +10,7 @@
# set last edit date + time # set last edit date + time
MODULE="mysql" MODULE="mysql"
MODULE_VERSION="1.0.0"; MODULE_VERSION="1.1.0";
DIR="${BASH_SOURCE%/*}" DIR="${BASH_SOURCE%/*}"
if [[ ! -d "$DIR" ]]; then DIR="$PWD"; fi if [[ ! -d "$DIR" ]]; then DIR="$PWD"; fi
@@ -42,10 +42,12 @@ MYSQL_CMD=${MYSQL_BASE_PATH}'mysql';
# no dump or mysql, bail # no dump or mysql, bail
if [ ! -f "${MYSQL_DUMP}" ]; then if [ ! -f "${MYSQL_DUMP}" ]; then
echo "[! $(date +'%F %T')] mysqldump binary not found"; echo "[! $(date +'%F %T')] mysqldump binary not found";
. "${DIR}/borg.backup.functions.close.sh" 1;
exit 1; exit 1;
fi; fi;
if [ ! -f "${MYSQL_CMD}" ]; then if [ ! -f "${MYSQL_CMD}" ]; then
echo "[! $(date +'%F %T')] mysql binary not found"; echo "[! $(date +'%F %T')] mysql binary not found";
. "${DIR}/borg.backup.functions.close.sh" 1;
exit 1; exit 1;
fi; fi;
# check that the user can actually do, else abort here # check that the user can actually do, else abort here
@@ -54,6 +56,7 @@ _MYSQL_CHECK=$(mysqladmin ${MYSQL_DB_CONFIG_PARAM} ping 2>&1);
_MYSQL_OK=$(echo "${_MYSQL_CHECK}" | grep "is alive"); _MYSQL_OK=$(echo "${_MYSQL_CHECK}" | grep "is alive");
if [ -z "${_MYSQL_OK}" ]; then if [ -z "${_MYSQL_OK}" ]; then
echo "[! $(date +'%F %T')] Current user has no access right to mysql database"; echo "[! $(date +'%F %T')] Current user has no access right to mysql database";
. "${DIR}/borg.backup.functions.close.sh" 1;
exit 1; exit 1;
fi; fi;
# below is for file name only # below is for file name only
@@ -89,35 +92,42 @@ if [ ! -z "${DATABASE_FULL_DUMP}" ]; then
SCHEMA_ONLY='--no-data'; SCHEMA_ONLY='--no-data';
schema_flag='schema'; schema_flag='schema';
fi; fi;
echo "--- [all databases: $(date +'%F %T')] --[${MODULE}]------------------------------------>"; echo "---[BACKUP: all databases: $(date +'%F %T')] --[${MODULE}]------------------------------------>";
# We only do a full backup and not per table backup here # We only do a full backup and not per table backup here
# Filename # Filename
FILENAME="all-${schema_flag}-${DB_TYPE}_${DB_VERSION}_${DB_HOST}_${DB_PORT}.sql" FILENAME="all-${schema_flag}-${DB_TYPE}_${DB_VERSION}_${DB_HOST}_${DB_PORT}.sql"
# backup set: # backup set:
BACKUP_SET_NAME="all-${schema_flag}-${BACKUP_SET}"; BACKUP_SET_PREFIX="${MODULE},all-";
BACKUP_SET_PREFIX="all-"; 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=$(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 "${MYSQL_DUMP} ${MYSQL_DB_CONFIG_PARAM} --all-databases --create-options --add-drop-database --events ${SCHEMA_ONLY} | ${BORG_CALL}"; echo "${MYSQL_DUMP} ${MYSQL_DB_CONFIG_PARAM} --all-databases --create-options --add-drop-database --events ${SCHEMA_ONLY} | ${BORG_CALL}";
echo "${BORG_PRUNE}"; if [ -z "${ONE_TIME_TAG}" ]; then
echo "${BORG_PRUNE}";
fi;
fi; fi;
if [ ${DRYRUN} -eq 0 ]; then if [ ${DRYRUN} -eq 0 ]; then
${MYSQL_DUMP} ${MYSQL_DB_CONFIG_PARAM} --all-databases --create-options --add-drop-database --events ${SCHEMA_ONLY} | ${BORG_CALL}; ${MYSQL_DUMP} ${MYSQL_DB_CONFIG_PARAM} --all-databases --create-options --add-drop-database --events ${SCHEMA_ONLY} | ${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}";
. "${DIR}/borg.backup.functions.close.sh" 1;
exit $_backup_error; exit $_backup_error;
fi; fi;
fi; fi;
echo "Prune repository with keep${KEEP_INFO:1}"; if [ -z "${ONE_TIME_TAG}" ]; then
${BORG_PRUNE}; echo "--- [PRUNE : all databases: $(date +'%F %T')] --[${MODULE}]------------------------------------>";
echo "Prune repository with keep${KEEP_INFO:1}";
${BORG_PRUNE};
fi;
else else
${MYSQL_CMD} ${MYSQL_DB_CONFIG_PARAM} -B -N -e "show databases" | ${MYSQL_CMD} ${MYSQL_DB_CONFIG_PARAM} -B -N -e "show databases" |
while read db; do while read db; do
echo "--- [${db}: $(date +'%F %T')] --[${MODULE}]------------------------------------>"; echo "========[DB: ${db}]========================[${MODULE}]====================================>";
echo "--- [BACKUP: ${db}: $(date +'%F %T')] --[${MODULE}]------------------------------------>";
# exclude checks # exclude checks
include=0; include=0;
if [ -s "${BASE_FOLDER}${INCLUDE_FILE}" ]; then if [ -s "${BASE_FOLDER}${INCLUDE_FILE}" ]; then
@@ -174,8 +184,8 @@ else
# prepare borg calls # prepare borg calls
FILENAME="${db}-${schema_flag}-${DB_TYPE}_${DB_VERSION}_${DB_HOST}_${DB_PORT}.sql" FILENAME="${db}-${schema_flag}-${DB_TYPE}_${DB_VERSION}_${DB_HOST}_${DB_PORT}.sql"
# backup set: # backup set:
BACKUP_SET_NAME="${db}-${schema_flag}-${BACKUP_SET}"; BACKUP_SET_PREFIX="${MODULE},${db}-"
BACKUP_SET_PREFIX="${db}-" 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=$(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}/");
@@ -190,16 +200,25 @@ else
_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}";
. "${DIR}/borg.backup.functions.close.sh" 1;
exit $_backup_error; exit $_backup_error;
fi; fi;
fi; fi;
echo "Prune repository prefixed ${BACKUP_SET_PREFIX} with keep${KEEP_INFO:1}"; if [ -z "${ONE_TIME_TAG}" ]; then
${BORG_PRUNE}; echo "--- [PRUNE : ${db}: $(date +'%F %T')] --[${MODULE}]------------------------------------>";
echo "Prune repository prefixed ${BACKUP_SET_PREFIX} with keep${KEEP_INFO:1}";
${BORG_PRUNE};
fi;
else else
echo "- [E] ${db}"; echo "- [E] ${db}";
fi; fi;
done; done;
fi; fi;
# run compact at the end if not a dry run
if [ -z "${ONE_TIME_TAG}" ]; then
# if this is borg version >1.2 we need to run compact after prune
. "${DIR}/borg.backup.functions.compact.sh";
fi;
. "${DIR}/borg.backup.functions.close.sh"; . "${DIR}/borg.backup.functions.close.sh";

View File

@@ -10,7 +10,7 @@
# set last edit date + time # set last edit date + time
MODULE="pgsql" MODULE="pgsql"
MODULE_VERSION="0.1.0"; MODULE_VERSION="1.2.0";
DIR="${BASH_SOURCE%/*}" DIR="${BASH_SOURCE%/*}"
@@ -22,6 +22,7 @@ if [[ ! -d "$DIR" ]]; then DIR="$PWD"; fi
INCLUDE_FILE="borg.backup.pgsql.include"; INCLUDE_FILE="borg.backup.pgsql.include";
EXCLUDE_FILE="borg.backup.pgsql.exclude"; EXCLUDE_FILE="borg.backup.pgsql.exclude";
SCHEMA_ONLY_FILE="borg.backup.pgsql.schema-only"; SCHEMA_ONLY_FILE="borg.backup.pgsql.schema-only";
DATA_ONLY_FILE="borg.backup.pgsql.data-only";
# init check file # init check file
BACKUP_INIT_CHECK="borg.backup.pgsql.init"; BACKUP_INIT_CHECK="borg.backup.pgsql.init";
@@ -43,6 +44,7 @@ _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
echo "[! $(date +'%F %T')] Cannot get PostgreSQL server version: ${_backup_error}"; echo "[! $(date +'%F %T')] Cannot get PostgreSQL server version: ${_backup_error}";
. "${DIR}/borg.backup.functions.close.sh" 1;
exit $_backup_error; exit $_backup_error;
fi; fi;
@@ -58,6 +60,7 @@ if [ ! -f "${PG_BASE_PATH}${_PATH_PG_VERSION}/bin/psql" ]; then
_PATH_PG_VERSION=$(echo "${PG_VERSION}" | sed -e 's/\.//'); _PATH_PG_VERSION=$(echo "${PG_VERSION}" | sed -e 's/\.//');
if [ ! -f "${PG_BASE_PATH}${_PATH_PG_VERSION}/bin/psql" ]; then if [ ! -f "${PG_BASE_PATH}${_PATH_PG_VERSION}/bin/psql" ]; then
echo "[! $(date +'%F %T')] PostgreSQL not found in any paths"; echo "[! $(date +'%F %T')] PostgreSQL not found in any paths";
. "${DIR}/borg.backup.functions.close.sh" 1;
exit 1; exit 1;
fi; fi;
fi; fi;
@@ -69,14 +72,17 @@ PG_DUMPALL=${PG_PATH}'pg_dumpall';
# check that command are here # check that command are here
if [ ! -f "${PG_PSQL}" ]; then if [ ! -f "${PG_PSQL}" ]; 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;
exit 1; exit 1;
fi; fi;
if [ ! -f "${PG_DUMP}" ]; then if [ ! -f "${PG_DUMP}" ]; 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;
exit 1; exit 1;
fi; fi;
if [ ! -f "${PG_DUMPALL}" ]; then if [ ! -f "${PG_DUMPALL}" ]; 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}";
. "${DIR}/borg.backup.functions.close.sh" 1;
exit 1; exit 1;
fi; fi;
@@ -95,58 +101,70 @@ if [ ! -z "${DATABASE_FULL_DUMP}" ]; then
SCHEMA_ONLY='-s'; SCHEMA_ONLY='-s';
schema_flag='schema'; schema_flag='schema';
fi; fi;
echo "--- [all databases: $(date +'%F %T')] --[${MODULE}]------------------------------------>"; echo "--- [BACKUP: all databases: $(date +'%F %T')] --[${MODULE}]------------------------------------>";
# Filename # Filename
FILENAME-"all.${DB_USER}.NONE.${schema_flag}-${DB_VERSION}_${DB_HOST}_${DB_PORT}.c.sql" FILENAME-"all.${DB_USER}.NONE.${schema_flag}-${DB_VERSION}_${DB_HOST}_${DB_PORT}.c.sql"
# backup set: # backup set:
BACKUP_SET_NAME="all-${schema_flag}-${BACKUP_SET}"; BACKUP_SET_PREFIX="${MODULE},all-";
BACKUP_SET_PREFIX="all-"; 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=$(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_DUMPALL} -U ${DB_USER} ${CONN_DB_HOST} ${CONN_DB_PORT} ${SCHEMA_ONLY} -c | ${BORG_CALL}"; echo "${PG_DUMPALL} -U ${DB_USER} ${CONN_DB_HOST} ${CONN_DB_PORT} ${SCHEMA_ONLY} -c | ${BORG_CALL}";
echo "${BORG_PRUNE}"; if [ -z "${ONE_TIME_TAG}" ]; then
echo "${BORG_PRUNE}";
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} -U ${DB_USER} ${CONN_DB_HOST} ${CONN_DB_PORT} ${SCHEMA_ONLY} -c | ${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}";
. "${DIR}/borg.backup.functions.close.sh" 1;
exit $_backup_error; exit $_backup_error;
fi; fi;
fi; fi;
echo "Prune repository with keep${KEEP_INFO:1}"; if [ -z "${ONE_TIME_TAG}" ]; then
${BORG_PRUNE}; echo "--- [PRUNE : all databases: $(date +'%F %T')] --[${MODULE}]------------------------------------>";
echo "Prune repository with keep${KEEP_INFO:1}";
${BORG_PRUNE};
fi;
else else
# dump globals first # dump globals first
db="pg_globals"; db="pg_globals";
schema_flag="data"; schema_flag="data";
echo "--- [${db}: $(date +'%F %T')] --[${MODULE}]------------------------------------>"; echo "--- [BACKUP: ${db}: $(date +'%F %T')] --[${MODULE}]------------------------------------>";
# Filename # Filename
FILENAME="${db}.${DB_USER}.NONE.${schema_flag}-${DB_VERSION}_${DB_HOST}_${DB_PORT}.c.sql" FILENAME="${db}.${DB_USER}.NONE.${schema_flag}-${DB_VERSION}_${DB_HOST}_${DB_PORT}.c.sql"
# backup set: # backup set:
BACKUP_SET_NAME="${db}-${schema_flag}-${BACKUP_SET}"; BACKUP_SET_PREFIX="${MODULE},${db}-";
BACKUP_SET_PREFIX="${db}-"; 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=$(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_DUMPALL} -U ${DB_USER} ${CONN_DB_HOST} ${CONN_DB_PORT} --globals-only | ${BORG_CALL}"; echo "${PG_DUMPALL} -U ${DB_USER} ${CONN_DB_HOST} ${CONN_DB_PORT} --globals-only | ${BORG_CALL}";
echo "${BORG_PRUNE}"; if [ -z "${ONE_TIME_TAG}" ]; then
echo "${BORG_PRUNE}";
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} -U ${DB_USER} ${CONN_DB_HOST} ${CONN_DB_PORT} --globals-only | ${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}";
. "${DIR}/borg.backup.functions.close.sh" 1;
exit $_backup_error; exit $_backup_error;
fi; fi;
fi; fi;
echo "Prune repository with keep${KEEP_INFO:1}"; if [ -z "${ONE_TIME_TAG}" ]; then
${BORG_PRUNE}; echo "--- [PRUNE : ${db}: $(date +'%F %T')] --[${MODULE}]------------------------------------>";
echo "Prune repository with keep${KEEP_INFO:1}";
${BORG_PRUNE};
fi;
# 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 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
@@ -154,7 +172,8 @@ else
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);
echo "--- [${db}: $(date +'%F %T')] --[${MODULE}]------------------------------------>"; echo "========[DB: ${db}]========================[${MODULE}]====================================>";
echo "--- [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 incl_db; do
@@ -177,9 +196,13 @@ else
fi; fi;
if [ ${include} -eq 1 ] && [ ${exclude} -eq 0 ]; then if [ ${include} -eq 1 ] && [ ${exclude} -eq 0 ]; then
# set dump type # set dump type
SCHEMA_ONLY=''; # empty for all SCHEMA_ONLY='';
schema_flag='data'; # or data schema_flag=''; # schema or data
# 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
SCHEMA_ONLY='';
schema_flag='data';
while read schema_db; do while read schema_db; do
if [ "${db}" = "${schema_db}" ]; then if [ "${db}" = "${schema_db}" ]; then
SCHEMA_ONLY='-s'; SCHEMA_ONLY='-s';
@@ -188,14 +211,31 @@ else
break; break;
fi; fi;
done<"${BASE_FOLDER}${SCHEMA_ONLY_FILE}"; done<"${BASE_FOLDER}${SCHEMA_ONLY_FILE}";
elif [ -s "${BASE_FOLDER}${DATA_ONLY_FILE}" ]; then
# default to schema, unless in data list
SCHEMA_ONLY='-s';
schema_flag='schema';
while read data_db; do
if [ "${db}" = "${data_db}" ]; then
SCHEMA_ONLY='';
schema_flag='data';
# skip out
break;
fi;
done<"${BASE_FOLDER}${DATA_ONLY_FILE}";
fi;
# if nothing is set, default to data
if [ -z "${schema_flag}" ]; then
SCHEMA_ONLY=''
schema_flag="data";
fi; fi;
# 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"
# backup set:
BACKUP_SET_NAME="${db}-${schema_flag}-${BACKUP_SET}";
# PER db either data or schema # PER db either data or schema
BACKUP_SET_PREFIX="${db}-"; BACKUP_SET_PREFIX="${MODULE},${db}-";
# 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
@@ -203,23 +243,34 @@ else
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} -U ${DB_USER} ${CONN_DB_HOST} ${CONN_DB_PORT} -c ${SCHEMA_ONLY} --format=c ${db} | ${BORG_CALL}";
echo "${BORG_PRUNE}"; if [ -z "${ONE_TIME_TAG}" ]; then
echo "${BORG_PRUNE}";
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} -U ${DB_USER} ${CONN_DB_HOST} ${CONN_DB_PORT} -c ${SCHEMA_ONLY} --format=c ${db} | ${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}";
. "${DIR}/borg.backup.functions.close.sh" 1;
exit $_backup_error; exit $_backup_error;
fi; fi;
fi; fi;
echo "Prune repository prefixed ${BACKUP_SET_PREFIX} with keep${KEEP_INFO:1}"; if [ -z "${ONE_TIME_TAG}" ]; then
${BORG_PRUNE}; echo "--- [PRUNE : ${db}: $(date +'%F %T')] --[${MODULE}]------------------------------------>";
echo "Prune repository prefixed ${BACKUP_SET_PREFIX} with keep${KEEP_INFO:1}";
${BORG_PRUNE};
fi;
else else
echo "- [E] ${db}"; echo "- [E] ${db}";
fi; fi;
done; done;
fi; fi;
# run compact at the end if not a dry run
if [ -z "${ONE_TIME_TAG}" ]; then
# if this is borg version >1.2 we need to run compact after prune
. "${DIR}/borg.backup.functions.compact.sh";
fi;
. "${DIR}/borg.backup.functions.close.sh"; . "${DIR}/borg.backup.functions.close.sh";

View File

@@ -3,7 +3,7 @@
# Backup zabbix config and settings only # Backup zabbix config and settings only
MODULE="zabbix" MODULE="zabbix"
MODULE_VERSION="1.0.0"; MODULE_VERSION="1.1.1";
DIR="${BASH_SOURCE%/*}" DIR="${BASH_SOURCE%/*}"
if [[ ! -d "$DIR" ]]; then DIR="$PWD"; fi if [[ ! -d "$DIR" ]]; then DIR="$PWD"; fi
@@ -24,7 +24,8 @@ if [ -z "${ZABBIX_DUMP_BIN}" ]; then
fi; fi;
if [ ! -z "${ZABBIX_CONFIG}" ] && [ ! -f "${ZABBIX_CONFIG}" ]; then if [ ! -z "${ZABBIX_CONFIG}" ] && [ ! -f "${ZABBIX_CONFIG}" ]; then
echo "[! $(date +'%F %T')] Cannot find zabbix config: ${ZABBIX_CONFIG}"; echo "[! $(date +'%F %T')] Cannot find zabbix config: ${ZABBIX_CONFIG}";
exit; . "${DIR}/borg.backup.functions.close.sh" 1;
exit 1;
fi; fi;
if [ -f "${ZABBIX_CONFIG}" ]; then if [ -f "${ZABBIX_CONFIG}" ]; then
OPT_ZABBIX_CONFIG="-z ${ZABBIX_CONFIG}"; OPT_ZABBIX_CONFIG="-z ${ZABBIX_CONFIG}";
@@ -34,10 +35,12 @@ if [ "${ZABBIX_DATABASE}" = "psql" ]; then
fi; fi;
if [ "${ZABBIX_DATABASE}" != "psql" ] && [ "${ZABBIX_DATABASE}" != "mysql" ]; then if [ "${ZABBIX_DATABASE}" != "psql" ] && [ "${ZABBIX_DATABASE}" != "mysql" ]; then
echo "[! $(date +'%F %T')] Zabbix dump must have database set to either psql or mysql"; echo "[! $(date +'%F %T')] Zabbix dump must have database set to either psql or mysql";
. "${DIR}/borg.backup.functions.close.sh" 1;
exit 1; exit 1;
fi; fi;
if [ ! -f "${ZABBIX_DUMP_BIN}" ]; then if [ ! -f "${ZABBIX_DUMP_BIN}" ]; then
echo "[! $(date +'%F %T')] Zabbix dump script could not be found: ${ZABBIX_DUMP_BIN}"; echo "[! $(date +'%F %T')] Zabbix dump script could not be found: ${ZABBIX_DUMP_BIN}";
. "${DIR}/borg.backup.functions.close.sh" 1;
exit 1; exit 1;
fi; fi;
# -i (ignore)/ -f (backup) # -i (ignore)/ -f (backup)
@@ -50,24 +53,34 @@ fi;
# Filename # Filename
FILENAME="zabbix-config.c.sql"; FILENAME="zabbix-config.c.sql";
# backup set: # backup set:
BACKUP_SET="zabbix-settings-${BACKUP_SET}"; BACKUP_SET_PREFIX="${MODULE},settings-";
BACKUP_SET_PREFIX="zabbix-settings-"; BACKUP_SET_NAME="${ONE_TIME_TAG}${BACKUP_SET_PREFIX}${BACKUP_SET}";
# borg call # borg call
BORG_CALL=$(echo "${_BORG_CALL}" | sed -e "s/##FILENAME##/${FILENAME}/" | sed -e "s/##BACKUP_SET##/${BACKUP_SET}/"); BORG_CALL=$(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}/"); BORG_PRUNE=$(echo "${_BORG_PRUNE}" | sed -e "s/##BACKUP_SET_PREFIX##/${BACKUP_SET_PREFIX}/");
# if prefix is emtpy remote "-P" # if prefix is emtpy remote "-P"
if [ -z "${BACKUP_SET_PREFIX}" ]; then if [ -z "${BACKUP_SET_PREFIX}" ]; then
BORG_PRUNE=$(echo "${BORG_PRUNE}" | sed -e 's/-P //'); BORG_PRUNE=$(echo "${BORG_PRUNE}" | sed -e 's/-P //');
fi; fi;
echo "--- [zabbix settings: $(date +'%F %T')] --[${MODULE}]------------------------------------>"; echo "--- [BACKUP: zabbix settings: $(date +'%F %T')] --[${MODULE}]------------------------------------>";
if [ ${DEBUG} -eq 1 ] || [ ${DRYRUN} -eq 1 ]; then if [ ${DEBUG} -eq 1 ] || [ ${DRYRUN} -eq 1 ]; then
echo "${ZABBIX_DUMP_BIN} -t ${ZABBIX_DATABASE} ${OPT_ZABBIX_UNKNOWN_TABLES} ${OPT_ZABBIX_DUMP} ${OPT_ZABBIX_CONFIG} -o - | ${BORG_CALL}" echo "${ZABBIX_DUMP_BIN} -t ${ZABBIX_DATABASE} ${OPT_ZABBIX_UNKNOWN_TABLES} ${OPT_ZABBIX_DUMP} ${OPT_ZABBIX_CONFIG} -o - | ${BORG_CALL}"
echo "${BORG_PRUNE}"; if [ -z "${ONE_TIME_TAG}" ]; then
echo "${BORG_PRUNE}";
fi;
fi; fi;
if [ ${DRYRUN} -eq 0 ]; then if [ ${DRYRUN} -eq 0 ]; then
${ZABBIX_DUMP_BIN} -t ${ZABBIX_DATABASE} ${OPT_ZABBIX_UNKNOWN_TABLES} ${OPT_ZABBIX_DUMP} ${OPT_ZABBIX_CONFIG} -o - | ${BORG_CALL}; ${ZABBIX_DUMP_BIN} -t ${ZABBIX_DATABASE} ${OPT_ZABBIX_UNKNOWN_TABLES} ${OPT_ZABBIX_DUMP} ${OPT_ZABBIX_CONFIG} -o - | ${BORG_CALL};
fi; fi;
echo "Prune repository with keep${KEEP_INFO:1}"; if [ -z "${ONE_TIME_TAG}" ]; then
${BORG_PRUNE}; echo "--- [PRUNE : $(date +'%F %T')] --[${MODULE}]------------------------------------>";
${BORG_PRUNE};
# if this is borg version >1.2 we need to run compact after prune
. "${DIR}/borg.backup.functions.compact.sh";
fi;
. "${DIR}/borg.backup.functions.close.sh";
# __EMD__