Automating storage pathing changes in ESX/ESXi

29 05 2010

Having three different arrays presenting storage to each of our hosts presents a few complications in the environment.  Probably the low-hanging fruit of these complications, storage pathing is something that we quickly realized would need to be automated.  Having to, one by one, change the pathing for a particular LUN to Round-Robin, or even more tedious, verifying that the pathing is set to Fixed on the correct path, had become a nightmare of administration in our environment.  Using PowerCLI helped me to make this problem a non-issue; here’s how I did it:

Storage coming from our Hitachi AMS2500 and USP could be identified by a prefix, naa.6006, which would result in a device ID like this one:

naa.60060e80100503c0052facec00000060

Luckily, storage from the AMS1000 has a different prefix, t10.HITACHI, which allowed us to differentiate when working towards automation:

t10.HITACHI_770135160150

It is likely that other storage devices will have different prefixes present, depending on any number of factors, but here is the fairly simple PowerShell code excerpt that allows you to switch the pathing to Round-Robin for the appropriate LUNs on a given host, once you have figured out the appropriate prefix:

param($hostFQDN, $devicePrefix)

$myVMHost = Get-VMHost -name $hostFQDN$LUNs = Get-ScsiLun -VMHost $myVMHost -LunType disk

foreach ($lun in $LUNs) {

  if ($lun.CanonicalName.Contains($devicePrefix)) {       $lun | set-scsilun -multipathpolicy RoundRobin    Write-Host ("Updated lun " + $lun.CanonicalName + " to round-robin pathing")  }} 

Finding and setting the correct Fixed path for a non active/active array is a little more involved and will rely on good communication with your SAN administrator. To do this, I like to keep a hash table that defines key-value pairs based on a LUN-path relationship for each host in the environment. Obviously this is simpler if all of your hosts are the same, but since they are not for us, the first part of the code ends up looking something like this:

if ($hostFQDN.equals("vmhost01") -or $hostFQDN.equals("vmhost03")) {

  $LUNPaths = @{

    "t10.HITACHI_770135160150"="50060E8010034CC0";    "t10.HITACHI_770135160089"="50060E8010034CC0";    "t10.HITACHI_770135160091"="50060E8010034CC0";    "t10.HITACHI_770135160049"="50060E8010034CC4";  }}elseif ($hostFQDN.equals("vmhost02") -or $hostFQDN.equals("vmhost04")) {

  $LUNPaths = @{

    "t10.HITACHI_770135160150"="50060E8010034CC4";    "t10.HITACHI_770135160089"="50060E8010034CC4";    "t10.HITACHI_770135160091"="50060E8010034CC4";    "t10.HITACHI_770135160049"="50060E8010034CC0";  }}

Once you have stored the proper relationship between LUN and path, the next step is to actually set the pathing based on that hash. This code will gather the possible paths for a particular LUN (actually all of the LUNs on a host, one by one), figure out which one matches with the previously defined key-value pair, and set it:

foreach ($lun in $LUNs) {    if ($LUNPaths.ContainsKey($lun.CanonicalName)) {    $paths = $lun | Get-ScsiLunPath    $lunpath0 = $paths[0].lunpath.toLower()    $lunpath0    $lunpath1 = $paths[1].lunpath.toLower()    $lunpath1    $newpath = $NULL    $LUNPaths.Get_Item($lun.CanonicalName)

    if ($lunpath0.Contains($LUNPaths.Get_Item($lun.CanonicalName).toLower())) {      $newpath = $paths[0]    } elseif ($lunpath1.Contains($LUNPaths.Get_Item($lun.CanonicalName).toLower())) {      $newpath = $paths[1]    } else {      Write-Host "Error: Neither path contains the correct target, making no change."    }

    $lun | set-scsilun -multipathpolicy fixed -preferredpath $newpath    Write-Host ("Updated lun " + $lun.CanonicalName + "to path " + $LUNPaths.Get_Item($lun.CanonicalName))  }}

Add in the missing pieces and here is the final code to set all of the Fixed pathing for a particular host:

param($hostFQDN)

$myVMHost = Get-VMHost -name $hostFQDN$LUNs = Get-ScsiLun -VMHost $myVMHost -LunType disk

if ($hostFQDN.equals("vmhost01") -or $hostFQDN.equals("vmhost03")) {

  $LUNPaths = @{

    "t10.HITACHI_770135160150"="50060E8010034CC0";    "t10.HITACHI_770135160089"="50060E8010034CC0";    "t10.HITACHI_770135160091"="50060E8010034CC0";    "t10.HITACHI_770135160049"="50060E8010034CC4";  }}elseif ($hostFQDN.equals("vmhost02") -or $hostFQDN.equals("vmhost04")) {

  $LUNPaths = @{

    "t10.HITACHI_770135160150"="50060E8010034CC4";    "t10.HITACHI_770135160089"="50060E8010034CC4";    "t10.HITACHI_770135160091"="50060E8010034CC4";    "t10.HITACHI_770135160049"="50060E8010034CC0";  }}

foreach ($lun in $LUNs) {    if ($LUNPaths.ContainsKey($lun.CanonicalName)) {    $paths = $lun | Get-ScsiLunPath    $lunpath0 = $paths[0].lunpath.toLower()    $lunpath0    $lunpath1 = $paths[1].lunpath.toLower()    $lunpath1    $newpath = $NULL    $LUNPaths.Get_Item($lun.CanonicalName)

    if ($lunpath0.Contains($LUNPaths.Get_Item($lun.CanonicalName).toLower())) {      $newpath = $paths[0]    } elseif ($lunpath1.Contains($LUNPaths.Get_Item($lun.CanonicalName).toLower())) {      $newpath = $paths[1]    } else {      Write-Host "Error: Neither path contains the correct target, making no change."    }

    $lun | set-scsilun -multipathpolicy fixed -preferredpath $newpath    Write-Host ("Updated lun " + $lun.CanonicalName + "to path " + $LUNPaths.Get_Item($lun.CanonicalName))  }}

Obviously there is room to combine these two snippets to create a larger script that takes in a hostname, a device ID, and then sets pathing accordingly – this is how we have come to ensure that pathing is always standardized across the hosts in our environment.

Advertisements

Actions

Information

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s




%d bloggers like this: