Skip to content

Commit 09a2109

Browse files
authored
sync with upstream vackup
1 parent fe4e0ce commit 09a2109

File tree

1 file changed

+117
-65
lines changed

1 file changed

+117
-65
lines changed

vackup all/vackup

Lines changed: 117 additions & 65 deletions
Original file line numberDiff line numberDiff line change
@@ -1,48 +1,101 @@
1-
#!/bin/bash
1+
#!/usr/bin/env bash
22
# Docker Volume File Backup and Restore Tool
33
# Easily tar up a volume on a local (or remote) engine
44
# Inspired by CLIP from Lukasz Lach
55

66
set -Eeo pipefail
77

88
handle_error() {
9-
exit_code=$?
9+
case $# in
10+
1) LINE_NUMBER=$1; EXIT_CODE=$? ;;
11+
2) LINE_NUMBER=$1; EXIT_CODE=$2 ;;
12+
*) LINE_NUMBER=$LINENO; EXIT_CODE=1 ;;
13+
esac
14+
1015
if [ -n "${VACKUP_FAILURE_SCRIPT}" ]; then
11-
/bin/bash "${VACKUP_FAILURE_SCRIPT}" "$1" $exit_code
16+
/bin/bash "${VACKUP_FAILURE_SCRIPT}" "$LINE_NUMBER" "$EXIT_CODE"
1217
fi
13-
exit $exit_code
18+
19+
exit "$EXIT_CODE"
1420
}
1521

1622
trap 'handle_error $LINENO' ERR
1723

1824
usage() {
1925
cat <<EOF
2026
21-
"Docker Volume Backup". Replicates image management commands for volumes.
27+
"Docker Volume Backup". Replicates container image management commands for container volumes.
2228
23-
export/import copies files between a host tarball and a volume. For making
24-
volume backups and restores.
29+
export/import copies files between a host tarball and a volume.
30+
For making volume backups and restores on your local file system.
2531
26-
save/load copies files between an image and a volume. For when you want to use
27-
image registries as a way to push/pull volume data.
32+
save/load copies files between a container image and a container volume.
33+
For storing container volumes in images and push/pulling to registries.
2834
29-
Usage:
35+
Usage:
3036
3137
vackup export VOLUME FILE
32-
Creates a gzip'ed tarball in current directory from a volume
38+
Creates a gzip'ed tarball in current directory from a container volume
3339
3440
vackup import FILE VOLUME
35-
Extracts a gzip'ed tarball into a volume
41+
Extracts a gzip'ed tarball into a container volume
3642
3743
vackup save VOLUME IMAGE
38-
Copies the volume contents to a busybox image in the /volume-data directory
44+
Copies a container volume to a busybox container image in the /volume-data directory
3945
4046
vackup load IMAGE VOLUME
41-
Copies /volume-data contents from an image to a volume
47+
Copies /volume-data from a container image to a container volume
4248
4349
EOF
4450
}
4551

52+
error() {
53+
if [ "$1" == 'u' ] || [ "$1" == 'usage' ]; then
54+
USAGE=1
55+
MESSAGE=$2
56+
CODE=$3
57+
else
58+
USAGE=0
59+
MESSAGE=$1
60+
CODE=$2
61+
fi
62+
63+
if [ -z "$MESSAGE" ]; then
64+
echo 1>&2 'Error'
65+
else
66+
echo 1>&2 "Error: $MESSAGE"
67+
fi
68+
69+
if [ $USAGE -eq 1 ]; then
70+
usage 1>&2
71+
fi
72+
73+
if [ -z "$CODE" ]; then
74+
CODE=1
75+
fi
76+
77+
LINE_NUMBER=$(caller | awk '{ print $1 }')
78+
handle_error "$LINE_NUMBER" "$CODE"
79+
}
80+
81+
fulldirname() {
82+
DIRECTORY=$(dirname "$1")
83+
84+
case "$DIRECTORY" in
85+
/*) ;;
86+
*) DIRECTORY="$(pwd)/$DIRECTORY" ;;
87+
esac
88+
89+
# Use realpath if available, else fallback to cd/pwd for macOS compatibility
90+
if command -v realpath >/dev/null 2>&1; then
91+
DIRECTORY=$(realpath "$DIRECTORY")
92+
else
93+
DIRECTORY=$(cd "$DIRECTORY" && pwd)
94+
fi
95+
96+
echo "$DIRECTORY"
97+
}
98+
4699
if [ -z "$1" ] || [ "$1" == "-h" ] || [ "$1" == "--help" ]; then
47100
usage
48101
exit 0
@@ -51,32 +104,28 @@ fi
51104
cmd_export() {
52105
VOLUME_NAME="$2"
53106
FILE_NAME="$3"
54-
107+
55108
if [ -z "$VOLUME_NAME" ] || [ -z "$FILE_NAME" ]; then
56-
echo "Error: Not enough arguments"
57-
usage
58-
exit 1
109+
error usage 'Not enough arguments'
59110
fi
60-
111+
61112
if ! docker volume inspect --format '{{.Name}}' "$VOLUME_NAME";
62113
then
63-
echo "Error: Volume $VOLUME_NAME does not exist"
64-
exit 1
114+
error "Volume $VOLUME_NAME does not exist"
65115
fi
66116

67-
# TODO: check if file exists on host, if it does
68-
# create a option for overwrite and check if that's set
69-
# TODO: if FILE_NAME starts with / we need to error out
70-
# unless we can translate full file paths
117+
# TODO: check if file exists on host, if it does, create overwrite option and check if set
118+
119+
DIRECTORY=$(fulldirname "$FILE_NAME")
120+
FILE_NAME=$(basename "$FILE_NAME")
71121

72122
if ! docker run --rm \
73-
-v "$VOLUME_NAME":/vackup-volume \
74-
-v "$(pwd)":/vackup \
123+
-v "$VOLUME_NAME":/volume-data \
124+
-v "$DIRECTORY":/mount-volume \
75125
busybox \
76-
tar -zcvf /vackup/"$FILE_NAME" -C /vackup-volume .;
126+
tar -cvzf /mount-volume/"$FILE_NAME" -C /volume-data .;
77127
then
78-
echo "Error: Failed to start busybox backup container"
79-
exit 1
128+
error 'Failed to start busybox backup container'
80129
fi
81130

82131
echo "Successfully tar'ed volume $VOLUME_NAME into file $FILE_NAME"
@@ -85,32 +134,37 @@ cmd_export() {
85134
cmd_import() {
86135
FILE_NAME="$2"
87136
VOLUME_NAME="$3"
88-
137+
89138
if [ -z "$VOLUME_NAME" ] || [ -z "$FILE_NAME" ]; then
90-
echo "Error: Not enough arguments"
91-
usage
92-
exit 1
139+
error usage 'Not enough arguments'
93140
fi
94-
141+
95142
if ! docker volume inspect --format '{{.Name}}' "$VOLUME_NAME";
96143
then
97-
echo "Error: Volume $VOLUME_NAME does not exist"
144+
echo "Warning: Volume $VOLUME_NAME does not exist, creating..."
98145
docker volume create "$VOLUME_NAME"
99146
fi
100147

101-
# TODO: check if file exists on host, if it does
102-
# create a option for overwrite and check if that's set
103-
# TODO: if FILE_NAME starts with / we need to error out
104-
# unless we can translate full file paths
148+
if [ ! -r "$FILE_NAME" ]; then
149+
echo "Error: Could not find or open tar file $FILE_NAME"
150+
exit 1
151+
fi
152+
153+
if [ -d "$FILE_NAME" ]; then
154+
echo "Error: $FILE_NAME is a directory"
155+
exit 1
156+
fi
157+
158+
DIRECTORY=$(fulldirname "$FILE_NAME")
159+
FILE_NAME=$(basename "$FILE_NAME")
105160

106161
if ! docker run --rm \
107-
-v "$VOLUME_NAME":/vackup-volume \
108-
-v "$(pwd)":/vackup \
162+
-v "$VOLUME_NAME":/volume-data \
163+
-v "$DIRECTORY":/mount-volume \
109164
busybox \
110-
tar -xvzf /vackup/"$FILE_NAME" -C /vackup-volume;
165+
tar -xvzf /mount-volume/"$FILE_NAME" -C /volume-data;
111166
then
112-
echo "Error: Failed to start busybox container"
113-
exit 1
167+
error 'Failed to start busybox container'
114168
fi
115169

116170
echo "Successfully unpacked $FILE_NAME into volume $VOLUME_NAME"
@@ -121,58 +175,55 @@ cmd_save() {
121175
IMAGE_NAME="$3"
122176

123177
if [ -z "$VOLUME_NAME" ] || [ -z "$IMAGE_NAME" ]; then
124-
echo "Error: Not enough arguments"
125-
usage
126-
exit 1
178+
error usage 'Not enough arguments'
127179
fi
128180

129-
if ! docker volume inspect --format '{{.Name}}' "$VOLUME_NAME";
181+
if ! docker volume inspect --format '{{.Name}}' "$VOLUME_NAME";
130182
then
131-
echo "Error: Volume $VOLUME_NAME does not exist"
132-
exit 1
183+
error "Volume $VOLUME_NAME does not exist"
133184
fi
134185

135186
if ! docker run \
187+
--pull missing \
136188
-v "$VOLUME_NAME":/mount-volume \
137189
busybox \
138190
cp -Rp /mount-volume/. /volume-data/;
139191
then
140-
echo "Error: Failed to start busybox container"
141-
exit 1
192+
error 'Failed to start busybox container'
142193
fi
143194

195+
# FIXME: this command assumes that no containers started between the cp and container rm commands.
196+
# It would be safer to capture ID of the busybox container on start, then delete that ID
144197
CONTAINER_ID=$(docker ps -lq)
145198

146-
docker commit -m "saving volume $VOLUME_NAME to /volume-data" "$CONTAINER_ID" "$IMAGE_NAME"
199+
docker commit -c "LABEL com.docker.desktop.volume-contents.action=true" -m "saving volume $VOLUME_NAME to /volume-data" "$CONTAINER_ID" "$IMAGE_NAME"
147200

148201
docker container rm "$CONTAINER_ID"
149-
202+
150203
echo "Successfully copied volume $VOLUME_NAME into image $IMAGE_NAME, under /volume-data"
151204
}
152205

153206
cmd_load() {
154207
IMAGE_NAME="$2"
155208
VOLUME_NAME="$3"
156-
209+
157210
if [ -z "$VOLUME_NAME" ] || [ -z "$IMAGE_NAME" ]; then
158-
echo "Error: Not enough arguments"
159-
usage
160-
exit 1
211+
error usage 'Not enough arguments'
161212
fi
162213

163-
if ! docker volume inspect --format '{{.Name}}' "$VOLUME_NAME";
214+
if ! docker volume inspect --format '{{.Name}}' "$VOLUME_NAME";
164215
then
165-
echo "Volume $VOLUME_NAME does not exist, creating..."
216+
echo "Warning: Volume $VOLUME_NAME does not exist, creating..."
166217
docker volume create "$VOLUME_NAME"
167218
fi
168-
219+
220+
# FIXME: this command assumes the image we're copying from has the cp command available
169221
if ! docker run --rm \
170222
-v "$VOLUME_NAME":/mount-volume \
171223
"$IMAGE_NAME" \
172-
cp -Rp /volume-data/. /mount-volume/;
224+
cp -Rp /volume-data/. /mount-volume/;
173225
then
174-
echo "Error: Failed to start container from $IMAGE_NAME"
175-
exit 1
226+
error "Failed to start container from $IMAGE_NAME"
176227
fi
177228

178229
echo "Successfully copied /volume-data from $IMAGE_NAME into volume $VOLUME_NAME"
@@ -184,6 +235,7 @@ case "$COMMAND" in
184235
import) cmd_import "$@" ;;
185236
save) cmd_save "$@" ;;
186237
load) cmd_load "$@" ;;
238+
*) echo "Error: '$COMMAND' is not a recognized command" ; usage ;;
187239
esac
188240

189241
exit 0

0 commit comments

Comments
 (0)