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
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
combined (out-commented line in service files for `systemd_failure_notify@.service`
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`.
To enable this, you need to link the proper `.target` which you like to use inside
the user service before.
```
```shell
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
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="RESTIC_FILE_INCLUDE=%h/.config/restic/%I.include"
Environment="RESTIC_FILE_EXCLUDE=%h/.config/restic/%I.exclude"
EnvironmentFile=%h/.config/restic/%I.env
[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
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="RESTIC_FILE_INCLUDE=%h/.config/restic/%I.include"
Environment="RESTIC_FILE_EXCLUDE=%h/.config/restic/%I.exclude"
EnvironmentFile=%h/.config/restic/%I.env
[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/restic backup \
--one-file-system \
--exclude-file /home/myuser/.config/restic/mybackup.exclude \
--files-from /home/myuser/.config/restic/mybackup.include
# pre action or use ExecStartPre
/usr/bin/restic forget \
--keep-daily 7 \
--keep-weekly 4 \
--keep-monthly 3
/usr/bin/restic backup \
"${RESTIC_ADDITIONAL_CREATE_PARAMS}" \
--exclude-file "${RESTIC_FILE_EXCLUDE}" \
--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_REPOSITORY="sftp://restic-mybackup//my/remote/path"
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/**/.cache
*.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;
}