From f3767318e8bb05cfa54f335d1bd1f0be718d0f29 Mon Sep 17 00:00:00 2001 From: Demmie <2e3s19@gmail.com> Date: Sat, 31 May 2025 23:18:53 -0400 Subject: [PATCH 1/6] Make destination optional --- docker-volume-snapshot | 37 +++++++++++++++++++++++++++---------- 1 file changed, 27 insertions(+), 10 deletions(-) diff --git a/docker-volume-snapshot b/docker-volume-snapshot index b327b6a..cb73fc8 100755 --- a/docker-volume-snapshot +++ b/docker-volume-snapshot @@ -4,36 +4,53 @@ set -e -o pipefail programname=`basename "$0"` display_usage() { - echo "usage: $programname (create|restore) source destination" + echo "usage: $programname (create|restore) source [destination]" echo " create create snapshot file from docker volume" echo " restore restore snapshot file to docker volume" echo " source source path" - echo " destination destination path" + echo " destination destination path (optional)" + echo + echo "If destination is not provided:" + echo " create: uses source name + .tar.gz" + echo " restore: derives volume name from archive filename" echo echo "Tip: Supports tar's compression algorithms automatically" echo " based on the file extention, for example .tar.gz" echo echo "Examples:" + echo "docker-volume-snapshot create xyz_volume" echo "docker-volume-snapshot create xyz_volume xyz_volume.tar" echo "docker-volume-snapshot create xyz_volume xyz_volume.tar.gz" + echo "docker-volume-snapshot restore xyz_volume.tar" + echo "docker-volume-snapshot restore xyz_volume.tar.gz" echo "docker-volume-snapshot restore xyz_volume.tar xyz_volume" echo "docker-volume-snapshot restore xyz_volume.tar.gz xyz_volume" } case "$1" in "create") - if [[ -z "$2" || -z "$3" ]]; then display_usage; exit 1; fi - directory=`dirname "$3"` + if [[ -z "$2" ]]; then display_usage; exit 1; fi + source="$2" + destination="${3:-$2.tar.gz}" + directory=`dirname "$destination"` if [ "$directory" == "." ]; then directory=$(pwd); fi - filename=`basename "$3"` - docker run --rm -v "$2:/source" -v "$directory:/dest" busybox tar cvaf "/dest/$filename" -C /source . + filename=`basename "$destination"` + docker run --rm -v "$source:/source" -v "$directory:/dest" busybox tar cvaf "/dest/$filename" -C /source . ;; "restore") - if [[ -z "$2" || -z "$3" ]]; then display_usage; exit 1; fi - directory=`dirname "$2"` + if [[ -z "$2" ]]; then display_usage; exit 1; fi + source="$2" + if [[ -z "$3" ]]; then + # Extract volume name from archive filename + basename_source=`basename "$source"` + destination="${basename_source%%.*}" + else + destination="$3" + fi + directory=`dirname "$source"` if [ "$directory" == "." ]; then directory=$(pwd); fi - filename=`basename "$2"` - docker run --rm -v "$3:/dest" -v "$directory:/source" busybox tar xvf "/source/$filename" -C /dest + filename=`basename "$source"` + docker run --rm -v "$destination:/dest" -v "$directory:/source" busybox tar xvf "/source/$filename" -C /dest ;; *) display_usage From 3e6ecfa9925afc86ad0d36a94abb1c8fed62bdb5 Mon Sep 17 00:00:00 2001 From: Demmie <2e3s19@gmail.com> Date: Sat, 31 May 2025 23:22:46 -0400 Subject: [PATCH 2/6] Make source optional rather than destination for restore mode --- docker-volume-snapshot | 26 +++++++++++++++----------- 1 file changed, 15 insertions(+), 11 deletions(-) diff --git a/docker-volume-snapshot b/docker-volume-snapshot index cb73fc8..18eabac 100755 --- a/docker-volume-snapshot +++ b/docker-volume-snapshot @@ -4,15 +4,17 @@ set -e -o pipefail programname=`basename "$0"` display_usage() { - echo "usage: $programname (create|restore) source [destination]" + echo "usage: $programname create source [destination]" + echo "usage: $programname restore [source] destination" echo " create create snapshot file from docker volume" echo " restore restore snapshot file to docker volume" echo " source source path" - echo " destination destination path (optional)" + echo " destination destination path" echo - echo "If destination is not provided:" - echo " create: uses source name + .tar.gz" - echo " restore: derives volume name from archive filename" + echo "If destination is not provided for create:" + echo " uses source name + .tar.gz" + echo "If source is not provided for restore:" + echo " uses destination name + .tar.gz" echo echo "Tip: Supports tar's compression algorithms automatically" echo " based on the file extention, for example .tar.gz" @@ -21,8 +23,7 @@ display_usage() { echo "docker-volume-snapshot create xyz_volume" echo "docker-volume-snapshot create xyz_volume xyz_volume.tar" echo "docker-volume-snapshot create xyz_volume xyz_volume.tar.gz" - echo "docker-volume-snapshot restore xyz_volume.tar" - echo "docker-volume-snapshot restore xyz_volume.tar.gz" + echo "docker-volume-snapshot restore xyz_volume" echo "docker-volume-snapshot restore xyz_volume.tar xyz_volume" echo "docker-volume-snapshot restore xyz_volume.tar.gz xyz_volume" } @@ -39,14 +40,17 @@ case "$1" in ;; "restore") if [[ -z "$2" ]]; then display_usage; exit 1; fi - source="$2" + if [[ -z "$3" ]]; then - # Extract volume name from archive filename - basename_source=`basename "$source"` - destination="${basename_source%%.*}" + # Only one argument provided - it's the destination + destination="$2" + source="$destination.tar.gz" else + # Two arguments provided - source and destination + source="$2" destination="$3" fi + directory=`dirname "$source"` if [ "$directory" == "." ]; then directory=$(pwd); fi filename=`basename "$source"` From 11854de08543a3e76afb329999254cf599be7e54 Mon Sep 17 00:00:00 2001 From: Demmie <2e3s19@gmail.com> Date: Sun, 1 Jun 2025 00:00:04 -0400 Subject: [PATCH 3/6] Add create-all argument --- docker-volume-snapshot | 47 +++++++++++++++++++++++++++++++++++++++--- 1 file changed, 44 insertions(+), 3 deletions(-) diff --git a/docker-volume-snapshot b/docker-volume-snapshot index 18eabac..5d805ca 100755 --- a/docker-volume-snapshot +++ b/docker-volume-snapshot @@ -3,13 +3,25 @@ set -e -o pipefail programname=`basename "$0"` +create() { + local source="$1" + local destination="$2" + local directory=`dirname "$destination"` + if [ "$directory" == "." ]; then directory=$(pwd); fi + local filename=`basename "$destination"` + docker run --rm -v "$source:/source" -v "$directory:/dest" busybox tar cvaf "/dest/$filename" -C /source . +} + display_usage() { echo "usage: $programname create source [destination]" + echo "usage: $programname create-all [destination]" echo "usage: $programname restore [source] destination" echo " create create snapshot file from docker volume" + echo " create-all create snapshots of all docker volumes into single archive" echo " restore restore snapshot file to docker volume" echo " source source path" echo " destination destination path" + echo " archive archive path (default: docker-volumes.tar.gz)" echo echo "If destination is not provided for create:" echo " uses source name + .tar.gz" @@ -23,6 +35,8 @@ display_usage() { echo "docker-volume-snapshot create xyz_volume" echo "docker-volume-snapshot create xyz_volume xyz_volume.tar" echo "docker-volume-snapshot create xyz_volume xyz_volume.tar.gz" + echo "docker-volume-snapshot create-all" + echo "docker-volume-snapshot create-all all-volumes.tar.gz" echo "docker-volume-snapshot restore xyz_volume" echo "docker-volume-snapshot restore xyz_volume.tar xyz_volume" echo "docker-volume-snapshot restore xyz_volume.tar.gz xyz_volume" @@ -33,10 +47,37 @@ case "$1" in if [[ -z "$2" ]]; then display_usage; exit 1; fi source="$2" destination="${3:-$2.tar.gz}" - directory=`dirname "$destination"` + create "$source" "$destination" + ;; + "create-all") + archive="${2:-docker-volumes.tar.gz}" + + echo "Getting list of Docker volumes..." + volumes=$(docker volume ls -q) + + if [ -z "$volumes" ]; then + echo "No Docker volumes found." + exit 0 + fi + temp_dir="/tmp/docker-volume-snapshots-$$" + mkdir -p "$temp_dir" + + echo "Creating individual volume snapshots..." + for volume in $volumes; do + echo "Backing up volume: $volume" + create "$volume" "$temp_dir/$volume.tar.gz" + done + + echo "Creating combined archive: $archive" + directory=$(dirname "$archive") if [ "$directory" == "." ]; then directory=$(pwd); fi - filename=`basename "$destination"` - docker run --rm -v "$source:/source" -v "$directory:/dest" busybox tar cvaf "/dest/$filename" -C /source . + filename=$(basename "$archive") + + docker run --rm -v "$temp_dir:/source" -v "$directory:/dest" busybox tar cvaf "/dest/$filename" -C /source . + + echo "Cleaning up temporary files..." + rm -rf "$temp_dir" + echo "All volumes backed up to: $archive" ;; "restore") if [[ -z "$2" ]]; then display_usage; exit 1; fi From d0372207dddb989262a66559b049eeb17b4712d4 Mon Sep 17 00:00:00 2001 From: Demmie <2e3s19@gmail.com> Date: Sun, 1 Jun 2025 00:21:13 -0400 Subject: [PATCH 4/6] Add restore-all argument --- docker-volume-snapshot | 40 +++++++++++++++++++++++++++++++++++++--- 1 file changed, 37 insertions(+), 3 deletions(-) diff --git a/docker-volume-snapshot b/docker-volume-snapshot index 5d805ca..ecbbeef 100755 --- a/docker-volume-snapshot +++ b/docker-volume-snapshot @@ -12,13 +12,24 @@ create() { docker run --rm -v "$source:/source" -v "$directory:/dest" busybox tar cvaf "/dest/$filename" -C /source . } +restore() { + local source="$1" + local destination="$2" + local directory=`dirname "$source"` + if [ "$directory" == "." ]; then directory=$(pwd); fi + local filename=`basename "$source"` + docker run --rm -v "$destination:/dest" -v "$directory:/source" busybox tar xvf "/source/$filename" -C /dest +} + display_usage() { echo "usage: $programname create source [destination]" echo "usage: $programname create-all [destination]" echo "usage: $programname restore [source] destination" + echo "usage: $programname restore-all archive" echo " create create snapshot file from docker volume" echo " create-all create snapshots of all docker volumes into single archive" echo " restore restore snapshot file to docker volume" + echo " restore-all restore all volumes from combined archive" echo " source source path" echo " destination destination path" echo " archive archive path (default: docker-volumes.tar.gz)" @@ -40,6 +51,7 @@ display_usage() { echo "docker-volume-snapshot restore xyz_volume" echo "docker-volume-snapshot restore xyz_volume.tar xyz_volume" echo "docker-volume-snapshot restore xyz_volume.tar.gz xyz_volume" + echo "docker-volume-snapshot restore-all docker-volumes.tar.gz" } case "$1" in @@ -92,10 +104,32 @@ case "$1" in destination="$3" fi - directory=`dirname "$source"` + restore "$source" "$destination" + ;; + "restore-all") + if [[ -z "$2" ]]; then display_usage; exit 1; fi + archive="$2" + + temp_dir="/tmp/docker-volume-snapshots-$$" + mkdir -p "$temp_dir" + + directory=$(dirname "$archive") if [ "$directory" == "." ]; then directory=$(pwd); fi - filename=`basename "$source"` - docker run --rm -v "$destination:/dest" -v "$directory:/source" busybox tar xvf "/source/$filename" -C /dest + filename=$(basename "$archive") + + docker run --rm -v "$directory:/source" -v "$temp_dir:/dest" busybox tar xvf "/source/$filename" -C /dest + + for volume_archive in "$temp_dir"/*.tar.gz; do + if [ -f "$volume_archive" ]; then + volume_name=$(basename "$volume_archive" .tar.gz) + echo "Restoring volume: $volume_name from $volume_archive" + restore "$volume_archive" "$volume_name" + fi + done + + echo "Cleaning up temporary files..." + rm -rf "$temp_dir" + echo "All volumes restored from: $archive" ;; *) display_usage From 2b9f860197a7d5946a6fb3cb4c03db7b4004bc0b Mon Sep 17 00:00:00 2001 From: Demmie <2e3s19@gmail.com> Date: Sun, 1 Jun 2025 09:50:54 -0400 Subject: [PATCH 5/6] Reverse source and destination requirement --- docker-volume-snapshot | 48 +++++++++++++++++++----------------------- 1 file changed, 22 insertions(+), 26 deletions(-) diff --git a/docker-volume-snapshot b/docker-volume-snapshot index ecbbeef..873699f 100755 --- a/docker-volume-snapshot +++ b/docker-volume-snapshot @@ -23,21 +23,23 @@ restore() { display_usage() { echo "usage: $programname create source [destination]" - echo "usage: $programname create-all [destination]" - echo "usage: $programname restore [source] destination" - echo "usage: $programname restore-all archive" + echo " $programname create-all [destination]" + echo " $programname restore source [destination]" + echo " $programname restore-all source" + echo echo " create create snapshot file from docker volume" echo " create-all create snapshots of all docker volumes into single archive" echo " restore restore snapshot file to docker volume" echo " restore-all restore all volumes from combined archive" echo " source source path" echo " destination destination path" - echo " archive archive path (default: docker-volumes.tar.gz)" echo echo "If destination is not provided for create:" echo " uses source name + .tar.gz" - echo "If source is not provided for restore:" - echo " uses destination name + .tar.gz" + echo "If destination is not provided for restore:" + echo " uses source name without extension" + echo "If destination is not provided for create-all:" + echo " uses current directory + docker-volumes.tar.gz" echo echo "Tip: Supports tar's compression algorithms automatically" echo " based on the file extention, for example .tar.gz" @@ -48,7 +50,7 @@ display_usage() { echo "docker-volume-snapshot create xyz_volume xyz_volume.tar.gz" echo "docker-volume-snapshot create-all" echo "docker-volume-snapshot create-all all-volumes.tar.gz" - echo "docker-volume-snapshot restore xyz_volume" + echo "docker-volume-snapshot restore xyz_volume.tar.gz" echo "docker-volume-snapshot restore xyz_volume.tar xyz_volume" echo "docker-volume-snapshot restore xyz_volume.tar.gz xyz_volume" echo "docker-volume-snapshot restore-all docker-volumes.tar.gz" @@ -58,11 +60,11 @@ case "$1" in "create") if [[ -z "$2" ]]; then display_usage; exit 1; fi source="$2" - destination="${3:-$2.tar.gz}" + destination="${3:-$(pwd)/$2.tar.gz}" create "$source" "$destination" ;; "create-all") - archive="${2:-docker-volumes.tar.gz}" + archive="${2:-$(pwd)/docker-volumes.tar.gz}" echo "Getting list of Docker volumes..." volumes=$(docker volume ls -q) @@ -81,11 +83,7 @@ case "$1" in done echo "Creating combined archive: $archive" - directory=$(dirname "$archive") - if [ "$directory" == "." ]; then directory=$(pwd); fi - filename=$(basename "$archive") - - docker run --rm -v "$temp_dir:/source" -v "$directory:/dest" busybox tar cvaf "/dest/$filename" -C /source . + tar -czf "$archive" -C "$temp_dir" . echo "Cleaning up temporary files..." rm -rf "$temp_dir" @@ -94,13 +92,15 @@ case "$1" in "restore") if [[ -z "$2" ]]; then display_usage; exit 1; fi + source="$2" if [[ -z "$3" ]]; then - # Only one argument provided - it's the destination - destination="$2" - source="$destination.tar.gz" + filename=$(basename "$source") + # Remove any extension from the filename + destination="${filename%.*}" + if [ "$destination" = "" ]; then + destination="$filename" + fi else - # Two arguments provided - source and destination - source="$2" destination="$3" fi @@ -108,16 +108,12 @@ case "$1" in ;; "restore-all") if [[ -z "$2" ]]; then display_usage; exit 1; fi - archive="$2" + source="$2" temp_dir="/tmp/docker-volume-snapshots-$$" mkdir -p "$temp_dir" - directory=$(dirname "$archive") - if [ "$directory" == "." ]; then directory=$(pwd); fi - filename=$(basename "$archive") - - docker run --rm -v "$directory:/source" -v "$temp_dir:/dest" busybox tar xvf "/source/$filename" -C /dest + tar -xf "$source" -C "$temp_dir" for volume_archive in "$temp_dir"/*.tar.gz; do if [ -f "$volume_archive" ]; then @@ -129,7 +125,7 @@ case "$1" in echo "Cleaning up temporary files..." rm -rf "$temp_dir" - echo "All volumes restored from: $archive" + echo "All volumes restored from: $source" ;; *) display_usage From 5f8732adba77ab48aec52e725be5bb4bb07209bc Mon Sep 17 00:00:00 2001 From: Demmie <2e3s19@gmail.com> Date: Sun, 1 Jun 2025 20:43:42 -0400 Subject: [PATCH 6/6] Add verbose flag --- docker-volume-snapshot | 40 +++++++++++++++++++++------------------- 1 file changed, 21 insertions(+), 19 deletions(-) diff --git a/docker-volume-snapshot b/docker-volume-snapshot index 873699f..c65ae42 100755 --- a/docker-volume-snapshot +++ b/docker-volume-snapshot @@ -3,13 +3,24 @@ set -e -o pipefail programname=`basename "$0"` +verbose="" +args=() +for arg in "$@"; do + if [ "$arg" = "--verbose" ]; then + verbose="v" + else + args+=("$arg") + fi +done +set -- "${args[@]}" + create() { local source="$1" local destination="$2" local directory=`dirname "$destination"` if [ "$directory" == "." ]; then directory=$(pwd); fi local filename=`basename "$destination"` - docker run --rm -v "$source:/source" -v "$directory:/dest" busybox tar cvaf "/dest/$filename" -C /source . + docker run --rm -v "$source:/source" -v "$directory:/dest" busybox tar c${verbose}af "/dest/$filename" -C /source . } restore() { @@ -18,28 +29,22 @@ restore() { local directory=`dirname "$source"` if [ "$directory" == "." ]; then directory=$(pwd); fi local filename=`basename "$source"` - docker run --rm -v "$destination:/dest" -v "$directory:/source" busybox tar xvf "/source/$filename" -C /dest + docker run --rm -v "$destination:/dest" -v "$directory:/source" busybox tar x${verbose}f "/source/$filename" -C /dest } display_usage() { - echo "usage: $programname create source [destination]" - echo " $programname create-all [destination]" - echo " $programname restore source [destination]" - echo " $programname restore-all source" + echo "usage: $programname [--verbose] create source [destination]" + echo " $programname [--verbose] create-all [destination]" + echo " $programname [--verbose] restore source [destination]" + echo " $programname [--verbose] restore-all source" echo - echo " create create snapshot file from docker volume" - echo " create-all create snapshots of all docker volumes into single archive" - echo " restore restore snapshot file to docker volume" + echo " create create snapshot file from docker volume. If destination is not provided for create it uses source name + .tar.gz" + echo " create-all create snapshots of all docker volumes into single archive. If destination is not provided for create-all it uses docker-volumes.tar.gz" + echo " restore restore snapshot file to docker volume. If destination is not provided for restore it uses source name without extension" echo " restore-all restore all volumes from combined archive" echo " source source path" echo " destination destination path" - echo - echo "If destination is not provided for create:" - echo " uses source name + .tar.gz" - echo "If destination is not provided for restore:" - echo " uses source name without extension" - echo "If destination is not provided for create-all:" - echo " uses current directory + docker-volumes.tar.gz" + echo " --verbose show detailed output" echo echo "Tip: Supports tar's compression algorithms automatically" echo " based on the file extention, for example .tar.gz" @@ -51,7 +56,6 @@ display_usage() { echo "docker-volume-snapshot create-all" echo "docker-volume-snapshot create-all all-volumes.tar.gz" echo "docker-volume-snapshot restore xyz_volume.tar.gz" - echo "docker-volume-snapshot restore xyz_volume.tar xyz_volume" echo "docker-volume-snapshot restore xyz_volume.tar.gz xyz_volume" echo "docker-volume-snapshot restore-all docker-volumes.tar.gz" } @@ -66,9 +70,7 @@ case "$1" in "create-all") archive="${2:-$(pwd)/docker-volumes.tar.gz}" - echo "Getting list of Docker volumes..." volumes=$(docker volume ls -q) - if [ -z "$volumes" ]; then echo "No Docker volumes found." exit 0