kvm_manage.sh - A script to manage your KVM machines

Note: Maarten commented in another post that there is a bug in Ubuntu related to snapshotted machines, which basically this scripts creates. Please read more here!!

This script is based on kvm_backup.sh that I have posted earlier. It is a copy of the previous one, but with some added features.
In this iteration the option to resize the disk(s) connected to a virtual machine. It gathers the disks connected to the VM and if there are more than one disk available the user is prompted for which disk to expand.
The script will shutdown the VM before modifying the disk file (utilising “virsh vol-resize” in order to change the size of the disk) and then start up the VM again. All within about 5-10 seconds.
After the VM has started you will have to extend the filesystem using the routines based on which OS it is running.

The script:

#!/bin/bash

#Script to backup KVM-machines using snapshots.  
 #Written by Jonas "Drakfot" Andersson

#Changelog  
 # Version 1.1  
 #20140309 – Initial scripting started.  
 #20140316 – Fixed an issue where a nonmounted drive (CD) could cause the script to fail.  
 #also sorted the part where the converted image will end up. Now the file is written  
 #directly to the destination instead of moved there after the convertion.  
 #20140328 – Added function to resize (expand) disk(s) for VMs.

#Info:  
 #This script uses a combination of "virsh" and "qemu-img" to discover  
 #the disk images attached to a VM. When doing a backup a snapshot is  
 #done for each disk used by the VM and each snapshot is then exported  
 #as a .qcow2 file for backup.  
 #NOTE: This script do only backup the disk image file, not the entire  
 #VM. The idea behind this is that it is quick to create a new KVM-  
 #machine and specify the backup image as harddrive for the new machine.

### License ###  
 #kvm_manage.sh – A script to manage your KVM machines  
 #Copyright (C) 2014 Jonas Andersson

#This program is free software; you can redistribute it and/or modify  
 #it under the terms of the GNU General Public License as published by  
 #the Free Software Foundation; either version 3 of the License, or  
 #(at your option) any later version.  
 #  
 #This program is distributed in the hope that it will be useful,  
 #but WITHOUT ANY WARRANTY; without even the implied warranty of  
 #MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the  
 #GNU General Public License for more details.  
 #  
 #You should have received a copy of the GNU General Public License  
 #along with this program; if not, write to the Free Software Foundation,  
 #Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA

#Prerequisites  
 #KVM being used as VM hypervisor.  
 #qemu-img path specified in the variable below.  
 #virsh path specified in the variable below.

#Variables  
 BACKUPDIR=/backup  
 BACKUPNAME=backup_`date +%Y%m%d%HH%MM`  
 VIRSHBIN=/usr/bin/virsh  
 QEMUIMG=/usr/bin/qemu-img  
 VIRTUAL_DISKS=""  
 VMDOMAIN=""

#Functions!  
 function get_domain_disk () {  
 N=0  
 for i in `$VIRSHBIN domblklist $1 | tail -n+3 | sed -e ‘s/^-$//g’ | awk ‘{print $2}’` ; do  
 VIRTUAL_DISKS[$N]="$i"  
 let "N= $N + 1"  
 done  
 }

function create_snapshot () {  
 for disk in ${VIRTUAL_DISKS[*]}  
 do  
 echo "Creating snapshot for disk $disk"  
 $QEMUIMG snapshot -c $BACKUPNAME $disk  
 echo "Snapshot $BACKUPNAME created for disk $disk at `date`"  
 done  
 }

function convert_snapshot_qcow2 () {  
 for disk in ${VIRTUAL_DISKS[@]}  
 do  
 echo "Converting snapshot for disk $disk"  
 $QEMUIMG convert -f qcow2 -O qcow2 -s $BACKUPNAME $disk $BACKUPDIR/$VMDOMAIN.$BACKUPNAME.qcow2  
 echo "Snapshot for $disk converted at `date` and placed at $BACKUPDIR"  
 done  
 }

function delete_snapshot () {  
 for disk in ${VIRTUAL_DISKS[@]}  
 do  
 echo "Deleting snapshot $BACKUPNAME for disk $disk"  
 $QEMUIMG snapshot -d $BACKUPNAME $disk  
 echo "Snapshot $BACKUPNAME deleted at `date`"  
 done  
 }

function check_vmname () {  
 if [ -z $VMDOMAIN ]  
 then  
 echo "No VM specified, please input the name using $0 -n VMName <options>"  
 exit  
 fi  
 }

function list_disks () {  
 echo "$VMDOMAIN contains the following disk(s):"  
 for disk in ${VIRTUAL_DISKS[@]}  
 do  
 echo "$disk"  
 done  
 }

function list_snapshots () {  
 echo "Listing (possible) snapshots for $VMDOMAIN:"  
 for disk in ${VIRTUAL_DISKS[@]}  
 do  
 $QEMUIMG snapshot -l $disk  
 done  
 }

function multiple_servers () {  
 echo "File with multiple server names specified"  
 cat $SERVERLIST |while read line  
 do  
 VMDOMAIN=$line  
 echo "Backing up $VMDOMAIN"  
 get_domain_disk $VMDOMAIN  
 create_snapshot  
 convert_snapshot_qcow2  
 delete_snapshot  
 done  
 }

function resize_disk () {  
 #Gather the disk(s) from the vitual machine  
 get_domain_disk $VMDOMAIN  
 echo "Preparing to extend the disk of Virtual machine $VMDOMAIN"  
 if [ ${#VIRTUAL_DISKS[@]} -gt 1 ]  
 then  
 echo "Multiple disks found, please select which one to resize: "  
 N=0  
 for disk in ${VIRTUAL_DISKS[@]}  
 do  
 echo "To select disk $disk, press $N"  
 let "N=$N + 1"  
 done  
 read RESIZE_DISK_NR  
 echo "You have selected disk ${VIRTUAL_DISKS[$RESIZE_DISK_NR]}"  
 RESIZE_DISK=${VIRTUAL_DISKS[$RESIZE_DISK_NR]}  
 else  
 RESIZE_DISK=${VIRTUAL_DISKS[0]}  
 echo "Setting disk $RESIZE_DISK as active."  
 fi  
 CURR_SIZE=`$VIRSHBIN domblkinfo $VMDOMAIN $RESIZE_DISK | grep Capacity | awk ‘{print $2}’`  
 CURR_SIZE=`echo "(($CURR_SIZE/1000)/1000)/1000" | bc`  
 echo "Current size of $RESIZE_DISK is $CURR_SIZE GB"

 echo -ne "Please specify the new size of the disk (current size + extended size) in GB: "  
 read NEW_SIZE  
 NEW_SIZE=${NEW_SIZE}GB

 #Setting the disk pool variable to default if nothing was specified as $OPTARG for -r  
 if [ $DISK_POOL = "0" ]  
 then  
 echo "Setting the disk pool to default"  
 DISK_POOL=default  
 fi

 #Shutting down the virtual machine  
 $VIRSHBIN shutdown $VMDOMAIN

 while [ 1 ]  
 do  
 sleep 3  
 VMSTATUS=`ps -eo pid,cmd | grep "qemu.* -name $VMDOMAIN" | grep -v grep | awk ‘{print $1}’`  
 echo "$VMDOMAIN is shutting down"  
 if [ -z ${VMSTATUS} ]; then  
 break  
 fi  
 #VMSTATUS=`ps -ef | grep -v grep |grep -v kvm | grep $VMDOMAIN`  
 done

 echo "$VMDOMAIN has shut down, continuing to resize the disk."  
 sleep 2  
 #Time to extend the selected disk  
 $VIRSHBIN vol-resize $RESIZE_DISK $NEW_SIZE –pool $DISK_POOL

 echo "Disk $RESIZE_DISK has been resized! Starting up $VMDOMAIN again."  
 echo "Please expand the filesystem inside the virtual machine $VMDOMAIN"  
 echo "in order to make use of the new disk space!"

 $VIRSHBIN start $VMDOMAIN  
 }

#Let’s check the args input and decide what functions to call based on them  
 while getopts ":n:blsc:d:hm:r:" opt; do  
 case "$opt" in  
 n)  
 if [ -a $OPTARG ]  
 then  
 SERVERLIST=$OPTARG  
 multiple_servers  
 exit  
 fi  
 VMDOMAIN=$OPTARG  
 ;;  
 m)  
 BACKUPDIR=$OPTARG  
 echo "Backup destination set to $OPTARG"  
 ;;  
 l)  
 check_vmname  
 get_domain_disk $VMDOMAIN  
 list_disks  
 ;;  
 s)  
 get_domain_disk $VMDOMAIN  
 list_snapshots  
 ;;  
 c)  
 get_domain_disk $VMDOMAIN  
 BACKUPNAME=$OPTARG  
 create_snapshot  
 ;;  
 d)  
 get_domain_disk $VMDOMAIN  
 BACKUPNAME=$OPTARG  
 delete_snapshot  
 ;;  
![:)](https://www.drakfot.se/wp-includes/images/smilies/simple-smile.png)  
 echo "option -$OPTARG requires an argument."  
 ;;  
 h)  
 echo "Usage: $0 -n VMname is required for useage."  
 echo "======================= Options available for $0: ======================="  
 echo "-b : Creates a snapshot of the disk, converts it to a qcow2 file and then moves it"  
 echo " to the backup destination, default is /backup."  
 echo " If a file with serverenames, one per row, is specified the script will loop"  
 echo " through the file and back up each server and its disk(s). No other options"  
 echo " will be parsed."  
 echo "-c : Creates snapshot(s) for the disk(s)in the specified VM. Requires an argument"  
 echo " to use as name for the snapshot. Eg -c snapshot_test"  
 echo "-d : Deletes the specified snapshot from the VM’s disk(s). Requires an argument"  
 echo " to use as name / ID specifying which snapshot to remove."  
 echo " Eg -d snapshot_test OR -d 1"  
 echo "-l : Lists the disks in the specified VM."  
 echo "-m : Specifies the destination where the backup will be saved. Default is /backup"  
 echo " NOTE: This option must be specified BEFORE the "-b" option to take effect!"  
 echo " Eg: -m /tmp/ -b"  
 echo "-r : Resizes a disk of the selected VM. It requires an argument specifying the"  
 echo " disk pool. Enter 0 to use the default pool. Use virsh pool-list to list"  
 echo " available pools."  
 echo "-s : Lists the snapshots for the specified VM."  
 ;;  
 b)  
 echo "Backing up $VMDOMAIN"  
 get_domain_disk $VMDOMAIN  
 create_snapshot  
 convert_snapshot_qcow2  
 delete_snapshot  
 ;;  
 r)  
 echo "Resizing disk"  
 DISK_POOL=$OPTARG  
 resize_disk  
 ;;

 ?)  
 echo "Invalid option: -$OPTARG. Use $0 -h to display the syntax."  
 ;;

 esac  
 done
Mastodon