NickCrew
8/22/2018 - 5:58 PM

Libvirt Live Snapshot with Block Commit

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