Sign Up
Log In
Log In
or
Sign Up
Places
All Projects
Status Monitor
Collapse sidebar
openSUSE:12.2:ARM
virt-utils
vm-snapshot-disk
Overview
Repositories
Revisions
Requests
Users
Attributes
Meta
File vm-snapshot-disk of Package virt-utils
#!/bin/bash #============================================================================ # vm-snapshot-disk # # Version = 0.6.0 # Date = 2011-07-01 # # Copyright - Ron Terry # License - GPL # # Maintainer(s) = Ron Terry - roncterry (at) gmail (dot) com # # The latest version can be found at: # # http://pronetworkconsulting.com/linux/scripts/virt-tools.html # # Description: # This script creates and manages snapshots of qcow2 and vhd virtual disks # and virtual disks on file systems that support snapshots (i.e. OCFS2) # # Individual snapshots and snapshot trees are supported. The names # of the snapshots in the snapshot tree are stored in the actual # filenames of the snapshots themselves. Descriptions of each # snapshot can be provided and will be stored in a file named # .$DISK.snap_descriptions # # The following operations can be performed: # # create -creates a new snapshot from the current position in the # snapshot tree # branch -creates a new branch of the snapshot tree from the # specified snapshot # revert -reverts to the specified snapshot and deletes all linked # snapshots from the snapshot tree # remove -removes all snapshosts and snapshot descriptions from # the disk image # list -list all snapshots and their descriptions # help -displays the description and usage # #============================================================================ ################################################################################### # Read config files and set variables ################################################################################### if which qemu-img > /dev/null 2>&1 then QEMU_IMG_CMD=qemu-img HAVE_QEMU_IMG=true elif which qemu-img-xen > /dev/null 2>&1 then QEMU_IMG_CMD=qemu-img-xen HAVE_QEMU_IMG=true else HAVE_QEMU_IMG=false fi if which reflink > /dev/null 2>&1 then REFLINK_CMD=`which reflink` HAVE_REFLINK=true else HAVE_REFLINK=false fi if which vhd-util > /dev/null 2>&1 then VHD_UTIL_CMD=`which vhd-util` HAVE_VHD_UTIL=true else HAVE_VHD_UTIL=false fi OCFS2_VOLS=`cat /proc/mounts | grep ocfs2 | cut -d \ -f 2` if `uname -r | grep -i xen` then HYPERVISOR=xen else HYPERVISOR=qemu fi ################################################################################### # Script Functions ################################################################################### ########## Function: description ############################### description() { echo " ================================================================================ Description: This script creates and manages snapshots of qcow2 and vhd virtual disks and virtual disks on file systems that support snapshots (i.e. OCFS2) Individual snapshots and snapshot trees are supported. The names of the snapshots in the snapshot tree are stored in the actual filenames of the snapshots themselves. Descriptions of each snapshot can be provided and will be stored in a file named .\$DISK.snap_descriptions The following operations can be performed: create -creates a new snapshot from the current position in the snapshot tree branch -creates a new branch of the snapshot tree from the specified snapshot revert -reverts to the specified snapshot and deletes all linked snapshots from the snapshot tree remove -removes all snapshosts and snapshot descriptions from the disk image list -list all snapshots and their descriptions help -displays the description and usage ================================================================================ " # delete -deletes the specified snapshot and all linked snapshots # from the snapshot tree } ########## Function: usage ########################################### usage() { echo echo "Usage: vm-snapshot-disk [create|branch|revert|remove|list|help] options" echo echo "Examples:" echo " vm-snapshot-disk create disk=<DISK_NAME> [snapname=<SNAPSHOT_NAME> description=\"<SNAPSHOT_DESCRIPTION>\"]" echo " vm-snapshot-disk branch disk=<DISK_NAME> snapname=<SNAPSHOT_NAME> [description=\"<SNAPSHOT_DESCRIPTION>\"]" echo " vm-snapshot-disk revert disk=<DISK_NAME> snapname=<SNAPSHOT_NAME>" echo " vm-snapshot-disk remove disk=<DISK_NAME>" echo " vm-snapshot-disk list disk=<DISK_NAME>" echo " vm-snapshot-disk help" echo } ########## Function: get_options ##################################### get_options() { case "$1" in #create|branch|revert|delete|help) create|branch|revert|remove|list) MODE="$1" ;; help|-h|--help) MODE=help ;; *) echo echo "ERROR: You must provide a valid mode!" usage exit 1 ;; esac if echo "$*" | grep -q "disk=" then local DISK_IMAGE_FULL=`echo "$*" | grep -o "disk=.*" | cut -d '=' -f 2 | cut -d ' ' -f 1` fi if echo $* | grep -q "snapname=" then SNAPSHOT_NAME=`echo $* | grep -o "snapname=.*" | cut -d '=' -f 2 | cut -d ' ' -f 1` fi if echo $* | grep -q "description=" then #SNAPSHOT_DESCR=`echo $* | grep -o "description=.*" | cut -d '=' -f 2 | cut -d ' ' -f 1` SNAPSHOT_DESCR=`echo $* | grep -o "description=.*" | cut -d '=' -f 2` fi if [ -z "$DISK_IMAGE_FULL" ] then case "$MODE" in help|-h) MODE=help description usage exit 99 ;; *) echo echo "ERROR: You must supply a disk image!" usage exit 1 esac else DISK_IMAGE=`get_file_name $DISK_IMAGE_FULL` DISK_PATH=`get_file_path $DISK_IMAGE_FULL` fi } ########## Function: get_file_path ###################################### get_file_path() { if [ -z $1 ] then echo "Usage: get_file_path <absolute|relative_path_to_file>" return 1 else local FILE="$1" fi local DIR_COUNT=`echo $FILE|grep -o "/"|wc -l` ((DIR_COUNT++)) local FILE_NAME=`echo $FILE|cut -d "/" -f $DIR_COUNT` local FILE_DIR=`echo $FILE|sed "s/$FILE_NAME$//g"` echo $FILE_DIR } ########## Function: get_file_name ###################################### get_file_name() { if [ -z $1 ] then echo "Usage: get_file_name <absolute|relative_path_to_file>" return 1 else local FILE="$1" fi local DIR_COUNT=`echo $FILE|grep -o "/"|wc -l` ((DIR_COUNT++)) local FILE_NAME=`echo $FILE|cut -d "/" -f $DIR_COUNT` local FILE_DIR=`echo $FILE|sed "s/$FILE_NAME$//g"` echo $FILE_NAME } ########## Function: test_disk ########################################### test_disk() { local DISK="$1" if ! [ -e "$DISK" ] then echo echo "ERROR: The specified disk \"$DISK\" does not exist!" echo exit 2 fi ON_OCFS2=false for VOL in ${OCFS2_VOLS} do while [ "${ON_OCFS2}" == false ] do if echo "${DISK}" | grep -q "${VOL}" then ON_OCFS2=true fi done done if ($QEMU_IMG_CMD info $DISK | grep "file format" | cut -d ' ' -f 3 | grep -q qcow2) 2> /dev/null then IMG_TYPE=qcow2 elif ($QEMU_IMG_CMD info $DISK | grep "file format" | cut -d ' ' -f 3 | grep -q raw) 2> /dev/null then IMG_TYPE=raw elif ($QEMU_IMG_CMD info $DISK | grep "file format" | cut -d ' ' -f 3 | grep -q vmdk) 2> /dev/null then IMG_TYPE=vmdk elif ($QEMU_IMG_CMD info $DISK | grep "file format" | cut -d ' ' -f 3 | grep -q vpc) 2> /dev/null then IMG_TYPE=vhd else echo echo "ERROR: The specified disk \"$DISK\" does not appear to be of a supported type" echo " You cannot snpashot this disk!" exit 3 fi } ########## Function: get_backing_disk ##################################### get_backing_disk() { case ${IMG_TYPE} in qcow2) "$QEMU_IMG_CMD" info "$1" | grep "backing file" | cut -d : -f 3 | sed 's/^ *//g' | sed 's/)//g' ;; vhd) "$VHD_UTIL_CMD" scan "$1" | cut -d \ -f 5 | cut -d \= -f 2 ;; *) echo "none" ;; esac } ########## Function: find_unused_snap_name ################################ find_unused_snap_name() { local DISK="$1" local SNAPNAME="$2" local SNAP_DESCR="$3" if [ -z "$SNAPNAME" ] then SNAMECOUNT=1 SNAPNAME=snap"$SNAMECOUNT" if ls "$DISK".* > /dev/null 2>&1 then #echo "Finding and unused snap name" until ! ls "$DISK".* | grep -q snap"$SNAMECOUNT" do ((SNAMECOUNT++)) SNAPNAME=snap"$SNAMECOUNT" done fi fi echo "$SNAPNAME" } ########## Function: create_first_snapshot ################################ create_first_snapshot() { local DISK="$1" local SNAPNAME="$2" local SNAP_DESCR="$3" local BDISK="$DISK".base start_first_snap_process() { SNAPNAME=`find_unused_snap_name "$DISK" "$SNAPNAME" "$SNAP_DESCR"` echo " Creating new snapshot: $BDISK.$SNAPNAME" echo "*****************************************************************" } rename_orig_disk() { mv "$DISK" "$BDISK" } link_orig_disk() { ln "$BDISK" "$BDISK"."$SNAPNAME" chmod a-w "$BDISK" chmod a-w "$BDISK"."$SNAPNAME" } do_qemu_image_first_snap() { "$QEMU_IMG_CMD" create -f qcow2 -b "$BDISK" "$BDISK"."$SNAPNAME"._working } do_reflink_first_snap() { "${REFLINK_CMD}" "${BDISK}" "${BDISK}"."${SNAPNAME}"._working } do_vhd_util_first_snap() { "$VHD_UTIL_CMD" snapshot -p "$BDISK" -n "$BDISK"."$SNAPNAME"._working } symlink_new_disk() { ln -s "$BDISK"."$SNAPNAME"._working "$DISK" } add_snapshot_description() { echo `echo "$BDISK.$SNAPNAME" | sed 's/\./_/g' | sed 's/__working//g'`"='$SNAP_DESCR'" >> ."$DISK".snap_descriptions } # case ${HYPERVISOR} in # qemu) case ${IMG_TYPE} in qcow2) start_first_snap_process rename_orig_disk link_orig_disk do_qemu_image_first_snap symlink_new_disk add_snapshot_description ;; vhd) start_first_snap_process rename_orig_disk link_orig_disk do_vhd_util_first_snap symlink_new_disk add_snapshot_description ;; *) case ${ON_OCFS2} in false) echo "ERROR: Disk is not of type qcow2 or vhd and not on a file system the supports snapshots!" echo echo " Will not create a snapshot" exit 6 ;; true) start_first_snap_process rename_orig_disk link_orig_disk do_reflink_first_snap symlink_new_disk add_snapshot_description ;; esac ;; esac # ;; # xen) # start_first_snap_process # rename_orig_disk # link_orig_disk # do_reflink_first_snap # symlink_new_disk # add_snapshot_description # ;; # esac } ########## Function: create_additional_snapshot ########################### create_additional_snapshot() { local DISK="$1" local SNAPNAME="$2" local SNAP_DESCR="$3" local BDISK=`ls -l "$DISK" |cut -d ">" -f 2 | sed 's/^ *//g'` start_additional_snap_process() { SNAPNAME=`find_unused_snap_name "$DISK" "$SNAPNAME" "$SNAP_DESCR"` BASE_BDISK="`echo "$BDISK" | sed 's/\._working//g'`" echo " Creating new snapshot: $BASE_BDISK.$SNAPNAME" echo "*****************************************************************" } do_qemu_image_additional_snap() { "$QEMU_IMG_CMD" create -f qcow2 -b "$BASE_BDISK"."$SNAPNAME" "$BASE_BDISK"."$SNAPNAME"._working } do_vhd_util_additional_snap() { "$VHD_UTIL_CMD" snapshot -p "$BASE_BDISK"."$SNAPNAME" -n "$BASE_BDISK"."$SNAPNAME"._working } do_reflink_additional_snap() { "${REFLINK_CMD}" "${BASE_DISK}"."${SNAPNAME}" "${BASE_DISK}"."${SNAPNAME}"._working } move_working_to_snap() { rm -f "$DISK" mv "$BDISK" "$BASE_BDISK"."$SNAPNAME" chmod a-w "$BASE_BDISK"."$SNAPNAME" } symlink_new_working_snap() { ln -s "$BASE_BDISK"."$SNAPNAME"._working "$DISK" } add_additional_snapshot_description() { echo `echo "$BASE_DISK.$SNAPNAME" | sed 's/\./_/g' | sed 's/__working//g'`"='$SNAP_DESCR'" >> ."$DISK".snap_descriptions } # case ${HYPERVISOR} in # qemu) case ${IMG_TYPE} in qcow2) start_additional_snap_process move_working_to_snap do_qemu_image_additional_snap symlink_new_working_snap add_additional_snapshot_description ;; vhd) start_additional_snap_process move_working_to_snap do_vhd_util_additional_snap symlink_new_working_snap add_additional_snapshot_description ;; *) case ${ON_OCFS2} in false) echo "ERROR: Disk is not of type qcow2 and not on a file system the supports snapshots!" echo echo " Will not create a snapshot" exit 6 ;; true) start_additional_snap_process move_working_to_snap do_reflink_additional_snap symlink_new_working_snap add_additional_snapshot_description ;; esac ;; esac # ;; # xen) # start_additional_snap_process # move_working_to_snap # do_reflink_additional_snap # symlink_new_working_snap # add_additional_snapshot_description # ;; # esac } ########## Function: create_snapshot ###################################### create_snapshot() { local DISK="$1" local SNAPNAME="$2" local SNAP_DESCR="$3" #echo "Testing for base disk image file" if ! [ -e "$DISK".base ] then create_first_snapshot "$DISK" "$SNAPNAME" "$SNAP_DESCR" #return elif [ -L "$DISK" ] then create_additional_snapshot "$DISK" "$SNAPNAME" "$SNAP_DESCR" #return fi } ########## Function: branch_at_snapshot ##################################### branch_at_snapshot() { local DISK="$1" local SNAPNAME="$2" local SNAP_DESCR="$3" local SNAP_POINT=`ls "$DISK".* | grep "$SNAPNAME$"` start_branch_process() { #echo "Finding and unused snap name" local SNAMECOUNT=1 until ! ls "$DISK".* | grep -q "$SNAPNAME"-"$SNAMECOUNT"$ do ((SNAMECOUNT++)) done SUB_SNAPNAME="$SNAPNAME"-"$SNAMECOUNT" echo "*****************************************************************" echo " Branching from snapshot: $SNAP_POINT" } remove_current_working() { rm -f "$DISK" rm -f "$DISK".*._working } do_qemu_img_branch_snap() { "$QEMU_IMG_CMD" create -f qcow2 -b "$SNAP_POINT" "$SNAP_POINT"."$SUB_SNAPNAME"._working } do_vhd_util_branch_snap() { "$VHD_UITL_CMD" snapshot -p "$SNAP_POINT" -n "$SNAP_POINT"."$SUB_SNAPNAME"._working } do_reflink_branch_snap() { "${REFLINK_CMD}" "${SNAP_POINT}" "${SNAP_POINT}"."${SUB_SNAPNAME}"._working } symlink_new_branch_snap() { ln -s "$SNAP_POINT"."$SUB_SNAPNAME"._working "$DISK" chmod a-w "$SNAP_POINT" } add_branch_snapshot_description() { echo `echo "${SNAP_POINT}.${SUB_SNAPNAME}" | sed 's/\./_/g' | sed 's/__working//g'`"='$SNAP_DESCR'" >> ."$DISK".snap_descriptions } if [ -z "$SNAPNAME" ] then echo echo "ERROR: You must supply a snapshot name to branch from!" echo exit 4 fi if ! ls "$DISK".* | grep -q "$SNAPNAME$" then echo echo "ERROR: The specified snapshot \"$SNAPNAME\" does not appear to exist!" echo exit 5 fi # case ${HYPERVISOR} in # qemu) case ${IMG_TYPE} in qcow2) start_branch_process remove_current_working do_qemu_img_branch_snap symlink_new_branch_snap add_branch_snapshot_description ;; *) case ${ON_OCFS2} in false) echo "ERROR: Disk is not of type qcow2 and not on a file system the supports snapshots!" echo echo " Will not create a snapshot" exit 6 ;; true) start_branch_process remove_current_working do_reflink_branch_snap symlink_new_branch_snap add_branch_snapshot_description ;; esac ;; esac # ;; # xen) # start_branch_process # remove_current_working # do_reflink_branch_snap # symlink_new_branch_snap # add_branch_snapshot_description # ;; # esac } ########## Function: revert_to_snapshot ##################################### revert_to_snapshot() { local DISK="$1" local SNAPNAME="$2" local SNAP_DESCR="$3" local SNAP_POINT=`ls "$DISK".* | grep "$SNAPNAME$"` start_revert_process() { echo "*****************************************************************" echo " Reverting to snapshot: $SNAP_POINT" echo "*****************************************************************" } remove_current_working_and_snap_point() { rm -f "$DISK" rm -f "$DISK".*._working rm -f "$SNAP_POINT".* } do_new_qemu_img_working_snap() { "$QEMU_IMG_CMD" create -f qcow2 -b "$SNAP_POINT" "$SNAP_POINT"._working } do_new_vhd_util_working_snap() { "$VHD_UTIL_CMD" snapshot -p "$SNAP_POINT" -n "$SNAP_POINT"._working } do_new_reflink_working_snap() { "${REFLINK_CMD}" "${SNAP_POINT}" "${SNAP_POINT}"._working } symlink_to_reverted_snap() { ln -s "$SNAP_POINT"._working "$DISK" chmod a-w "$SNAP_POINT" } remove_reverted_snapshot_description() { sed -i "/$SNAP_POINT\..*/d" ."$DISK".snap_descriptions } if [ -z "$SNAPNAME" ] then echo echo "ERROR: You must supply a snapshot name to revert to!" echo exit 4 fi if ! ls "$DISK".* | grep -q "$SNAPNAME$" then echo echo "ERROR: The specified snapshot \"$SNAPNAME\" does not appear to exist!" echo exit 5 fi # case ${HYPERVISOR} in # qemu) case ${IMG_TYPE} in qcow2) start_revert_process remove_current_working_and_snap_point do_new_qemu_img_working_snap symlink_to_reverted_snap remove_reverted_snapshot_description ;; *) case ${ON_OCFS2} in false) echo "ERROR: Disk is not of type qcow2 and not on a file system the supports snapshots!" echo echo " Will not create a snapshot" exit 6 ;; true) start_revert_process remove_current_working_and_snap_point do_new_reflink_working_snap symlink_to_reverted_snap remove_reverted_snapshot_description ;; esac ;; esac # ;; # xen) # start_revert_process # remove_current_working_and_snap_point # do_new_reflink_working_snap # symlink_to_reverted_snap # remove_reverted_snapshot_description # ;; # esac } ########## Function: remove_snapshot ##################################### remove_snapshots() { local DISK="$1" local SNAPNAME="$2" local SNAP_DESCR="$3" #echo "Testing for base disk image file" if ! [ -e "$DISK".base ] then echo "$DISK doesn't appear to have any snapshots" else echo "*****************************************************************" echo " Removing all snapshots from: $DISK" echo "*****************************************************************" rm -f "$DISK" chmod u+w "$DISK".base.* rm -r "$DISK".base.* # remove snapshot description rm -f ."$DISK".snap_descriptions mv "$DISK".base "$DISK" fi } ########## Function: list_snapshots ###################################### list_snapshots() { local DISK="$1" local SNAPNAME="$2" local SNAP_DESCR="$3" #echo "Testing for base disk image file" if ! [ -e "$DISK".base ] then echo "$DISK doesn't appear to have any snapshots" else for SNAP in `ls "$DISK".base.*` do if ! echo "$SNAP" | grep -q "_working" then local DOT_COUNT=`echo $SNAP | grep -o \\\. | wc -l` ((DOT_COUNT++)) local SNAP_NAME=`echo "$SNAP" | cut -d \. -f "$DOT_COUNT"` local SNAP_ENTRY=`echo $SNAP | sed 's/\./_/g'` echo -n "$SNAP_NAME = ";grep "$SNAP_ENTRY=" ."$DISK".snap_descriptions | cut -d '=' -f 2 fi done fi } ########## Function: delete_snapshot ##################################### # Disabled until I can figure out how to 'merge' cow snapshots delete_snapshot() { local DISK="$1" local SNAPNAME="$2" local SNAP_DESC="$3" if [ -z "$SNAPNAME" ] then echo echo "ERROR: You must supply a snapshot name to delete!" echo exit 4 fi if ! ls "$DISK".* | grep -q "$SNAPNAME$" then echo echo "ERROR: The specified snapshot \"$SNAPNAME\" does not appear to exist!" echo exit 5 fi if [ "$DISK.$SNAPNAME" = "$DISK.base" ] then echo echo "ERROR: You cannot delete the base image!" echo exit 6 fi local SNAP_DEL=`ls "$DISK".* | grep "$SNAPNAME$"` local SNAP_POINT=`echo $SNAP_DEL | sed "s/\.$SNAPNAME$//g"` if [ "$SNAP_POINT" = "$DISK.base" ] then echo > /dev/null #echo "Guess its the base" #continue elif ls "$SNAP_POINT".* > /dev/null 2>&1 then #echo "SNAP_POINT=$SNAP_POINT, looking for end of snap train" local SNAP_POINT_OPTIONS=`ls "$SNAP_POINT".*` #echo "My choices are: $SNAP_POINT_OPTIONS" if ! [ "$SNAP_POINT_OPTIONS" = "$SNAP_DEL" ] then for SP in $SNAP_POINT_OPTIONS do if ! ls "$SP".* > /dev/null 2>&1 then if ! [ "$SP" = "$SNAP_DEL" ] then SNAP_POINT="$SP" fi fi done #else # echo "Oops. guess I don't need to look after all" fi elif [ "$SNAP_POINT" = "$SNAP_DEL" ] then #echo "Opps. Del point = Snap point. trying to fix..." local FCOUNT=`echo $SNAP_POINT | grep -o "\." | wc -l` ((FCOUNT++)) LAST_FLD=`echo $SNAP_POINT | cut -d '.' -f $FCOUNT` SNAP_POINT=`echo $SNAP_POINT | sed "s/\.$LAST_FLD//g"` fi echo "*****************************************************************" echo " Deleting snapshot: $SNAP_DEL" echo " Reverting to snapshot: $SNAP_POINT" echo "*****************************************************************" if [ -L "$DISK" ] then rm -f "$DISK" fi rm -f "$DISK".*._working rm -f "$SNAP_DEL"* "$QEMU_IMG_CMD" create -f qcow2 -b "$SNAP_POINT" "$SNAP_POINT"._working ln -s "$SNAP_POINT"._working "$DISK" # remove snapshot description sed -i "/$SNAP_DEL.*/d" ."$DISK".snap_descriptions } ################################################################################### # Main Code Body ################################################################################### get_options $* cd "$DISK_PATH" test_disk "$DISK_IMAGE" case "$MODE" in create) echo "*****************************************************************" create_snapshot "$DISK_IMAGE" "$SNAPSHOT_NAME" "$SNAPSHOT_DESCR" ;; branch) branch_at_snapshot "$DISK_IMAGE" "$SNAPSHOT_NAME" "$SNAPSHOT_DESCR" ;; revert) revert_to_snapshot "$DISK_IMAGE" "$SNAPSHOT_NAME" "$SNAPSHOT_DESCR" ;; remove) remove_snapshots "$DISK_IMAGE" "$SNAPSHOT_NAME" "$SNAPSHOT_DESCR" ;; list) list_snapshots "$DISK_IMAGE" "$SNAPSHOT_NAME" "$SNAPSHOT_DESCR" ;; # Disabled until I can figure out how to merge cow snapshots # delete) # delete_snapshot "$DISK_IMAGE" "$SNAPSHOT_NAME" "$SNAPSHOT_DESCR" # ;; help) description usage ;; esac exit 0
Locations
Projects
Search
Status Monitor
Help
OpenBuildService.org
Documentation
API Documentation
Code of Conduct
Contact
Support
@OBShq
Terms
openSUSE Build Service is sponsored by
The Open Build Service is an
openSUSE project
.
Sign Up
Log In
Places
Places
All Projects
Status Monitor