Difference between revisions of "KVM backup.sh"
Jump to navigation
Jump to search
(Created page with "<pre> # Set the language to English so virsh does it's output # in English as well # LANG=en_US SCRIPTNAME=kvm-backup # Local backup folder LOCALBKFOLDER=/arc/vm # Clean lo...") |
|||
(9 intermediate revisions by the same user not shown) | |||
Line 1: | Line 1: | ||
− | + | https://gist.githubusercontent.com/maxim-gorkin/f0e8a2c01a93ca65ad2ad10566a78d72/raw/7fd7f5690f54ed02823f7f35f26d15adc09c2799/kvm_backup.sh | |
− | |||
− | |||
− | |||
− | |||
− | # Local backup folder | + | # Set the language to English so virsh does it's output |
− | LOCALBKFOLDER=/arc/vm | + | # in English as well |
− | + | # LANG=en_US | |
− | # Clean local backup folders older then days | + | |
− | ERASEBCKPDAYS=3 | + | SCRIPTNAME=kvm-backup |
− | + | ||
− | # Mounted network backup folder | + | # Local backup folder |
− | NETBKFOLDER=/mnt/backup/VMs | + | LOCALBKFOLDER=/arc/vm |
− | + | ||
− | echo "Start backup script at $(date +'%d-%m-%Y %H:%M:%S')" | systemd-cat -p info -t $SCRIPTNAME | + | # Clean local backup folders older then days |
− | + | ERASEBCKPDAYS=3 | |
− | # List domains | + | |
− | DOMAINS=$(virsh list | tail -n +3 | awk '{print $2}') | + | # Mounted network backup folder |
− | + | NETBKFOLDER=/mnt/backup/VMs | |
− | for DOMAIN in $DOMAINS; do | + | |
− | + | echo "Start backup script at $(date +'%d-%m-%Y %H:%M:%S')" | systemd-cat -p info -t $SCRIPTNAME | |
− | + | ||
− | + | # List domains | |
− | + | DOMAINS=$(virsh list | tail -n +3 | awk '{print $2}') | |
− | + | ||
− | + | for DOMAIN in $DOMAINS; do | |
− | + | ||
− | + | echo "Starting backup for $DOMAIN on $(date +'%d-%m-%Y %H:%M:%S')" | systemd-cat -p info -t $SCRIPTNAME | |
− | + | ||
+ | # Generate the backup folder URI - this is something you should | ||
+ | # change/check | ||
+ | BACKUPFOLDER=$LOCALBKFOLDER/$DOMAIN/$(date +%d-%m-%Y) | ||
+ | NBACKUPFOLDER=$NETBKFOLDER/$DOMAIN | ||
+ | echo "Create BACKUPFOLDER = $BACKUPFOLDER" | systemd-cat -p info -t $SCRIPTNAME | ||
+ | mkdir -p $BACKUPFOLDER | ||
echo "Create NBACKUPFOLDER = $NBACKUPFOLDER" | systemd-cat -p info -t $SCRIPTNAME | echo "Create NBACKUPFOLDER = $NBACKUPFOLDER" | systemd-cat -p info -t $SCRIPTNAME | ||
− | + | mkdir -p $NBACKUPFOLDER | |
− | + | # Get the target disk | |
− | + | TARGETS=$(virsh domblklist $DOMAIN --details | grep disk | awk '{print $3}') | |
− | + | ||
− | + | # Get the image page | |
− | + | IMAGES=$(virsh domblklist $DOMAIN --details | grep disk | awk '{print $4}') | |
− | + | ||
− | + | # Create the snapshot/disk specification | |
− | + | DISKSPEC="" | |
− | + | ||
− | + | for TARGET in $TARGETS; do | |
− | + | DISKSPEC="$DISKSPEC --diskspec $TARGET,snapshot=external" | |
− | + | done | |
− | + | echo "Create snapshot for $DOMAIN, DISKSPEC = $DISKSPEC" | systemd-cat -p info -t $SCRIPTNAME | |
− | + | virsh snapshot-create-as --domain $DOMAIN --name "backup-$DOMAIN" --no-metadata --atomic --disk-only $DISKSPEC | |
− | + | ||
− | + | if [ $? -ne 0 ]; then | |
− | + | echo "Failed to create snapshot for $DOMAIN" | systemd-cat -p warning -t $SCRIPTNAME | |
− | + | exit 1 | |
− | + | fi | |
− | + | ||
− | + | # Copy disk image | |
− | + | for IMAGE in $IMAGES; do | |
− | + | NAME=$(basename $IMAGE) | |
− | + | echo "Sync $IMAGE and $BACKUPFOLDER/$NAME" | systemd-cat -p info -t $SCRIPTNAME | |
− | + | rsync -ahW --no-o --no-g --progress $IMAGE $BACKUPFOLDER/$NAME | |
− | + | done | |
− | + | ||
− | + | # Merge changes back | |
− | + | BACKUPIMAGES=$(virsh domblklist $DOMAIN --details | grep disk | awk '{print $4}') | |
− | + | ||
− | + | for TARGET in $TARGETS; do | |
− | + | echo "Blockcommit for $DOMAIN, TARGET = $TARGET" | systemd-cat -p info -t $SCRIPTNAME | |
− | + | virsh blockcommit $DOMAIN $TARGET --active --pivot # 1>/dev/null 2>&1 | |
− | + | ||
− | + | if [ $? -ne 0 ]; then | |
− | + | echo "Could not merge changes for disk of $TARGET of $DOMAIN. VM may be in invalid state." | systemd-cat -p warning -t $SCRIPTNAME | |
− | + | exit 1 | |
− | + | fi | |
− | + | done | |
− | + | ||
− | + | # Cleanup left over backups | |
− | + | for BACKUP in $BACKUPIMAGES; do | |
echo "Remove $BACKUP" | systemd-cat -p info -t $SCRIPTNAME | echo "Remove $BACKUP" | systemd-cat -p info -t $SCRIPTNAME | ||
− | + | rm -f $BACKUP | |
− | + | done | |
− | + | ||
− | + | # Dump the configuration information. | |
− | + | echo "Create xml for $DOMAIN - $BACKUPFOLDER/$DOMAIN.xml" | systemd-cat -p info -t $SCRIPTNAME | |
− | + | virsh dumpxml $DOMAIN > $BACKUPFOLDER/$DOMAIN.xml # 1>/dev/null 2>&1 | |
echo "Create xml for $DOMAIN - $NBACKUPFOLDER/$DOMAIN.xml" | systemd-cat -p info -t $SCRIPTNAME | echo "Create xml for $DOMAIN - $NBACKUPFOLDER/$DOMAIN.xml" | systemd-cat -p info -t $SCRIPTNAME | ||
− | + | virsh dumpxml $DOMAIN > $NBACKUPFOLDER/$DOMAIN.xml | |
− | + | ||
− | + | # Copy disk to network backup disk | |
for IMAGE in $IMAGES; do | for IMAGE in $IMAGES; do | ||
NAME=$(basename $IMAGE) | NAME=$(basename $IMAGE) | ||
− | + | echo "Copy $BACKUPFOLDER/$NAME to $NBACKUPFOLDER/$NAME" | systemd-cat -p info -t $SCRIPTNAME | |
− | + | cp $BACKUPFOLDER/$NAME $NBACKUPFOLDER/$NAME | |
− | + | done | |
− | + | ||
− | + | echo "Finished backup of $DOMAIN at $(date +'%d-%m-%Y %H:%M:%S')" | systemd-cat -p info -t $SCRIPTNAME | |
− | done | + | done |
+ | |||
+ | # Cleanup local backup folders | ||
+ | echo "Delete local backups $LOCALBKFOLDER older then $ERASEBCKPDAYS days" | systemd-cat -p info -t $SCRIPTNAME | ||
+ | find $LOCALBKFOLDER/* -ctime +$ERASEBCKPDAYS -type d -exec rm -r {} + | ||
+ | |||
+ | echo "Finished backup script at $(date +'%d-%m-%Y %H:%M:%S')" | systemd-cat -p info -t $SCRIPTNAME | ||
+ | exit 0 | ||
− | |||
− | |||
− | |||
− | + | == See also == | |
− | + | * <code>[[virsh blockcommit]]</code> | |
− | </ | + | * [[KVM backup]] |
Latest revision as of 15:45, 5 October 2020
# Set the language to English so virsh does it's output # in English as well # LANG=en_US SCRIPTNAME=kvm-backup # Local backup folder LOCALBKFOLDER=/arc/vm # Clean local backup folders older then days ERASEBCKPDAYS=3 # Mounted network backup folder NETBKFOLDER=/mnt/backup/VMs echo "Start backup script at $(date +'%d-%m-%Y %H:%M:%S')" | systemd-cat -p info -t $SCRIPTNAME # List domains DOMAINS=$(virsh list | tail -n +3 | awk '{print $2}') for DOMAIN in $DOMAINS; do echo "Starting backup for $DOMAIN on $(date +'%d-%m-%Y %H:%M:%S')" | systemd-cat -p info -t $SCRIPTNAME # Generate the backup folder URI - this is something you should # change/check BACKUPFOLDER=$LOCALBKFOLDER/$DOMAIN/$(date +%d-%m-%Y) NBACKUPFOLDER=$NETBKFOLDER/$DOMAIN echo "Create BACKUPFOLDER = $BACKUPFOLDER" | systemd-cat -p info -t $SCRIPTNAME mkdir -p $BACKUPFOLDER echo "Create NBACKUPFOLDER = $NBACKUPFOLDER" | systemd-cat -p info -t $SCRIPTNAME mkdir -p $NBACKUPFOLDER # Get the target disk TARGETS=$(virsh domblklist $DOMAIN --details | grep disk | awk '{print $3}') # Get the image page IMAGES=$(virsh domblklist $DOMAIN --details | grep disk | awk '{print $4}') # Create the snapshot/disk specification DISKSPEC="" for TARGET in $TARGETS; do DISKSPEC="$DISKSPEC --diskspec $TARGET,snapshot=external" done echo "Create snapshot for $DOMAIN, DISKSPEC = $DISKSPEC" | systemd-cat -p info -t $SCRIPTNAME virsh snapshot-create-as --domain $DOMAIN --name "backup-$DOMAIN" --no-metadata --atomic --disk-only $DISKSPEC if [ $? -ne 0 ]; then echo "Failed to create snapshot for $DOMAIN" | systemd-cat -p warning -t $SCRIPTNAME exit 1 fi # Copy disk image for IMAGE in $IMAGES; do NAME=$(basename $IMAGE) echo "Sync $IMAGE and $BACKUPFOLDER/$NAME" | systemd-cat -p info -t $SCRIPTNAME rsync -ahW --no-o --no-g --progress $IMAGE $BACKUPFOLDER/$NAME done # Merge changes back BACKUPIMAGES=$(virsh domblklist $DOMAIN --details | grep disk | awk '{print $4}') for TARGET in $TARGETS; do echo "Blockcommit for $DOMAIN, TARGET = $TARGET" | systemd-cat -p info -t $SCRIPTNAME virsh blockcommit $DOMAIN $TARGET --active --pivot # 1>/dev/null 2>&1 if [ $? -ne 0 ]; then echo "Could not merge changes for disk of $TARGET of $DOMAIN. VM may be in invalid state." | systemd-cat -p warning -t $SCRIPTNAME exit 1 fi done # Cleanup left over backups for BACKUP in $BACKUPIMAGES; do echo "Remove $BACKUP" | systemd-cat -p info -t $SCRIPTNAME rm -f $BACKUP done # Dump the configuration information. echo "Create xml for $DOMAIN - $BACKUPFOLDER/$DOMAIN.xml" | systemd-cat -p info -t $SCRIPTNAME virsh dumpxml $DOMAIN > $BACKUPFOLDER/$DOMAIN.xml # 1>/dev/null 2>&1 echo "Create xml for $DOMAIN - $NBACKUPFOLDER/$DOMAIN.xml" | systemd-cat -p info -t $SCRIPTNAME virsh dumpxml $DOMAIN > $NBACKUPFOLDER/$DOMAIN.xml # Copy disk to network backup disk for IMAGE in $IMAGES; do NAME=$(basename $IMAGE) echo "Copy $BACKUPFOLDER/$NAME to $NBACKUPFOLDER/$NAME" | systemd-cat -p info -t $SCRIPTNAME cp $BACKUPFOLDER/$NAME $NBACKUPFOLDER/$NAME done echo "Finished backup of $DOMAIN at $(date +'%d-%m-%Y %H:%M:%S')" | systemd-cat -p info -t $SCRIPTNAME done # Cleanup local backup folders echo "Delete local backups $LOCALBKFOLDER older then $ERASEBCKPDAYS days" | systemd-cat -p info -t $SCRIPTNAME find $LOCALBKFOLDER/* -ctime +$ERASEBCKPDAYS -type d -exec rm -r {} + echo "Finished backup script at $(date +'%d-%m-%Y %H:%M:%S')" | systemd-cat -p info -t $SCRIPTNAME exit 0
See also[edit]
Advertising: