09 November 2011

Evacuate Templates from a Host -- on the Quick!

We recently had the need to move templates off a VMHost in a cluster. As you may know, the Move-Template cmdlet in PowerCLI does not allow for moving a template from one host to another. The cmdlet only allows for the -Destination to be a Datacenter or a VM Folder (a.k.a. "blue" inventory folders in the vSphere client).

There are posts out there that discuss ways to move templates to different datastores, how to move them to different inventory folders in vCenter, how to move templates to a particular host, etc. (links to a few such items are provided at the end of this post), but none fit the bill for our need.

So, with speed in mind, I wrote the following script that is careful to stay fast and low maintenance -- move all templates off of the given host, placing them on the other hosts in the given cluster.

The script:
## Script function: migrate templates from one VMhost to the rest of the hosts in the cluster (at random, for good dispersion)
## Author: vNugglets.com -- Aug 2011

## full name of VMHost from which to move templates
$strSourceVMHost = "someVMHost.domain.com"
## name of resource pool in the cluster into which to migrate the template (default ResPool name is "Resources")
$strDestResPoolName = "Resources"
#### end config section

## .NET View object of VMHost on which templates reside
$viewSourceVMHost = Get-View -ViewType HostSystem -Property Parent -Filter @{"Name" = [RegEx]::escape($strSourceVMHost)}
## .NET View object of cluster in which the VMHost (and, so, templates) reside
$viewTemplsCluster = Get-View -Id $viewSourceVMHost.Parent -Property Name

## get the view object of the destination resource pool
$viewDestResPool = Get-View -ViewType ResourcePool -Property Name -SearchRoot $viewTemplsCluster.MoRef -Filter @{"Name" = [RegEx]::escape($strDestResPoolName)}

## array of .NET View objects of templates to move
$arrTemplViewsToMove = Get-View -ViewType VirtualMachine -Property Name -SearchRoot $viewSourceVMHost.MoRef -Filter @{"Config.Template" = "true"}
## array of .NET View objects of VMHosts to which to move templates
$arrDestHostViews = Get-View -ViewType HostSystem -Property Name -SearchRoot $viewTemplsCluster.MoRef | ?{$_.Name -ne $strSourceVMHost}

## move the templates to other hosts
$arrTemplViewsToMove | %{
    ## MigrateVM_Task() not supported on templates (does not work), so go this route:
    ## mark template as a VM, putting the template on a different host in the process (takes advantage of the Host param to change the Host on which the template resides in the process of marking it as a VM)
    #   http://pubs.vmware.com/vsphere-50/topic/com.vmware.wssdk.apiref.doc_50/vim.VirtualMachine.html?path=5_0_2_5_12_4#markAsVirtualMachine
    $_.MarkAsVirtualMachine($viewDestResPool.MoRef, ($arrDestHostViews | Get-Random).MoRef)

    ## mark VM as template again
    #   http://pubs.vmware.com/vsphere-50/topic/com.vmware.wssdk.apiref.doc_50/vim.VirtualMachine.html?path=5_0_2_5_12_3#markAsTemplate
    $_.MarkAsTemplate()
} ## end foreach-object

This takes advantage of the second parameter of the MarkAsVirtualMachine() method that is the VMHost on which to place the VM.  When it is time for the target host to be done with its maintenance, moving the templates back is almost easier. Use:
## move them back to their original host
$arrTemplViewsToMove | %{
    ## MigrateVM_Task() not supported on templates (does not work), so go this route:
    ## mark template as a VM, putting the template on a different host in the process (takes advantage of the Host param to change the Host on which the template resides in the process of marking it as a VM)
    $_.MarkAsVirtualMachine($viewDestResPool.MoRef, $viewSourceVMHost.MoRef)

    ## mark VM as template again
    $_.MarkAsTemplate()
} ## end foreach-object

and the templates that were evacuated from the host are migrated back to that host. As you can see, that is going to be FaF.

Some of the other posts/ways previously mentioned, for reference:

No comments:

Post a Comment