Last active
September 9, 2024 12:59
-
-
Save sebastiaanfranken/3ccec782f6e687ce0e30418bdfff78a4 to your computer and use it in GitHub Desktop.
Backup all VM's in KVM
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/bin/bash | |
# This script creates a backup for all running libvirtd domains on the host it's | |
# run on. | |
# | |
# I created this script because I needed a lightweight backup solution for a pure libvirtd | |
# virtual machine host. | |
# | |
# You can use / modify this script however you like. All I ask is that if you find a bug or something | |
# very wrong (or if you find a massive upgrade point) is that you let me know! | |
# If this is set to 1 this script will | |
# output a lot more, for debugging | |
VERBOSE=1 | |
# Set the script language to English | |
LANG=en_US.UTF-8 | |
# Define the script name for use in the journal | |
SCRIPTNAME=kvm-backup-test | |
# List the domains | |
DOMAINS="$(virsh list| tail -n +3 | awk '{print $2}')" | |
# Loop over the domains and start the backup | |
# cycle. | |
for DOMAIN in $DOMAINS; do | |
# Check if the ignore backup config file (/etc/kvm-backup.ignore) exists | |
# and parse it if required. | |
if [[ -f /etc/kvm-backup.ignore ]]; then | |
if grep -Fxq "$DOMAIN" /etc/kvm-backup.ignore; then | |
systemd-cat -t $SCRIPTNAME echo "Ignoring domain '$DOMAIN' per config" | |
continue | |
fi | |
fi | |
systemd-cat -t $SCRIPTNAME echo "Starting backup for domain '$DOMAIN'" | |
# Generate the backup folder URI | |
# Lifed from Aaron Studer's revision of my original script, see | |
# https://gist.github.com/aaronstuder/f481f4b9ff270f9ddcd098f283dc71cd#file-kvm-backup-sh-L24 | |
# for source | |
BACKUPFOLDER="/mnt/backups/$DOMAIN/$(date +%Y)/$(date +%m)/$(date +%d)/" | |
if [[ $VERBOSE -eq 1 ]]; then | |
systemd-cat -t $SCRIPTNAME echo "Backup folder URI is '$BACKUPFOLDER'" | |
fi | |
if [[ ! -d $BACKUPFOLDER ]]; then | |
mkdir -p $BACKUPFOLDER | |
fi | |
# Get VM disk info | |
DISKINFO=$(virsh domblklist $DOMAIN --details | grep disk | awk '{print $3,$4}') | |
# Get the disk type (sda, vda, etc) | |
DISKTYPE=$(echo $DISKINFO | awk '{print $1}') | |
# Get the disk path | |
DISKPATH=$(echo $DISKINFO | awk '{print $2}') | |
if [[ $VERBOSE -eq 1 ]]; then | |
systemd-cat -t $SCRIPTNAME echo "Disk info is '$DISKINFO', disk type is '$DISKTYPE', disk path is '$DISKPATH'" | |
fi | |
# Do the snapshot | |
if [[ $VERBOSE -eq 1 ]]; then | |
systemd-cat -t $SCRIPTNAME virsh snapshot-create-as --domain $DOMAIN --name "snapshot" --no-metadata --atomic --disk-only --diskspec $DISKTYPE,snapshot=external | |
else | |
virsh snapshot-create-as --domain $DOMAIN --name "snapshot" --no-metadata --atomic --disk-only --diskspec $DISKTYPE,snapshot=external > /dev/null | |
fi | |
if [[ $? -ne 0 ]]; then | |
systemd-cat -t $SCRIPTNAME echo "Failed to create snapshot for domain '$DOMAIN'" | |
fi | |
# Copy the disk image | |
DISKPATHBASENAME=$(basename $DISKPATH) | |
cp $DISKPATH $BACKUPFOLDER/$DISKPATHBASENAME | |
if [[ $VERBOSE -eq 1 ]]; then | |
systemd-cat -t $SCRIPTNAME echo "Done copying the disk for domain '$DOMAIN'" | |
fi | |
# Get the backup disk (sda, vda, etc) path now so we can | |
# remove it later | |
BACKUPDISKPATH=$(virsh domblklist $DOMAIN --details | grep disk | awk '{print $4}') | |
if [[ $VERBOSE -eq 1 ]]; then | |
systemd-cat -t $SCRIPTNAME echo "Backup disk path is '$BACKUPDISKPATH'" | |
fi | |
# merge the changes back | |
if [[ $VERBOSE -eq 1 ]]; then | |
systemd-cat -t $SCRIPTNAME virsh blockcommit $DOMAIN $DISKTYPE --active --pivot | |
else | |
virsh blockcommit $DOMAIN $DISKTYPE --active --pivot > /dev/null | |
fi | |
if [[ $? -ne 0 ]]; then | |
systemd-cat -t $SCRIPTNAME echo "Could not merge changed for disk of type '$DISKTYPE' on domain '$DOMAIN'. VM *may* be in an invalid state." | |
else | |
rm -f $BACKUPDISKPATH | |
if [[ $VERBOSE -eq 1 ]]; then | |
systemd-cat -t $SCRIPTNAME echo "Removed backup disk for domain '$DOMAIN'" | |
fi | |
fi | |
# Dump the VM xml | |
virsh dumpxml $DOMAIN > $BACKUPFOLDER/$DOMAIN.xml | |
if [[ $? -ne -0 ]]; then | |
systemd-cat -t $SCRIPTNAME echo "Could not dump XML for domain '$DOMAIN'" | |
fi | |
systemd-cat -t $SCRIPTNAME echo "Finished backup of domain '$DOMAIN'" | |
done | |
exit 0 |
"virsh list" shows only running VMs. Well, maybe we do not need to snapshot shut off VMs, but we need to backup 'em anyway, eh? So, "virsh list --al" and then some checks is VM running (snapshot/backup) or shut off (backup only).
As the literal first line of this scripts says:
This script creates a backup for all running libvirtd domains on the host it's
run on.
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
"virsh list" shows only running VMs. Well, maybe we do not need to snapshot shut off VMs, but we need to backup 'em anyway, eh?
So, "virsh list --al" and then some checks is VM running (snapshot/backup) or shut off (backup only).