Home > PowerCLI, PowerShell, RDM, SDK, vSphere > RDM & vMotion: inaccessible direct-access LUN

RDM & vMotion: inaccessible direct-access LUN

December 16th, 2009 LucD Leave a comment Go to comments

When you try to migrate a guest, that is using one or more RDM disks, you might see this message.

compatibility

The reason this is most probably because the LUN IDs are different on the source and the destination ESX server.

One solution is:

  • stop the guest
  • write down the Physical LUN ID
  • remove the RDM disk(s)
  • vMotion the guest
  • add the RDM disk(s) to the guest based on the Physical LUN ID
  • start the guest

But why do this the hard (manual) way when we have PowerCLI ?

Automating the above scenario doesn’t look too difficult, but there are some pitfalls on the way.

Gathering the information

In this step I collect extensive information about the guest and the RDM disk(s) it has connected.

As a safety-measure, the collected information is dumped to a CSV file. This should allow, in case of script-failure, to restore the RDM mappings quite easily.

The collected information should also include to which controller the RDM disk is connected and the RDM’s unit number. This is important because otherwise the guest’s OS might mix up the drive lettering.

Removing the RDM

For this step I use a filter, called Remove-HD. This makes it easy to combine this in a pipe with the Get-Harddisk cmdlet.

I could have used PowerCLI’s Remove-Harddisk but this cmdlet leaves the mapping files on the datastore and thus makes your guest consume unused disk space.

The filter has two steps, the first one removes the RDM from the guest’s configuration (ReconfigVM_Task) and the second step removes (DeleteDatastoreFile_Task) the mapping file(s) from the datastore.

Connecting the RDM

This function (New-RawHardDisk) already appeared in the PowerCLI Community thread Adding an existing hard disk. I just added some logic to be able to add physical and virtual mode RDMs.

Main function

This is driving part of the script. It controls the logic and the order in which the different functions and filters are called.

The script

# ESX server against which you want to execute the script
$tgtESX = "My-target-ESX-host"

# Attach a RDM disk to a VM on a specified controller
function New-RawHardDisk{
	param($vm, $DeviceName, $DiskType, $controller, $unitnumber, $capacity)

	$vmMo = $vm | Get-View
	$spec = New-Object VMware.Vim.VirtualMachineConfigSpec
	$chg = New-Object VMware.Vim.VirtualDeviceConfigSpec
	$chg.operation = "add"
	$chg.fileoperation = "create"
	$dev = New-Object VMware.Vim.VirtualDisk
	$dev.CapacityInKB = $capacity
	$dev.Key = - 100
	$back = New-Object VMware.Vim.VirtualDiskRawDiskMappingVer1BackingInfo
	$back.deviceName = $devicename
	if($DiskType -eq "RawPhysical"){
		$back.compatibilityMode = "physicalMode"
	}
	else{
		$back.compatibilityMode = "virtualMode"
	}
	$back.FileName = ""
	$dev.Backing = $back
	$dev.ControllerKey = $controller
	$dev.UnitNumber = $unitnumber
	$chg.device = $dev
	$spec.deviceChange += $chg
	$taskMoRef = $vmMo.ReconfigVM_Task($spec)
	$task = Get-View $taskMoRef
	while("running","queued" -contains $task.Info.State){
		$task.UpdateViewData("Info.State")
	}
	$task.UpdateViewData("Info.Result")
}

# Remove a RDM disk from a VM and optionally delete the backing file
filter remove-HD {
	param($Delete)
	$HDname = $_.Name
	$vm = Get-View -Id $_.ParentId
	# Get device key for the hard disk
	foreach($dev in $vm.Config.Hardware.Device){
		if ($dev.DeviceInfo.Label -eq $HDname){
			continue
		}
	}
	$spec = New-Object VMware.Vim.VirtualMachineConfigSpec
	$spec.deviceChange = @()
	$spec.deviceChange += New-Object VMware.Vim.VirtualDeviceConfigSpec
	$spec.deviceChange[0].device = New-Object VMware.Vim.VirtualDevice
	$spec.deviceChange[0].device.key = $dev.Key
	$spec.deviceChange[0].device.unitnumber = $dev.UnitNumber
	$spec.deviceChange[0].operation = "remove"
	$taskMoRef = $vm.ReconfigVM_Task($spec)
	$task = Get-View $taskMoRef
	while("running","queued" -contains $task.Info.State){
		$task.UpdateViewData("Info.State")
	}
	$task.UpdateViewData("Info.Result")

# Remove hard disk files (backing) from datastore
	if ($Delete){
		$fileMgr = Get-View (Get-View ServiceInstance).Content.fileManager
		$datacenter = (Get-View (Get-VM $vm.name | Get-Datacenter).ID).get_MoRef()
		foreach($disk in $vm.LayoutEx.Disk){
			if($disk.Key -eq $dev.Key){
				foreach($chain in $disk.Chain){
					foreach($fileKey in $chain.FileKey){
						$name = $vm.LayoutEx.File[$fileKey].Name
						$taskMoRef = $fileMgr.DeleteDatastoreFile_Task($name, $datacenter)
						$task = Get-View $taskMoRef
						while("running","queued" -contains $task.Info.State){
							$task.UpdateViewData("Info.State")
						}
						$task.UpdateViewData("Info.Result")
					}
				}
				continue
			}
		}
	}
}

# Main
$report = @()

# Report on all the VMs that have a RDM
$vms = Get-View -ViewType VirtualMachine
foreach($vm in $vms){
	foreach($dev in $vm.Config.Hardware.Device){
		if(($dev.gettype()).Name -eq "VirtualDisk"){
			if(($dev.Backing.CompatibilityMode -eq "physicalMode") -or
			($dev.Backing.CompatibilityMode -eq "virtualMode")){
				$esx = Get-View $vm.Runtime.Host
				$lun = $esx.Config.StorageDevice.ScsiLun | where {$_.Uuid -eq $dev.Backing.LunUuid}
				$report += New-Object PSObject -Property @{
					VMName = $vm.Name
					VMHost = ($esx).Name
					HDLabel = $dev.DeviceInfo.Label
					HDDeviceName = $dev.Backing.DeviceName
					HDFileName = $dev.Backing.FileName
					HDMode = $dev.Backing.CompatibilityMode
					HDSize = $dev.CapacityInKB
					LunDisplayName = $lun.DisplayName
					HDCtrlType = ($vm.Config.Hardware.Device | where {$_.Key -eq $dev.ControllerKey}).GetType().Name
					HDController = $dev.ControllerKey
					HDUnit = $dev.UnitNumber
					HDDiskMode = $dev.Backing.DiskMode
					LunCanonical = $lun.CanonicalName
					LunDeviceName = $lun.DeviceName
				}
			}
		}
	}
}
$report | Export-Csv "C:\VM-with-RDM.csv" -NoTypeInformation -UseCulture

$report | Group-Object -Property VMName | % {
	$vm = Get-VM $_.Name
# Stop the VM
	Write-Host "Stop VM" $_.Name
	$VM | Get-VMGuest | where {$_.State -eq "Running"} | Shutdown-VMGuest - Confirm:$false
# Remove the RDM disk(s)
	$_.Group | % {
		Write-Host "`tremove HD" $_.HDLabel
		$vm | Get-HardDisk -DiskType ("Raw" + $_.HDMode.TrimEnd("Mode")) | Remove-HD - Delete:$true
	}
# vMotion the VM
	Write-Host "Moving VM"
	$newvm = $vm | Move-VM -Destination (Get-VMHost -Name $tgtESX)
# Attach the RDM disk(s) back
	$_.Group | % {
		Write-Host "`tAdd HD" $_.HDLabel
		New-RawHardDisk -Vm $newvm -DiskType ("Raw" + $_.HDMode.TrimEnd("Mode")) -DeviceName $_.LunDeviceName -Controller $_.HDController -UnitNumber $_.HDUnit -Capacity $_.HDSize
	}
# Power on the VM
	Write-Host "Start VM" $_.Name
	$newvm | Start-VM - Confirm:$false
}

Annotation

Line 2: destination ESX server

Line 18-23: support for physical and virtual mode RDM

Line 118: dump the RDM info to a CSV file

Line 120-141: this is the part where the RDM disk(s) are removed, the VM vMotioned and the RDM disk(s) re-attached.

Line 136: because a guest can have more than one RDM I use the Group-Object cmdlet

Categories: PowerCLI, PowerShell, RDM, SDK, vSphere Tags: , , ,
  1. John House
    February 9th, 2010 at 16:38 | #1

    updated my email address.

  2. John House
    February 9th, 2010 at 15:17 | #2

    Hi Luc – thanks for doing that, it does make it a lot clearer – although i still cant seem to hack it for what I need.

    Essentially, we are cloning VMs using the storage array and i’ve “written” (pinched) scripts to do that for normal vms (without RDM) – but we have some clusters that use RDMs and they do not clone well. So I need to 1) remove the RDMs from the cloned VMs (because these are invalid), 2) Readd the cloned RDM LUNs (which have different LUN ids to the originals).

    Long shot – but do you know of any existing scripts (and i initially thought I could use this) – so I can pass it some parameters “VM Name”, “SCSI Controller ID”,”LUN ID” etc.. and it will add the RDM in physical compatibility mode to the VM?

    Thanks again – ur a king in the community!

  3. February 8th, 2010 at 21:21 | #3

    John, there are no stupid questions, just stupid answers ;-)

    The script run against all the VMs on a specific ESX (which you specify in line 2).

    I have added a few comment lines to the script and indented the lines where appropriate.
    Let me know if that helps ?
    Luc.

  4. John House
    February 8th, 2010 at 19:33 | #4

    Hi – stupid question, but how do you actually run this. I cant see anywhere where the VM is specified. Pasting the above code into PS doesnt do anything.

    THanks

  5. justasimpledude
    January 21st, 2010 at 03:18 | #5

    So much typing !!
    Why not copy and paste your script ;-) must have taken ages to type , instead why not do the following …much less effort!

    * stop the guest
    * write down the Physical LUN ID
    * remove the RDM disk(s)
    * vMotion the guest
    * add the RDM disk(s) to the guest based on the Physical LUN ID
    * start the guest

    • January 21st, 2010 at 07:20 | #6

      Thanks for the tip.
      While I agree this would surely be faster than me typing the script, the script has it’s advantage when you have to migrate substantial numbers of guests with RDMs.
      And you avoid making “human errors” ;-)
      Automation proves it’s worth when the task becomes repetitive and when you have to tackle bigger numbers.

  6. shatztal
    December 21st, 2009 at 20:27 | #7

    Come on man ,couldn’t you have post this 3 Weeks ago ?
    i wanted to write a script’ but because i didn’t have the time ‘; it did not happend.

    nice one .
    BTW : The Problem happens also if the LUN ID is the same in Both Host.

    • December 21st, 2009 at 21:04 | #8

      Sorry that my timing was not optimal ;-)

      Thanks for the info on identical LUN ids, didn’t know that one.

  7. nate
    December 16th, 2009 at 23:19 | #9

    Even if the LUN ID is the same under certain circumstances the error can still pop up – http://www.techopsguys.com/2009/08/18/its-not-a-bug-its-a-feature/

    Worked fine in ESX 3.0, 3.02, 3.5 (when the LUN ID is the same). I call it a bug, they call it a feature.

    • December 17th, 2009 at 08:46 | #10

      Thanks for the feedback.
      At least you can now automate the tedious process of re-mapping all the RDM volumes ;-)

  1. December 16th, 2009 at 22:27 | #1