«

»

Oct 21 2010

How to script Datastore Multipathing change using PowerShell

There is a recurring situation that I face whenever I am deploying a new VMware View environment (also applicable to any vSphere deployment) . Due to natural limitations on number of IOPS per datastore (LUN), VMware recommends that you size your datastores for a maximum of 64 virtual desktops. This number could be higher, however you will need to pay attention to the number of IOPS required to support the workload, and verify that each LUN and backend array/spindles are able to provide the required performance. Normally this performance is measured by the latency number between I/O requests. There are references that mention that if I/O latency is higher than 10 milliseconds on average and higher than 20 milliseconds at peak your workload is under I/O contention.

Because of the limitation on number of VMs per datastore you will end up with a large number of datastores. As an example, 1000 VMs would require approximately 16 datastores. Those 16 datastores would be then presented to all hosts in a 8 node cluster. (8 hosts is the maximum host limit when using View Composer).

Now take your storage array. If the storage array supports active/active multipathing you will probably want to change the multipathing policy option to Round Robin for better throughput and utilisation of the fabric. That’s when my configuration issues begin.

To change multipathing manually trough vCenter it’s is necessary modify every datastore for each host, and after a portion of mouse clicks change the multipathing from MRU (Most Recently Used) to Round Robin. Do the math: 16 datastores x 8 hosts = 128 datastores to change multipathing. Yeah, I know it’s a pain.

 

image

 

Now, there are multiple PowerShell and Perl scripts widely available on the net to do a bunch of things but I haven’t found a ready-made script to automatically change multipathing for all datastores in all hosts. So, I created one to help me during my deployments.

I have to warn you that I am no PowerShell scripting expert and I know the script could be a lot more intelligent, but it works for me. So, if you want to improve the script please send it back to me for publishing with acknowledgements, off course.

 

Connect-VIServer vCenterServer

foreach ($hostx in get-vmhost) {

$hostview = Get-View $hostx
$storageSystem = Get-View $hostview.ConfigManager.StorageSystem
$policy = new-object VMware.Vim.HostMultipathInfoLogicalUnitPolicy

#$policy.policy = "VMW_PSP_MRU"
$policy.policy = "VMW_PSP_RR"

$storageSystem.StorageDeviceInfo.MultipathInfo.lun | foreach { $storageSystem.SetMultipathLunPolicy($_.ID, $policy) }
}

Note: I offer no guarantee and the script and you may use under your own responsibility.

9 comments

Skip to comment form

  1. Sven Kempf

    Hi Andre,

    it is not necessary to build an own object to change the policy. You could simply use the commandlet “set-ScsiLun”.
    In your example the “script” could look like this:

    get-vmhost|get-scsilun|set-scsilun -MultiPathPolicy RoundRobin

    Kind regards
    Sven

  2. orzdude

    Here’s what I’m using on the vMA to set the RR policy and also to set the a custom RR IOPS value (adjust the grep as neccessary by your LUN naa identifiers or use a list like I’m doing with the hosts). It also outputs the current and post-adjustment configuration:

    for esxhost in “esx01” “esx02” “esx03”; do echo -e “\n\n——–Current configuration of $esxhost——–“; vicfg-scsidevs -m | grep -Po ‘^naa.600508b[a-f0-9]+’ | while read lunid; do echo “—–“;Current “Old config of $lunid:”;esxcli –server $esxhost nmp psp getconfig –device $lunid; echo “Setting new config for $lunid”;esxcli –server $esxhost nmp device setpolicy –device $lunid –psp VMW_PSP_RR;sleep 1; esxcli –server $esxhost nmp roundrobin setconfig –type “iops” –iops 1 –device $lunid; echo “New config of $lunid:”; esxcli –server $esxhost nmp psp getconfig –device $lunid; done; done

    Yes, sure is a single, fine one-liner.

  3. orzdude

    @orzdude
    I actually just noticed that you might want to insert a vifptarget -s $esxhost sequence before the vicfg-scsidevs command unless all your LUN naa IDs of the host you are currently vifastpath’d to are identical to all hosts.

  4. Andre Leibovici

    @Sven Kempf
    There is always a smarter way to do everything and that is at least a 1000 times simpler.
    Thanks for that. How would go about selecting only the SAN disk LUNS or specific datastores?

  5. Jeff O'Connor

    I find the easiest, is to set the default PSP. Use the command below on all ESX hosts, and reboot.

    esxcli nmp satp setdefaultpsp –satp VMW_SATP_ALUA –psp VM_PSP_RR

    Following this, all luns would be set to Round Robin automagically – both now and after future storage is presented. This example above is not correct for all storage platforms, but works for ALUA based arrays like the HP EVA. You just need to work out the correct syntax based on your type of storage.

    Cheers,
    Jeff

  6. Sven Kempf

    @Andre Leibovici
    You can narrow down the selected LUNs by giving some optins to the commandlet “get-scsilun”. For example:
    get-scsilun -Luntype disk
    or
    get-scsilun -Datastore

    The original Example would look like this:
    Get-ScsiLun -Hba (get-VMHost | Get-VMHostHba -type FibreChannel) | set-scsilun -MultipathP

    Thera are a lot of more options for get-scsilun:
    get-help get-scsilun -examples

    But I agree to Jeff: The best way is to set the policies to a new default to avoid wrong Failover policies for new added LUNs.

    Kind regards
    Sven
    olicy RoundRobin

  7. Sven Kempf

    Ups – something missed: Of course you will have to give the name of the datastore after “get-scsilun -datastore”:
    get-scsilun -datastore NameOfTheDatastore

    😉

    Kind Regards
    Sven

  8. Sven Kempf

    Sometimes it would be better to read a post before klicking on Submit 🙁 (Sorry for that!)

    Get-ScsiLun -Hba (get-VMHost | Get-VMHostHba -type FibreChannel) | set-scsilun -MultipathPolicy RoundRobin

  9. Paul

    This is a script I use, it will prompt for the vCenter Server name, a Cluster name and an ESX password, it requires vSphere CLI and Powershell.

    I use get-cluster as generally the storage and pathing is standard across a cluster but this can easily be changed. The script sets the default SATP for new LUN’s, manually sets each device to ensure any existing luns have the correct policy and then enables the use non-optimised paths as some ALUA storage systems like EMC CX4 need this to actually enable all paths.

    #Variables
    #ESX host username
    $Username = “root”
    #vSphere CLI esxcli.exe path
    $esxcli = “C:\Program Files\VMware\VMware vSphere CLI\bin\esxcli.exe”
    #Prompt for vCenter Server
    $viServer = Read-Host “Enter vCenter server Name: ”
    Connect-VIServer $viServer
    #Prompt for vCenter Server Cluster
    $viCluster = Read-Host “Enter vCenter Cluster: ”

    #list of ESX and ESXi host to perform operation against
    $vihosts = Get-Cluster $viCluster | Get-vmhost | sort Name | % {$_.Name}

    #prompt user for password
    $passwordInput = Read-Host -AsSecureString:$true “Please enter your common password for the ESX hosts”

    #convert secure password to normal string
    $Ptr = [System.Runtime.InteropServices.Marshal]::SecureStringToCoTaskMemUnicode($passwordInput)
    $Password = [System.Runtime.InteropServices.Marshal]::PtrToStringUni($Ptr)
    [System.Runtime.InteropServices.Marshal]::ZeroFreeCoTaskMemUnicode($Ptr)

    #loop through array of hosts and set default SATP policy to RoundRobin
    for($i = 0; $i -le $vihosts.length -1; $i++) {
    write-Host Executing set default PSP for ALUA_CX to RR on $vihosts[$i]
    & $esxcli –server $vihosts[$i] –username $Username –password $Password nmp satp setdefaultpsp –satp VMW_SATP_ALUA_CX –psp VMW_PSP_RR
    }

    #loop through array of hosts and set PSP policy to RoundRobin
    foreach ($viHost in $vihosts)
    {
    write-Host Executing set policy RR per device on $viHost
    $lunList = get-vmhost $viHost | get-scsilun -CanonicalName “naa.6006*” | % {$_.CanonicalName}
    foreach ($lun in $lunList)
    {
    & $esxcli –server $viHost –username $Username –password $Password nmp device setpolicy –psp VMW_PSP_RR –device $lun
    }
    }

    #loop through array of hosts and enable the use of non-optimised paths
    foreach ($viHost in $vihosts){
    write-Host Executing use unoptimized paths on $viHost
    foreach ($lun in $lunList){
    & $esxcli –server $viHost –username $Username –password $Password nmp roundrobin setconfig –useANO 1 –device $lun
    }
    }

Leave a Reply