Add restore command and test.
This commit is contained in:
parent
3449bae491
commit
bb060e5eec
3 changed files with 90 additions and 22 deletions
65
dvbackup.sh
65
dvbackup.sh
|
@ -1,50 +1,71 @@
|
|||
#!/usr/bin/env bash
|
||||
#!/usr/bin/env sh
|
||||
|
||||
if [ -z "$DOCKER" ]; then
|
||||
DOCKER=docker
|
||||
fi
|
||||
|
||||
|
||||
echo_and_run() {
|
||||
echo "$@"
|
||||
"$@"
|
||||
return $?
|
||||
}
|
||||
|
||||
backup() {
|
||||
local volume
|
||||
local target
|
||||
local target_dir
|
||||
local target_name
|
||||
volume="$1"
|
||||
target="$(realpath "$2")"
|
||||
target_dir="$(dirname "$target")"
|
||||
target_name="$(basename "$target")"
|
||||
|
||||
test -z "$(docker volume ls | grep "$volume")" && { echo "Error: No such volume, aborting" >&2; exit 1; }
|
||||
test -z "$("$DOCKER" volume ls | grep "$volume")" && { echo "Error: No such volume, aborting" >&2; exit 1; }
|
||||
test -z "$target_dir" && { echo "Error: No base folder found for target=$target" >&2; exit 2; }
|
||||
test -z "$target_name" && { echo "Error: No target name found for target=$target" >&2; exit 3; }
|
||||
|
||||
set -x
|
||||
docker run --rm --mount="type=volume,source=$volume,destination=/data,ro=true" --mount="type=bind,source=$target_dir,destination=/data2" busybox /bin/sh -c "tar cvf '/data2/$target_name' /data && chown $(id -u):$(id -g) /data2/$target_name"
|
||||
set +x
|
||||
"$DOCKER" run --rm \
|
||||
--mount="type=volume,source=$volume,destination=/data,ro=true" \
|
||||
--mount="type=bind,source=$target_dir,destination=/data2" \
|
||||
busybox /bin/sh -c \
|
||||
"cd /data/ && tar cf '/data2/$target_name' ./* && chown $(id -u):$(id -g) /data2/$target_name"
|
||||
}
|
||||
|
||||
restore() {
|
||||
local volume
|
||||
local target
|
||||
local target_dir
|
||||
local target_name
|
||||
target="$(realpath "$1")"
|
||||
target_dir="$(dirname "$target")"
|
||||
target_name="$(basename "$target")"
|
||||
volume="$2"
|
||||
|
||||
test -z "$(docker volume ls | grep "$volume")" && { echo "Error: No such volume, aborting" >&2; exit 1; }
|
||||
test -z "$("$DOCKER" volume ls | grep "$volume")" && { echo "Error: No such volume, aborting" >&2; exit 1; }
|
||||
test -z "$target_dir" && { echo "Error: No base folder found for target=$target" >&2; exit 2; }
|
||||
test -z "$target_name" && { echo "Error: No target name found for target=$target" >&2; exit 3; }
|
||||
|
||||
set -x
|
||||
docker run --rm --mount="type=volume,source=$volume,destination=/data" --mount="type=bind,source=$target_dir,destination=/data2" busybox /bin/sh -c "rm -rf /data/* && cd / && tar xvf '/data2/$target_name'"
|
||||
"$DOCKER" run --rm \
|
||||
--mount="type=volume,source=$volume,destination=/data" \
|
||||
--mount="type=bind,source=$target_dir,destination=/data2" \
|
||||
busybox /bin/sh -c \
|
||||
"cd /data/ && rm -rf ./* && tar xf '/data2/$target_name'"
|
||||
set +x
|
||||
}
|
||||
|
||||
main() {
|
||||
local volumes
|
||||
volumes="$(docker volume ls | tail -n+2 | egrep -v '[a-z]+\s+[0-9a-f]+$' | egrep -o '\s.+$' | sed 's/\s//g')"
|
||||
while read -r line; do
|
||||
echo "$line -> $line.tar"
|
||||
backup "$line" "$line.tar"
|
||||
done <<< "$volumes"
|
||||
backup_all() {
|
||||
"$DOCKER" volume ls \
|
||||
| awk '!/^[a-z]+ +[0-9a-f]+$/ && (NR>1) {print $2}' \
|
||||
| while read -r volume_name; do
|
||||
echo "$volume_name -> $volume_name.tar"
|
||||
backup "$volume_name" "$volume_name.tar"
|
||||
done
|
||||
}
|
||||
|
||||
restore_all() {
|
||||
for tarball in "$@"; do
|
||||
volume_name="${tarball%.tar}"
|
||||
echo "$volume_name -> $volume"
|
||||
if ! "$DOCKER" volume inspect "$volume_name" 1>&2 2>/dev/null; then
|
||||
echo "Error: no such volume $volume_name" >&2
|
||||
exit 4
|
||||
fi
|
||||
restore "$tarball" "$volume_name"
|
||||
done
|
||||
}
|
||||
|
||||
"$@"
|
||||
|
|
24
test/mock-docker.sh
Executable file
24
test/mock-docker.sh
Executable file
|
@ -0,0 +1,24 @@
|
|||
#!/usr/bin/env sh
|
||||
|
||||
volume() {
|
||||
if [ "$1" = 'ls' ]; then
|
||||
echo "DRIVER VOLUME NAME"
|
||||
echo "local 00c674e3f3c1587d88c2ebf2f91da5843b9dddb3e8df272898bdfd4e596aef79"
|
||||
echo "local $DOCKER_MOCK_VOLUME"
|
||||
return 0
|
||||
elif [ "$2" = 'inspect' ]; then
|
||||
if [ "$3" = "$DOCKER_MOCK_VOLUME" ]; then
|
||||
return 0
|
||||
else
|
||||
return 1
|
||||
fi
|
||||
fi
|
||||
}
|
||||
|
||||
|
||||
if [ "$1" = "volume" ]; then
|
||||
"$@"
|
||||
else
|
||||
docker "$@"
|
||||
fi
|
||||
|
23
test/test.sh
Executable file
23
test/test.sh
Executable file
|
@ -0,0 +1,23 @@
|
|||
#!/usr/bin/env sh
|
||||
|
||||
|
||||
cd "$(dirname "$0")" || exit 1
|
||||
|
||||
VOLUME_NAME="$(dd if=/dev/random bs=6 count=1 | base64)"
|
||||
docker volume create "$VOLUME_NAME"
|
||||
|
||||
# shellcheck disable=SC2064
|
||||
trap "docker volume rm $VOLUME_NAME && rm -f $VOLUME_NAME.tar" EXIT
|
||||
|
||||
docker run --rm --volume="$VOLUME_NAME:/data" alpine \
|
||||
sh -c 'echo "test" > /data/a.txt'
|
||||
DOCKER=./mock-docker.sh DOCKER_MOCK_VOLUME="$VOLUME_NAME" \
|
||||
../dvbackup.sh backup_all
|
||||
stat "$VOLUME_NAME.tar" || exit 1
|
||||
docker run --rm --volume="$VOLUME_NAME:/data" alpine \
|
||||
sh -c 'rm /data/a.txt' || exit 1
|
||||
DOCKER=./mock-docker.sh DOCKER_MOCK_VOLUME="$VOLUME_NAME" \
|
||||
../dvbackup.sh restore_all "$VOLUME_NAME.tar" || exit 1
|
||||
docker run --rm --volume="$VOLUME_NAME:/data" alpine \
|
||||
sh -c 'stat /data/a.txt' || exit 1
|
||||
exit 0
|
Loading…
Reference in a new issue