3 Commits

Author SHA1 Message Date
Erik Westrup
7f3647fb0c Rel should have been major as of breaking change 2022-02-01 19:41:02 +01:00
Erik Westrup
dd073dfc73 Fix arguments by using arrays to buildup 2022-02-01 19:24:38 +01:00
Erik Westrup
b23d552f0b Allow set but empty envvars 2022-02-01 18:31:27 +01:00
5 changed files with 56 additions and 40 deletions

View File

@@ -6,11 +6,20 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
## [Unreleased]
## [4.0.0] - 2022-02-01
### Fixed
- Use arrays to build up command lines. When fixing `shellcheck(1)` errors, quotes would disable expansion on e.g. $RESTIC_BACKUP_PATHS
- **BREAKING CHANGE** `RESTIC_BACKUP_PATHS` is now a string with `:` separated values
## [3.0.1] - 2022-02-01
### Fixed
- Environment variable assertion should allow empty values e.g. `RESTIC_BACKUP_EXTRA_ARGS`
## [3.0.0] - 2022-02-01
### Added
- Allow extra arguments to restic-backup with `$RESTIC_BACKUP_EXTRA_ARGS`.
- Add `$RESTIC_VERBOSITY_LEVEL` for debugging.
- Assertion on all needed envionment variables in the backup and check scripts.
- Assertion on all needed environment variables in the backup and check scripts.
- Added linter (`shellcheck(1)`) that is run on push and PRs.
### Changed

View File

@@ -20,7 +20,8 @@ export B2_ACCOUNT_KEY="<b2-application-key>" # TODO fill with your applicationKe
# How many network connections to set up to B2. Default is 5.
export B2_CONNECTIONS=10
# Extra args to restic-backup. This is empty here and profiles can override this after sourcing this file.
# Optional extra space-separated args to restic-backup.
# This is empty here and profiles can override this after sourcing this file.
export RESTIC_BACKUP_EXTRA_ARGS=
# Verbosity level from 0-3. 0 means no --verbose.

View File

@@ -15,10 +15,11 @@ source /etc/restic/_global.env
export RESTIC_REPOSITORY="b2:<b2-repo-name>" # TODO fill with your repo name
# What to backup (paths our mountpoints) e.g. "/ /boot /home /mnt/media".
# What to backup. Colon-separated paths e.g. to different mountpoints "/home:/mnt/usb_disk".
# To backup only your home directory, set "/home/your-user"
export RESTIC_BACKUP_PATHS="" # TODO fill conveniently with one or multiple paths
# Example below of how to dynamically add a path that is mounted e.g. external USB disk.
# restic does not fail if a specified path is not mounted, but it's nicer to only add if they are available.
#test -d /mnt/media && RESTIC_BACKUP_PATHS+=" /mnt/media"
@@ -33,8 +34,8 @@ export RESTIC_RETENTION_WEEKS=16
export RESTIC_RETENTION_MONTHS=18
export RESTIC_RETENTION_YEARS=3
# Optional extra arguments to restic-backup.
# Optional extra space-separated arguments to restic-backup.
# Example: Add two additional exclude files to the global one in RESTIC_PASSWORD_FILE.
#RESTIC_BACKUP_EXTRA_ARGS="--exclude-file /path/to/extra/exclude/file/a /path/to/extra/exclude/file/b"
#RESTIC_BACKUP_EXTRA_ARGS="--exclude-file /path/to/extra/exclude/file/a --exclude-file /path/to/extra/exclude/file/b"
# Example: exclude all directories that have a .git/ directory inside it.
#RESTIC_BACKUP_EXTRA_ARGS="--exclude-if-present .git"

View File

@@ -11,14 +11,24 @@
# Exit on error, unset var, pipe failure
set -euo pipefail
# Clean up lock if we are killed.
# If killed by systemd, like $(systemctl stop restic), then it kills the whole cgroup and all it's subprocesses.
# However if we kill this script ourselves, we need this trap that kills all subprocesses manually.
exit_hook() {
echo "In exit_hook(), being killed" >&2
jobs -p | xargs kill
restic unlock
}
trap exit_hook INT TERM
# Assert that all needed environment variables are set.
# TODO in future if this grows, move this to a restic_lib.sh
assert_envvars() {
local varnames=("$@")
for varname in "${varnames[@]}"; do
# Check if variable is set, then if it is not empty (need to do both as of `set -u`).
if [ -z ${!varname+x} ] || [ -z "${!varname}" ] ; then
printf "%s must be set with a value for this script to work.\n\nDid you forget to source a /etc/restic/*.env profile in the current shell before executing this script?\n" "$varname" >&2
if [ -z ${!varname+x} ]; then
printf "%s must be set for this script to work.\n\nDid you forget to source a /etc/restic/*.env profile in the current shell before executing this script?\n" "$varname" >&2
exit 1
fi
done
@@ -30,25 +40,20 @@ assert_envvars \
RESTIC_RETENTION_DAYS RESTIC_RETENTION_MONTHS RESTIC_RETENTION_WEEKS RESTIC_RETENTION_YEARS
# Clean up lock if we are killed.
# If killed by systemd, like $(systemctl stop restic), then it kills the whole cgroup and all it's subprocesses.
# However if we kill this script ourselves, we need this trap that kills all subprocesses manually.
exit_hook() {
echo "In exit_hook(), being killed" >&2
jobs -p | xargs kill
restic unlock
}
trap exit_hook INT TERM
# Convert to arrays, as arrays should be used to build command lines. See https://github.com/koalaman/shellcheck/wiki/SC2086
IFS=':' read -ra backup_paths <<< "$RESTIC_BACKUP_PATHS"
IFS=' ' read -ra extra_args <<< "$RESTIC_BACKUP_EXTRA_ARGS"
# Set up exclude files: global + path-specific ones
# NOTE that restic will fail the backup if not all listed --exclude-files exist. Thus we should only list them if they are really all available.
## Global backup configuration.
exclusion_args="--exclude-file ${RESTIC_BACKUP_EXCLUDE_FILE}"
## Self-contained backup files per backup path. E.g. having an USB disk at /mnt/media in RESTIC_BACKUP_PATHS,
# a file /mnt/media/.backup_exclude.txt will automatically be detected and used:
for backup_path in "${RESTIC_BACKUP_PATHS[@]}"; do
exclusion_args=(--exclude-file "$RESTIC_BACKUP_EXCLUDE_FILE")
## Self-contained backup exclusion files per backup path. E.g. having an USB disk at /mnt/media in RESTIC_BACKUP_PATHS,
# then a file /mnt/media/.backup_exclude.txt will automatically be detected and used:
for backup_path in "${backup_paths[@]}"; do
if [ -f "$backup_path/.backup_exclude.txt" ]; then
exclusion_args+=" --exclude-file $backup_path/.backup_exclude.txt"
exclusion_args=("${exclusion_args[@]}" --exclude-file "$backup_path/.backup_exclude.txt")
fi
done
@@ -70,9 +75,9 @@ restic backup \
--one-file-system \
--tag "$RESTIC_BACKUP_TAG" \
--option b2.connections="$B2_CONNECTIONS" \
"$exclusion_args" \
"$RESTIC_BACKUP_EXTRA_ARGS" \
"$RESTIC_BACKUP_PATHS" &
"${exclusion_args[@]}" \
"${extra_args[@]}" \
"${backup_paths[@]}" &
wait $!
# Dereference and delete/prune old backups.

View File

@@ -5,21 +5,6 @@
# Exit on error, unset var, pipe failure
set -euo pipefail
# Assert that all needed environment variables are set.
assert_envvars() {
local varnames=("$@")
for varname in "${varnames[@]}"; do
# Check if variable is set, then if it is not empty (need to do both as of `set -u`).
if [ -z ${!varname+x} ] || [ -z "${!varname}" ] ; then
printf "%s must be set with a value for this script to work.\n\nDid you forget to source a /etc/restic/*.env profile in the current shell before executing this script?\n" "$varname" >&2
exit 1
fi
done
}
assert_envvars \
B2_ACCOUNT_ID B2_ACCOUNT_KEY B2_CONNECTIONS \
RESTIC_PASSWORD_FILE RESTIC_REPOSITORY RESTIC_VERBOSITY_LEVEL
# Clean up lock if we are killed.
# If killed by systemd, like $(systemctl stop restic), then it kills the whole cgroup and all it's subprocesses.
# However if we kill this script ourselves, we need this trap that kills all subprocesses manually.
@@ -30,6 +15,21 @@ exit_hook() {
}
trap exit_hook INT TERM
# Assert that all needed environment variables are set.
assert_envvars() {
local varnames=("$@")
for varname in "${varnames[@]}"; do
if [ -z ${!varname+x} ]; then
printf "%s must be set for this script to work.\n\nDid you forget to source a /etc/restic/*.env profile in the current shell before executing this script?\n" "$varname" >&2
exit 1
fi
done
}
assert_envvars \
B2_ACCOUNT_ID B2_ACCOUNT_KEY B2_CONNECTIONS \
RESTIC_PASSWORD_FILE RESTIC_REPOSITORY RESTIC_VERBOSITY_LEVEL
# Remove locks from other stale processes to keep the automated backup running.
# NOTE nope, don't unlock like restic_backup.sh. restic_backup.sh should take precedence over this script.
#restic unlock &