#!/bin/sh ########################################################################### ## Copyright (C) Wizardry and Steamworks 2017 - License: GNU GPLv3 ## ## Please see: http://www.gnu.org/licenses/gpl.html for legal details, ## ## rights of fair usage, the disclaimer and warranty conditions. ## ########################################################################### # Live backup script for libvirt/qemu virtual machines using blockcommit. # # The script is designed to query all the active libvirt domains, create # # a snap overlay, copy over the image or the block device to a file and # # finally merge the overlay with the image - all these operations are # # performed without needing to suspend or shut down the virtual machine. # # # # Requirements: # # * pxz (parallel xz) # # # # Setup: Configure the script in the configuration section and then run # # the script - the script is designed to be run from cron. # ########################################################################### ########################################################################### # CONFIGURATION # ########################################################################### # This absolute path to a directory where the machines will be stored. BACKUP_DIRECTORY=/mnt/archie/Backups/VMS # A temporary directory to hold the temporary snapshots. SNAP_DIRECTORY=/var/lib/libvirt/snapshots # A space-separated list of domains to exclude from backup. EXCLUDE_DOMAINS="corrade.internal" ########################################################################### # INTERNALS # ########################################################################### # Get active domains. DOMAINS=`virsh -c qemu:///system list | grep -o '[0-9]* [a-z]*.*running' | awk '{print $2}'` # Generate a timestamp. TIMESTAMP=`date +%Y%m%d` # Acquire lock. if mkdir /var/lock/virsh-backup; then for DOMAIN in $DOMAINS; do # Check if this domain has been excluded. for EXCLUDE in $EXCLUDE_DOMAINS; do if [ "$DOMAIN" = "$EXCLUDE" ]; then DOMAIN="" fi done if [ -z "$DOMAIN" ]; then continue; fi # Get block devices. VIRT_BLOCK_DEVICE=`virsh domblklist "$DOMAIN" | grep '/' | head -1 | awk '{print $1}'` HOST_BLOCK_DEVICE=`virsh domblklist "$DOMAIN" | grep '/' | head -1 | awk '{print $2}'` if [ -z "$VIRT_BLOCK_DEVICE" ]; then echo "Block device not found for domain "$DOMAIN continue; fi if [ ! -d "$SNAP_DIRECTORY" ]; then mkdir -p "$SNAP_DIRECTORY" fi # Create snapshot virsh snapshot-create-as \ --domain "$DOMAIN" "$DOMAIN-snap-$TIMESTAMP" \ --diskspec "$VIRT_BLOCK_DEVICE",file="$SNAP_DIRECTORY/$DOMAIN-snap-$TIMESTAMP" \ --disk-only \ --atomic \ --no-metadata \ --quiesce >/dev/null 2>&1 if [ "$?" -ne "0" ]; then echo "Failed snapshoting domain "$DOMAIN continue; fi if [ ! -f "$SNAP_DIRECTORY/$DOMAIN-snap-$TIMESTAMP" ]; then echo "Snapshot file for domain "$DOMAIN" does not exit" continue; fi if [ ! -d "$BACKUP_DIRECTORY/$DOMAIN" ]; then mkdir -p "$BACKUP_DIRECTORY/$DOMAIN" fi dd if="$HOST_BLOCK_DEVICE" \ conv=noerror status=none \ bs=1M | pxz -0 > "$BACKUP_DIRECTORY/$DOMAIN/$TIMESTAMP.img.xz" virsh blockcommit "$DOMAIN" "$VIRT_BLOCK_DEVICE" \ --active \ --pivot >/dev/null 2>&1 if [ "$?" -ne "0" ]; then echo "Could not commit back snapshot for domain "$DOMAIN continue; fi rm "$SNAP_DIRECTORY/$DOMAIN-snap-$TIMESTAMP" done # Release lock. rm -rf /var/lock/virsh-backup fi