Skip to content

Commit

Permalink
Merge pull request djmaze#120 from djmaze/fix_backup_sources_with_spaces
Browse files Browse the repository at this point in the history
Fix backup sources with spaces
  • Loading branch information
djmaze committed Apr 18, 2022
2 parents 1d2852b + d2bd491 commit 3507b1c
Show file tree
Hide file tree
Showing 3 changed files with 59 additions and 15 deletions.
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,7 @@ _Note: `BACKUP_CRON`, `PRUNE_CRON` and `CHECK_CRON` are mutually exclusive._
- `RESTIC_REPOSITORY` - Location of the restic repository. You can use [any target supported by restic](https://restic.readthedocs.io/en/stable/030_preparing_a_new_repo.html). Default `/mnt/restic`
- `RESTIC_BACKUP_SOURCES` - Source directory to backup. Make sure to mount this into the container as a volume (see the example configs). Default `/data`
- `RESTIC_PASSWORD` - Password for the restic repository. Will also be used to initialize the repository if it is not yet initialized
- `RESTIC_BACKUP_ARGS` - If specified `restic backup` is run with the given arguments, e.g. for tags, exclude definitions, or verbose logging: `--tag docker-volumes --exclude-file='exclude.txt' --verbose`. See the [restic backup documentation](https://restic.readthedocs.io/en/stable/040_backup.html) for available options
- `RESTIC_BACKUP_ARGS` - If specified `restic backup` is run with the given arguments, e.g. for tags, exclude definitions, or verbose logging: `--tag docker-volumes --exclude-file 'exclude.txt' --verbose`. Make sure **not** to use the `=` form of assignment, but use spaces between parameter and value. See the [restic backup documentation](https://restic.readthedocs.io/en/stable/040_backup.html) for available options
- `RESTIC_BACKUP_TAGS` - _Deprecated_. Tags to set for each snapshot, separated by commas. This option will soon be removed. Please use `RESTIC_BACKUP_ARGS` to define tags.
- `RESTIC_FORGET_ARGS` - If specified `restic forget` is run with the given arguments after each backup or before every prune, e.g. `--prune --keep-last 14 --keep-daily 1`. See the [restic forget documentation](https://restic.readthedocs.io/en/stable/060_forget.html) for available options
- `RESTIC_PRUNE_ARGS` - If specified `restic prune` is run with the given arguments, e.g. for B2 concurrent connection settings and verbose logging: `-o b2.connections=10 --verbose`.
Expand Down
40 changes: 31 additions & 9 deletions backup
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ set -eo pipefail

function run_commands {
COMMANDS=$1
while IFS= read -r cmd; do echo $cmd && eval $cmd ; done < <(printf '%s\n' "$COMMANDS")
while IFS= read -r cmd; do echo "$cmd" && eval "$cmd" ; done < <(printf '%s\n' "$COMMANDS")
}

function run_exit_commands {
Expand All @@ -12,24 +12,45 @@ function run_exit_commands {
run_commands "${POST_COMMANDS_EXIT:-}"
}

function replace_spaces {
echo "${1/\\ /\\}"
}

function replace_spaces_back {
echo "${1/\\/ }"
}

trap run_exit_commands EXIT

run_commands "${PRE_COMMANDS:-}"

RESTIC_BACKUP_SOURCES=${RESTIC_BACKUP_SOURCES:-/data}
IFS=" " read -r -a RESTIC_BACKUP_SOURCES <<< "$(replace_spaces "${RESTIC_BACKUP_SOURCES:-/data}")"
RESTIC_BACKUP_TAGS="${RESTIC_BACKUP_TAGS:-}"
IFS=" " read -r -a RESTIC_BACKUP_ARGS <<< "$(replace_spaces "$RESTIC_BACKUP_ARGS")"

tags="$(echo "$RESTIC_BACKUP_TAGS" | tr "," "\n")"
tag_options=""
tag_options=()
for tag in $tags; do
tag_options="${tag_options} --tag $tag"
tag_options=("${tag_options[@]}" --tag "$tag")
done

backup_sources=()
for source in "${RESTIC_BACKUP_SOURCES[@]}"; do
source="$(replace_spaces_back "$source")"
backup_sources=("${backup_sources[@]}" "$source")
done

backup_args=()
for arg in "${RESTIC_BACKUP_ARGS[@]}"; do
arg="$(replace_spaces_back "$arg")"
backup_args=("${backup_args[@]}" "$arg")
done

start=`date +%s`
start=$(date +%s)
echo Starting Backup at $(date +"%Y-%m-%d %H:%M:%S")

set +e
restic --repo="${RESTIC_REPOSITORY}" backup ${RESTIC_BACKUP_ARGS:-} ${tag_options} ${RESTIC_BACKUP_SOURCES}
restic --repo="${RESTIC_REPOSITORY}" backup "${backup_args[@]}" "${tag_options[@]}" "${backup_sources[@]}"
rc=$?
set -e
if [ $rc -ne 0 ]; then
Expand All @@ -40,11 +61,12 @@ fi
echo Backup successful

if [ -n "${RESTIC_FORGET_ARGS}" ]; then
echo Forget about old snapshots based on RESTIC_FORGET_ARGS = ${RESTIC_FORGET_ARGS}
restic forget ${tag_options} ${RESTIC_FORGET_ARGS}
IFS=" " read -r -a RESTIC_FORGET_ARGS <<< "$RESTIC_FORGET_ARGS"
echo Forget about old snapshots based on RESTIC_FORGET_ARGS = "${RESTIC_FORGET_ARGS[@]}"
restic forget "${tag_options[@]}" "${RESTIC_FORGET_ARGS[@]}"
fi

end=`date +%s`
end=$(date +%s)
echo Finished backup at $(date +"%Y-%m-%d %H:%M:%S") after $((end-start)) seconds

run_commands "${POST_COMMANDS_SUCCESS:-}"
32 changes: 27 additions & 5 deletions spec/backup_spec.sh
Original file line number Diff line number Diff line change
Expand Up @@ -10,12 +10,13 @@ Describe "backup script"
local extra_env

docker_exec() {
extra_args=""
[[ -f "$extra_env" ]] && extra_args="--env-file $extra_env"
extra_args=()
[[ -f "$extra_env" ]] && extra_args=(--env-file "${extra_env[@]}")

# shellcheck disable=SC2086
$DOCKER exec -i \
-e RESTIC_PASSWORD=test \
$extra_args \
"${extra_args[@]}" \
"$container" \
bash -c "$*; exit \$?"
}
Expand All @@ -25,7 +26,7 @@ Describe "backup script"
container=$($DOCKER run -d --entrypoint bash "$IMAGE" -c "sleep 10000")
extra_env="$(mktemp /tmp/extra.env.XXX)"
docker_exec restic init
docker_exec "mkdir -p /data && echo 1 >/data/dummy"
docker_exec "mkdir -p /data && echo 123 >/data/dummy && mkdir -p /my\ data && echo 123 >/my\ data/dummy && echo 456 >/my\ data/dreck"
}

cleanup() {
Expand All @@ -39,7 +40,18 @@ Describe "backup script"
It "Runs a backup successfully"
When call docker_exec backup
The output should include "Backup successful"
The output should match pattern "*Added to the repo: 70? B*"
The output should match pattern "*processed 1 files*"
The status should be success
End

It "Runs a backup on a path with spaces successfully"
cat <<HERE >"$extra_env"
RESTIC_BACKUP_SOURCES=/my\ data
RESTIC_BACKUP_ARGS=--verbose=3 --exclude /my\ data/dreck
HERE
When call docker_exec backup
The output should include "Backup successful"
The output should match pattern "*processed 1 files*"
The status should be success
End

Expand All @@ -63,4 +75,14 @@ HERE
The output should include "Total failure!"
The status should eq 1
End

It "Forgets old backups after backup"
cat <<HERE >"$extra_env"
RESTIC_FORGET_ARGS=--keep-last 1
HERE
When call docker_exec "backup && backup"
The status should be success
The output should match pattern "*keep 1 snapshots*"
End

End

0 comments on commit 3507b1c

Please sign in to comment.