diff --git a/extra/docker_volume_backupper/docker_volume_restore.sh b/extra/docker_volume_backupper/docker_volume_restore.sh new file mode 100755 index 0000000..9902094 --- /dev/null +++ b/extra/docker_volume_backupper/docker_volume_restore.sh @@ -0,0 +1,72 @@ +#!/usr/bin/env bash +set -euo pipefail + +if [ $# -lt 1 ]; then + echo "Usage: $0 [backup-file2 ...]" + exit 1 +fi + +extract_volume_name() { + local f="$1" + local b + b="$(basename "$f")" + # strip known extensions + b="${b%.tar.gz}" + b="${b%.tgz}" + b="${b%.tar}" + # strip trailing _YYYY-MM-DD or -YYYY-MM-DD (optionally followed by anything) + b="$(echo "$b" | sed -E 's/([_-][0-9]{4}-[0-9]{2}-[0-9]{2})([_-].*)?$//')" + printf '%s' "$b" +} + +volume_exists() { + docker volume inspect "$1" >/dev/null 2>&1 +} + +tar_flag_for() { + case "$1" in + *.tar.gz|*.tgz) echo "xzf" ;; + *.tar) echo "xf" ;; + *) echo "xzf" ;; # default assume gzip + esac +} + +for backup in "$@"; do + if [ ! -f "$backup" ]; then + echo "SKIP: file not found: $backup" + continue + fi + + vol="$(extract_volume_name "$backup")" + if [ -z "$vol" ]; then + echo "SKIP: could not infer volume name from $backup" + continue + fi + + if ! volume_exists "$vol"; then + echo "SKIP: docker volume does not exist: $vol (from $backup)" + continue + fi + + absdir="$(realpath "$(dirname "$backup")")" + base="$(basename "$backup")" + tarflags="$(tar_flag_for "$backup")" + cname="restore_${vol}_$(date +%s)_$$" + + echo "RESTORE: $base -> volume $vol" + + # restore into volume: wipe existing contents then extract + docker run --rm \ + --name "$cname" \ + -v "$vol":/data \ + -v "$absdir":/backup \ + alpine sh -c " + set -e + cd /data + rm -rf ./* .??* 2>/dev/null || true + tar ${tarflags} \"/backup/${base}\" -C /data + " + + echo "OK: restored $vol" +done +