Last active
May 13, 2019 11:47
-
-
Save migae21/f94f8f3bef00cc9f254403b5c51ce151 to your computer and use it in GitHub Desktop.
My Way to backup my Virtual machines under Linux/KVM
This file contains 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 | |
unset TRY_RUN | |
#Uncomment the following line to get a TRY RUN (no actions taken just output) | |
#TRY_RUN="TRUE" | |
cmd_eval () | |
{ if [ ! -z "$TRY_RUN" ]; then | |
echo "$*" | |
return 0 | |
else | |
eval "$*" | |
if [ $? -ne 0 ]; then | |
loging "Failed to execute $*" | |
loging "exiting" | |
return 1 | |
fi | |
return 0 | |
fi } | |
unset DEBUG | |
#Uncomment the following line to get debuging ouput | |
DEBUG="TRUE" | |
#Use this function to echo text | |
debugecho () | |
{ if [ ! -z "$DEBUG" ]; then echo "$*"; fi } | |
if [ ! -z "$DEBUG" ]; then | |
RSYNC_OPTION="-avhW --inplace --chmod u=rw,g=rw,o=r --progress" | |
else | |
RSYNC_OPTION="-ahW --inplace --chmod u=rw,g=rw,o=r" | |
fi | |
# Optional add S to options | |
LOGENTRYNAME=backup_virtual_machines | |
unset SYSTEMD_LOGING | |
{ if [ ! -z "$TRY_RUN" ]; then | |
unset SYSTEMD_LOGING | |
else | |
SYSTEMD_LOGING="TRUE" | |
fi } | |
#scriptname for systemd loging | |
loging () | |
{ if [ ! -z "$SYSTEMD_LOGING" ]; then systemd-cat -t "$LOGENTRYNAME" echo "$*"; fi } | |
SCRIPTNAME=backup_virtual_machines | |
#scriptname for systemd logging | |
#connect to the right kvm Instance | |
export LIBVIRT_DEFAULT_URI='qemu:///system' | |
#debian default connect virsh to qemu:///session for non-root | |
#Path to the Backup | |
BACKUPPATH="/srv/backup/virtual_machines/autobackup/" | |
# List domains | |
DOMAINS=$(virsh list --all | tail -n +3 | awk '{print $2}') | |
debugecho "DOMAINS: $DOMAINS" | |
# Loop over the DOMAINS | |
for DOMAIN in $DOMAINS; do | |
debugecho "### STARTING with Domain: $DOMAIN ###" | |
# Generate the backup folder URI - this is something you should | |
# change/check | |
BACKUPFOLDER="$BACKUPPATH$DOMAIN/" | |
mkdir -p $BACKUPFOLDER | |
# 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}') | |
#only for running Domains | |
STATE=$(virsh dominfo $DOMAIN | grep "State" | cut -d " " -f 11) | |
if [ "$STATE" = "running" ]; then | |
debugecho "$Domain is running" | |
debugecho "Starting backup for running $DOMAIN on $(date +'%d-%m-%Y %H:%M:%S')" | |
loging "Starting backup for running $DOMAIN on $(date +'%d-%m-%Y %H:%M:%S')" | |
# Create the snapshot/disk specification | |
DISKSPEC="" | |
for TARGET in $TARGETS; do | |
DISKSPEC="$DISKSPEC --diskspec $TARGET,snapshot=external" | |
done | |
cmd_eval "virsh snapshot-create-as --domain $DOMAIN --name "backupSNAP-$DOMAIN" --no-metadata --atomic --disk-only $DISKSPEC 1>/dev/null 2>&1" | |
if [ $? -ne 0 ]; then | |
debugecho "Failed to create snapshot for $DOMAIN --> exiting" | |
loging "Failed to create snapshot for $DOMAIN --> exiting" | |
exit 1 | |
fi | |
debugecho "Snapshot for $DOMAIN created" | |
# Copy disk image | |
for IMAGE in $IMAGES; do | |
STARTZEIT=$(date "+%s") | |
NAME=$(basename $IMAGE) | |
# cp $IMAGE $BACKUPFOLDER/$NAMEqem | |
# pv $IMAGE > $BACKUPFOLDER/$NAME | |
cmd_eval "rsync $RSYNC_OPTION $IMAGE $BACKUPFOLDER/$NAME" | |
if [ $? -ne 0 ]; then | |
loging "Failed to copy snapshot for $DOMAIN --> exiting" | |
exit 1 | |
fi | |
ENDZEIT=$(date "+%s") | |
debugecho "Backup done: $IMAGE to $BACKUPFOLDER/$NAME in: "$(( $ENDZEIT - $STARTZEIT ))" sekunden" | |
loging "Backup done: $IMAGE to $BACKUPFOLDER/$NAME in: "$(( $ENDZEIT - $STARTZEIT ))" sekunden" | |
done | |
# Merge changes back | |
BACKUPIMAGES=$(virsh domblklist $DOMAIN --details | grep disk | awk '{print $4}') | |
STARTZEIT=$(date "+%s") | |
for TARGET in $TARGETS; do | |
cmd_eval "virsh blockcommit $DOMAIN $TARGET --active --pivot 1>/dev/null 2>&1" | |
if [ $? -ne 0 ]; then | |
loging "Failed to revert snapshot for $DOMAIN --> exiting" | |
exit 1 | |
fi | |
done | |
ENDZEIT=$(date "+%s") | |
debugecho "Reverting Snapshot done for $IMAGE in: "$(( $ENDZEIT - $STARTZEIT ))" sekunden" | |
loging "Reverting Snapshot done for $IMAGE in: "$(( $ENDZEIT - $STARTZEIT ))" sekunden" | |
# Cleanup left over backups | |
for BACKUP in $BACKUPIMAGES; do | |
if [[ $BACKUP =~ .*backupSNAP.* ]] | |
then | |
cmd_eval "rm -f $BACKUP" | |
else | |
loging "Filename $DOMAIN snapshot doesent include scurity token --> exiting" | |
exit 1 | |
fi | |
done | |
# Dump the configuration information. | |
cmd_eval "virsh dumpxml $DOMAIN > $BACKUPFOLDER/$DOMAIN.xml 1>/dev/null 2>&1" | |
else | |
debugecho "$Domain is not running" | |
loging "Starting copy for not running $DOMAIN on $(date +'%d-%m-%Y %H:%M:%S')" | |
# For not running Domains just copy the disks | |
# no snnapshot and merge needed | |
# Copy disk image | |
for IMAGE in $IMAGES; do | |
STARTZEIT=$(date "+%s") | |
NAME=$(basename $IMAGE) | |
# cp $IMAGE $BACKUPFOLDER/$NAMEqem | |
# pv $IMAGE > $BACKUPFOLDER/$NAME | |
cmd_eval "rsync $RSYNC_OPTION $IMAGE $BACKUPFOLDER/$NAME" | |
if [ $? -ne 0 ]; then | |
loging "Failed to copy $IMAGE for $DOMAIN --> exiting" | |
exit 1 | |
fi | |
ENDZEIT=$(date "+%s") | |
debugecho "Backup done: $IMAGE to $BACKUPFOLDER/$NAME in: "$(( $ENDZEIT - $STARTZEIT ))" sekunden" | |
loging "Backup done: $IMAGE to $BACKUPFOLDER/$NAME in: "$(( $ENDZEIT - $STARTZEIT ))" sekunden" | |
done | |
cmd_eval "virsh dumpxml $DOMAIN > $BACKUPFOLDER/$DOMAIN.xml 1>/dev/null 2>&1" | |
fi | |
debugecho "### Finished backup of $DOMAIN at $(date +'%d-%m-%Y %H:%M:%S') ###" | |
loging "### Finished backup of $DOMAIN at $(date +'%d-%m-%Y %H:%M:%S') ###" | |
done | |
exit 0 | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment