-
Notifications
You must be signed in to change notification settings - Fork 0
/
sanoid_vm_backup
executable file
·107 lines (91 loc) · 5.52 KB
/
sanoid_vm_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
#!/usr/bin/env bash
export
libvirt_domains=$(libvirt_domains)
export SANOID_TARGETS=${SANOID_TARGETS:-${SANOID_TARGET}}
export SANOID_SCRIPT=${SANOID_SCRIPT:-${1}}
export SANOID_SNAPNAMES=${SANOID_SNAPNAMES:-${SANOID_SNAPNAME}}
export
while read TARGET; do
printf '%b\n' "Sanoid is processing target: '${TARGET}'"
domains=$(printf '%b' "${libvirt_domains}" | yq "{ \"domains\": [ .domains[] | select(.block_devices[].zfs_dataset == \"${TARGET}\") ] }")
#printf '%b\n' "${domains}"
while read domain; do
printf '%b\n' "The domain '${domain}' has volumes on the '${TARGET}' dataset."
if [ "${SANOID_SCRIPT}" == "pre" ]; then
domain_state=$(printf '%b' "${domains}" | yq ".domains[] | select(.name == \"${domain}\") | .state")
dom_freeze_support=$(printf '%b' "${domains}" | yq ".domains[] | select(.name == \"${domain}\") | .fs_freeze_thaw_supported")
dom_trim_support=$(printf '%b' "${domains}" | yq ".domains[] | select(.name == \"${domain}\") | .fs_freeze_thaw_supported")
printf '%b\n' "The domain '${domain}' is currently '${domain_state}'."
printf '%b\n' "The domain '${domain}' suppports filesystem freezing: ${dom_freeze_support}"
printf '%b\n' "The domain '${domain}' suppports filesystem trimming: ${dom_trim_support}"
#TODO: export the machine .xml with "virsh dumpxml"
if [ "${domain_state}" == "running" ]; then
# Ask the guest to trim it's filesystems
if [ "${dom_trim_support}" == "true" ]; then
printf '%b\n' "virsh domfstrim \"${domain}\""
virsh domfstrim "${domain}" || true
fi
# Ask the guest to freeze it's filesystems
if [ "${dom_freeze_support}" == "true" ]; then
printf '%b\n' "virsh domfsfreeze \"${domain}\""
virsh domfsfreeze "${domain}" || true
fi
# Everything should now be synced to disk. Suspend the VM.
printf '%b\n' "virsh suspend \"${domain}\""
virsh suspend "${domain}" || true
fi
fi
while read zfs_dataset; do
if [ "${SANOID_SCRIPT}" == "pre" ]; then
# Atomic Snapshot creation
#TODO: what about datasets we don't want to snapshot
atomic_name="atomic_"$(printf '%b' "${SANOID_SNAPNAMES}" | awk 'BEGIN{FS="_"}{print $2"_"$3}')
printf '%b\n' "The domain '${domain}' needs an atomic snapshot created on '${zfs_dataset}'"
printf '%b\n' "zfs snapshot \"${zfs_dataset}@${atomic_name}"
zfs snapshot "${zfs_dataset}@${atomic_name}"
elif [ "${SANOID_SCRIPT}" == "post" ]; then
true
# Should we run syncoid here?
for (( d=0; d<=10; d++ )) do
#user:net.openoid.syncoid.destination.${d}
destination=$(zfs get "user:net.openoid.syncoid.destination.${d}" "${TARGET}" | tail -n +2 | awk '{print $3}')
ds_name=$(basename "${zfs_dataset}")
destination=$(printf '%b' "${destination}" | sed "s/%d/${ds_name}/g")
destination_nbd=$(zfs get "user:net.openoid.syncoid.destination_nbd.${d}" "${TARGET}" | tail -n +2 | awk '{print $3}')
if [ "${destination}" != "" ] && [ "${destination}" != "-" ]; then
#TODO: For pull backups...?
echo "systemd-run --unit=\"syncoid-${zfs_dataset}\" -G /usr/sbin/syncoid --compress=none --create-bookmark --no-sync-snap --sendoptions=\"w\" \"${zfs_dataset}\" \"${destination}\""
systemd-run --unit="syncoid-${zfs_dataset}" /usr/sbin/syncoid --debug --dumpsnaps --compress=none --create-bookmark --no-sync-snap --sendoptions="w" "${zfs_dataset}" "${destination}"
fi
if [ "${zfs_dataset}" != "${TARGET}" ]; then
destination=$(zfs get "user:net.openoid.syncoid.destination.${d}" "${zfs_dataset}" | tail -n +2 | awk '{print $3}')
destination=$(printf '%b' "${destination}" | sed "s/%d/${ds_name}/g")
if [ "${destination}" != "" ] && [ "${destination}" != "-" ]; then
echo "systemd-run --unit=\"syncoid-${zfs_dataset}\" -G /usr/sbin/syncoid --compress=none --create-bookmark --no-sync-snap --sendoptions=\"w\" \"${zfs_dataset}\" \"${destination}\""
systemd-run --unit="syncoid-${zfs_dataset}" /usr/sbin/syncoid --debug --dumpsnaps --compress=none --create-bookmark --no-sync-snap --sendoptions="w" "${zfs_dataset}" "${destination}"
fi
fi
done
elif [ "${SANOID_SCRIPT}" == "prune" ]; then
# Atomic Snapshot cleanup
atomic_name="atomic_"$(printf '%b' "${SANOID_SNAPNAMES}" | awk 'BEGIN{FS="_"}{print $2"_"$3}')
while read snapname; do
printf '%b\n' "zfs destroy \"${snapname}\""
done < <(zfs list -t snapshot -r "${zfs_dataset}" | grep "@${atomic_name}")
# TODO: Cleanup bookmarks as they will hold space from being freed
fi
done < <(printf '%b' "${domains}" | yq ".domains[] | select(.name == \"${domain}\") | .block_devices[].zfs_dataset" | grep -v 'null' | sort | uniq)
if [ "${SANOID_SCRIPT}" == "pre" ]; then
printf '%b\n' "virsh resume \"${domain}\""
virsh resume "${domain}" || true
sleep 5
printf '%b\n' "virsh resume \"${domain}\" (again, just to be sure)"
virsh resume "${domain}" 2>/dev/null || true
printf '%b\n' "virsh domfsthaw \"${domain}\""
virsh domfsthaw "${domain}" 2>/dev/null || true
sleep 2
printf '%b\n' "virsh domfsthaw \"${domain}\" (again, just to be sure)"
virsh domfsthaw "${domain}" 1>/dev/null 2>/dev/null || true
fi
done < <(printf '%b' "${domains}" | yq '.domains[].name')
done < <(printf '%b\n' "${SANOID_TARGETS}" | sed 's/,/\n/g')