-
-
Notifications
You must be signed in to change notification settings - Fork 669
/
Copy pathrsyncbackup.sh
286 lines (256 loc) Β· 9.68 KB
/
rsyncbackup.sh
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
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
#!/bin/bash
# T&M Hansson IT AB Β© - 2024, https://www.hanssonit.se/
# Copyright Β© 2021 Simon Lindner (https://github.com/szaimen)
true
SCRIPT_NAME="Rsync Backup"
SCRIPT_EXPLAINER="This script creates the off-shore backup of your server."
# shellcheck source=lib.sh
source /var/scripts/fetch_lib.sh
# Check for errors + debug code and abort if something isn't right
# 1 = ON
# 0 = OFF
DEBUG=0
debug_mode
# Check if root
root_check
# Variables
START_TIME=$(date +%s)
CURRENT_DATE=$(date --date @"$START_TIME" +"%Y%m%d_%H%M%S")
CURRENT_DATE_READABLE=$(date --date @"$START_TIME" +"%d.%m.%Y - %H:%M:%S")
LOG_FILE="$VMLOGS/rsyncbackup-$CURRENT_DATE.log"
# This is needed for running via cron
PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/snap/bin
# Functions
inform_user() {
echo -e "\n\n# $2"
print_text_in_color "$1" "$2"
}
paste_log_file() {
cat "$LOG_FILE" >> "$RSYNC_BACKUP_LOG"
echo -e "\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n" >> "$RSYNC_BACKUP_LOG"
}
remove_log_file() {
rm "$LOG_FILE"
}
show_drive_usage() {
inform_user "$ICyan" "Showing drive usage..."
lsblk -o FSUSE%,SIZE,MOUNTPOINT,NAME | grep -v "loop[0-9]" | grep "%" | sed 's|`-||;s/|-//;s/ | //'
echo ""
df -h | grep -v "loop[0-9]" | grep -v "tmpfs" | grep -v "^udev" | grep -v "^overlay"
}
send_error_mail() {
if [ -d "$BACKUP_TARGET_DIRECTORY" ]
then
if [ -z "$DO_NOT_UMOUNT_BACKUP_DRIVES" ]
then
inform_user "$ICyan" "Unmounting the offshore backup drive..."
umount "$BACKUP_MOUNTPOINT"
fi
fi
if [ -d "$BACKUP_SOURCE_DIRECTORY" ]
then
if [ -z "$DO_NOT_UMOUNT_BACKUP_DRIVES" ]
then
inform_user "$ICyan" "Unmounting the daily backup drive..."
umount "$BACKUP_SOURCE_MOUNTPOINT"
fi
fi
get_expiration_time
inform_user "$IRed" "Off-shore backup sent error on $END_DATE_READABLE ($DURATION_READABLE)"
inform_user "$IRed" "Off-shore backup failed! $1"
if ! send_mail "Off-shore backup failed! $1" "$(cat "$LOG_FILE")"
then
notify_admin_gui \
"Off-shore backup failed! Though mail sending didn't work!" \
"Please look at the log file $LOG_FILE if you want to find out more."
paste_log_file
else
paste_log_file
remove_log_file
fi
exit 1
}
re_rename_snapshot() {
inform_user "$ICyan" "Re-renaming the snapshot..."
if ! lvrename /dev/ubuntu-vg/NcVM-snapshot-pending /dev/ubuntu-vg/NcVM-snapshot
then
return 1
else
return 0
fi
}
get_expiration_time() {
END_TIME=$(date +%s)
END_DATE_READABLE=$(date --date @"$END_TIME" +"%d.%m.%Y - %H:%M:%S")
DURATION=$((END_TIME-START_TIME))
DURATION_SEC=$((DURATION % 60))
DURATION_MIN=$(((DURATION / 60) % 60))
DURATION_HOUR=$((DURATION / 3600))
DURATION_READABLE=$(printf "%02d hours %02d minutes %02d seconds" $DURATION_HOUR $DURATION_MIN $DURATION_SEC)
}
# Write output to logfile.
exec > >(tee -i "$LOG_FILE")
exec 2>&1
# Send mail that backup was started
if ! send_mail "Off-shore backup started!" "You will be notified again when the backup is finished!
Please don't restart or shutdown your server until then!"
then
notify_admin_gui "Off-shore backup started!" "You will be notified again when the backup is finished!
Please don't restart or shutdown your server until then!"
fi
# Start backup
inform_user "$IGreen" "Off-shore backup started! $CURRENT_DATE_READABLE"
# Check if the file exists
if ! [ -f "$SCRIPTS/off-shore-rsync-backup.sh" ]
then
send_error_mail "The off-shore-rsync-backup.sh doesn't exist."
fi
# Check if all needed variables are there (they get exported by the local off-shore-rsync-backup.sh)
if [ -z "$BACKUP_TARGET_DIRECTORY" ] || [ -z "$BACKUP_MOUNTPOINT" ] || [ -z "$RSYNC_BACKUP_LOG" ] \
|| [ -z "$BACKUP_SOURCE_MOUNTPOINT" ] || [ -z "$BACKUP_SOURCE_DIRECTORY" ]
then
send_error_mail "Didn't get all needed variables."
fi
# Check if pending snapshot is existing and cancel the backup in this case.
if does_snapshot_exist "NcVM-snapshot-pending"
then
DO_NOT_UMOUNT_BACKUP_DRIVES=1
msg_box "The snapshot pending does exist. Can currently not proceed.
Please try again later.\n
If you are sure that no update or backup is currently running, you can fix this by rebooting your server."
send_error_mail "NcVM-snapshot-pending exists. Please try again later!"
fi
# Check if snapshot can get created
if ! does_snapshot_exist "NcVM-snapshot"
then
send_error_mail "NcVM-snapshot doesn't exists."
fi
# Check if at least one daily backup drive has run
BORGBACKUP_LOG="$(grep "^export BORGBACKUP_LOG" "$SCRIPTS/daily-borg-backup.sh" \
| sed 's|.*BORGBACKUP_LOG="||' | sed 's|"$||')"
if [ -z "$BORGBACKUP_LOG" ] || ! [ -f "$BORGBACKUP_LOG" ] || ! grep -q "Backup finished on" "$BORGBACKUP_LOG"
then
send_error_mail "Not even one daily backup was successfully created. Please wait for that first."
fi
# Prepare backup repository
inform_user "$ICyan" "Mounting the daily backup drive..."
if ! [ -d "$BACKUP_SOURCE_DIRECTORY" ]
then
mount "$BACKUP_SOURCE_MOUNTPOINT" &>/dev/null
if ! [ -d "$BACKUP_SOURCE_DIRECTORY" ]
then
send_error_mail "Could not mount the daily backup drive. Is it connected?"
fi
fi
# Prepare backup repository
inform_user "$ICyan" "Mounting the off-shore backup drive..."
if ! [ -d "$BACKUP_TARGET_DIRECTORY" ]
then
mount "$BACKUP_MOUNTPOINT" &>/dev/null
if ! [ -d "$BACKUP_TARGET_DIRECTORY" ]
then
send_error_mail "Could not mount the off-shore backup drive. Please connect it!"
fi
fi
# Check daily backup
rm -f /tmp/DAILY_BACKUP_CHECK_SUCCESSFUL
export SKIP_DAILY_BACKUP_CREATION=1
bash "$SCRIPTS/daily-borg-backup.sh"
if ! [ -f "/tmp/DAILY_BACKUP_CHECK_SUCCESSFUL" ]
then
send_error_mail "Daily backup check failed!" \
"Backup check was unsuccessful! $(date +%T)"
fi
# Test if btrfs volume
if grep " $BACKUP_MOUNTPOINT " /etc/mtab | grep -q btrfs
then
IS_BTRFS_PART=1
mkdir -p "$BACKUP_MOUNTPOINT/.snapshots"
btrfs subvolume snapshot -r "$BACKUP_MOUNTPOINT" "$BACKUP_MOUNTPOINT/.snapshots/@$CURRENT_DATE"
while [ "$(find "$BACKUP_MOUNTPOINT/.snapshots/" -maxdepth 1 -mindepth 1 -type d -name '@*_*' | wc -l)" -gt 4 ]
do
DELETE_SNAP="$(find "$BACKUP_MOUNTPOINT/.snapshots/" -maxdepth 1 -mindepth 1 -type d -name '@*_*' | sort | head -1)"
btrfs subvolume delete "$DELETE_SNAP"
done
fi
# Check if pending snapshot is existing and cancel the backup in this case.
if does_snapshot_exist "NcVM-snapshot-pending"
then
DO_NOT_UMOUNT_BACKUP_DRIVES=1
msg_box "The snapshot pending does exist. Can currently not proceed.
Please try again later.\n
If you are sure that no update or backup is currently running, you can fix this by rebooting your server."
send_error_mail "NcVM-snapshot-pending exists. Please try again later!"
fi
# Rename the snapshot to represent that the backup is pending
inform_user "$ICyan" "Renaming the snapshot..."
if ! lvrename /dev/ubuntu-vg/NcVM-snapshot /dev/ubuntu-vg/NcVM-snapshot-pending
then
send_error_mail "Could not rename the snapshot to snapshot-pending."
fi
# Create the backup
inform_user "$ICyan" "Creating the off-shore backup..."
if ! rsync --archive --human-readable --delete --stats "$BACKUP_SOURCE_DIRECTORY/" "$BACKUP_TARGET_DIRECTORY"
then
show_drive_usage
re_rename_snapshot
send_error_mail "Something failed during the rsync job."
fi
# Adjust permissions and scrub volume
if [ -n "$IS_BTRFS_PART" ]
then
inform_user "$ICyan" "Adjusting permissions..."
find "$BACKUP_MOUNTPOINT/" -not -path "$BACKUP_MOUNTPOINT/.snapshots/*" \
\( ! -perm 600 -o ! -group root -o ! -user root \) -exec chmod 600 {} \; -exec chown root:root {} \;
inform_user "$ICyan" "Making sure that all data is written out correctly by waiting 10 min..."
# This fixes an issue where checksums are not yet created before the scrub command runs which then reports checksum errors
if ! sleep 10m
then
re_rename_snapshot
send_error_mail "Some errors were reported while waiting for the data to get written out."
fi
inform_user "$ICyan" "Scrubbing BTRFS partition..."
if ! btrfs scrub start -B "$BACKUP_MOUNTPOINT"
then
re_rename_snapshot
send_error_mail "Some errors were reported while scrubbing the BTRFS partition."
fi
fi
# Rename the snapshot back to normal
if ! re_rename_snapshot
then
send_error_mail "Could not rename the snapshot-pending to snapshot."
fi
# Print usage of drives into log
show_drive_usage
# Unmount the backup drive
inform_user "$ICyan" "Unmounting the off-shore backup drive..."
if mountpoint -q "$BACKUP_MOUNTPOINT" && ! umount "$BACKUP_MOUNTPOINT"
then
send_error_mail "Could not unmount the off-shore backup drive!"
fi
# Unmount the backup drive
inform_user "$ICyan" "Unmounting the daily backup drive..."
if mountpoint -q "$BACKUP_SOURCE_MOUNTPOINT" && ! umount "$BACKUP_SOURCE_MOUNTPOINT"
then
send_error_mail "Could not unmount the daily backup drive!"
fi
# Resetting the timer for off-shore backups
inform_user "$ICyan" "Resetting the timer for off-shore backups..."
sed -i 's|^DAYS_SINCE_LAST_BACKUP.*|DAYS_SINCE_LAST_BACKUP=0|' "$SCRIPTS/off-shore-rsync-backup.sh"
# Show expiration time
get_expiration_time
inform_user "$IGreen" "Off-shore backup finished on $END_DATE_READABLE ($DURATION_READABLE)"
# Send mail about successful backup
if ! send_mail "Off-shore backup successful! You can now disconnect the off-shore backup drive!" "$(cat "$LOG_FILE")"
then
notify_admin_gui \
"Off-shore backup successful! Though mail sending didn't work!" \
"You can now disconnect the off-shore backup drive! \
Please look at the log file $LOG_FILE if you want to find out more."
paste_log_file
else
paste_log_file
remove_log_file
fi
exit