Improve new restic scripts and remove resticwrapper, borgwrapper; provide a PKGBUILD for ArchLinux

This commit is contained in:
Alexander Schäferdiek 2022-06-13 02:21:33 +02:00
parent da266c680b
commit 287fa053f5
18 changed files with 58 additions and 564 deletions

View file

@ -1,22 +1,31 @@
# README # README
A collection of scripts and systemd services which might be useful for servers. A collection of scripts and systemd services which might be useful.
After you pulled, use `./sync` and pick an action which should be self-explaining. Use at your own risk.
## Installation
1. After you pulled, use `./sync` and pick an action which should be self-explaining.
2. Alternatively, build a `pacman` package for ArchLinux via `makepkg -csi` inside the `dist/` folder.
## Usage
Services and scripts don't depend on each other but have hints that they can be Services and scripts don't depend on each other but have hints that they can be
combined (out-commented line in service files for `systemd_failure_notify@.service` combined (out-commented line in service files for `systemd_failure_notify@.service`
for example). for example).
Use at your own risk. Examples are given inside `usr/share/doc/`.
## User network-online.target ## FAQ
### User cannot use network-online.target
By default, no user unit can depend on system events like `network-online.target`. By default, no user unit can depend on system events like `network-online.target`.
To enable this, you need to link the proper `.target` which you like to use inside To enable this, you need to link the proper `.target` which you like to use inside
the user service before. the user service before.
``` ```shell
systemctl --user link /usr/lib/systemd/system/network-online.target systemctl --user link /usr/lib/systemd/system/network-online.target
``` ```

2
dist/.gitignore vendored Normal file
View file

@ -0,0 +1,2 @@
dotfiles-system-git
*.zst

22
dist/PKGBUILD vendored Normal file
View file

@ -0,0 +1,22 @@
pkgname=dotfiles-system-git
_pkgname="dotfiles-system"
pkgver=r81.da266c6
pkgrel=1
pkgdesc="Common system helper scripts"
arch=('any')
url="https://git.myservermanager.com/alexander.schaeferdiek/dotfiles-system"
makedepends=('git')
license=('GPL')
source=("${pkgname}::git+https://git.myservermanager.com/alexander.schaeferdiek/dotfiles-system.git")
sha256sums=('SKIP')
pkgver() {
cd ${pkgname}
printf "r%s.%s" "$(git rev-list --count HEAD)" "$(git rev-parse --short HEAD)"
}
package() {
cd "${srcdir}/${pkgname}"
cp -r etc/ "${pkgdir}/etc"
cp -r usr/ "${pkgdir}/usr"
}

View file

@ -10,6 +10,8 @@ Type=oneshot
ExecStart=sh %h/.config/restic/%I-create.sh ExecStart=sh %h/.config/restic/%I-create.sh
Environment="PATH=/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:%h/.bin" Environment="PATH=/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:%h/.bin"
Environment="SSH_AUTH_SOCK=/run/user/%u/keyring/ssh" Environment="SSH_AUTH_SOCK=/run/user/%u/keyring/ssh"
Environment="RESTIC_FILE_INCLUDE=%h/.config/restic/%I.include"
Environment="RESTIC_FILE_EXCLUDE=%h/.config/restic/%I.exclude"
EnvironmentFile=%h/.config/restic/%I.env EnvironmentFile=%h/.config/restic/%I.env
[Install] [Install]

View file

@ -1,13 +0,0 @@
[Unit]
Description=Run borgwrapper
#OnFailure=systemd_failure_notify@%n.service
[Service]
Type=oneshot
ExecStart=borgwrapper
#ExecStart=borgwrapper /home/myUser/borgwrapper-custom.conf
#Environment="PATH=/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/home/myUser/.customBinaryPathWithBorgSymlinkForVirtualenv"
#Environment="SSH_AUTH_SOCK=/run/user/myUserId/keyring/ssh"
[Install]
WantedBy=default.target

View file

@ -1,9 +0,0 @@
[Unit]
Description=Run borgwrapper
[Timer]
OnCalendar=20:00
Persistent=false
[Install]
WantedBy=timers.target

View file

@ -10,6 +10,8 @@ Type=oneshot
ExecStart=sh %h/.config/restic/%I-create.sh ExecStart=sh %h/.config/restic/%I-create.sh
Environment="PATH=/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:%h/.bin" Environment="PATH=/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:%h/.bin"
Environment="SSH_AUTH_SOCK=/run/user/%u/keyring/ssh" Environment="SSH_AUTH_SOCK=/run/user/%u/keyring/ssh"
Environment="RESTIC_FILE_INCLUDE=%h/.config/restic/%I.include"
Environment="RESTIC_FILE_EXCLUDE=%h/.config/restic/%I.exclude"
EnvironmentFile=%h/.config/restic/%I.env EnvironmentFile=%h/.config/restic/%I.env
[Install] [Install]

View file

@ -1,15 +0,0 @@
[Unit]
Description=Run resticwrapper
OnFailure=systemd_failure_notify@%n.service
Wants=network-online.target
After=network-online.target
Requires=network-online.target
[Service]
Type=oneshot
ExecStart=resticwrapper
Environment="PATH=/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:%h/.bin"
Environment="SSH_AUTH_SOCK=/run/user/%u/keyring/ssh"
[Install]
WantedBy=multi-user.target

View file

@ -1,9 +0,0 @@
[Unit]
Description=Run resticwrapper
[Timer]
OnCalendar=23:00
Persistent=false
[Install]
WantedBy=timers.target

View file

@ -1,221 +0,0 @@
#!/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 the most common use case for borg: creating a backup and sending a notification.
If no CONFIG_FILE is given, \$HOME/.borgwrapper.conf is used. This fallback option
has to exist if no other CONFIG_FILE exists. Otherwise the script exits.
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 if needed
- 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="~/.borgwrapper-\$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="~/.borgwrapper-\$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
- BORGWRAPPER_BACKUP_COMPRESSION="lz4" // compress repository
- BORGWRAPPER_BACKUP_ENCRYPTION="none" // encrypt repository
Borg specific values can also be overwritten and have reasonable defaults:
- BORG_BINARY=borg; // defaults to /usr/bin/borg (determined by 'which borg'), adjust to a virtualenv if needed
- BORGWRAPPER_BORG_INIT_PARAMS="init --encryption=\$BORGWRAPPER_BACKUP_ENCRYPTION"; // encryption=none|repokey-blake2|...
- BORGWRAPPER_BORG_CREATE_PARAMS="create -v -s -p -C \$BORGWRAPPER_BACKUP_COMPRESSION";
- BORGWRAPPER_BORG_CHECK_PARAMS="check -v";
- BORGWRAPPER_BORG_PRUNE_PARAMS="prune -v -s -d \$BORGWRAPPER_BACKUP_KEEP_IN_DAYS";
- BORGWRAPPER_BORG_LIST_PARAMS="list -v";
- BORGWRAPPER_BORG_INFO_PARAMS="info";
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;
# helper functions
source_config() {
local config=$1;
local configFallback=$2;
if [[ ! -f "$config" ]]; then
if [[ ! -f "$configFallback" ]]; then
echo "No config file specified and could not find default in '${configFallback}'!";
echo "";
usage;
exit 1;
else
config=${configFallback};
fi
fi
set -a;
source "${config}";
set +a;
}
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/.borgwrapper-${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/.borgwrapper-${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=none;
[[ -z ${BORGWRAPPER_BACKUP_ENCRYPTION} ]] && BORGWRAPPER_BACKUP_ENCRYPTION=none;
[[ -z ${BORG_BINARY} ]] && BORG_BINARY=$(which borg);
[[ -z ${BORGWRAPPER_BORG_INIT_PARAMS} ]] && BORGWRAPPER_BORG_INIT_PARAMS="init --encryption=${BORGWRAPPER_BACKUP_ENCRYPTION}";
[[ -z ${BORGWRAPPER_BORG_CREATE_PARAMS} ]] && BORGWRAPPER_BORG_CREATE_PARAMS="create -v -s -p -C ${BORGWRAPPER_BACKUP_COMPRESSION}";
[[ -z ${BORGWRAPPER_BORG_CHECK_PARAMS} ]] && BORGWRAPPER_BORG_CHECK_PARAMS="check -v";
[[ -z ${BORGWRAPPER_BORG_PRUNE_PARAMS} ]] && BORGWRAPPER_BORG_PRUNE_PARAMS="prune -v -s -d ${BORGWRAPPER_BACKUP_KEEP_IN_DAYS}";
[[ -z ${BORGWRAPPER_BORG_LIST_PARAMS} ]] && BORGWRAPPER_BORG_LIST_PARAMS="list -v";
[[ -z ${BORGWRAPPER_BORG_INFO_PARAMS} ]] && BORGWRAPPER_BORG_INFO_PARAMS="info";
}
check_required() {
if [[ -z ${BORGWRAPPER_BACKUP_REPOSITORY} ]]; then
echo "BORGWRAPPER_BACKUP_REPOSITORY is required"
exit 1;
fi
if [[ -z ${BORGWRAPPER_BACKUP_NAME} ]]; then
echo "BORGWRAPPER_BACKUP_NAME is required"
exit 1;
fi
type ${BORG_BINARY} >/dev/null 2>&1 || { echo >&2 "Require '${BORG_BINARY}' (binary) but it's not installed. Aborting."; exit 1; }
}
# define wrapper functions
backup() {
echo "Using ${BORG_BINARY} as binary";
borgwrapper_pre_backup;
if [ ! -z "${BORGWRAPPER_BACKUP_PASSWORD}" ]; then
export BORG_PASSPHRASE=${BORGWRAPPER_BACKUP_PASSWORD};
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:";
echo "${BORG_BINARY} ${BORGWRAPPER_BORG_INIT_PARAMS} ${BORGWRAPPER_BACKUP_REPOSITORY}${BORGWRAPPER_BACKUP_NAME}";
# create
${BORG_BINARY} ${BORGWRAPPER_BORG_CREATE_PARAMS} ${BORGWRAPPER_BACKUP_REPOSITORY}${BORGWRAPPER_BACKUP_NAME}::${BORGWRAPPER_BACKUP_TIMESTAMP_FORMAT} "${BORGWRAPPER_BACKUP_FILES[@]}";
# notify UI
if [ "${BORGWRAPPER_BACKUP_NOTIFY_UI}" = true ]; then
notify-send "Started backup" ${BORGWRAPPER_BACKUP_REPOSITORY}${BORGWRAPPER_BACKUP_NAME}::${BORGWRAPPER_BACKUP_TIMESTAMP_FORMAT};
fi
# check
if [ "${BORGWRAPPER_BACKUP_CHECK}" = true ]; then
# use for first time creation
doCheck=false
if [ ! -f "${BORGWRAPPER_BACKUP_CHECK_FILE}" ]; then
touch ${BORGWRAPPER_BACKUP_CHECK_FILE}
doCheck=true
fi
# compare date
lastMod=$(date -r ${BORGWRAPPER_BACKUP_CHECK_FILE} +%s)
age=$((${BORGWRAPPER_BACKUP_TIMESTAMP_FORMAT} - ${lastMod}))
if [ "$age" -gt "${BORGWRAPPER_BACKUP_CHECK_MAX_AGE_IN_SECONDS}" ]; then
doCheck=true
fi
if [ "$doCheck" = true ]; then
${BORG_BINARY} ${BORGWRAPPER_BORG_CHECK_PARAMS} ${BORGWRAPPER_BACKUP_REPOSITORY}${BORGWRAPPER_BACKUP_NAME};
touch ${BORGWRAPPER_BACKUP_CHECK_FILE}
fi
fi
# prune
if [ "${BORGWRAPPER_BACKUP_PRUNE}" = true ]; then
${BORG_BINARY} ${BORGWRAPPER_BORG_PRUNE_PARAMS} ${BORGWRAPPER_BACKUP_REPOSITORY}${BORGWRAPPER_BACKUP_NAME};
fi
# log
if [ "${BORGWRAPPER_BACKUP_LOG}" = true ]; then
if [ "${BORGWRAPPER_BACKUP_LOG_PRUNE}" = true ] && [ -f "${BORGWRAPPER_BACKUP_LOG_FILE}" ]; then
rm ${BORGWRAPPER_BACKUP_LOG_FILE};
fi
touch ${BORGWRAPPER_BACKUP_LOG_FILE};
${BORG_BINARY} ${BORGWRAPPER_BORG_LIST_PARAMS} ${BORGWRAPPER_BACKUP_REPOSITORY}${BORGWRAPPER_BACKUP_NAME} >> ${BORGWRAPPER_BACKUP_LOG_FILE};
echo "---" >> ${BORGWRAPPER_BACKUP_LOG_FILE};
${BORG_BINARY} ${BORGWRAPPER_BORG_INFO_PARAMS} ${BORGWRAPPER_BACKUP_REPOSITORY}${BORGWRAPPER_BACKUP_NAME}::${BORGWRAPPER_BACKUP_TIMESTAMP_FORMAT} >> ${BORGWRAPPER_BACKUP_LOG_FILE};
if [ "${BORGWRAPPER_BACKUP_NOTIFY_VIA_MAIL}" = true ]; then
local hostname=$(hostname)
cat ${BORGWRAPPER_BACKUP_LOG_FILE}|mailx -Ssendwait -s "[borgwrapper on ${hostname}] ${BORGWRAPPER_BACKUP_REPOSITORY}${BORGWRAPPER_BACKUP_NAME}::${BORGWRAPPER_BACKUP_TIMESTAMP_FORMAT} finished" ${BORGWRAPPER_BACKUP_NOTIFY_MAIL_ADDRESS};
fi
fi
# notify UI
if [ "${BORGWRAPPER_BACKUP_NOTIFY_UI}" = true ]; then
notify-send "Finished backup" ${BORGWRAPPER_BACKUP_REPOSITORY}${BORGWRAPPER_BACKUP_NAME}::${BORGWRAPPER_BACKUP_TIMESTAMP_FORMAT};
fi
borgwrapper_post_backup;
}
# check requirements
CONFIG_FILE="$1";
FALLBACK_CONFIG_FILE="${HOME}/.borgwrapper.conf";
source_config "${CONFIG_FILE}" "${FALLBACK_CONFIG_FILE}";
apply_defaults;
check_required;
COMMAND="backup"
case "$COMMAND" in
backup)
backup;
;;
*)
echo "Unsupported command or no command given" >&2
usage;
exit 1
;;
esac

View file

@ -1,225 +0,0 @@
#!/usr/bin/env bash
# called before backup
resticwrapper_pre_backup() {
return;
}
# called after backup
resticwrapper_post_backup() {
return;
}
# usage
usage() {
USAGE=$(cat <<EOF
Usage: resticwrapper [CONFIG_FILE (absolute path)]
A script which wraps the most common use case for restic: creating a backup and sending a notification.
If no CONFIG_FILE is given, \$HOME/.resticwrapper.conf is used. This fallback option
has to exist if no other CONFIG_FILE exists. Otherwise the script exits.
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:
- RESTICWRAPPER_BACKUP_NAME // [a-z09], should be unique for multiple backups (with the same remote user)
- RESTICWRAPPER_BACKUP_FILES // an array of files and directories to backup, e.g. =('/home', '/root')
- RESTICWRAPPER_BACKUP_REPOSITORY // trailing slash, add "user@host:/dir/" if remote
The following are optional or have reasonable defaults:
- RESTICWRAPPER_BACKUP_PASSWORD='' // the password if needed
- RESTICWRAPPER_BACKUP_PASSWORD_FILE='' // a password file if needed
- RESTICWRAPPER_BACKUP_PRUNE=true // prune the repository (cleans old backups; uses \$RESTICWRAPPER_BACKUP_KEEP_IN_DAYS)? false|true
- RESTICWRAPPER_BACKUP_KEEP_IN_DAYS=60 // in days, integer only (used for prune)
- RESTICWRAPPER_BACKUP_CHECK=true // checks entire repository, this is slow! false|true
- RESTICWRAPPER_BACKUP_CHECK_MAX_AGE_IN_SECONDS=604800 // determine when "restic check" has to run by comparing current time with latest run check (determined by last mod time of \$RESTICWRAPPER_BACKUP_CHECK_FILE). default is 7 days, 0 will always run the check
- RESTICWRAPPER_BACKUP_CHECK_FILE="~/.resticwrapper-\$RESTICWRAPPER_BACKUP_NAME.check" // used for time comparison
- RESTICWRAPPER_BACKUP_LOG=true // log? false|true
- RESTICWRAPPER_BACKUP_LOG_PRUNE=true // overwrite old log for each execution? false|true
- RESTICWRAPPER_BACKUP_LOG_FILE="~/.resticwrapper-\$RESTICWRAPPER_BACKUP_NAME.log" // log file to save output to to
- RESTICWRAPPER_BACKUP_NOTIFY_VIA_MAIL=false // send email (\$RESTICWRAPPER_BACKUP_LOG has to be set to true)? false|true
- RESTICWRAPPER_BACKUP_NOTIFY_MAIL_ADDRESS="" // mail.rc has to be configured
- RESTICWRAPPER_BACKUP_NOTIFY_UI=false // use notify-send for UI notification? false|true
Borg specific values can also be overwritten and have reasonable defaults:
- RESTIC_BINARY=restic; // defaults to /usr/bin/restic (determined by 'which restic'), adjust to a virtualenv if needed
- RESTICWRAPPER_RESTIC_INIT_PARAMS="init -r=\${RESTICWRAPPER_BACKUP_REPOSITORY}\${RESTICWRAPPER_BACKUP_NAME}";
- RESTICWRAPPER_RESTIC_CREATE_PARAMS="backup --verbose";
- RESTICWRAPPER_RESTIC_CHECK_PARAMS="check";
- RESTICWRAPPER_RESTIC_PRUNE_PARAMS="forget --prune --keep-within 0y0m\${RESTICWRAPPER_BACKUP_KEEP_IN_DAYS}d0h";
- RESTICWRAPPER_RESTIC_LIST_PARAMS="snapshots";
- RESTICWRAPPER_RESTIC_INFO_PARAMS="stats";
More information can be found in the docs: https://restic.readthedocs.io
The following functions are executed before and after the backup and can also be overwritten in the config file by redefining them:
- resticwrapper_pre_backup
- resticwrapper_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;
# helper functions
source_config() {
local config=$1;
local configFallback=$2;
if [[ ! -f "$config" ]]; then
if [[ ! -f "$configFallback" ]]; then
echo "No config file specified and could not find default in '${configFallback}'!";
echo "";
usage;
exit 1;
else
config=${configFallback};
fi
fi
set -a;
source "${config}";
set +a;
}
apply_defaults() {
[[ -z ${RESTICWRAPPER_BACKUP_PASSWORD} ]] && RESTICWRAPPER_BACKUP_PASSWORD='';
[[ -z ${RESTICWRAPPER_BACKUP_PASSWORD_FILE} ]] && RESTICWRAPPER_BACKUP_PASSWORD_FILE='';
[[ -z ${RESTICWRAPPER_BACKUP_PRUNE} ]] && RESTICWRAPPER_BACKUP_PRUNE=true;
[[ -z ${RESTICWRAPPER_BACKUP_KEEP_IN_DAYS} ]] && RESTICWRAPPER_BACKUP_KEEP_IN_DAYS=60;
[[ -z ${RESTICWRAPPER_BACKUP_CHECK} ]] && RESTICWRAPPER_BACKUP_CHECK=true;
[[ -z ${RESTICWRAPPER_BACKUP_CHECK_MAX_AGE_IN_SECONDS} ]] && RESTICWRAPPER_BACKUP_CHECK_MAX_AGE_IN_SECONDS=604800;
[[ -z ${RESTICWRAPPER_BACKUP_CHECK_FILE} ]] && RESTICWRAPPER_BACKUP_CHECK_FILE="$HOME/.resticwrapper-${RESTICWRAPPER_BACKUP_NAME}.check";
[[ -z ${RESTICWRAPPER_BACKUP_LOG} ]] && RESTICWRAPPER_BACKUP_LOG=true;
[[ -z ${RESTICWRAPPER_BACKUP_LOG_PRUNE} ]] && RESTICWRAPPER_BACKUP_LOG_PRUNE=true;
[[ -z ${RESTICWRAPPER_BACKUP_LOG_FILE} ]] && RESTICWRAPPER_BACKUP_LOG_FILE="$HOME/.resticwrapper-${RESTICWRAPPER_BACKUP_NAME}.log";
[[ -z ${RESTICWRAPPER_BACKUP_NOTIFY_VIA_MAIL} ]] && RESTICWRAPPER_BACKUP_NOTIFY_VIA_MAIL=false;
[[ -z ${RESTICWRAPPER_BACKUP_NOTIFY_MAIL_ADDRESS} ]] && RESTICWRAPPER_BACKUP_NOTIFY_MAIL_ADDRESS="";
[[ -z ${RESTICWRAPPER_BACKUP_NOTIFY_UI} ]] && RESTICWRAPPER_BACKUP_NOTIFY_UI=false;
[[ -z ${RESTIC_BINARY} ]] && RESTIC_BINARY=$(which restic);
[[ -z ${RESTICWRAPPER_RESTIC_INIT_PARAMS} ]] && RESTICWRAPPER_RESTIC_INIT_PARAMS="init -r ${RESTIC_REPOSITORY}";
[[ -z ${RESTICWRAPPER_RESTIC_CREATE_PARAMS} ]] && RESTICWRAPPER_RESTIC_CREATE_PARAMS="backup --verbose";
[[ -z ${RESTICWRAPPER_RESTIC_CHECK_PARAMS} ]] && RESTICWRAPPER_RESTIC_CHECK_PARAMS="check";
[[ -z ${RESTICWRAPPER_RESTIC_PRUNE_PARAMS} ]] && RESTICWRAPPER_RESTIC_PRUNE_PARAMS="forget --prune --keep-within 0y0m${RESTICWRAPPER_BACKUP_KEEP_IN_DAYS}d0h";
[[ -z ${RESTICWRAPPER_RESTIC_LIST_PARAMS} ]] && RESTICWRAPPER_RESTIC_LIST_PARAMS="snapshots";
[[ -z ${RESTICWRAPPER_RESTIC_INFO_PARAMS} ]] && RESTICWRAPPER_RESTIC_INFO_PARAMS="stats";
}
check_required() {
if [[ -z ${RESTICWRAPPER_BACKUP_REPOSITORY} ]]; then
echo "RESTICWRAPPER_BACKUP_REPOSITORY is required"
exit 1;
fi
if [[ -z ${RESTICWRAPPER_BACKUP_NAME} ]]; then
echo "RESTICWRAPPER_BACKUP_NAME is required"
exit 1;
fi
type ${RESTIC_BINARY} >/dev/null 2>&1 || { echo >&2 "Require '${RESTIC_BINARY}' (binary) but it's not installed. Aborting."; exit 1; }
}
# define wrapper functions
backup() {
echo "Using ${RESTIC_BINARY} as binary";
resticwrapper_pre_backup;
set -a;
RESTIC_REPOSITORY="${RESTICWRAPPER_BACKUP_REPOSITORY}${RESTICWRAPPER_BACKUP_NAME}";
set +a;
if [ ! -z "${RESTICWRAPPER_BACKUP_PASSWORD}" ]; then
export RESTIC_PASSWORD=${RESTICWRAPPER_BACKUP_PASSWORD};
fi
if [ ! -z "${RESTICWRAPPER_BACKUP_PASSWORD_FILE}" ]; then
export RESTIC_PASSWORD_FILE=${RESTICWRAPPER_BACKUP_PASSWORD};
fi
# init hint
echo "Hint: If you haven't, you need to create the restic repository manually before first run if it doesn't exist:";
echo "${RESTIC_BINARY} ${RESTICWRAPPER_RESTIC_INIT_PARAMS} ${RESTICWRAPPER_BACKUP_REPOSITORY}${RESTICWRAPPER_BACKUP_NAME}";
# create
${RESTIC_BINARY} ${RESTICWRAPPER_RESTIC_CREATE_PARAMS} "${RESTICWRAPPER_BACKUP_FILES[@]}"
# notify UI
if [ "${RESTICWRAPPER_BACKUP_NOTIFY_UI}" = true ]; then
notify-send "Started backup" ${RESTIC_REPOSITORY};
fi
# check
if [ "${RESTICWRAPPER_BACKUP_CHECK}" = true ]; then
# use for first time creation
doCheck=false
if [ ! -f "${RESTICWRAPPER_BACKUP_CHECK_FILE}" ]; then
touch ${RESTICWRAPPER_BACKUP_CHECK_FILE}
doCheck=true
fi
# compare date
lastMod=$(date -r ${RESTICWRAPPER_BACKUP_CHECK_FILE} +%s)
age=$(($(date "+%s") - ${lastMod}))
if [ "$age" -gt "${RESTICWRAPPER_BACKUP_CHECK_MAX_AGE_IN_SECONDS}" ]; then
doCheck=true
fi
if [ "$doCheck" = true ]; then
${RESTIC_BINARY} ${RESTICWRAPPER_RESTIC_CHECK_PARAMS};
touch ${RESTICWRAPPER_BACKUP_CHECK_FILE}
fi
fi
# prune
if [ "${RESTICWRAPPER_BACKUP_PRUNE}" = true ]; then
${RESTIC_BINARY} ${RESTICWRAPPER_RESTIC_PRUNE_PARAMS};
fi
# log
if [ "${RESTICWRAPPER_BACKUP_LOG}" = true ]; then
if [ "${RESTICWRAPPER_BACKUP_LOG_PRUNE}" = true ] && [ -f "${RESTICWRAPPER_BACKUP_LOG_FILE}" ]; then
rm ${RESTICWRAPPER_BACKUP_LOG_FILE};
fi
touch ${RESTICWRAPPER_BACKUP_LOG_FILE};
${RESTIC_BINARY} ${RESTICWRAPPER_RESTIC_LIST_PARAMS} >> ${RESTICWRAPPER_BACKUP_LOG_FILE};
echo "---" >> ${RESTICWRAPPER_BACKUP_LOG_FILE};
${RESTIC_BINARY} ${RESTICWRAPPER_RESTIC_INFO_PARAMS} >> ${RESTICWRAPPER_BACKUP_LOG_FILE};
if [ "${RESTICWRAPPER_BACKUP_NOTIFY_VIA_MAIL}" = true ]; then
local hostname=$(hostname)
cat ${RESTICWRAPPER_BACKUP_LOG_FILE}|mailx -Ssendwait -s "[resticwrapper on ${hostname} for ${RESTICWRAPPER_BACKUP_NAME}]" ${RESTICWRAPPER_BACKUP_NOTIFY_MAIL_ADDRESS};
fi
fi
# notify UI
if [ "${RESTICWRAPPER_BACKUP_NOTIFY_UI}" = true ]; then
notify-send "Finished backup" ${RESTIC_REPOSITORY};
fi
resticwrapper_post_backup;
}
# check requirements
CONFIG_FILE="$1";
FALLBACK_CONFIG_FILE="${HOME}/.resticwrapper.conf";
source_config "${CONFIG_FILE}" "${FALLBACK_CONFIG_FILE}";
apply_defaults;
check_required;
COMMAND="backup"
case "$COMMAND" in
backup)
backup;
;;
*)
echo "Unsupported command or no command given" >&2
usage;
exit 1
;;
esac

View file

@ -1,15 +0,0 @@
#!/usr/bin/env bash
BORGWRAPPER_BACKUP_NAME="backup-name"
BORGWRAPPER_BACKUP_REPOSITORY="/mnt/myBackups/"
BORGWRAPPER_BACKUP_FILES=(\
'/etc/' \
'$HOME/' \
)
borgwrapper_pre_backup() {
return;
}
borgwrapper_post_backup() {
return;
}

View file

@ -1,22 +0,0 @@
#!/usr/bin/env bash
#BORG_RSH="ssh -i /path/to/another/rsa_key/.ssh/backup-key"
BORGWRAPPER_BACKUP_NAME="backup-name"
BORGWRAPPER_BACKUP_REPOSITORY="ssh://user@remoteHost:Port/./"
BORGWRAPPER_BACKUP_FILES=(\
'/etc/' \
'$HOME/' \
)
BORGWRAPPER_BACKUP_ENCRYPTION="repokey-blake2"
BORGWRAPPER_BACKUP_PASSWORD="secretPassword"
BORGWRAPPER_BORG_CREATE_PARAMS="create -v -s -p --exclude-from /path/to/.borgwrapper.exclude"
BORGWRAPPER_BACKUP_LOG=true
BORGWRAPPER_BACKUP_NOTIFY_VIA_MAIL=true
BORGWRAPPER_BACKUP_NOTIFY_MAIL_ADDRESS="alias@domain.tld"
borgwrapper_pre_backup() {
return;
}
borgwrapper_post_backup() {
return;
}

View file

@ -1,4 +0,0 @@
/proc/**
/var/log/**
*/build/**
*/node_modules/**

View file

@ -1,11 +1,12 @@
#!/usr/bin/env bash #!/usr/bin/env bash
/usr/bin/restic backup \ # pre action or use ExecStartPre
--one-file-system \
--exclude-file /home/myuser/.config/restic/mybackup.exclude \
--files-from /home/myuser/.config/restic/mybackup.include
/usr/bin/restic forget \ /usr/bin/restic backup \
--keep-daily 7 \ "${RESTIC_ADDITIONAL_CREATE_PARAMS}" \
--keep-weekly 4 \ --exclude-file "${RESTIC_FILE_EXCLUDE}" \
--keep-monthly 3 --files-from "${RESTIC_FILE_INCLUDE}"
/usr/bin/restic forget "${RESTIC_KEEP}"
# post action or adapt ExecStartPost

View file

@ -12,3 +12,7 @@ RESTIC_CACHE_DIR="..."
RESTIC_PASSWORD="..." RESTIC_PASSWORD="..."
#RESTIC_REPOSITORY="sftp://restic-mybackup//my/remote/path" #RESTIC_REPOSITORY="sftp://restic-mybackup//my/remote/path"
RESTIC_REPOSITORY="..." RESTIC_REPOSITORY="..."
RESTIC_KEEP="--keep-daily 7 --keep-weekly 4 --keep-monthly 3"
# advanced parameters
RESTIC_ADDITIONAL_CREATE_PARAMS="--one-file-system"

View file

@ -1,3 +1,4 @@
/home/lost+found /home/lost+found
/home/**/.cache /home/**/.cache
*.bak/** *.bak/**
*/.cache/**

View file

@ -1,16 +0,0 @@
#!/usr/bin/env bash
RESTICWRAPPER_BACKUP_NAME="backup-name"
RESTICWRAPPER_BACKUP_REPOSITORY="/mnt/myBackups/"
RESTICWRAPPER_BACKUP_FILES=(\
'/etc/' \
'$HOME/' \
)
RESTICWRAPPER_BACKUP_PASSWORD="myPassword"
resticwrapper_pre_backup() {
return;
}
resticwrapper_post_backup() {
return;
}