VMware Cloud Community
quattad
Contributor
Contributor

SCSILun path state Active and Active (I/O) paths as 'active' only when VMware PSP and SATP used

Hi all,

I wrote a script that fetches storage information pertaining to a particular cluster, including path state as below.

 

 

# Define default timestamp format
$timestampFormat = 'yyyy-MM-dd HH:mm:ss'

# Initialize timestamp for output
filter timestamp {"$(Get-Date -Format 'yyyy-MM-dd HH:mm:ss'): $_"}  # format according to mysql TIMESTAMP format

foreach ($CurrentServerIP in $ServerIPs) {
  
  Write-Host "Connecting to vCenter server IP: $CurrentServerIP ... "

  try {
    Connect-ViServer -server $CurrentServerIP -User $User -password $UnsecurePassword -ErrorAction Stop
  } catch {
    Throw $error[0]
  }

  # Fetch clusters according to user input if present, if not defaults to fetching all clusters allocated to current vCenter IP
  if ($ClusterInput) {
    Write-Host "Reading cluster input: $ClusterInput"
    $Clusters = Get-Cluster -Name $ClusterInput
  } else {
    Write-Host "No input for cluster, fetching information for all clusters ... "
    $Clusters = Get-Cluster | Sort-Object Name
  }

  foreach ($Cluster in $Clusters) {
    $ClusterName = $Cluster.Name
    $DatacenterName = (Get-Datacenter -cluster $Cluster).Name
    $VMHosts = $Cluster | Get-VMHost | Sort-Object Name
    
    foreach ($VMHost in $VMHosts) {
      $VMHostName = $VMHost.Name
      $VMHostConnectionState = $VMHost.ConnectionState
      
      Write-Host "Getting for VMHost: $VMHostName with Connection State: $VMHostConnectionState..."

      # Ignore disconnected hosts since Get-View cmdlet will fail
      if ($VMHost.ConnectionState -ne "Disconnected" ) {
        $objViewESX = Get-View -id $VMHost.id
        $objViewESXstorageSys = Get-View -id $objViewESX.ConfigManager.StorageSystem
        $objEsxCli = (Get-ESXCli -VMHost $VMHost -v2)

        $objScsidisks = $objViewESXstorageSys.StorageDeviceInfo.ScsiLun | Where-Object {
          ($_.LunType -eq 'disk') -and ($_.LocalDisk -eq $false)
        }
        
        foreach ($objScsidisk in $objScsidisks) {
          $HbaSet = @{}
          $objAdapters = $objViewESXstorageSys.StorageDeviceInfo.HostBusAdapter | Where-Object {$_.Key -like "*FibreChannelHba*"}
        
          foreach ($objAdapter in $objAdapters) {
            $HbaSet[$objAdapter.Device] = $objAdapter
          }

          $objScsilun = $objViewESXstorageSys.StorageDeviceInfo.MultiPathInfo.Lun | Where-Object {
            ($_.Id -eq $objScsidisk.Uuid)
          }

          $objDatastore = $objViewESXstorageSys.FileSystemVolumeInfo.MountInfo | Where-Object {
            ($_.Volume.Extent.DiskName -eq $objScsidisk.CanonicalName)
          }

          if ($objDatastore) {
            $Datastore = Get-Datastore -name $objDatastore.Volume.Name            
          }

          $IoOperationLimit = ""
          $LimitType = ""

          if ($objScsilun.Policy.Policy -match 'RR') {
            $IoOperationLimit = $objEsxCli.storage.nmp.psp.roundrobin.deviceconfig.get.Invoke(@{'device'=$objScsidisk.CanonicalName}).IOOperationLimit
            $LimitType = $objEsxCli.storage.nmp.psp.roundrobin.deviceconfig.get.Invoke(@{'device'=$objScsidisk.CanonicalName}).LimitType
          }

          $objPaths = $objScsilun.Path

          foreach($objPath in $objPaths) {
            $objAdapter = $objAdapters | Where-Object {
              ($_.Key -eq $objPath.Adapter)
            }
            $AdapterName = $objAdapter.Device
            
            if ($AdapterName) {
              $HbaSet.Remove($AdapterName)

              $result = [PSCustomObject]@{
                'CountryCode' = $CountryCode
                'vCenter_IP' = $CurrentServerIP
                'Datacenter' = $DatacenterName
                'Cluster' = $ClusterName
                'VMHost' = $VMHost.Name
                'VMHost_ConnectionState' = $VMHost.ConnectionState
                'SCSILun_DeviceName' = $objScsidisk.CanonicalName
                'SCSILun_Type' = $objScsidisk.LunType
                'SCSILun_Vendor' = $objScsidisk.Vendor
                'SCSILun_IsLocal' = $objScsidisk.LocalDisk
                'SCSILun_IsSSD' = $objScsidisk.Ssd
                'SCSILun_CapacityGB' = [math]::round($objScsidisk.capacity.BlockSize * $objScsidisk.capacity.Block / 1GB,1)
                'SCSILun_Datastore_Name' = $objDatastore.Volume.Name
                'SCSILun_Datastore_Type' = $objDatastore.Volume.Type
                'SCSILun_Datastore_VMFS_Version' = $objDatastore.Volume.Version
                'SCSILun_Datastore_CapacityGB' = $Datastore.CapacityGB
                'SCSILun_Datastore_FreeSpaceGB' = $Datastore.FreeSpaceGB
                'SCSILun_Datastore_StorageIOControlEnabled'= $Datastore.StorageIOControlEnabled
                'SCSILun_Datastore_CongestionThreshold_ms'= $Datastore.CongestionThresholdMillisecond
                'SCSILun_Datastore_CongestionThreshold_Mode'= $Datastore.ExtensionData.IORMConfiguration.CongestionThresholdMode
                'SCSILun_Datastore_CongestionThreshold_PrcntofPeakThrput'= $Datastore.ExtensionData.IORMConfiguration.PercentOfPeakThroughput
                'SCSILun_PathSelectionPolicy' = $objScsilun.Policy.Policy
                'SCSILun_IoOperationLimit' = $IoOperationLimit
                'SCSILun_LimitType' = $LimitType
                'SCSILun_StorageArrayType' = $objScsilun.StorageArrayTypePolicy.Policy
                'SCSILunPath_Name' = $objPath.Name
                'SCSILunPath_Preferred' = $objPath.IsWorkingPath
                'SCSILunPath_State' = $objPath.State
                'SCSILunPath_PortWWN' = "{0:x}" -f $objPath.Transport.PortWorldWideName -replace '(..(?!$))','$1:'
                'SCSILunPath_NodeWWN' = "{0:x}" -f $objPath.Transport.NodeWorldWideName -replace '(..(?!$))','$1:'
                'HBA_Name' = $objAdapter.Device
                'HBA_Type' = "FibreChannel"
                'HBA_PCI' = $objAdapter.Pci
                'HBA_Driver' = $objAdapter.Driver
                'HBA_Model' = $objAdapter.Model
                'HBA_Status' = $objAdapter.Status
                'HBA_PortWWN' = "{0:x}" -f $objAdapter.PortWorldWideName -replace '(..(?!$))','$1:'
                'HBA_NodeWWN' = "{0:x}" -f $objAdapter.NodeWorldWideName -replace '(..(?!$))','$1:'
                'Timestamp' = Get-Date -Format $timestampFormat
              }
            
              # Write out at every line
              $result | Export-CSV -path $FilePath -NoTypeInformation -Append -ErrorAction Stop
            }
          }

          # HBAs that have missing paths for particular Lun, path fields as blank
          if ($HbaSet.Count -ne 0) {
            $HbaSet.Values | % {
              $AdapterStatus = "missing"
              
              if ($_.Status) {
                $AdapterStatus = $_.Status
              }

              $result = [PSCustomObject]@{
                'CountryCode' = $CountryCode
                'vCenter_IP' = $CurrentServerIP
                'Datacenter' = $DatacenterName
                'Cluster' = $ClusterName
                'VMHost' = $VMHost.Name
                'VMHost_ConnectionState' = $VMHost.ConnectionState
                'SCSILun_DeviceName' = $objScsidisk.CanonicalName
                'SCSILun_Type' = $objScsidisk.LunType
                'SCSILun_Vendor' = $objScsidisk.Vendor
                'SCSILun_IsLocal' = $objScsidisk.LocalDisk
                'SCSILun_IsSSD' = $objScsidisk.Ssd
                'SCSILun_CapacityGB' = [math]::round($objScsidisk.capacity.BlockSize * $objScsidisk.capacity.Block / 1GB,1)
                'SCSILun_Datastore_Name' = $objDatastore.Volume.Name
                'SCSILun_Datastore_Type' = $objDatastore.Volume.Type
                'SCSILun_Datastore_VMFS_Version' = $objDatastore.Volume.Version
                'SCSILun_Datastore_CapacityGB' = $Datastore.CapacityGB
                'SCSILun_Datastore_FreeSpaceGB' = $Datastore.FreeSpaceGB
                'SCSILun_Datastore_StorageIOControlEnabled'= $Datastore.StorageIOControlEnabled
                'SCSILun_Datastore_CongestionThreshold_ms'= $Datastore.CongestionThresholdMillisecond
                'SCSILun_Datastore_CongestionThreshold_Mode'= $Datastore.ExtensionData.IORMConfiguration.CongestionThresholdMode
                'SCSILun_Datastore_CongestionThreshold_PrcntofPeakThrput'= $Datastore.ExtensionData.IORMConfiguration.PercentOfPeakThroughput
                'SCSILun_PathSelectionPolicy' = $objScsilun.Policy.Policy
                'SCSILun_IoOperationLimit' = $IoOperationLimit
                'SCSILun_LimitType' = $LimitType
                'SCSILun_StorageArrayType' = $objScsilun.StorageArrayTypePolicy.Policy
                'SCSILunPath_Name' = "N.A."
                'SCSILunPath_Preferred' = $null
                'SCSILunPath_State' = "N.A."
                'SCSILunPath_PortWWN' = "N.A."
                'SCSILunPath_NodeWWN' = "N.A."
                'HBA_Name' = $_.Device
                'HBA_Type' = "FibreChannel"
                'HBA_PCI' = $_.Pci
                'HBA_Driver' = $_.Driver
                'HBA_Model' = $_.Model
                'HBA_Status' = $AdapterStatus
                'HBA_PortWWN' = $_.PortWorldWideName
                'HBA_NodeWWN' = $_.NodeWorldWideName
                'Timestamp' = Get-Date -Format $timestampFormat
              }
                    
              # Write out at every line
              $result | Export-CSV -path $FilePath -NoTypeInformation -Append -ErrorAction Stop
            }

          }
        }
      }
      }
    }
    
    Disconnect-VIServer -server $CurrentServerIP -Confirm:$false
  }

 

 

 

Upon running the script, I noticed that the path objects returned from LUNs configured with VMware's PSP and SATP only had 'active' as path state, regardless of whether the state shown in vCenter was Active or Active (I/O) 

Screenshot_1.PNG

Contrasted with LUNs configured with Hitachi Dynamic Link Manager (HDLM), which shows path state as Active and Standby below. Output from PowerCLI also shows 'active' or 'standby'.

 

Screenshot_2.PNG

Is there any way to distinguish between Active and Active I/O paths using PowerCLI, such as using different PowerCLI modules as the ones I am currently using in my script?

Thanks in advance.

Labels (1)
0 Kudos
1 Reply
LucD
Leadership
Leadership

The IO indication is not present in the State property of the HostMultipathInfoPath object.

To find the IO indication you have to look at the IsWorkingPath property. As is explained in the API Reference "Paths slated for I/O can be found using isWorkingPath."


Blog: lucd.info  Twitter: @LucD22  Co-author PowerCLI Reference