Develop for XenServer

Copy or live migrate a VM across pools

The following tutorial shows how to use the XenServer PS module to migrate a running VM or copy a halted VM from a pool or standalone server, hereafter referred to as the source server, to a different pool or standalone server, hereafter referred to as the destination server.

This example also displays how to work with multiple sessions and use implicitly the global variable $XenServer_Default_Session.

We’re starting by connecting to the source server. The session created with the source server will be more frequently used, so it makes sense to set it as the default session:

Connect-XenServer -Url $sourceServerUrl -UserName $sourceServerUsername -Password $sourceServerPwd -SetDefaultSession
<!--NeedCopy-->

Let’s select the VM we are going to copy or live migrate from the source pool:

$theVM = Get-XenVM -Name $nameOfSourceVmToCopy
<!--NeedCopy-->

Note that in the above call we did not need to specify the -Session parameter since we have set the source session as the default one.

Then we need to connect to the destination pool and obtain its coordinator. Note that we will need to specify the -Session parameter in all calls made to the destination pool since this session is not the default one.

$destSession = Connect-XenServer -Url $destServerUrl -UserName $destServerUsername -Password $destServerPwd -PassThru

$destCoordinator = Get-XenPool -Session $destSession.opaque_ref | `
    select -ExpandProperty master | `
    Get-XenHost -Session $destSession.opaque_ref
<!--NeedCopy-->

The coordinator of the destination pool has to be prepared to receive the VM that will be live migrated or copied. For this, we will also need to obtain the details of the network on the destination pool through which migration traffic will be received.

$destTransferNetwork = Get-XenNetwork -Name $destTransferNetworkName -Session $destSession.opaque_ref

$destMap = Invoke-XenHost -XenAction MigrateReceive -XenHost $destCoordinator -Network $destTransferNetwork -Session $destSession.opaque_ref -options @null -PassThru
<!--NeedCopy-->

The next step is to map the VM’s VIFs to networks on the destination pool. Let’s consider a case where the destination pool has as many networks as the VIFs on the VM we want to live migrate or copy, so we can create a one-to-one mapping of VIFs to networks as follows:

$targetNetworkRefs = Get-XenNetwork -SessionOpaqueRef $destSession.opaque_ref | ConvertTo-XenRef

$vmVifRefs = $theVM.VIFs | Get-XenVIF | ConvertTo-XenRef

$vifmap = @{}

for ($i = 0; $i -lt $vmVifRefs.Count; $i++) {
    $vifmap[$vmVifRefs[$i]] = $targetNetworkRefs[$i]
}
<!--NeedCopy-->

Similarly, we proceed to map the VM’s disks to storage repositories on the destination pool. Let’s consider a simple case where we want to place all VM disks on the same storage repository with name $destSrName.

$targetSrRef = Get-XenSR -name $destSrName -SessionOpaqueRef $destSession.opaque_ref | ConvertTo-XenRef

$vdiRefs = $theVM.VBDs | Get-XenVBD | `
    where { $_.type -eq [XenAPI.vbd_type]::Disk} | `
    select -ExpandProperty VDI

$vdimap = @{}

foreach ($vdiRef in $vdiRefs) {
    $vdimap[$vdiRef] = $targetSrRef
}
<!--NeedCopy-->

Now we are ready to live migrate or copy the VM to the destination pool. Both operations are performed using the same cmdlet. However, we need to specify different options in each case. The call is run on the source pool session. Due to the long duration of the operation, it is recommended to run it asynchronously.

To live migrate a running VM:

$theTask = Invoke-XenVM -VM $theVM -XenAction MigrateSend -Live $true `
    -Dest $destMap -VifMap $vifmap -VdiMap $vdimap `
    -Options @{} -Verbose -Async -PassThru
<!--NeedCopy-->

Or, to copy a halted VM:

$theTask = Invoke-XenVM -VM $theVM -XenAction MigrateSend -Live $false `
    -Dest $destMap -VifMap $vifmap -VdiMap $vdimap `
    -Options @{"copy"="true"} -Verbose -Async -PassThru
<!--NeedCopy-->

In either case, we can monitor the task progress:

Wait-XenTask -Task $theTask -ShowProgress
<!--NeedCopy-->

Once the task is finished, we can query it to obtain the new VM on the destination pool:

$theTask = Get-XenTask -uuid $theTask.uuid

if ($theTask.status -eq [XenAPI.task_status_type]::success) {
    $doc = [xml]$theTask.result
    $newVmRef = $doc.value
    Get-XenVM -Ref $newVmRef -SessionOpaqueRef $destSession.opaque_ref
}
else {
    Write-Host "Operation failed: " $theTask.error_info
}
<!--NeedCopy-->

Finally, we need to disconnect from the source and the destination pools:

Get-XenSession | Disconnect-XenServer
<!--NeedCopy-->
Copy or live migrate a VM across pools

In this article