libvirt-zsh-backup/libvirt-zsh-backup.sh

159 lines
4.4 KiB
Bash

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