2019-01-25 17:28:29 +00:00
#!/usr/bin/env bash
# called before backup
borgwrapper_pre_backup() {
return;
}
# called after backup
borgwrapper_post_backup() {
return;
}
# usage
usage() {
USAGE=$(cat <<EOF
Usage: borgwrapper [CONFIG_FILE (absolute path)]
A script which wraps commonly used functions for borg.
If no CONFIG_FILE is given, HOME/.borgwrapper.conf is used. This fallback option
has to exist or the script will exit.
Configuration can be done in any file and any pre-defined variable can be overwritten.
The following are at least required for the script to work:
- BORGWRAPPER_BACKUP_NAME // [a-z09], should be unique for multiple backups (with the same remote user)
- BORGWRAPPER_BACKUP_FILES // an array of files and directories to backup, e.g. =('/home', '/root')
- BORGWRAPPER_BACKUP_REPOSITORY // trailing slash, add "user@host:/dir/" if remote
The following are optional or have reasonable defaults:
- BORGWRAPPER_BACKUP_PASSWORD='' // the password
- BORGWRAPPER_BACKUP_TIMESTAMP_FORMAT=$(date "+%s")
- BORGWRAPPER_BACKUP_PRUNE=true // prune the repository (cleans old backups; uses BORGWRAPPER_BACKUP_KEEP_IN_DAYS)? false|true
- BORGWRAPPER_BACKUP_KEEP_IN_DAYS=60 // in days, integer only (used for prune)
- BORGWRAPPER_BACKUP_CHECK=true // checks entire repository, this is slow! false|true
- BORGWRAPPER_BACKUP_CHECK_MAX_AGE_IN_SECONDS=604800 // determine when "borg check" has to run by comparing current time with latest run check (determined by last mod time of $BORGWRAPPER_BACKUP_CHECK_FILE). default is 7 days, 0 will always run the check
- BORGWRAPPER_BACKUP_CHECK_FILE="~/.borg-backup-BORGWRAPPER_BACKUP_NAME.check" // used for time comparison
- BORGWRAPPER_BACKUP_LOG=true // log? false|true
- BORGWRAPPER_BACKUP_LOG_PRUNE=true // overwrite old log for each execution? false|true
- BORGWRAPPER_BACKUP_LOG_FILE="~/.borg-backup-BORGWRAPPER_BACKUP_NAME.log" // log file to save output to to
- BORGWRAPPER_BACKUP_NOTIFY_VIA_MAIL=false // send email (BORGWRAPPER_BACKUP_LOG has to be set to true)? false|true
- BORGWRAPPER_BACKUP_NOTIFY_MAIL_ADDRESS="" // mail.rc has to be configured
- BORGWRAPPER_BACKUP_NOTIFY_UI=false // use notify-send for UI notification? false|true
2019-08-11 20:08:25 +00:00
- BORGWRAPPER_BACKUP_COMPRESSION="lz4" // compress repository
- BORGWRAPPER_BACKUP_ENCRYPTION="none" // encrypt repository
2019-01-25 17:28:29 +00:00
Borg specific values can also be overwritten and have reasonable defaults:
- BORGWRAPPER_BORG_BINARY=borg; // defaults to /usr/bin/borg (determined by 'which borg'), adjust to a virtualenv if needed
2019-08-11 20:08:25 +00:00
- BORGWRAPPER_BORG_INIT_PARAMS="--encryption=BORGWRAPPER_BACKUP_ENCRYPTION"; // encryption=none|repokey-blake2|...
- BORGWRAPPER_BORG_CREATE_PARAMS="-v -s -p -C BORGWRAPPER_BACKUP_COMPRESSION";
2019-01-25 17:28:29 +00:00
- BORGWRAPPER_BORG_CHECK_PARAMS="-v";
- BORGWRAPPER_BORG_PRUNE_PARAMS="-v -s -d BORGWRAPPER_BACKUP_KEEP_IN_DAYS";
More information can be found in the docs: https://borgbackup.readthedocs.io
The following functions are executed before and after the backup and can also be overwritten in the config file by redefining them:
- borgwrapper_pre_backup
- borgwrapper_post_backup
You can copy this script to '/usr/local/bin' and use create a custom CONFIG_FILE as user. Examples can be found in '/usr/share/doc/<scriptname>'.
EOF
)
echo "$USAGE";
}
set -e;
2019-08-11 20:08:25 +00:00
# helper functions
2019-01-25 17:28:29 +00:00
source_config() {
local config=$1;
local configFallback=$2;
if [[ ! -f "$config" ]]; then
2019-01-25 18:02:33 +00:00
if [[ ! -f "$configFallback" ]]; then
2019-08-11 20:08:25 +00:00
echo "No config file specified and could not find default in '${configFallback}'!";
2019-01-25 17:28:29 +00:00
echo "";
usage;
exit 1;
else
2019-08-11 20:08:25 +00:00
config=${configFallback};
2019-01-25 17:28:29 +00:00
fi
fi
set -a;
2019-08-11 20:08:25 +00:00
source "${config}";
2019-01-25 17:28:29 +00:00
set +a;
}
2019-08-11 20:08:25 +00:00
apply_defaults() {
[ -z ${BORGWRAPPER_BACKUP_PASSWORD} ] && BORGWRAPPER_BACKUP_PASSWORD='';
[ -z ${BORGWRAPPER_BACKUP_TIMESTAMP_FORMAT} ] && BORGWRAPPER_BACKUP_TIMESTAMP_FORMAT=$(date "+%s");
[ -z ${BORGWRAPPER_BACKUP_PRUNE} ] && BORGWRAPPER_BACKUP_PRUNE=true;
[ -z ${BORGWRAPPER_BACKUP_KEEP_IN_DAYS} ] && BORGWRAPPER_BACKUP_KEEP_IN_DAYS=60;
[ -z ${BORGWRAPPER_BACKUP_CHECK} ] && BORGWRAPPER_BACKUP_CHECK=true;
[ -z ${BORGWRAPPER_BACKUP_CHECK_MAX_AGE_IN_SECONDS} ] && BORGWRAPPER_BACKUP_CHECK_MAX_AGE_IN_SECONDS=604800;
[ -z ${BORGWRAPPER_BACKUP_CHECK_FILE} ] && BORGWRAPPER_BACKUP_CHECK_FILE="$HOME/.borg-backup-${BORGWRAPPER_BACKUP_NAME}.check";
[ -z ${BORGWRAPPER_BACKUP_LOG} ] && BORGWRAPPER_BACKUP_LOG=true;
[ -z ${BORGWRAPPER_BACKUP_LOG_PRUNE} ] && BORGWRAPPER_BACKUP_LOG_PRUNE=true;
[ -z ${BORGWRAPPER_BACKUP_LOG_FILE} ] && BORGWRAPPER_BACKUP_LOG_FILE="$HOME/.borg-backup-${BORGWRAPPER_BACKUP_NAME}.log";
[ -z ${BORGWRAPPER_BACKUP_NOTIFY_VIA_MAIL} ] && BORGWRAPPER_BACKUP_NOTIFY_VIA_MAIL=false;
[ -z ${BORGWRAPPER_BACKUP_NOTIFY_MAIL_ADDRESS} ] && BORGWRAPPER_BACKUP_NOTIFY_MAIL_ADDRESS="";
[ -z ${BORGWRAPPER_BACKUP_NOTIFY_UI} ] && BORGWRAPPER_BACKUP_NOTIFY_UI=false;
[ -z ${BORGWRAPPER_BACKUP_COMPRESSION} ] && BORGWRAPPER_BACKUP_COMPRESSION=lz4;
[ -z ${BORGWRAPPER_BACKUP_ENCRYPTION} ] && BORGWRAPPER_BACKUP_ENCRYPTION=none;
[ -z ${BORGWRAPPER_BORG_BINARY} ] && BORGWRAPPER_BORG_BINARY=$(which borg);
[ -z ${BORGWRAPPER_BORG_INIT_PARAMS} ] && BORGWRAPPER_BORG_INIT_PARAMS="--encryption=${BORGWRAPPER_BACKUP_ENCRYPTION}";
[ -z ${BORGWRAPPER_BORG_CREATE_PARAMS} ] && BORGWRAPPER_BORG_CREATE_PARAMS="-v -s -p -C ${BORGWRAPPER_BACKUP_COMPRESSION}";
[ -z ${BORGWRAPPER_BORG_CHECK_PARAMS} ] && BORGWRAPPER_BORG_CHECK_PARAMS="-v";
[ -z ${BORGWRAPPER_BORG_PRUNE_PARAMS} ] && BORGWRAPPER_BORG_PRUNE_PARAMS="-v -s -d ${BORGWRAPPER_BACKUP_KEEP_IN_DAYS}";
}
# check for config file and use it
source_config "$1" "${HOME}/.borgwrapper.conf";
apply_defaults;
2019-01-25 17:28:29 +00:00
# start and info
2019-08-11 20:08:25 +00:00
echo "Using ${BORGWRAPPER_BORG_BINARY} as binary";
2019-01-25 17:28:29 +00:00
borgwrapper_pre_backup;
# export passphrase if not blank
2019-08-11 20:08:25 +00:00
if [ ! -z "${BORGWRAPPER_BACKUP_PASSWORD}" ]; then
export BORG_PASSPHRASE=${BORGWRAPPER_BACKUP_PASSWORD};
2019-01-25 17:28:29 +00:00
fi
# init hint
echo "Hint: If you haven't, you need to create the borg repository manually before first run if it doesn't exist:";
2019-08-11 20:08:25 +00:00
echo "${BORGWRAPPER_BORG_BINARY} init ${BORGWRAPPER_BORG_INIT_PARAMS} ${BORGWRAPPER_BACKUP_REPOSITORY}${BORGWRAPPER_BACKUP_NAME}";
2019-01-25 17:28:29 +00:00
# notify UI
2019-08-11 20:08:25 +00:00
if [ "${BORGWRAPPER_BACKUP_NOTIFY_UI}" = true ]; then
notify-send "Starting backup" ${BORGWRAPPER_BACKUP_REPOSITORY}${BORGWRAPPER_BACKUP_NAME}::${BORGWRAPPER_BACKUP_TIMESTAMP_FORMAT};
2019-01-25 17:28:29 +00:00
fi
# create
2019-08-11 20:08:25 +00:00
${BORGWRAPPER_BORG_BINARY} create ${BORGWRAPPER_BORG_CREATE_PARAMS} ${BORGWRAPPER_BACKUP_REPOSITORY}${BORGWRAPPER_BACKUP_NAME}::${BORGWRAPPER_BACKUP_TIMESTAMP_FORMAT} "${BORGWRAPPER_BACKUP_FILES[@]}";
2019-01-25 17:28:29 +00:00
# check
2019-08-11 20:08:25 +00:00
if [ "${BORGWRAPPER_BACKUP_CHECK}" = true ]; then
2019-01-25 17:28:29 +00:00
# use for first time creation
doCheck=false
2019-08-11 20:08:25 +00:00
if [ ! -f "${BORGWRAPPER_BACKUP_CHECK_FILE}" ]; then
touch ${BORGWRAPPER_BACKUP_CHECK_FILE}
2019-01-25 17:28:29 +00:00
doCheck=true
fi
# compare date
2019-08-11 20:08:25 +00:00
lastMod=$(date -r ${BORGWRAPPER_BACKUP_CHECK_FILE} +%s)
age=$((${BORGWRAPPER_BACKUP_TIMESTAMP_FORMAT} - ${lastMod}))
2019-01-25 17:28:29 +00:00
2019-08-11 20:08:25 +00:00
if [ "$age" -gt "${BORGWRAPPER_BACKUP_CHECK_MAX_AGE_IN_SECONDS}" ]; then
2019-01-25 17:28:29 +00:00
doCheck=true
fi
if [ "$doCheck" = true ]; then
2019-08-11 20:08:25 +00:00
${BORGWRAPPER_BORG_BINARY} check ${BORGWRAPPER_BORG_CHECK_PARAMS} ${BORGWRAPPER_BACKUP_REPOSITORY}${BORGWRAPPER_BACKUP_NAME};
touch ${BORGWRAPPER_BACKUP_CHECK_FILE}
2019-01-25 17:28:29 +00:00
fi
fi
# prune
2019-08-11 20:08:25 +00:00
if [ "${BORGWRAPPER_BACKUP_PRUNE}" = true ]; then
${BORGWRAPPER_BORG_BINARY} prune ${BORGWRAPPER_BORG_PRUNE_PARAMS} ${BORGWRAPPER_BACKUP_REPOSITORY}${BORGWRAPPER_BACKUP_NAME};
2019-01-25 17:28:29 +00:00
fi
# log
2019-08-11 20:08:25 +00:00
if [ "${BORGWRAPPER_BACKUP_LOG}" = true ]; then
2019-01-25 17:28:29 +00:00
2019-08-11 20:08:25 +00:00
if [ "${BORGWRAPPER_BACKUP_LOG_PRUNE}" = true ] && [ -f "${BORGWRAPPER_BACKUP_LOG_FILE}" ]; then
rm ${BORGWRAPPER_BACKUP_LOG_FILE};
2019-01-25 17:28:29 +00:00
fi
2019-08-11 20:08:25 +00:00
touch ${BORGWRAPPER_BACKUP_LOG_FILE};
${BORGWRAPPER_BORG_BINARY} list -v ${BORGWRAPPER_BACKUP_REPOSITORY}${BORGWRAPPER_BACKUP_NAME} >> ${BORGWRAPPER_BACKUP_LOG_FILE};
echo "---" >> ${BORGWRAPPER_BACKUP_LOG_FILE};
${BORGWRAPPER_BORG_BINARY} info ${BORGWRAPPER_BACKUP_REPOSITORY}${BORGWRAPPER_BACKUP_NAME}::${BORGWRAPPER_BACKUP_TIMESTAMP_FORMAT} >> ${BORGWRAPPER_BACKUP_LOG_FILE};
2019-01-25 17:28:29 +00:00
2019-08-11 20:08:25 +00:00
if [ "${BORGWRAPPER_BACKUP_NOTIFY_VIA_MAIL}" = true ]; then
cat ${BORGWRAPPER_BACKUP_LOG_FILE}|mailx -Ssendwait -s "[borgwrapper ${BORGWRAPPER_BACKUP_NAME}]" ${BORGWRAPPER_BACKUP_NOTIFY_MAIL_ADDRESS};
2019-01-25 17:28:29 +00:00
fi
fi
# notify UI
2019-08-11 20:08:25 +00:00
if [ "${BORGWRAPPER_BACKUP_NOTIFY_UI}" = true ]; then
notify-send "Finished backup" ${BORGWRAPPER_BACKUP_REPOSITORY}${BORGWRAPPER_BACKUP_NAME}::${BORGWRAPPER_BACKUP_TIMESTAMP_FORMAT};
2019-01-25 17:28:29 +00:00
fi
2019-08-11 20:08:25 +00:00
borgwrapper_post_backup;