VMware Cloud Community
wila
Immortal
Immortal

New Script for moving vm to another storage

Hi Guys/Gals,

This week i needed to move a bunch of VMs from local storage to iSCSI so that i can accomodate for more storage. The normal way for me to do this is to either do this by hand or write a 10 lines long script for each VM... as i don't have Virtual Center yet.

So i decided that it might be nice to create a general script for this. For details and usage, see in the source. Hope you like it, this is my first attempt at a more advanced bash script, so i'm sure that some things could have been done easier. Robustness (is that a word?) was my priority.

The source might also need a bit cleanup of commented out things, but alas.. no more time now. It seems to work fine for me.

More updates/cleanup when i get the time.

#!/bin/bash

#

\# vm-relocate.sh

#

\# Script for Virtual Infrastructure 3.x to migrate an existing VM to

\# another VMFS storage. An example of this would be to move a VM from

\# local storage to iSCSI storage.

\# In short, what the script does is; unregister the VM passed by its name.

\# Then copy all disks using vmkfstools, copy all other files, update

\# the configuration file for the changed location, and register the VM again.

\# order and details are a little different, but you get the idea.

#

\# Features:

\# - Only VMs that are powered down will be relocated.

\# - Only connected disks are migrated, making it easier to intentially skip a disk

\# - All target disks will be moved to the new location, even if your machine now

\# has disks over separate lun's

\# - You should pass it the vmname, this can be different from the display name,

\# the parameter is case insensitive.

\# - The original VM is not removed at all ONLY unregistered, so you can

\# always go back by unregistering/deleting the clone and registering the original .vmx

\# again.

#

\# Note:

\# - This is NOT a backup script, this is not the intention and never will be.

#

\# Example usage:

\# ./vm-relocate browserappliance /vmfs/volumes/lun-x/browse

\# This will relocate the vm "browserappliance.vmx" to a new folder called

\# "browse" on the volume with name "lun-x"

#

#

\# Author: Wil van Antwerpen

\# Date: June 15, 2007

\# License: GPL

\# Version: 0.2

#

\# Bugreports & suggestions can be send via PM to wila in VMTN

\# or you can leave them in this thread.

#

\# declare some global variables to work with

strVMname="" # short VM filename without path or file extension (.vmx)

strDisplayName="" # Display Name of the VM

strVMX="" # full location of the vmx file to move in UUID style

strVMXpath="" # The default path of where our source vmx (and disks) is stored

strVMDK="" # List of vmdk source disks to move, full path UUID again

strVMDKname="" # List of vmdk disks without the path

strVMDKdevice="" # List of scsi devices

strTarget="" # path where you are moving the VM towards

verbose_state=0

LOGFILE="vm-relocate.log"

#

\# Return the complete file location for the strVMname passed and store

\# that in strVMX

#

function vmxfileForVMname ()

{

local vm

echo -e -n $"Searching for vm \"$strVMname\" on our host... "

for vm in `vmware-cmd -l`

do

if echo "$vm.vmx" | grep -i -q "$strVMname" ; then

echo "Ok"

logOutput "Found VM:\n $vm"

strVMX=$vm

strVMXpath=$\{vm%/*}

logOutput "Source path = $\{strVMXpath}"

fi

done

if \[ -z "$strVMX" ]; then

verbose_state=1

logOutput "$strVMname not found, unable to comply with the request, exiting...."

exit 3

fi

} # vmxfileForVMname

#

\# Are the minimal required parameters passed?

#

#

function testParams ()

{

if \[ -z "$strVMname" ]; then

verbose_state=1

logOutput "No VM to relocate has been provided in the command line. Exiting."

showHelp

exit 3

fi

if \[ -z "$strTarget" ]; then

verbose_state=1

logOutput "No target folder to move the VM towards is passed on the command line. Exiting."

showHelp

exit 3

fi

}

#

\# Checks the preconditions that must be met for the script to

\# work properly

\# - did we find an existing vm?

\# - is it still running?

\# - does the target folder already exist?

\# - if not can we create it?

#

function checkConditions ()

{

local currentState=""

local displayName=""

if \[ -z "$strVMX" ]; then # How many times can one check the same thing Smiley Wink

verbose_state=1

logOutput "No VM to relocate has been provided in the command line. Exiting."

logOutput ""

exit 3

fi

echo -n $"Checking to make sure the VM is not running.... "

currentState=`vmware-cmd "$strVMX" getstate -q`

strDisplayName=`vmware-cmd "$strVMX" getconfig displayName -q`

if echo $currentState | grep -i -q "on" ; then

verbose_state=1

logOutput "Running state = $currentState"

logOutput "The vm $strDisplayName is still running, this is not supported, aborting.."

exit 4

fi

echo "Ok"

echo -n $"Checking to make sure the target doesn't exist.... "

if \[ -d $strTarget ]; then

verbose_state=1

logOutput "The folder $\{strTarget} already exists. Exiting."

exit 5

fi

echo "Ok"

} # checkConditions

function showHelp ()

{

echo ""

echo "Usage:"

echo " vm-relocate.sh \[options] $\{LOGFILE}

}

function processArguments ()

{

while test "$1" != "" ; do

case $1 in

--help|-h)

showHelp

exit 0

;;

--version|V)

echo "vm-relocate.sh version 0.2"

exit 0

;;

--verbose|v)

verbose_state=1

;;

-*)

echo "Error: Unknown option $1"

showHelp

exit 1

;;

*)

strVMname=$1

shift

strTarget=$1

shift

;;

esac

shift

done

testParams

} # processArguments

#

\# Searches the vmx file for lines with vmdk files and extracts those along with

\# the relevant parameters for a later query.

#

function getVirtualDisks ()

{

local vmdk=""

IFS=$'\n'

logOutput "Find all disks in VM"

strVMDK=`cat $strVMX | grep -i ".vmdk"`

logOutput "Disks in vmx:\n$strVMDK"

for word in $strVMDK

do

word=$\{word#*=}

word=${word#*\"}

word=${word%*\"}

vmdk=`echo -e "$word\n$vmdk"`

word=$\{word##*/}

strVMDKname=`echo -e "$\{word}\n$strVMDKname"`

done

for word in $strVMDK

do

word=$\{word%=*}

word=$\{word%.fileName*}

strVMDKdevice=`echo -e "$\{word}\n$strVMDKdevice"`

done

strVMDK=$\{vmdk}

logOutput "\nDone:\n$\{strVMDK}\nDisks:\n$\{strVMDKname}\nDevices:\n$\{strVMDKdevice}"

} # getVirtualDisks

#

\# Removes the disks from our result that are marked as NOT present

\# in the vmx config file.

#

function removeNonpresentDisks ()

{

local n=0

local connected=0

local device=""

local devices=""

local svmdk=""

local vmdks=""

local vmdk_path=""

local vmdk_path_list=""

IFS=$'\n'

\# checking if the vmdk's are connected

devices=""

for device in $strVMDKdevice

do

((n += 1))

connected=`vmware-cmd "$vmx" getconfig "$\{device}.present" -q`

echo "connected $device = $connected"

if \[ $connected == "1" ]; then

  1. create a new devices list with only the devices marked as present.

svmdk=`echo "$\{strVMDKname}" | sed -n "$\{n}p"`

vmdk_path=`echo "$\{strVMDK}" | sed -n "$\{n}p"`

logOutput "Adding connected disk: $\{svmdk} at $\{vmdk_path}"

if \[ -z $devices ]; then

devices=$\{device}

vmdk_path_list=$\{vmdk_path}

vmdks=$\{svmdk}

else

devices=`echo -e "$\{devices}\n$\{device}"`

vmdk_path_list=`echo -e "$\{vmdk_path_list}\n$\{vmdk_path}"`

vmdks=`echo -e "$\{vmdks}\n$\{svmdk}"`

fi

fi

done

strVMDKdevice=$\{devices}

strVMDKname=$\{vmdks}

strVMDK=$\{vmdk_path_list}

} # removeNonpresentDisks

#

\# Last chance!

\# Display the devices that the script will copy and ask for a confirmation.

#

function confirmMigration ()

{

local n=0

local svmdk=""

local confirmation=""

echo -e "----


"

echo -e "The details of the VM that is to be migrated are:"

echo -e "Display Name: $\{strDisplayName}"

echo -e "VM : $\{strVMX##*/}"

echo -e "Source Path : $\{strVMXpath}"

echo -e "Target Path : $\{strTarget}"

echo -e "With the following disks:"

for device in $strVMDKdevice

do

((n += 1))

svmdk=`echo "$\{strVMDKname}" | sed -n "$\{n}p"`

echo -e "$\{device} = $svmdk"

done

echo -e "----


"

echo -e "Do you want to continue (Y)es/(N)o ?"

read confirmation

if \[ -z $confirmation ]; then

confirmation="N"

fi

if ! `echo "$confirmation" | grep -i -q "Y"` ; then

verbose_state=1

logOutput "Cancelled by user request."

exit 7

fi

logOutput "Confirmation accepted."

}

#

\# performs the actual copying of the disks

#

#

function copyDisks ()

{

local vmx=""

local svmdk=""

local target=""

local diskDevice=""

local n=0

IFS=$'\n'

vmx=$\{strVMX}

target=$\{strTarget}

removeNonpresentDisks

\# Confirmation on the copy

confirmMigration

echo -n $"Creating folder $strTarget .... "

mkdir $strTarget

if \[ ! -d $strTarget ]; then

verbose_state=1

logOutput "Unable to create target folder $\{strTarget}. Exiting."

exit 6

fi

echo "Ok"

\# The actual copy of the disks

for sourceDisk in $strVMDK

do

((n += 1))

svmdk=`echo "$\{strVMDKname}" | sed -n "$\{n}p"`

if echo "$sourceDisk" | grep -i -q "/" ; then

logOutput "vmkfstools -i $\{sourceDisk} $\{target}/$\{svmdk}"

vmkfstools -i "$\{sourceDisk}" "$\{target}/$\{svmdk}"

else

logOutput "vmkfstools -i $\{strVMXpath}/$\{sourceDisk} $\{target}/$\{svmdk}"

vmkfstools -i "$\{strVMXpath}/$\{sourceDisk}" "$\{target}/$\{svmdk}"

fi

done

#echo "cd $\{target}"

#logOutput `"cp $\{strVMXpath}/*.vmx $\{target}/"`

logOutput `cp $\{strVMXpath}/*.vmx $\{target}/`

#cp "$\{strVMXpath}/*.vmx" "$\{target}/" 1>>$\{LOGFILE}

logOutput `cp $\{strVMXpath}/*.vmxf $\{target}/`

#cp "$\{strVMXpath}/*.vmxf" "$\{target}/" 1>>$\{LOGFILE}

logOutput `cp $\{strVMXpath}/*.nvram $\{target}/`

#cp "$\{strVMXpath}/*.nvram" "$\{target}/" 1>>$\{LOGFILE}

} # copyDisks

#

\# unregister old, register new, update disks so that no old disks are accidentily

\# referenced by path.

#

function finalizeMigration ()

{

local VMXtarget

local svmdk

echo -e "\nAll disks migrated, now updating the host to finalize the change"

#VMXtarget="$\{strTarget}/$\{strVMname}.vmx"

VMXtarget="$\{strTarget}/$\{strVMX##*/}"

verbose_state=1

logOutput "vmware-cmd -s unregister $\{strVMX}"

logOutput `vmware-cmd -s unregister $\{strVMX}`

#vmware-cmd -s unregister \"$\{strVMX}\"

sleep 20

logOutput "vmware-cmd -s register $\{VMXtarget}"

logOutput `vmware-cmd -s register $\{VMXtarget}`

#vmware-cmd -s register \"$\{VMXtarget}\"

\# Update the config file so that all disks ARE local to the target path

for device in $strVMDKdevice

do

((n += 1))

svmdk=`echo "$\{strVMDKname}" | sed -n "$\{n}p"`

logOutput "vmware-cmd \"$\{VMXtarget}\" setconfig $\{device}.fileName \"$svmdk\""

vmware-cmd $\{VMXtarget} setconfig $\{device}.fileName "$\{strTarget}/$svmdk"

done

}

processArguments $@

vmxfileForVMname # find the vmx config file for the vmname passed

checkConditions # is VM still running? is the target folder already there? if so QUIT

getVirtualDisks

copyDisks

finalizeMigration

| Author of Vimalin. The virtual machine Backup app for VMware Fusion, VMware Workstation and Player |
| More info at vimalin.com | Twitter @wilva
0 Kudos
16 Replies
Oczkov
Enthusiast
Enthusiast

Hi Wil,

Thanks for sending this on the forum. To the topic of your thread I would add that the script is for copying to another LOCAL VMFS storage ;).

Guess what I need? Copying VM's from one VMFS to another, but located on a different ESX machine (in the environemt where where the customer doesn;t have Virtual Center or even if he have I've never seen \[Relocate] option working...) This would surely direct me to the thread on how to do it efficiently:

http://www.vmware.com/community/thread.jspa?threadID=29721&tstart=0

Combining your product with the knowledge from this thread we should be able to do it.

Cheers,

0 Kudos
wila
Immortal
Immortal

Hi Oczkov, thanks for the kind words.

To the topic of your thread I would add that the script is for

copying to another LOCAL VMFS storage Smiley Wink.

Good suggestion, i can't change it in the main topic anymore though.

Guess what I need? Copying VM's from one VMFS to

another, but located on a different ESX machine (in

the environemt where where the customer doesn;t have

Virtual Center or even if he have I've never seen

\[Relocate] option working...) This would surely

direct me to the thread on how to do it efficiently:

http://www.vmware.com/community/thread.jspa?threadID=2

9721&tstart=0

Combining your product with the knowledge from this

thread we should be able to do it.

I've also found that in this particular scenario the free vmware converter (see download section) works wonders. You can copy a VM straight onto the target host, unless the target ESX host is a starter edition. Even hotclone if you like.

At the moment i have no plans for adding the possibility to copy (it's not a move is it?) to a remote host over SSH. Trying to keep things simple, for such a script i would do it like you suggest, take the source and copy the parts you need from it.

PS: You probably want to remove the part that unregisters the source VM at the source Host.

| Author of Vimalin. The virtual machine Backup app for VMware Fusion, VMware Workstation and Player |
| More info at vimalin.com | Twitter @wilva
0 Kudos
wila
Immortal
Immortal

Here's an update to the script, version 0.3

List of changes can be found at the top.

Warning: the confirmation default was "No" and has been changed into "Yes"

Usage tip: Suppose you have similarly named VM's like "foo" and "a-foo" and you want to move "foo" and not "a-foo" while the script suggests to move "a-foo" when you supply it with the search string "foo" (got that? Smiley Happy )

Simply add part of the path in your search string so search for "foo/foo" and you should be fine.

#!/bin/bash
#
\# vm-relocate.sh
#
\# Script for Virtual Infrastructure 3.x to migrate an existing VM to
\# another local VMFS storage. An example of this would be to move a VM from 
\# local storage to iSCSI storage.
\# In short, what the script does is; unregister the VM passed by its name.
\# Then copy all disks using vmkfstools, copy all other files, update
\# the configuration file for the changed location, and register the VM again. 
\# order and details are a little different, but you get the idea.
#
\# Features:
\# - Only VMs that are powered down will be relocated.
\# - Only connected disks are migrated, making it easier to intentially skip a disk 
\# - All target disks will be moved to the new location, even if your machine now
\#   has disks over separate lun's
\# - You should pass it the vmname, this can be different from the display name, 
\#   the parameter is case insensitive.
\# - The original VM is not removed at all ONLY unregistered, so you can
\#   always go back by unregistering/deleting the clone and registering the original .vmx 
\#   again.
#
\# Note:
\# - This is NOT a backup script, this is not the intention and never will be.
#
\# Example usage:
\#   ./vm-relocate browserappliance /vmfs/volumes/lun-x/browse
\# This will relocate the vm "browserappliance.vmx" to a new folder called 
\# "browse" on the volume with name "lun-x"
#
#
\# Author: Wil van Antwerpen
\# Date: June 15, 2007
\# License: GPL
\# Version: 0.3
#
\# Bugreports & suggestions can be send via PM to wila in VMTN
\# or you can leave them in this thread.
#
\# Changes:
\# version 0.3 - Jun 29 2007
\# o Changed default confirmation from default "No" to default to "Yes" instead.
\# It was only "No" for initial testing purposes.
\# o Cleaned up echo for connected devices, this is now written to the log instead.
\# o Fixed writing out the datetime stamp in the log
\# o Added check for running as root in checkConditions()
\# o Confirmation now displays source with device label instead of UUID
\# o Fixed case sensitivity problem with parsing the scsiX:X.fileName property


\# declare some global variables to work with
strVMname=""      # short VM filename without path or file extension (.vmx)
strDisplayName="" # Display Name of the VM
strVMX=""         # full location of the vmx file to move in UUID style
strVMXpath=""     # The default path of where our source vmx (and disks) is stored (UUID)
strSourcePath=""  # The default path of where our source vmx (and disks) is stored NON UUID
strVMDK=""        # List of vmdk source disks to move, full path UUID again
strVMDKname=""    # List of vmdk disks without the path
strVMDKdevice=""  # List of scsi devices
strTarget=""      # path where you are moving the VM towards
verbose_state=0
LOGFILE="vm-relocate.log"

E_NOACCESS=20     # Not enough access rights
#
\# Return the complete file location for the strVMname passed and store
\# that in strVMX
#
function vmxfileForVMname ()
{
 local vm
 echo -e -n $"Searching for vm \"$strVMname\" on our host...             "
 for vm in `vmware-cmd -l`
 do
   if echo "$vm.vmx" | grep -i -q "$strVMname" ; then
     echo "Ok"
     logOutput "Found VM:\n $vm"
     strVMX=$vm
     strVMXpath=$\{vm%/*}
     logOutput "Source path = $\{strVMXpath}"   
   fi
 done
 if \[ -z "$strVMX" ]; then
   verbose_state=1
   logOutput "$strVMname not found, unable to comply with the request, exiting...."
   exit 3
 fi
} # vmxfileForVMname


#
\# Are the minimal required parameters passed?
#
#
function testParams ()
{
if \[ -z "$strVMname" ]; then
 verbose_state=1
 logOutput "No VM to relocate has been provided in the command line. Exiting."
 showHelp
 exit 3
fi
if \[ -z "$strTarget" ]; then
 verbose_state=1
 logOutput "No target folder to move the VM towards is passed on the command line. Exiting."
 showHelp
 exit 3
fi
}


#
\# Checks the preconditions that must be met for the script to
\# work properly
\#  - did we find an existing vm?
\#  - is it still running?
\#  - does the target folder already exist?
\#  - if not can we create it?
#
function checkConditions ()
{
local currentState=""
local displayName=""

if \[ -z "$strVMX" ]; then # How many times can one check the same thing ;)
 verbose_state=1
 logOutput "No VM to relocate has been provided in the command line. Exiting."
 logOutput ""
 exit 3
fi


if \[ "$UID" -ne "0" ]
then
 verbose_state=1
 logOutput "You must be root to run this script.\nYou can use 'su -' or 'sudo' to get root access"
 exit E_NOACCESS
fi 

echo -n $"Checking to make sure the VM is not running....            "
currentState=`vmware-cmd "$strVMX" getstate -q` 
strDisplayName=`vmware-cmd "$strVMX" getconfig displayName -q`
if echo $currentState | grep -i -q "on" ; then
 verbose_state=1
 logOutput "Running state = $currentState"
 logOutput "The vm $strDisplayName is still running, this is not supported, aborting.."
 exit 4
fi
echo "Ok"
echo -n $"Checking to make sure the target doesn't exist....         "
if \[ -d $strTarget ]; then
  verbose_state=1
  logOutput "The folder $\{strTarget} already exists. Exiting."
  exit 5
fi
echo "Ok"
} # checkConditions



function showHelp ()
{
        echo ""
	echo "Usage:"
	echo "      vm-relocate.sh \[options] <vmname> <target>"
        echo ""
	echo "This script moves a registered VM to another VMFS location with ease."
	echo "The original VM is not erased afterwards, so that you can verify the correct"
        echo "working of the clone before the original is removed."
        echo ""
        echo "<vmname> - This is the filename of the VM without the .vmx extention or path."
        echo "           case insensitive "
        echo "<target> - The folder on the VMFS volume that you want to migrate the vm to."
        echo "           This folder must not already exist or the operation is cancelled."
        echo ""
        echo "Options: "
        echo "  -v/--verbose     Display all the details of what the script is doing"
        echo "  -h/--help        This screen and exits"
        echo "  -V/--version     Prints version of the script and exits"
} # showHelp


\# writes the output to logfile vm-relocate.log in your current folder name
function logOutput ()
{
local logtime
  if \[ $verbose_state -eq 1 ] ; then
    echo -e $@
  fi
  echo -e "$(date +'%b %d %H:%M%S') - $@" 1>>$\{LOGFILE}
}



function processArguments ()
{
while test "$1" != "" ; do
  case $1 in
	--help|-h)
		showHelp
		exit 0
	;;
	--version|V)
		echo "vm-relocate.sh version 0.3"
		exit 0
	;;
	--verbose|v)
		verbose_state=1
	;;
	-*)
		echo "Error: Unknown option $1"
		showHelp
		exit 1
	;;
        *)
		strVMname=$1
		shift
		strTarget=$1
		shift
        ;;
  esac
  shift
done
testParams
} # processArguments


#
\# Searches the vmx file for lines with vmdk files and extracts those along with
\# the relevant parameters for a later query.
#
function getVirtualDisks ()
{
local vmdk=""
IFS=$'\n'
logOutput "Find all disks in VM"
strVMDK=`cat $strVMX | grep -i ".vmdk"`
logOutput "Disks in vmx:\n$strVMDK"

for word in $strVMDK
do
 word=$\{word#*=}
 word=${word#*\"}
 word=${word%*\"}
 vmdk=`echo -e "$word\n$vmdk"`
 word=$\{word##*/}
 strVMDKname=`echo -e "$\{word}\n$strVMDKname"`
done
for word in $strVMDK
do
 word=$\{word%=*} 
 word=`echo -e "$\{word}" | sed 's/\.filename *//i'`
 strVMDKdevice=`echo -e "$\{word}\n$strVMDKdevice"`
done
strVMDK=$\{vmdk}
logOutput "\nDone:\n$\{strVMDK}\nDisks:\n$\{strVMDKname}\nDevices:\n$\{strVMDKdevice}"
} # getVirtualDisks

#
\# Removes the disks from our result that are marked as NOT present
\# in the vmx config file.
#
function removeNonpresentDisks ()
{
local n=0
local connected=0
local device=""
local devices=""
local svmdk=""
local vmdks=""
local vmdk_path=""
local vmdk_path_list=""
IFS=$'\n'
\# checking if the vmdk's are connected

devices=""
for device in $strVMDKdevice
do
  ((n += 1))
  connected=`vmware-cmd "$vmx" getconfig "$\{device}.present" -q`
  logOutput "connected $device = $connected"
  if \[ $connected == "1" ]; then

    # create a new devices list with only the devices marked as present.
    svmdk=`echo "$\{strVMDKname}" | sed -n "$\{n}p"`
    vmdk_path=`echo "$\{strVMDK}" | sed -n "$\{n}p"`
    logOutput "Adding connected disk: $\{svmdk} at $\{vmdk_path}"
    if \[ -z $devices ]; then
      devices=$\{device}
      vmdk_path_list=$\{vmdk_path}
      vmdks=$\{svmdk}
    else 
      devices=`echo -e "$\{devices}\n$\{device}"`
      vmdk_path_list=`echo -e "$\{vmdk_path_list}\n$\{vmdk_path}"`
      vmdks=`echo -e "$\{vmdks}\n$\{svmdk}"`
    fi
  fi
done
strVMDKdevice=$\{devices}
strVMDKname=$\{vmdks}
strVMDK=$\{vmdk_path_list}
} # removeNonpresentDisks

#
\# Find the label for the sourcepath as the UUID is not that
\# easy to use for use humans
#
function findLabelForUUID()
{
local lunPATH=$1
local devUUID=""
local devLABEL=""
local devROOT="/vmfs/volumes/"

devUUID="$\{strVMXpath#$devROOT}"
devUUID="$\{devUUID%%/*}"
devLABEL=`ls -l  $\{devROOT} | grep "> $\{devUUID}" | awk '\{print $9}'`
lunPATH="$\{strVMXpath//$devUUID/$devLABEL}"
strSourcePath="$\{lunPATH}"
logOutput "Source UUID  : $\{devUUID}"
logOutput "Source LABEL : $\{devLABEL}"
logOutput "Source Path  : $\{lunPATH}"
} # findLabelForUUID

#
\# Last chance! 
\# Display the devices that the script will copy and ask for a confirmation.
#
function confirmMigration ()
{
local n=0
local svmdk=""
local confirmation=""
echo -e "------------------------------------------------------------------"
echo -e "The details of the VM that is to be moved are:"
echo -e "Display Name: $\{strDisplayName}"
echo -e "VM          : $\{strVMX##*/}"
echo -e "Source Path : $\{strSourcePath}"
echo -e "Target Path : $\{strTarget}"
echo -e "With the following disks:"
for device in $strVMDKdevice
do
 ((n += 1))
 svmdk=`echo "$\{strVMDKname}" | sed -n "$\{n}p"`
 echo -e "$\{device} = $svmdk"
done
echo -e "------------------------------------------------------------------"
echo -e "Do you want to continue (Y)es/(N)o [Y]?"
read confirmation
if \[ -z $confirmation ]; then
  confirmation="Y"
fi
if ! `echo "$confirmation" | grep -i -q "Y"` ; then
  verbose_state=1
  logOutput "Cancelled by user request."
  exit 7
fi
logOutput "Confirmation accepted."
}

#
\# performs the actual copying of the disks
#
#
function copyDisks ()
{
local vmx=""
local svmdk=""
local target=""
local diskDevice=""
local n=0
IFS=$'\n'
vmx=$\{strVMX}
target=$\{strTarget}

removeNonpresentDisks

\# Confirmation on the copy
confirmMigration

echo -n $"Creating folder $strTarget ....                 "
mkdir $strTarget
if \[ ! -d $strTarget ]; then
  verbose_state=1
  logOutput "Unable to create target folder $\{strTarget}. Exiting."
  exit 6
fi
echo "Ok"

\# The actual copy of the disks
for sourceDisk in $strVMDK
do
  
  ((n += 1))
  svmdk=`echo "$\{strVMDKname}" | sed -n "$\{n}p"`
  if echo "$sourceDisk" | grep -i -q "/" ; then
    logOutput "vmkfstools -i $\{sourceDisk} $\{target}/$\{svmdk}"
    vmkfstools -i "$\{sourceDisk}" "$\{target}/$\{svmdk}"
  else
    logOutput "vmkfstools -i $\{strVMXpath}/$\{sourceDisk} $\{target}/$\{svmdk}"
    vmkfstools -i "$\{strVMXpath}/$\{sourceDisk}" "$\{target}/$\{svmdk}"
  fi
done
#echo "cd $\{target}"
#logOutput `"cp $\{strVMXpath}/*.vmx $\{target}/"`
logOutput `cp $\{strVMXpath}/*.vmx $\{target}/`
#cp "$\{strVMXpath}/*.vmx" "$\{target}/" 1>>$\{LOGFILE}
logOutput `cp $\{strVMXpath}/*.vmxf $\{target}/`
#cp "$\{strVMXpath}/*.vmxf" "$\{target}/" 1>>$\{LOGFILE}
logOutput `cp $\{strVMXpath}/*.nvram $\{target}/`
#cp "$\{strVMXpath}/*.nvram" "$\{target}/" 1>>$\{LOGFILE}
} # copyDisks


#
\# unregister old, register new, update disks so that no old disks are accidentily 
\# referenced by path.
#
function finalizeMigration ()
{
local VMXtarget
local svmdk
echo -e "\nAll disks migrated, now updating the host to finalize the change"

#VMXtarget="$\{strTarget}/$\{strVMname}.vmx" 
VMXtarget="$\{strTarget}/$\{strVMX##*/}" 
verbose_state=1
logOutput "vmware-cmd -s unregister $\{strVMX}"
logOutput `vmware-cmd -s unregister $\{strVMX}`
#vmware-cmd -s unregister \"$\{strVMX}\"
sleep 20
logOutput "vmware-cmd -s register $\{VMXtarget}"
logOutput `vmware-cmd -s register $\{VMXtarget}`
#vmware-cmd -s register \"$\{VMXtarget}\"
\# Update the config file so that all disks ARE local to the target path
for device in $strVMDKdevice
do
  
  ((n += 1))
  svmdk=`echo "$\{strVMDKname}" | sed -n "$\{n}p"`
  logOutput "vmware-cmd \"$\{VMXtarget}\" setconfig $\{device}.fileName \"$svmdk\""
  vmware-cmd $\{VMXtarget} setconfig $\{device}.fileName "$\{strTarget}/$svmdk"
done
}

#clear # to be removed
processArguments $@ 
vmxfileForVMname  # find the vmx config file for the vmname passed
findLabelForUUID
checkConditions   # is VM still running? is the target folder already there? if so QUIT
getVirtualDisks
copyDisks
finalizeMigration

edit: changed code markers to "new forum style", please use the attached version below though as this one still contains a few funny characters that I never put there. I left it in here for easier reading. Can't remove it from the top post unfortunately.

| Author of Vimalin. The virtual machine Backup app for VMware Fusion, VMware Workstation and Player |
| More info at vimalin.com | Twitter @wilva
0 Kudos
rboussen
Contributor
Contributor

Very nice script Wil.

Perhaps you could let the script generate another script

with the unregister/register commands to get back to the old situation very quickly.

0 Kudos
wila
Immortal
Immortal

Thanks, not a bad idea.

The thing to take into account then is that there's a danger of ending up with VMs and scripts being out of sync. So if at all possible i would try to get you the functionality -without- generating extra scripts.

Now let's be honest, even without additional scripts it is really easy to go back to the old situation. It's just a matter of rightclicking the VM in the VIC, selecting "unregister machine", then double click on the storage where the old VM is, navigate to the folder where the VM is stored and rightclick the .vmx and select "register".

The extra i was thinking about adding, that seems to overlap your request here, is to add some sort of "copy" parameter that would still go through all the normal steps, but on the end leaves your current VM as current.

| Author of Vimalin. The virtual machine Backup app for VMware Fusion, VMware Workstation and Player |
| More info at vimalin.com | Twitter @wilva
0 Kudos
espi3030
Expert
Expert

wila,

I stumbled upon this thread, and glad I did. Right now I am using a backup script to relocate my VM's (which is fine for now) but it would be nice to implement your script. I see the last post was in August of 2007, have you made any additional changes/updates to this script?

Thank you

0 Kudos
espi3030
Expert
Expert

BTW, what is the syntax for the "TARGET"?

Thank you

0 Kudos
fasteddy
Contributor
Contributor

Hi,

is there another way moving machines from one storage to another?

I have some Maschines named with some spaces between characters, an these are not processed correctly by the script...

Thanks in advance.

Stefan

0 Kudos
espi3030
Expert
Expert

Have you used VMware converter?

0 Kudos
fasteddy
Contributor
Contributor

No, I did not use the converter.

I created some machines using the Windows VMware Infrastructure Client and named them with some spaces... an because ESX creates folders/files named as the initial display name of the machine, I still have these spaces. And the script is not able to process them as arguments coorectly.

So, when I enter

vm-relocate.sh "Windows XP" SNIT-VMS01

it SHOULD move the machine "Windows XP" to a new location on the storage SNIT-VMS01, if I understand it right.

But instead it wants to move the Machine "Windows" to a new location on "X"...

0 Kudos
espi3030
Expert
Expert

I'm sorry, I meant have you tried VMware converter to relocate the machines to new storage. That is an option if you can't get the script working.

You are correct with your in assuming the command you mentioned SHOULD move the VM. All my VM's are named without spaces or contain a - dash or _ underscore, so I really don't know how this script "escapes" the spaces. In the script when you specify the computer name instead of "Windows XP" (encased in double quotes) try using 'Windows XP' (encased in single quotes). This has worked in other scripts for me when I have to pass complex passwords that contain "illegal" characters. It maybe a longshot worth trying!

Another thing you can do is email or PM the author of the script, I did to ask him the correct "TARGET" syntax. It took him a couple of days but he did reply.

0 Kudos
fasteddy
Contributor
Contributor

The single quotes do not work, too.

Trying to use the converter blasted off my Windows-PC resulting in a blue screen an a lot of work repairing it...

I think I will try the PM-method... Smiley Wink

0 Kudos
aerogerm
Contributor
Contributor

Hi,

excuse that i drop into this.....i found your script to be very usefull for our purposes and i've authorized myself to edit the script and doing some indentions for better readability......just my half cent...and just to whom it may concern.

Find it attached

Best regards.

0 Kudos
mcscotty
Enthusiast
Enthusiast

I know this is a minor nit, but neither the -v nor the -V options work, due to missing characters in function processArguments.

Also, do the vmware tools like vmkfstools return any codes upon failure? I didn't see any testing of the results of these calls; if vmkfstools -i fails (maybe the destination ran out of space) it would be nice if this script would detect and report the problem and maybe even NOT unregister the machine, rather than just silently ignore the problem.

Thanks for the great tool. I have my virtualcenter running as a VM on the cluster it manages, and migrating the VC to new storage was a lot easier with this tool than it would have been without it.

0 Kudos
wila
Immortal
Immortal

HI,

Thanks, haven't checked your modifications, but I did notice that I wasn't getting any email notifications on this topic anymore... which is why I haven't replied here anymore in a long time Smiley Happy



--

Wil

edit: attached the script as a file as the "new" forum messed up the script pretty severely. Btw, I'm still on the 2007 0.3 version as it worked for me.

| Author of Vimalin. The virtual machine Backup app for VMware Fusion, VMware Workstation and Player |
| More info at vimalin.com | Twitter @wilva
0 Kudos
AntakarDonvar
Contributor
Contributor

Hello Wila,

Can you tell me will images stay thin provisioned after copying them from host-to-host using your script?

0 Kudos