NetApp E-Series Performance Monitor Data Source

NetAppESeries.PerformanceMonitorDataSourceType (DataSourceModuleType)

Element properties:

TypeDataSourceModuleType
IsolationAny
AccessibilityPublic
RunAsDefault
OutputTypeSystem.PropertyBagData

Member Modules:

ID Module Type TypeId RunAs 
PerformanceDS DataSource System.CommandExecuterPropertyBagSource Default

Source Code:

<DataSourceModuleType ID="NetAppESeries.PerformanceMonitorDataSourceType" Accessibility="Public" Batching="false">
<Configuration>
<xsd:element xmlns:xsd="http://www.w3.org/2001/XMLSchema" minOccurs="1" name="IntervalSeconds" type="xsd:integer"/>
<xsd:element xmlns:xsd="http://www.w3.org/2001/XMLSchema" minOccurs="1" name="TimeoutSeconds" type="xsd:integer"/>
<xsd:element xmlns:xsd="http://www.w3.org/2001/XMLSchema" minOccurs="1" name="PerformanceThreshold" type="xsd:integer"/>
<xsd:element xmlns:xsd="http://www.w3.org/2001/XMLSchema" minOccurs="1" name="PerformanceMetric" type="xsd:string"/>
<xsd:element xmlns:xsd="http://www.w3.org/2001/XMLSchema" minOccurs="1" name="Trace" type="xsd:integer"/>
</Configuration>
<ModuleImplementation Isolation="Any">
<Composite>
<MemberModules>
<DataSource ID="PerformanceDS" TypeID="System!System.CommandExecuterPropertyBagSource">
<IntervalSeconds>$Config/IntervalSeconds$</IntervalSeconds>
<ApplicationName>%windir%\system32\windowspowershell\v1.0\powershell.exe</ApplicationName>
<WorkingDirectory/>
<CommandLine>-File ".\NetAppESeriesPerformanceMonitor.ps1" "$Config/PerformanceMetric$" $Config/PerformanceThreshold$ $Config/Trace$</CommandLine>
<TimeoutSeconds>$Config/TimeoutSeconds$</TimeoutSeconds>
<RequireOutput>true</RequireOutput>
<Files>
<File>
<Name>NetAppESeriesPerformanceMonitor.ps1</Name>
<Contents><Script># This is MP version 2.1.0.3
param([String]$Metric, [int]$Threshold, [int]$Trace)


function Log([string] $Message)
{
Write-EventLog -LogName 'NetApp Operations Manager' -Source 'NetApp Monitoring Web Service' `
-EventId 2 -Category 0 -Message $Message -EntryType Information
}

function LogError([string] $Message)
{
Write-EventLog -LogName 'NetApp Operations Manager' -Source 'NetApp Monitoring Web Service' `
-EventId 2 -Category 0 -Message $Message -EntryType Error
}
function LogWarning([string] $Message)
{
Write-EventLog -LogName 'NetApp Operations Manager' -Source 'NetApp Monitoring Web Service' `
-EventId 2 -Category 0 -Message $Message -EntryType Warning
}

function Process-Hits([string] $MetricLabel)
{
if ($volumeList.Count -gt 0)
{
$msg=""
$vols=""
foreach ($vol in $volumeList.Keys)
{
$rt= $volumeList[$vol]
$msg+="Volume: $vol ${MetricLabel}: $rt`n"
$vols+="$vol,"
}
LogWarning "Volumes to investigate (${arrayName}) Metric (${Metric}) Threshold (${Threshold}) : `n$msg"
$bag.addValue("State","Attention")
$bag.addValue("VolumeName",$msg)
$api.addItem($bag)

}
else
{
$bag.addValue("State","Acceptable")
$bag.addValue("VolumeName","N/A")
$api.addItem($bag)
}
}

function Analyze-Volumes([PSCustomObject]$volStatResp, [string]$metricName="readresponsetime")
{
try
{
# iterate over the analyzed volume stats
foreach ($line in $volStatResp)
{
$script:volumeCount++
$volumeName=$line.volumename
# slight of hand here - dereference the name of the metric so it can be accessed from the stat line.
$reading=$line.$($metricName)

# Formatting theReading changes the type from double to string.
# which means it cannot be compared (accurately) to the $Threshold
# limit.
$theFormattedReading = "{00:N4}" -f $reading

if ($Trace)
{
$m=@"
Array,Volume,$perfAbbrev,Metric,Threshold
$arrayName,$volumename,$theFormattedReading,$Metric,$Threshold
"@
Log $m
}

if ($reading -gt [double]$Threshold)
{
$volumeList.Add($volumeName,$theFormattedReading)
}

}
} catch [system.exception] {
# Fill out property bag with a message that stats were unable to be obtained.
# The array will
LogError "Exception getting vol stats for $arrayWwn"
continue
}
}

function Get-WebServerPort([string] $dir)
{

[xml]$wsConfig=Get-Content "$dir/webserver/wsconfig.xml" -ErrorAction SilentlyContinue
$val=$wsConfig.config.port
if ($val -eq $null)
{
LogError "Error parsing wsConfig.xml in $dir"
}
$val
}

# - - Script Start - - #

$script:volumeCount=0
# init a timer
$watch=[System.Diagnostics.Stopwatch]::StartNew()

$arrayCount=0

$scriptName = "NetAppESeriesPerformanceMonitor.ps1"
$E_LVL_ERROR = 2
$E_LVL_WARNING = 1
$E_LVL_INFO = 0
$E_NBR_TRACEM = 3701
$SnapinName = (Get-ItemProperty HKLM:\Software\NetApp\MP PSSnapinName).PSSnapinName
$IntPackDir = (Get-ItemProperty HKLM:\Software\NetApp\MP IntegrationPackRoot).IntegrationPackRoot

$api= New-Object -ComObject 'MOM.ScriptAPI'

if ( $Trace )
{
# LogScriptEvent will log events to the Operations Manager log.
$api.LogScriptEvent($ScriptName, $E_NBR_TRACEM, $E_LVL_INFO, 'performance monitoring started')

}
$m=@"
NetApp ESeries Performance Monitoring Started
Date,Metric,Threshold,Trace
$(Get-Date),$Metric,$Threshold,$Trace
"@
Log $m
if ( (Get-PSSnapin -Name $SnapinName -ErrorAction SilentlyContinue) -eq $null )
{
Add-PsSnapin $SnapinName
}

# Create webservice credential. This is based on an encrypted file called rwPw.txt in the
# integration pack root directory.

$wsPass = cat $IntPackDir/rwPw.txt | ConvertTo-SecureString -Key (1..16)
$wsCred = New-Object -TypeName System.Management.Automation.PSCredential("rw",$wsPass)
$wsPort = Get-WebServerPort $IntPackDir

# Get Disk System Data
$DSCredentials = @(Get-SDCredential -All)

# The logic is to iterate over array.
# For each array get analyzed volume statistics.
# The monitor (this script) will create a property bag for each array, not for
# each volume.
# While collecting volume stats, keep track of the volumes that exceed the
# threshold. The volumes will be posted in the alert for the storage array. If
# this cardinality is messed up (1 bag per volume, for instance), then the
# monitor on the RMS will always be 'Healthy'

foreach ($cxn in $DSCredentials)
{
$arrayCount++
$DS = Get-StorageDevice -Credentials $cxn
$arrayWWN = $DS.WWN
$arrayWWN = $arrayWWN.Replace(" ","")
$arrayName= $DS.FriendlyName

# irm is a PoSH alias for Invoke-RestMethod.
# Call NetApp REST API
$statUrl="http://localhost:$wsPort/devmgr/v1/storage-systems/$arrayWWN/analysed-volume-statistics"
$statResp=irm -uri $statUrl -meth GET -credential $wsCred
$volStatResp = $statResp |Select-Object volumename,readresponsetime,writeresponsetime,readiops,writeiops,readthroughput,writethroughput
$volumeList=@{}

# Create propBag and fill out global stuff now
$bag = $api.CreatePropertyBag()
$bag.addValue("SSGUID",$DS.WWN)
$bag.addValue("PerformanceMetric",$Metric)
if ($Metric -eq "Volume Read Response")
{
$theReading= "readresponsetime"
$perfAbbrev="read response time (ms)"

}
elseif ($Metric -eq "Volume Write Response")
{
$theReading= "writeresponsetime"
$perfAbbrev="write response time (ms)"
}
elseif ($Metric -eq "Volume Read IOPs")
{
$theReading= "readiops"
$perfAbbrev="read IOPs"
}
elseif ($Metric -eq "Volume Write IOPs")
{
$theReading= "writeiops"
$perfAbbrev="write IOPs"
}
elseif ($Metric -eq "Volume Read Throughput")
{
$theReading= "readthroughput"
$perfAbbrev="read throughput (MB/s)"
}
elseif ($Metric -eq "Volume Write Throughput")
{
$theReading= "writethroughput"
$perfAbbrev="write throughput (MB/s)"
}
Analyze-Volumes $volStatResp $theReading
Process-Hits $perfAbbrev
}
$elapsed=$watch.Elapsed.ToString()
$summary=@"
NetApp ESeries Performance Monitoring ($Metric) Complete
Arrays,Volumes,ElapsedTime
$arrayCount,$script:volumeCount,$elapsed
"@
Log $summary

# Send all property bags to the output pipeline.
$api.returnItems()</Script></Contents>
<Unicode>true</Unicode>
</File>
</Files>
</DataSource>
</MemberModules>
<Composition>
<Node ID="PerformanceDS"/>
</Composition>
</Composite>
</ModuleImplementation>
<OutputType>System!System.PropertyBagData</OutputType>
</DataSourceModuleType>