-
Notifications
You must be signed in to change notification settings - Fork 0
/
backup
executable file
·154 lines (134 loc) · 4.09 KB
/
backup
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
#!/bin/sh
# ==============================================================================
# Utilities
# ==============================================================================
_fatal() {
echo "ERROR:" "$@" >&2
exit 1
}
_fail() {
_fatal "Last command failed, exiting"
}
_assert_set() {
if [ -z "$1" ]; then
_fatal "Value for environment variable \"$2\" missing"
fi
}
# ==============================================================================
# rclone
# ==============================================================================
# Credits to https://gist.github.com/earthgecko/3089509
_random_string() {
# shellcheck disable=SC2002
cat /dev/urandom | \
tr -dc 'a-zA-Z0-9' | \
fold -w "$1" | \
head -n 1
}
RCLONE_MAX_TRY="${RCLONE_MAX_TRY:-5}"
RCLONE_PASSWORD=$(_random_string 32)
RCLONE_PORT=8888
RCLONE_USER=$(_random_string 32)
rclone_start() {
_assert_set "$S3_ACCESS_KEY" S3_ACCESS_KEY
_assert_set "$S3_ENDPOINT" S3_ENDPOINT
_assert_set "$S3_PATH" S3_PATH
_assert_set "$S3_REGION" S3_REGION
_assert_set "$S3_SECRET_KEY" S3_SECRET_KEY
if [ -z "${S3_PROVIDER}" ]; then
S3_PROVIDER="AWS"
echo "S3_PROVIDER not set, defaulting to '$S3_PROVIDER'"
fi
rclone config create s3 s3 \
access_key_id "$S3_ACCESS_KEY" \
acl private \
endpoint "$S3_ENDPOINT" \
env_auth false \
force_path_style false \
region "$S3_REGION" \
secret_access_key "$S3_SECRET_KEY" \
provider "$S3_PROVIDER" \
> /dev/null || _fail
rclone serve restic \
--addr localhost:"$RCLONE_PORT" \
--user "$RCLONE_USER" \
--pass "$RCLONE_PASSWORD" \
s3:"$S3_PATH" || _fail &
if [ "$1" = "no_check_rclone" ]; then
echo "Not pinging rclone, waiting 5s"
sleep 5
return 0
fi
sleep 1
for i in $(seq 1 "$RCLONE_MAX_TRY"); do
echo "Attempting to connect to local rclone server ($i/$RCLONE_MAX_TRY)"
if restic snapshots > /dev/null 2>&1; then
return 0
else
sleep 2
fi
done
_fatal "rclone server didn't start within $RCLONE_MAX_TRY tries, aborting"
}
# ==============================================================================
# restic
# ==============================================================================
export RESTIC_PASSWORD
export RESTIC_REPOSITORY="rest:http://$RCLONE_USER:$RCLONE_PASSWORD@localhost:$RCLONE_PORT"
# ==============================================================================
# main
# ==============================================================================
backup() {
ROOTFS_PATH="${ROOTFS_PATH:-/rootfs}"
rclone_start
restic backup "$ROOTFS_PATH" || _fail
restic forget --keep-within "${RESTIC_DURATION:-10y}" || _fail
}
help() {
echo "Usage: $0 [command]
Available commands:
backup Backups the volume to the restic repository
help Prints this message and exit
init Inits the restic repository
restic [cmd] Executes a restic command
restore [id] Empties the volume (!), and restores snapshot [id]
snapshots Lists available snapshots
"
}
init() {
rclone_start "no_check_rclone"
restic init || _fail
}
restic_cmd() {
ROOTFS_PATH="${ROOTFS_PATH:-/rootfs}"
rclone_start
restic "$@" || _fail
}
restore() {
ROOTFS_PATH="${ROOTFS_PATH:-/rootfs}"
SNAPSHOT_ID="${1:-latest}"
for ITEM in "$ROOTFS_PATH"/*; do rm -rf "$ITEM" || _fail; done
rclone_start
restic restore "$SNAPSHOT_ID" \
--path "$ROOTFS_PATH" \
--target / \
|| _fail
}
snapshots() {
rclone_start
restic snapshots || _fail
}
COMMAND=$1
case $COMMAND in
backup|init|restore|snapshots)
shift
$COMMAND "$@"
;;
restic)
shift
restic_cmd "$@"
;;
*)
help
;;
esac