Mapping RDM Devices

This post was driven by a requirement to map RDM volumes on target side in preparation for a disaster recovery test.  I thought I would share some of my automation and process with regards to mapping RDM devices that will be used to present RecoverPoint replicated devices to VMs as part of a DR test.

Step 1:  Install VMware vCLI and PowerCLI
Step 2:  Open PowerCLI command prompt
Step 3:  Execute addvcli.ps1 (. .\addvcli.ps1)
function Add-vCLIfunction {
  <#
  .SYNOPSIS
    Adds the VMware vSphere Command-Line Interface perl scripts as PowerCLI functions.

  .DESCRIPTION
    Adds all the VMware vSphere Command-Line Interface perl scripts as PowerCLI functions.
    VMware vSphere Command-Line Interface has to be installed on the system where you run this function.
    You can download the VMware vSphere Command-Line Interface from:
    http://communities.vmware.com/community/vmtn/server/vsphere/automationtools/vsphere_cli?view=overview

  .EXAMPLE
    Add-vCLIfunction
    Adds all the VMware vSphere Command-Line Interface perl scripts as PowerCLI functions to your PowerCLI session.

  .COMPONENT
    VMware vSphere PowerCLI

  .NOTES
    Author:  Robert van den Nieuwendijk
    Date:    21-07-2011
    Version: 1.0
  #>

  process {
    # Test if VMware vSphere Command-Line Interface is installed
    If (-not (Test-Path -Path "$env:ProgramFiles\VMware\VMware vSphere CLI\Bin\")) {
      Write-Error "VMware vSphere CLI should be installed before running this function."
    }
    else {
      # Add all the VMware vSphere CLI perl scripts as PowerCLI functions
      Get-ChildItem -Path "$env:ProgramFiles\VMware\VMware vSphere CLI\Bin\*.pl" | ForEach-Object {
        $Function = "function global:$($_.Name.Split('.')[0]) { perl '$env:ProgramFiles\VMware\VMware vSphere CLI\bin\$($_.Name)'"
        $Function += ' $args }'
        Invoke-Expression $Function
      }
    }
  }
}
Step 4:  Execute getluns.ps1 (. .\getluns.ps1)
#Initialize variables
#Replace [INSERT VCENTER SERVER NAME] with your vCenter server name, leave preceding and and trailing "
$VCServer = "[INSERT VCENTER SERVER NAME]"
$objLuns = @()
$objRDMs = @()

#Connect to vCenter Server
Connect-VIServer $VCServer

$clusters = Get-cluster

foreach ($cl in $clusters) {
    $clv = $cl | Get-View
    if ($clv.Host.count -gt 0) {
        #assume that all ESX hosts see the same luns
        $vmhost = get-view $clv.host[0]
        #Get ScsiLuns except local storage
        $ScsiLuns = $vmhost.Config.StorageDevice.ScsiLun  | ? {$_.canonicalname -notmatch "vmhba0"}
        #Get Datastore volumes
        $Datastores = $vmhost.Config.FileSystemVolume.MountInfo
        foreach ($Lun in $ScsiLuns) {
            #Define Custom object
            $objVolume = "" | Select ClusterName,LunName,LunUuid,Lunsize,VolumeName

            #Add porperties to the newly created object
            $objVolume.ClusterName = $clv.Name
            $objVolume.LunName = $Lun.CanonicalName
            $objVolume.LunUuid = $Lun.Uuid
            $objVolume.LunSize = $Lun.Capacity.Block * $Lun.Capacity.BlockSize / 1GB

            foreach ($vol in $Datastores | % {$_.volume}) {
                if ($vol.extent | % {$_.diskname -eq $Lun.CanonicalName}) {
                    $objVolume.VolumeName = $vol.Name
                }
            }
            $objLuns += $objVolume

        }
    }
    #RDM information
    $vms = $cl | Get-VM  | Get-View
    if ($null -ne $vms) {
        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")){
                        $rdm = "" | select VMName, LunUuid, DiskLabel
                        $rdm.VMName = $vm.Name
                        $rdm.LunUuid = $dev.Backing.LunUuid
                        $rdm.DiskLabel = $dev.DeviceInfo.Label
                        $objRDMs += $rdm
                    }
                }
            }
        }
    }
}

foreach ($rdm in $objRDMs) {
    foreach ($disk in $objLuns) {
         if ($disk.LunUuid -eq $rdm.LunUuid) {$disk.VolumeName = $rdm.VMName + "/" + $rdm.DiskLabel}
     }
}

$objLuns | export-csv "scsiluns.csv" -notypeinformation -useculture

Disconnect-VIServer -Confirm:$false
Step 5:  Execute mpath.ps1 (. .\mpath.ps1)
Add-vCLIfunction
$env:VI_USERNAME="root" 
$env:VI_PASSWORD="password"

 $result = foreach($esx in Get-VMHost){
  esxcfg-mpath -l --server $esx.Name | %{
        if($_.Length -gt 0){
            if($_.Contains(': ')){
                $temp = $_.Split(":")
				$desc = $temp[0].trim(0)
				$value = $temp[1..50] -join ":"
				Add-Member -InputObject $obj -Name $desc.trim() -Value $value.trim() -MemberType NoteProperty
            }
            else{
                $obj = New-Object PSObject -Property @{
                    VMHost = $esx.Name
                    Name = $_
                }
            }
        }
        else{
            $obj
        }
    }
    $obj
}

$result | export-csv "mpath.csv" -notypeinformation -useculture
Step 6:  Get SP collect from EMC CLARiiON / VNX array
At this point you should have all the data required to map the RDM volumes on the DR side.  I simply import the two CSVs generated by the scripts into excel (scsiluns.csv, mpath.csv) as well as the LUNs tab from the SP Collect (cap report).
Using Excel and some simple vlookups with the data gathered above you can create a table that looks like the following:
I could probably combine these three scripts into one but under a time crunch so just needed the data, maybe I will work on that at a later date or maybe someone can do it and share with me.

Leave a Reply

Your email address will not be published. Required fields are marked *