Emulex.Pro.MigrateHighIoVMWATypePRO (WriteActionModuleType)

Element properties:

TypeWriteActionModuleType
IsolationAny
AccessibilityInternal
RunAsDefault
InputTypeSystem.BaseData
OutputTypeSystem.CommandOutput

Member Modules:

ID Module Type TypeId RunAs 
Emulex.Pro.MigrateVMWAPRO WriteAction System.CommandExecuter Default

Overrideable Parameters:

IDParameterTypeSelector
EventDescriptionstring$Config/EventDescription$

Source Code:

<WriteActionModuleType ID="Emulex.Pro.MigrateHighIoVMWATypePRO" Accessibility="Internal" Batching="false">
<Configuration>
<xsd:element name="EventDescription" type="xsd:string"/>
</Configuration>
<OverrideableParameters>
<OverrideableParameter ID="EventDescription" Selector="$Config/EventDescription$" ParameterType="string"/>
</OverrideableParameters>
<ModuleImplementation Isolation="Any">
<Composite>
<MemberModules>
<WriteAction ID="Emulex.Pro.MigrateVMWAPRO" TypeID="System!System.CommandExecuter">
<ApplicationName>%SystemRoot%\system32\windowspowershell\v1.0\powershell.exe</ApplicationName>
<WorkingDirectory/>
<CommandLine>-Command "&amp; {.\EmulexHighBandwidthMonitorScript.ps1 '$Config/EventDescription$'}"
</CommandLine>
<TimeoutSeconds>86400</TimeoutSeconds>
<RequireOutput>false</RequireOutput>
<Files>
<File>
<Name>EmulexHighBandwidthMonitorScript.ps1</Name>
<Contents><Script>
$eventContent = $args[0];
$eventContent = $eventContent.Split(':');
if ($eventContent.Count -Lt 4) {
eventcreate /T Error /ID 100 /L APPLICATION /SO VmmPro /D 'Invalid number of parameters are passed to the script.';
return;
}

$hostName = $eventContent[$eventContent.Count - 4].Replace('\n','').Trim();
$serverName = $eventContent[$eventContent.Count - 3].Trim();
$ProtipId = $eventContent[$eventContent.Count - 2].Trim();
$vmErrorCode = $eventContent[$eventContent.Count - 1].Trim()[0];
$debugMessage = 'Starting PRO Tip execution. Parameters passed: Host Name: ' + $hostName + ', Server Name: ' + `
$serverName + ', Tip Id : ' + $ProtipId + ', VM Error Code: ' + $vmErrorCode;

eventcreate /T Information /ID 100 /L APPLICATION /SO VmmPro /D $debugMessage;

$Error.Clear();
$VmmSnapinName = "Microsoft.SystemCenter.VirtualMachineManager"
$AllPsSnapins = Get-PSSnapin | Where-Object { $_.Name -eq $VmmSnapinName }
if ($AllPsSnapins -eq $null) {
add-pssnapin -name $VmmSnapinName;
}
if( $Error.Count -ne 0 ) {
eventcreate /T Error /ID 111 /L APPLICATION /SO VmmPro /D $Error[0];
return;
}


function new-array { $args }

function FailGenericError {
Set-PROTip -PROTipId $args[0] -LastError $args[1] -TipStatus Failed;
}

function FailHostNotFound {
$params = new-array 'Could not find a host for VM migration' $args[1];
Set-PROTip -PROTipId $args[0] -LastErrorOpsMgrString $params -TipStatus Failed;
}

function FailNoVMFound {
switch($args[1]) {
1 { $params = new-array 'Could not find a VM to migrate' $args[2]; }
2 { $params = new-array 'Could not find a VM to migrate' $args[2]; }
}

Set-PROTip -PROTipId $args[0] -LastErrorOpsMgrString $params -TipStatus Failed;
}

function FailNoVMToMigrate {
$params = new-array 'No eligible VMs found for migration' $args[1];
Set-PROTip -PROTipId $args[0] -LastErrorOpsMgrString $params -TipStatus Failed;
}

function FailNoHostToMigrateTo {
$params = new-array 'Target Host Not found' $args[1];
Set-PROTip -PROTipId $args[0] -LastErrorOpsMgrString $params -TipStatus Failed;
}

function FailInvalidErrorCode {
$params = new-array 'Invalid Error Code';
Set-PROTip -PROTipId $args[0] -LastErrorOpsMgrString $params -TipStatus Failed;
}

function FailHostMigrationError {
$params = new-array $args[1];
Set-PROTip -PROTipId $args[0] -LastErrorOpsMgrString $params -TipStatus Failed;
}

Function WWNToString( $arrayWWN ) {
$WwnToString = Hex0($arrayWWN[0])
$NumArray = (1..7)
foreach ($number in $numArray ) {
$hexNum = Hex0($arrayWWN[$number])
$WwnToString = $WwnToString + ":" + $hexNum
}
return $WwnToString
}

# Helper Function for converting digits of the WWN into hex
Function Hex0($n) {
$hexNum = "{0:X}" -f $n
if ($n -lt 16) {$hexNum = "0" + $hexNum}
return $hexNum
}

Function IsWwnEqual( $arrayWWN1, $arrayWWN2 ) {
$IsWwnEqual = $true
$NumArray = (0..7)
foreach ($number in $numArray ) {
If ($arrayWWN1[$number] -ne $arrayWWN2[$number]) {
$IsWwnEqual = $false
}
}
return $IsWwnEqual
};

function Main {
$Error.Clear();
$serverObj = get-vmmserver -computerName $serverName;

if( $Error.Count -ne 0) {
FailGenericError $ProtipId $Error[0];
return;
}

Set-PROTip -PROTipId $ProtipId -TipStatus Running;
$hostobj = get-vmhost -computername $hostName -vmmserver $serverObj;

if( $hostobj -eq $null ) {
FailHostNotFound $ProtipId $hostName;
return;
}

$type = [Microsoft.Win32.RegistryHive]::LocalMachine
$regKey = [Microsoft.Win32.RegistryKey]::OpenRemoteBaseKey($type, $hostName)
$regKey = $regKey.OpenSubKey("SYSTEM\MountedDevices")

$VMsOnNpivLuns = @{};
$WwpnToVmCount = @{};
$VmToWwpn = @{};

$colVMItems = get-wmiobject -class Msvm_VirtualSystemSettingData -namespace "root\virtualization" -computername $hostName

foreach ($objVMItem in $colVMItems) {

$strQuery = 'associators of {Msvm_VirtualSystemSettingData.InstanceID="' + $objVMItem.InstanceID + '"} where ResultClass=Msvm_ResourceAllocationSettingData'
$resourceColItems = get-wmiobject -namespace "root\virtualization" -computername $hostName -query $strQuery | `
where {($_.ResourceType -eq 21) -and ($_.ResourceSubType -like "Microsoft Virtual Hard Disk") -and `
($_.Connection -ne $null)}

foreach ($resourceObjItem in $resourceColItems) {

$vhdFile = $resourceObjItem.Connection[0]
$isVHDFileMapped = $false

$strDriveLetter = $resourceObjItem.Connection[0].substring(0, 3) + "\"
$colVolumeItems = get-wmiobject -class Win32_MountPoint -namespace "root\cimv2" -computername $hostName | `
where {($_.__RELPATH -like "*$($strDriveLetter)*")}

foreach ($objVolumeItem in $colVolumeItems) {

$strDirectory = $objVolumeItem.Directory.TrimStart("Win32_Directory.Name=")
$strDirectory = $strDirectory.replace('"',"")
$strDirectory = $strDirectory.SubString(0, $strDirectory.length).replace("\\","\")

$volumeDeviceId = $objVolumeItem.Volume
$isVMOnVolume = $vhdFile.ToLower().StartsWith($strDirectory.ToLower())

if ($isVMOnVolume) {

$volumeDeviceId = $volumeDeviceId.TrimStart("Win32_Volume.DeviceID=").replace('"' + "\\\\?","\??")
$volumeDeviceId = $volumeDeviceId.replace("\\","\")
$volumeRegValue = $volumeDeviceId.substring(0, $volumeDeviceId.length - 2)
$binVolumeSignatureFromReg = $regkey.GetValue($volumeRegValue)

$i = 0
$hexVolumeSignatureFromReg = ""
foreach ($binNumber in $binVolumeSignatureFromReg ) {
if ($i -ge 4) {break}

$hexVolumeSignatureFromReg = ("{0:X}" -f $binNumber) + $hexVolumeSignatureFromReg
if ($binNumber -lt 16) {
$hexVolumeSignatureFromReg = "0" + $hexVolumeSignatureFromReg
}
$i++
}

$intVolumeSignatureFromReg = [Convert]::ToInt32($hexVolumeSignatureFromReg,16)
If ($intVolumeSignatureFromReg -lt 0) {
$intVolumeSignatureFromReg = $intVolumeSignatureFromReg + [math]::pow(2,32)
}

$strQuery = "Select * From Win32_DiskDrive where Signature=" + $intVolumeSignatureFromReg
$colDiskDriveItems = get-wmiobject -namespace "root\cimv2" -computername $hostName -query $strQuery

foreach ($objDiskDriveItem in $colDiskDriveItems) {

If ($objDiskDriveItem -ne $null) {

$strQuery = "Select * From MSFC_NPIVLUNMappingInformation where OSBus=" + $objDiskDriveItem.SCSIBus + `
" and OSTarget=" + $objDiskDriveItem.SCSITargetId + " and OSLun=" + $objDiskDriveItem.SCSILogicalUnit

$colNpivLunMappingItems = get-wmiobject -namespace "root\wmi" -computername $hostName -query $strQuery
foreach ($objNpivLunMappingItem in $colNpivLunMappingItems) {

if (!(IsWwnEqual $objNpivLunMappingItem.WWPNPhysicalPort $objNpivLunMappingItem.WWPNVirtualPort)) {

$strQuery = 'Select * from MSFC_FibrePortHBAAttributes where InstanceName LIKE "' + "%VEN_10DF%" + '"'
$colPhysPortItems = get-wmiobject -namespace "root\wmi" -computername $hostName -query $strQuery

foreach ($objPhysPortItem in $colPhysPortItems) {

if ((IsWwnEqual $objPhysPortItem.Attributes.PortWWN $objNpivLunMappingItem.WWPNPhysicalPort)) {

if (!$VMsOnNpivLuns.ContainsKey($objVMItem.ElementName)) {
$VMsOnNpivLuns.Add($objVMItem.ElementName, $objVMItem)
}

$strPortWwn = WWNToString($objPhysPortItem.Attributes.PortWWN)

if ($VmToWwpn.ContainsKey($objVMItem.ElementName)) {
$WwpnArray = $VmToWwpn.Get_Item($objVMItem.ElementName)
$WwpnArray = $WwpnArray + $strPortWwn;
$VmToWwpn.Set_Item($objVMItem.ElementName, $WwpnArray)
}
else {
$PortWwnArray = @();
$PortWwnArray = $PortWwnArray + $strPortWwn;
$VmToWwpn.Add($objVMItem.ElementName, $PortWwnArray)
}

if ($WwpnToVmCount.ContainsKey($strPortWwn)) {
$VmCount = $WwpnToVmCount.Get_Item($strPortWwn)
$VmCount++;
$WwpnToVmCount.Set_Item($strPortWwn, $VmCount)
}
else {
$WwpnToVmCount.Add($strPortWwn, 1)
}

$isVHDFileMapped = $true
}
}
}
}
}
}
}
if ($isVHDFileMapped) {break;}
}
}
}

$allvms = $hostobj | Get-VM;

if (($hostobj.VMs -eq $null) -or ($hostobj.VMs.Count -eq 0)) {
FailNoVMFound $ProtipId $vmErrorCode $hostName;
return;
}

if ($hostobj.VMs.Count -eq 1) {
FailGenericError $ProtipId "The host $($hostname) has a single VM `"$($hostobj.VMs[0].Name)`" on an HBA port that is utilizing bandwidth outside the accepted range. This implementation will not migrate this VM to prevent possible migration cycles between hosts. Please inspect this VM manually to determine cause of high I/O utilization";
return;
}

$candidateVMs = @();
foreach( $cVMOnHost in $hostobj.VMs | where { $_.Status -eq 'Running' } | where { $_.ExcludeFromPRO -ne $TRUE} ) {
foreach ($cVMOnNpivLun in $VMsOnNpivLuns.GetEnumerator()) {
if ($cVMOnNpivLun.Name -eq $cVMOnHost.Name) {
$candidateVMs = $candidateVMs + $cVMOnHost;
}
}
}
if($candidateVMs.Count -eq 0) {
FailNoVMToMigrate $ProtipId $hostName; return;
}

if($candidateVMs.Count -eq 1) {
FailGenericError $ProtipId "The host $($hostname) has a single, running VM `"$($candidateVMs[0])`" on an HBA port that is utilizing bandwidth outside the accepted range. This implementation will not migrate this VM to prevent possible migration cycles between hosts. Please inspect this VM manually to determine cause of high I/O utilization";
return;
}

$candidateVMsSorted = @();
switch($vmErrorCode) {
1 { $candidateVMsSorted = $candidateVMs | sort PerfDiskBytesRead -Descending; }
2 { $candidateVMsSorted = $candidateVMs | sort PerfDiskBytesWrite -Descending; }
default { FailInvalidErrorCode $ProtipId; return; }
}

$vmCount = 0
foreach( $tVM in $candidateVMsSorted ) {

$isQuickMigration = $false;
$hostList = @();
Get-VMHost;

if(($hostobj.HostCluster -ne $null ) -and ($hostobj.HostCluster.Nodes.Count -ne 1)) {
foreach ( $tmpHost in $hostobj.HostCluster.Nodes ) {
if( $tmpHost.Name -ne $hostobj.Name ) {
$hostList = $hostList + $tmpHost;
$isQuickMigration = $true;
}
}
}
else {
foreach ( $tmpHost in $hostobj.VMHostGroup.Hosts ) {
if ( $tmpHost.Name -ne $hostobj.Name ) {
$hostList = $hostList + $tmpHost;
}
}
}

if(($hostList -ne $null) -or ($hostList.Count -ne 0)) {
$vmHostRatings = @();
$vmHostRatings = $vmHostRatings + ( @(Get-VMHostRating -VM $tVM -VMHost $hostList -IsMigration `
-UseDefaultPath -CPUPriority 0 -MemoryPriority 0 -NetworkPriority 0 -DiskPriority 10) | Sort-Object `
-property Rating -descending | where { $_.TransferType -eq 'San' });

if ( $vmHostRatings.Count -ne $null) {
if (( $vmHostRatings.Count -eq 1) -and ( $vmHostRatings[0].Rating -eq 0) -and `
($candidateVMs.Count -eq ($vmCount + 1))) {
FailHostMigrationError $ProtipId $vmHostRatings[0].Description; return;
}
else {
$selectedVMHost = $hostList | where { ($_.Name -eq $vmHostRatings[0].VMHost.Name) };
if ($selectedVMHost -ne $null) {
$skipThisVm = $false;

if ($VmToWwpn.ContainsKey($tVM.Name)) {
$aWwpnObj = $VmToWwpn.Get_Item($tVM.Name);
foreach ($tWwpn in $aWwpnObj) {
if ($WwpnToVmCount.ContainsKey($tWwpn)) {
$iCount = $WwpnToVmCount.Get_Item($tWwpn);
if ($iCount -eq 1) {
$skipThisVm = $true;
}
}
}
}

if ($skipThisVm) {
break;
}
else {
$selectedVM = $tVM;
break;
}
}
}
}
} # if(($hostList -ne $null) -or ($hostList.Count -ne 0))
$vmCount++;
} # foreach ( $tVM in $candidateVMsSorted )

if ( ( $hostList -eq $null ) -or ( $hostList.Count -eq 0 ) ) { FailNoHostToMigrateTo $ProtipId $hostName; return; }
if ( $vmHostRatings.Count -eq $null ) { FailNoHostToMigrateTo $ProtipId $hostName; return; }
if ( $selectedVMHost -eq $null ) { FailNoHostToMigrateTo $ProtipId $hostName; return; }
if ( $selectedVM -eq $null ) { FailNoVMFound $ProtipId $vmErrorCode $hostName; return; }

$Error.Clear();

if($isQuickMigration) {
Move-VM -VM $selectedVM -VMHost $selectedVMHost -PROTipId $ProtipId;
}
else {
if ( $selectedVMHost.VMPaths -eq $null ) {
FailNoHostToMigrateTo $ProtipId $hostName; return;
}
else {
$defaultPaths = @($selectedVMHost.VMPaths | where { $_.StartsWith($vmHostRatings[0].PreferredVolume) -eq 1 });
}

if( $defaultPaths[0] -eq $null) {
FailNoHostToMigrateTo $ProtipId $hostName; return;
}

Move-VM -VM $selectedVM -VMHost $selectedVMHost -Path $defaultPaths[0] -PROTipId $ProtipId;
}

if( $Error.Count -ne 0) { FailGenericError $ProtipId $Error[0]; return; }

Set-PROTip -PROTipId $ProtipId -TipStatus Resolved;
}

Main;
</Script></Contents>
<Unicode>true</Unicode>
</File>
</Files>
</WriteAction>
</MemberModules>
<Composition>
<Node ID="Emulex.Pro.MigrateVMWAPRO"/>
</Composition>
</Composite>
</ModuleImplementation>
<OutputType>System!System.CommandOutput</OutputType>
<InputType>System!System.BaseData</InputType>
</WriteActionModuleType>