Libvirt Live Snapshot with Block Commit
#!/bin/bash
#
# Take an external snapshot with virsh using live block commit feature
#
# Usage: ./snap domain-name backup-destination prune_lvl(integer)
#
# Creates log collection directory in backup-destination
#
# PRUNE_LVL variable determines how many snapshots will be kept for each
# domain. 4 is the default.
#
# You must have the qemu-guest-agent installed and enabled on the guest, otherwise
# the --quiesce argument must be removed from the snapshot-create command
# before the script will function.
#
# Nicholas Ferguson 2018 MIT License https://gitlab.com/nickopotamus/
DOMAIN=$1
# check if guest is running
if [[ $(virsh list --all | grep "$DOMAIN" | awk '{print $3}' | awk 'NR==1{print $1}') == "running" ]]; then
echo "Guest running...continuing..."
else
echo "Guest is not running...stopping..."
exit 1
fi
# check for correct arguments
if [ "$#" -ne 2 ]; then
echo "Missing arguments! Provide domain and backup directory." >&2
exit 1
fi
# does the backup destination exit
if ! [ -e "$2" ]; then
echo "$2 not found!" >&2
exit 1
fi
# is the backup destination a directory
if ! [ -d "$2" ]; then
echo "$2 is not a directory!" >&2
exit 1
fi
# generate time stamp
TIME=`date "+%Y%m%d-%H%M%S"`
BACKUP_DEST="$2"/"$1"
# create backup dir if it does not exist
[ -d "$BACKUP_DEST" ] || mkdir -p "$BACKUP_DEST"
# label snapshot with timestamp
STATE="$1"_"$TIME"
# take care of logging
LOG_DIR="$2"/snapshot_logs
[ -d "$LOG_DIR" ] || mkdir -p "$LOG_DIR"
SNAP_LOG="$LOG_DIR"/"$DOMAIN"_latest.log
rm "$SNAP_LOG"
touch "$SNAP_LOG"
exec 3>&1 4>&2
trap 'exec 2>&4 1>&3' 0 1 2 3
exec 1>"$SNAP_LOG" 2>&1
# name the overlay file
OVERLAY="$STATE"_overlay
# target is domain name, image is virtual disk file
TARGET=`virsh domblklist --details "$1" | grep ^file | awk '{print $3}'`
IMAGE=`virsh domblklist --details "$1" | grep ^file | awk '{print $4}'`
POOLDIR=`dirname "$IMAGE"`
# take the snapshot. will fail without a working qemu-guest-agent
virsh snapshot-create-as --domain "$1" "$STATE" \
--diskspec "$TARGET",file="$POOLDIR"/"$OVERLAY".qcow2 \
--disk-only \
--atomic \
--quiesce
# perform the backup
echo "Copying image to backup location..."
cp -a "$IMAGE" "$BACKUP_DEST"/"$STATE"
# live block commit
echo "Performing live block commit..."
virsh blockcommit "$1" "$TARGET" --active --verbose --pivot
# remove the overlay file
rm "$POOLDIR"/"$OVERLAY".qcow2
# remove the snapshot from domain
virsh snapshot-delete $1 --metadata "$STATE"
echo 'Current snapshots attached to this guest:'
virsh snapshot-list $1
echo '------------------------'
echo 'Most recent external snapshots:'
ls "$BACKUP_DEST"
echo '------------------------'
echo 'Current disk image in use:'
virsh domblklist $DOMAIN