-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathdocker-volume
executable file
·225 lines (203 loc) · 6.6 KB
/
docker-volume
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
#!/usr/bin/env bash
USER_COMMAND=
USER_COMMAND_TARGETS=
BACKUP_DIRECTORY=
USE_FORCE=no
VOLUME_BACKUP_IMAGE_NAME=docker-volume-backup-helper
VOLUME_BACKUP_IMAGE_VERSION=1
VOLUME_BACKUP_IMAGE="$VOLUME_BACKUP_IMAGE_NAME:$VOLUME_BACKUP_IMAGE_VERSION"
PATH_TO_IMAGE_BUILD_DIR="/tmp/docker-volume-backup-helper-v$VOLUME_BACKUP_IMAGE_VERSION"
ARG_COUNTER=1
set $(getopt --path: "$@")
while [ $# -gt 0 ]
do
case "$1" in
backup|restore|clean)
if [ "$ARG_COUNTER" = "1" ]; then
USER_COMMAND="$1"
if [ "$USER_COMMAND" = backup ]; then
BACKUP_DIRECTORY=$(pwd)
fi
else
echo ERROR first argument must be command, \'backup\' or \'restore\'
exit 2
fi
;;
-f)
USE_FORCE=yes
;;
--path)
if [ $USER_COMMAND = backup ]; then
BACKUP_DIRECTORY="$(cd "$(dirname "$2")" ; pwd -P)/$(basename "$2")" # absolute path
shift 1
else
echo "The --path key works only with backup command"
exit 2
fi
;;
--help|-h)
echo "This script saves content of docker volume to file.tar (BACKUP), "
echo " and creates volume out of file.tar (RESTORE), created from the volume."
echo "BACKUP usage: "
echo " docker-volume backup [--path PATH] [VOLUME...]"
echo " PATH - directory for backups, \$PWD by default."
echo " VOLUMEs - names of docker volumes to be backed up in folder PATH, all volumes by default"
echo "RESTORE usage: "
echo " docker-volume restore [-f] [FILE...|PATH...]"
echo " -f - remove previous volume, prune containers if needed, interactive."
echo " PATHs - directories of backups, where all *.tar files to be restored located."
echo " FILEs - docker volume backups files *.tar, that were created by this script."
exit 2
;;
--version|-v)
echo docker-volume version $VOLUME_BACKUP_IMAGE_VERSION
exit 0
;;
*)
if [ "$ARG_COUNTER" = "1" ]; then
echo ERROR invalid command \'"$1"\', only \'backup\' and \'restore\' alowed;
exit 2
else
USER_COMMAND_TARGETS="$USER_COMMAND_TARGETS $1"
fi
;;
esac
shift
ARG_COUNTER=$((ARG_COUNTER + 1))
done
if [ "$ARG_COUNTER" = "1" ]; then
echo "no arguments, use --help"
exit 2
fi
function build_and_install_helper {
# TODO check if dir creation permitted
mkdir -p "$PATH_TO_IMAGE_BUILD_DIR"
echo '
FROM alpine:latest
COPY --chmod=777 backup-volumes.sh /var/backup-volumes.sh
CMD sh /var/backup-volumes.sh
' > "$PATH_TO_IMAGE_BUILD_DIR"/Dockerfile
echo '
#!/bin/env bash
if [ $COMMAND = BACKUP ]; then
cd /var/src && tar -c ./ > /var/dst/"$VOLUME_NAME".tar
exit $?
elif [ $COMMAND = RESTORE ]; then
cd /var/dst/ && tar -xf /var/src/"$VOLUME_NAME".tar
exit $?
else
exit 1
fi
' > "$PATH_TO_IMAGE_BUILD_DIR"/backup-volumes.sh
function clear_building_docker_backup_helper_image {
rm "$PATH_TO_IMAGE_BUILD_DIR"/Dockerfile
rm "$PATH_TO_IMAGE_BUILD_DIR"/backup-volumes.sh
rmdir "$PATH_TO_IMAGE_BUILD_DIR"
}
docker build -t "$VOLUME_BACKUP_IMAGE_NAME:$VOLUME_BACKUP_IMAGE_VERSION" "$PATH_TO_IMAGE_BUILD_DIR"
if [ $? -ne 0 ]; then
echo ERROR cannot build helper image
clear_building_docker_backup_helper_image
exit 1
fi
clear_building_docker_backup_helper_image
return $?
}
# check if docker available
docker --version > /dev/null
if [ $? -ne 0 ]; then
echo ERROR docker is not available
exit 1
fi
function contains {
if [[ $1 =~ (^|[[:space:]])$2($|[[:space:]]) ]]; then
return 0
else
return 1
fi
}
VB_INSTALLED_IMAGE=$(docker images "$VOLUME_BACKUP_IMAGE_NAME" --format '{{.Repository}}:{{.Tag}}')
#if ! [[ "$VB_INSTALLED_IMAGE" =~ "$VOLUME_BACKUP_IMAGE" ]]; then
if ! contains "$VB_INSTALLED_IMAGE" "$VOLUME_BACKUP_IMAGE"; then
# no helper image installed
build_and_install_helper
fi
if [ "$USER_COMMAND" = backup ]; then
mkdir -p "$BACKUP_DIRECTORY"
if [ $? -ne 0 ]; then
echo cannot access directory for backups
exit 1
fi
EXISTING_VOLUMES=$(docker volume ls --format '{{.Name}}')
if [ -z "$USER_COMMAND_TARGETS" ]; then
USER_COMMAND_TARGETS="$EXISTING_VOLUMES"
fi
for VOLUME in $USER_COMMAND_TARGETS; do
if contains "$EXISTING_VOLUMES" "$VOLUME"; then
docker run -e COMMAND=BACKUP -e VOLUME_NAME="$VOLUME" -v "$VOLUME":/var/src --mount type=bind,source="$BACKUP_DIRECTORY",target=/var/dst/ "$VOLUME_BACKUP_IMAGE"
if [ "$?" -ne "0" ]; then
echo ERROR could not backup volume \'"$VOLUME"\'
fi
else
echo ERROR volume \'"$VOLUME"\' was not found
fi
done
fi
function remove_volume_if_need_to_use_fore {
local VOLUME_NAME="$1"
if [ "$USE_FORCE" = "yes" ]; then
docker volume rm $VOLUME_NAME
if [ $? -ne 0 ]; then
docker container prune
docker volume rm $VOLUME_NAME
fi
else
echo WARNING: volume \'"$VOLUME_NAME"\' exists, it will not be restored, delete it... or use the force
fi
return $?
}
function create_docker_volume_and_restore_data {
local VOLUME_NAME="$1"
local BACKUP_DIRECTORY="$2"
docker volume create "$VOLUME_NAME" > /dev/null
if [ $? -ne 0 ]; then
echo ERROR could not create volume \'"$VOLUME_NAME"\'
return 1
fi
docker run -e COMMAND=RESTORE -e VOLUME_NAME="$VOLUME_NAME" -v "$VOLUME_NAME":/var/dst --mount type=bind,source="$BACKUP_DIRECTORY",target=/var/src/ "$VOLUME_BACKUP_IMAGE"
if [ $? -ne 0 ]; then
echo ERROR could not run restoration for \'"$VOLUME_NAME"\'
return 1
fi
}
if [ "$USER_COMMAND" = restore ]; then
EXISTING_VOLUMES=$(docker volume ls --format '{{.Name}}')
for BACKED_FILE in $USER_COMMAND_TARGETS; do
BACKED_FILE="$(cd "$(dirname "$BACKED_FILE")"; pwd -P)/$(basename "$BACKED_FILE")" # absolute path
if [ -f $BACKED_FILE ]; then
VOLUME_NAME=$(basename "$BACKED_FILE" | sed 's/\.tar$//')
if contains "$EXISTING_VOLUMES" "$VOLUME_NAME"; then
remove_volume_if_need_to_use_fore "$VOLUME_NAME"
fi
create_docker_volume_and_restore_data "$VOLUME_NAME" $(dirname "$BACKED_FILE")
elif [ -d "$BACKED_FILE" ]; then
VOLUMES=$(find "$BACKED_FILE" -name '*.tar')
for VOLUME_NAME in $VOLUMES; do
VOLUME_NAME=$(basename $VOLUME_NAME| sed 's/\.tar//')
if contains "$EXISTING_VOLUMES" "$VOLUME_NAME"; then
remove_volume_if_need_to_use_fore "$VOLUME_NAME"
fi
create_docker_volume_and_restore_data "$VOLUME_NAME" "$BACKED_FILE"
done
else
echo ERROR tar-file or directory \'"$BACKED_FILE"\' does not exist
fi
done
fi
if [ "$USER_COMMAND" = clean ]; then
docker image rm "$VOLUME_BACKUP_IMAGE"
if [ $? -ne 0 ]; then
docker container prune
docker image rm "$VOLUME_BACKUP_IMAGE"
fi
fi