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
openSUSE Build Service is sponsored by