2021-01-06 06:57:50 +00:00
|
|
|
#!/bin/bash
|
|
|
|
|
|
|
|
helpFunction()
|
|
|
|
{
|
|
|
|
echo ""
|
2021-01-07 07:38:44 +00:00
|
|
|
echo "Usage: $0 -v VmName -t TargetHost -d TargetDataset -l LIMIT"
|
2021-01-06 06:57:50 +00:00
|
|
|
echo -e "\t-v Name of the vm to backup"
|
|
|
|
echo -e "\t-t Backup target host name"
|
|
|
|
echo -e "\t-s VM source zfs dataset"
|
|
|
|
echo -e "\t-d Backup target zfs dataset"
|
2021-01-06 10:07:05 +00:00
|
|
|
echo -e "\t-l Limit Bandwith"
|
2021-01-06 06:57:50 +00:00
|
|
|
exit 1 # Exit script after printing help
|
|
|
|
}
|
|
|
|
|
2021-01-06 10:07:05 +00:00
|
|
|
while getopts "v:t:s:d:l:" opt
|
2021-01-06 06:57:50 +00:00
|
|
|
do
|
|
|
|
case "$opt" in
|
|
|
|
v ) VM="$OPTARG" ;;
|
|
|
|
t ) DESTHOST="$OPTARG" ;;
|
|
|
|
s ) SRCZFS="$OPTARG" ;;
|
|
|
|
d ) DESTZFS="$OPTARG" ;;
|
2021-01-06 10:07:05 +00:00
|
|
|
l ) LIMIT="$OPTARG" ;;
|
2021-01-06 06:57:50 +00:00
|
|
|
? ) helpFunction ;; # Print helpFunction in case parameter is non-existent
|
|
|
|
esac
|
|
|
|
done
|
|
|
|
|
|
|
|
# Print helpFunction in case parameters are empty
|
2021-01-06 10:07:05 +00:00
|
|
|
if [ -z "$VM" ] || [ -z "$DESTHOST" ] || [ -z "$DESTZFS" ] || [ -z "$SRCZFS" ] || [ -z "$LIMIT" ]
|
2021-01-06 06:57:50 +00:00
|
|
|
then
|
|
|
|
echo "Some or all of the parameters are empty";
|
|
|
|
helpFunction
|
|
|
|
fi
|
|
|
|
|
2021-01-07 12:14:44 +00:00
|
|
|
echo "$(date +%Y-%m-%d_%H:%M:%S): Starting Backup of $VM"
|
|
|
|
|
2021-01-07 12:10:30 +00:00
|
|
|
DAYS=$(zfs get backup:days -H -o value $SRCZFS)
|
|
|
|
if [[ $DAYS == "-" ]]
|
|
|
|
then
|
|
|
|
DAYS=7
|
|
|
|
fi
|
2021-01-07 12:14:44 +00:00
|
|
|
echo "$(date +%Y-%m-%d_%H:%M:%S): Keeping backups for $DAYS days"
|
2021-01-07 12:10:30 +00:00
|
|
|
DAYS=$(($DAYS + 1))
|
2021-01-06 09:18:14 +00:00
|
|
|
DATE=$(date "+%Y%m%d%H%M")
|
2021-01-07 12:10:30 +00:00
|
|
|
DATEOLD=$(date -d -"$DAYS"day "+%Y%m%d")
|
2021-01-06 08:24:19 +00:00
|
|
|
SNAPNAME="backup_$DATE"
|
2021-01-06 06:57:50 +00:00
|
|
|
|
2021-01-07 11:10:48 +00:00
|
|
|
|
2021-01-07 08:54:55 +00:00
|
|
|
abortFunction()
|
|
|
|
{
|
|
|
|
zfs set backup:success="false" $SRCZFS
|
|
|
|
zfs set backup:failed="$DATE" $SRCZFS
|
|
|
|
exit 1
|
|
|
|
}
|
|
|
|
|
2021-01-13 12:14:37 +00:00
|
|
|
VMDISKS=$(virsh domblklist $VM | grep qcow2 | egrep -o [vs]d.)
|
2021-01-06 08:24:19 +00:00
|
|
|
DISKSPEC=""
|
|
|
|
for disk in $VMDISKS
|
|
|
|
do
|
2021-01-06 08:54:25 +00:00
|
|
|
DISKSPEC+="--diskspec $disk,file=/srv/snapshots/$VM/$VM-$disk-$SNAPNAME.qcow2,snapshot=external "
|
2021-01-06 08:24:19 +00:00
|
|
|
done
|
2021-01-06 08:46:28 +00:00
|
|
|
|
2021-01-06 09:18:14 +00:00
|
|
|
# create snapshot dataset
|
|
|
|
zfs create tank/snapshots/$VM
|
|
|
|
|
2021-01-06 10:58:51 +00:00
|
|
|
# create virsh xml-dump of vm
|
|
|
|
virsh dumpxml $VM > /srv/vms/$VM/vm-$VM.xml
|
|
|
|
|
2021-01-07 11:58:28 +00:00
|
|
|
echo "$(date +%Y-%m-%d_%H:%M:%S): Create VM snapshot of $VM"
|
2021-01-06 09:50:06 +00:00
|
|
|
virsh snapshot-create-as --domain $VM --name $SNAPNAME --quiesce --atomic --disk-only $DISKSPEC >/dev/null 2>&1
|
2021-01-06 08:46:28 +00:00
|
|
|
if [ $? -ne 0 ]
|
|
|
|
then
|
2021-01-06 09:50:06 +00:00
|
|
|
virsh snapshot-create-as --domain $VM --name $SNAPNAME --disk-only $DISKSPEC >/dev/null 2>&1
|
|
|
|
if [ $? -ne 0 ]
|
|
|
|
then
|
|
|
|
echo "VM snapshot creation failed" >&2
|
2021-01-07 08:54:55 +00:00
|
|
|
abortFunction
|
2021-01-06 09:50:06 +00:00
|
|
|
else
|
2021-01-08 06:59:46 +00:00
|
|
|
echo "$(date +%Y-%m-%d_%H:%M:%S): Snapshot created without --quiesce"
|
2021-01-06 09:50:06 +00:00
|
|
|
fi
|
2021-01-06 08:46:28 +00:00
|
|
|
fi
|
|
|
|
|
2021-01-07 11:58:28 +00:00
|
|
|
echo "$(date +%Y-%m-%d_%H:%M:%S): Creating ZFS snapshot $SRCZFS@$SNAPNAME"
|
2021-01-06 08:46:28 +00:00
|
|
|
zfs snapshot "$SRCZFS"@"$SNAPNAME"
|
|
|
|
if [ $? -ne 0 ]
|
|
|
|
then
|
|
|
|
echo "ZFS snapshot creation failed" >&2
|
2021-01-07 08:54:55 +00:00
|
|
|
abortFunction
|
2021-01-06 08:46:28 +00:00
|
|
|
fi
|
|
|
|
|
2021-01-07 11:58:28 +00:00
|
|
|
echo "$(date +%Y-%m-%d_%H:%M:%S): Deleting vm disk snapshots"
|
2021-01-06 08:46:28 +00:00
|
|
|
for disk in $VMDISKS
|
|
|
|
do
|
|
|
|
virsh blockcommit $VM $disk --pivot --active >/dev/null
|
|
|
|
done
|
|
|
|
|
2021-01-13 12:14:37 +00:00
|
|
|
VMDISKS=$(virsh domblklist $VM | egrep [vs]d.)
|
2021-01-06 08:46:28 +00:00
|
|
|
for disk in $VMDISKS
|
|
|
|
do
|
|
|
|
if [[ $disk == *"snapshot"* ]]
|
|
|
|
then
|
|
|
|
echo "Snapshot deletion failed for $disk" >&2
|
2021-01-07 08:54:55 +00:00
|
|
|
abortFunction
|
2021-01-06 08:46:28 +00:00
|
|
|
fi
|
|
|
|
done
|
|
|
|
|
2021-01-07 11:58:28 +00:00
|
|
|
virsh snapshot-delete $VM $SNAPNAME --metadata > /dev/null
|
2021-01-06 09:18:14 +00:00
|
|
|
|
2021-01-06 09:29:58 +00:00
|
|
|
SUCCESS=$(zfs get backup:success -H -o value $SRCZFS)
|
2021-01-07 11:10:48 +00:00
|
|
|
LASTBACKUP=$(zfs get backup:date -H -o value $SRCZFS)
|
2021-01-06 09:29:58 +00:00
|
|
|
if [[ $SUCCESS == "true" ]]
|
|
|
|
then
|
|
|
|
LASTSNAP="backup_$LASTBACKUP"
|
2021-01-07 11:58:28 +00:00
|
|
|
echo "$(date +%Y-%m-%d_%H:%M:%S): Sending incremental snapshot from $LASTSNAP"
|
2021-01-11 10:36:35 +00:00
|
|
|
ssh $DESTHOST sudo zfs rollback "$DESTZFS"@"$LASTSNAP"
|
|
|
|
zfs send -R -i "$SRCZFS"@"$LASTSNAP" "$SRCZFS"@"$SNAPNAME" | pv -L $LIMIT | ssh $DESTHOST sudo zfs recv $DESTZFS
|
2021-01-06 09:29:58 +00:00
|
|
|
else
|
2021-01-07 11:10:48 +00:00
|
|
|
if [[ $LASTBACKUP != "-" ]]
|
|
|
|
then
|
|
|
|
LASTSNAP="backup_$LASTBACKUP"
|
2021-01-07 11:58:28 +00:00
|
|
|
echo "$(date +%Y-%m-%d_%H:%M:%S): Trying to send incremental snapshot from $LASTSNAP"
|
2021-01-11 09:43:55 +00:00
|
|
|
ssh $DESTHOST sudo zfs rollback "$DESTZFS"@"$LASTSNAP"
|
|
|
|
zfs send -R -i "$SRCZFS"@"$LASTSNAP" "$SRCZFS"@"$SNAPNAME" | pv -L $LIMIT | ssh $DESTHOST sudo zfs recv $DESTZFS
|
2021-01-07 11:10:48 +00:00
|
|
|
else
|
2021-01-07 11:58:28 +00:00
|
|
|
echo "$(date +%Y-%m-%d_%H:%M:%S): Sending full snapshot"
|
2021-01-07 11:10:48 +00:00
|
|
|
zfs send -R "$SRCZFS"@"$SNAPNAME" | pv -L $LIMIT | ssh $DESTHOST sudo zfs recv -F $DESTZFS
|
|
|
|
fi
|
2021-01-06 09:29:58 +00:00
|
|
|
fi
|
2021-01-06 09:18:14 +00:00
|
|
|
if [ $? -eq 0 ]
|
|
|
|
then
|
|
|
|
zfs set backup:success="true" $SRCZFS
|
|
|
|
zfs set backup:date="$DATE" $SRCZFS
|
2021-01-07 11:58:28 +00:00
|
|
|
zfs set backup:failed="-" $SRCZFS
|
2021-01-07 11:10:48 +00:00
|
|
|
if [ -n $LASTSNAP ]
|
|
|
|
then
|
2021-01-07 11:58:28 +00:00
|
|
|
echo "$(date +%Y-%m-%d_%H:%M:%S): Deleting old ZFS snapshot $LASTSNAP"
|
2021-01-07 11:10:48 +00:00
|
|
|
zfs destroy "$SRCZFS"@"$LASTSNAP"
|
|
|
|
fi
|
2021-01-06 09:18:14 +00:00
|
|
|
else
|
2021-01-07 08:54:55 +00:00
|
|
|
abortFunction
|
2021-01-06 09:18:14 +00:00
|
|
|
fi
|
|
|
|
|
|
|
|
zfs destroy tank/snapshots/$VM
|
2021-01-07 08:54:55 +00:00
|
|
|
|
|
|
|
# cleanup old backups
|
|
|
|
|
2021-01-07 12:10:30 +00:00
|
|
|
OLDSNAPS=$(ssh $DESTHOST zfs list -r -t snapshot -o name $DESTZFS 2>/dev/null | grep $DATEOLD)
|
2021-01-07 08:54:55 +00:00
|
|
|
if [ ${#OLDSNAPS} -gt 0 ]
|
|
|
|
then
|
|
|
|
for oldsnap in $OLDSNAPS
|
|
|
|
do
|
2021-01-07 11:58:28 +00:00
|
|
|
echo "$(date +%Y-%m-%d_%H:%M:%S): Deleting old snapshots on target"
|
2021-01-07 08:54:55 +00:00
|
|
|
ssh $DESTHOST sudo zfs destroy $oldsnap
|
|
|
|
done
|
|
|
|
else
|
2021-01-07 12:10:30 +00:00
|
|
|
echo "$(date +%Y-%m-%d_%H:%M:%S): No old snapshots to cleanup on target"
|
2021-01-07 08:54:55 +00:00
|
|
|
fi
|
2021-01-07 11:58:28 +00:00
|
|
|
|
|
|
|
echo "$(date +%Y-%m-%d_%H:%M:%S): Backup Completed"
|