Array Discovery

NetAppSANtricity.NetAppSANtricity.ArrayDiscovery (Discovery)

Description for the new discovery.

Element properties:

TargetNetAppSANtricity.Proxy
EnabledTrue
Frequency3600
RemotableFalse

Object Discovery Details:

Discovered Classes and their attribuets:

Member Modules:

ID Module Type TypeId RunAs 
DS DataSource Microsoft.Windows.TimedPowerShell.DiscoveryProvider Default

Source Code:

<Discovery ID="NetAppSANtricity.NetAppSANtricity.ArrayDiscovery" Target="NetAppSANtricity.Proxy" Enabled="true" ConfirmDelivery="false" Remotable="true" Priority="Normal">
<Category>Discovery</Category>
<DiscoveryTypes>
<DiscoveryClass TypeID="NetAppSANtricity.StorageArray"/>
<DiscoveryClass TypeID="NetAppSANtricity.StoragePoolsGroup"/>
<DiscoveryClass TypeID="NetAppSANtricity.StoragePool"/>
</DiscoveryTypes>
<DataSource ID="DS" TypeID="Windows!Microsoft.Windows.TimedPowerShell.DiscoveryProvider">
<IntervalSeconds>3600</IntervalSeconds>
<SyncTime>06:00</SyncTime>
<ScriptName>ArrayDiscovery.ps1</ScriptName>
<ScriptBody><Script>##############################################################################
# Copyright (c) 2015 NetApp Inc.
# All rights reserved.
#
# ArrayDiscovery.ps1
# Script to run deep discovery of managed arrays.
#

param ($sourceId, $managedEntityId, [Boolean]$Trace)

##############################################################################
# Script utilities
#
function GetTrueFalseString($value)
{

if ($value -eq "true")
{
$result = "True"
}
else
{
$result = "False"
}
return $result
}

function GetStateStatusString($value)
{
if ($value -eq "optimal")
{
$result = "Optimal"
}
elseif ($value -eq "needsAttn")
{
$result = "Needs Attention"
}
elseif ($value -eq "failed")
{
$result = "Failed"
}
elseif ($value -eq "complete")
{
$result = "Complete"
}
elseif ($value -eq "degraded")
{
$result = "Degraded"
}
elseif ($value -eq "impaired")
{
$result = "Impaired"
}
elseif ($value -eq "initialSync")
{
$result = "Initial Sync"
}
elseif ($value -eq "incomplete")
{
$result = "Incomplete"
}
elseif ($value -eq "orphan")
{
$result = "Orphan"
}
elseif ($value -eq "stoppped")
{
$result = "Stopped"
}
elseif ($value -eq "disabled")
{
$result = "Disabled"
}
elseif ($value -eq "offline")
{
$result = "Offline"
}
elseif ($value -eq "purged")
{
$result = "Purged"
}
elseif ($value -eq "contingent")
{
$result = "Contingent"
}
elseif ($value -eq "exported")
{
$result = "Exported"
}
elseif ($value -eq "forced")
{
$result = "Forced"
}
elseif ($value -eq "missing")
{
$result = "Missing"
}
elseif ($value -eq "partial")
{
$result = "Partial"
}
elseif ($value -eq "unknown")
{
$result = "Unknown"
}
elseif ($value -eq "neverContacted")
{
$result = "Unreachable"
}
elseif ($value -eq "removed")
{
$result = "Removed"
}
else
{
$result = $value
}
return $result
}

function GetRaidString($value)
{
if ($value -eq "raidDiskPool")
{
$result = "RAID Disk Pool"
}
elseif ($value -eq "raid0")
{
$result = "RAID 0"
}
elseif ($value -eq "raid1")
{
$result = "RAID 1"
}
elseif ($value -eq "raid10")
{
$result = "RAID 10"
}
elseif ($value -eq "raid3")
{
$result = "RAID 3"
}
elseif ($value -eq "raid5")
{
$result = "RAID 5"
}
elseif ($value -eq "raid6")
{
$result = "RAID 6"
}
else
{
$result = $value
}
return $result
}

function GetDateFormatString
{
return "MM/dd/yyyy hh:mm:ss tt"
}

function GetFormattedSize($value)
{
$size = $value / 1KB
if ($size -lt 1)
{
$result = "" + $value + " Bytes"
}
elseif ($size -lt 1024)
{
$size = $size.ToString(".00")
$result = "" + $size + " KB"
}
else
{
$size = $value / 1MB
if ($size -lt 1024)
{
$size = $size.ToString(".00")
$result = "" + $size + " MB"
}
else
{
$size = $value / 1GB
if ($size -lt 1024)
{
$size = $size.ToString(".00")
$result = "" + $size + " GB"
}
else
{
$size = $value / 1TB
$size = $size.ToString(".00")
$result = "" + $size + " TB"
}
}
}
return $result
}

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

[xml]$wsConfig = Get-Content "$dir/webserver/wsconfig.xml" -ErrorAction SilentlyContinue
$val = $wsConfig.config.port
$val
}

##############################################################################

# Setup variables for deserialization if output is too big
#
Add-Type -AssemblyName System.Web.Extensions
$javaScriptSerializer = New-Object System.Web.Script.Serialization.JavaScriptSerializer
$javaScriptSerializer.MaxJsonLength = [System.Int32]::MaxValue
$javaScriptSerializer.RecursionLimit = 99

##############################################################################

&lt;#
Target here will be the Proxy Server
#&gt;

# Script variables
$private:scriptName = "ArrayDiscovery.ps1"
$private:E_LVL_INFO = 0
$private:E_LVL_ERROR = 1
$private:E_LVL_WARNING = 2
$private:E_NBR_TRACE = 3902
$private:intPackDir = (Get-ItemProperty HKLM:\Software\NetApp\MP IntegrationPackRoot).IntegrationPackRoot

$SnapinName = (Get-ItemProperty HKLM:\Software\NetApp\MP PSSnapinName).PSSnapinName
$ManagingSystem = "$Target/Host/Property[Type='Windows!Microsoft.Windows.Computer']/NetworkName$"

# Script varaibles for SCOM
$private:api = New-Object -ComObject 'MOM.ScriptAPI'
$discoveryData = $api.CreateDiscoveryData(0, $sourceId, $managedEntityId)

if ($Trace)
{
$api.LogScriptEvent($scriptName, $E_NBR_TRACE, $E_LVL_INFO, 'Storage Array Discovery In Process')
$api.LogScriptEvent($scriptName, $E_NBR_TRACE, $E_LVL_INFO, 'params: ' + $ManagedEntityId + ' and ' + $ManagingSystem + ' and ' + $SnapinName)
}

$v = $PSVersionTable.PSVersion
$CurrentValue = [Environment]::GetEnvironmentVariable("PSModulePath", "Machine")
$psInfo = 'PS Info: ' + $v.Major + ' ' + $v.Minor + ' ' + $v.Build + ' ' + $v.Revision
$psInfo = $psInfo + ' ' + $CurrentValue

if ($v.Major -lt 3)
{
$api.LogScriptEvent($ScriptName, $E_NBR_TRACE, $E_LVL_ERROR, 'NetApp SANtricity Storage Array MP scripts require Powershell version 3.0 or greater. This Agent is running version ' + $v.Major + '.' + $v.Minor + '.')
$api.LogScriptEvent($ScriptName, $E_NBR_TRACE, $E_LVL_WARNING, $psInfo)
}

if ( (Get-PSSnapin -Name $SnapinName -ErrorAction SilentlyContinue) -eq $null )
{
Add-PsSnapin $SnapinName
}

# Common parameters used for the web service calls
$securePwd = ConvertTo-SecureString "rw" -AsPlainText -Force
$cred = New-Object System.Management.Automation.PSCredential("rw", $securePwd)

$wsPort = Get-WebServerPort $intPackDir
if ($wsPort -eq $null)
{
$api.LogScriptEvent($ScriptName, $E_NBR_TRACE, $E_LVL_ERROR, "Error parsing wsConfig.xml in" + $intPackDir)
$wsPort = "8080" # try 8080 if we can't find anything else...
}
$baseUrl = "http://localhost:$wsPort/devmgr/v2/storage-systems/"

# Create objects for the agents
$proxyInstance = $discoveryData.CreateClassInstance("$MPElement[Name='NetAppSANtricity.Proxy']$")
$proxyInstance.AddProperty("$MPElement[Name='NetAppSANtricity.Proxy']/SnapinName$", $SnapinName)
$proxyInstance.AddProperty("$MPElement[Name='Windows!Microsoft.Windows.Computer']/PrincipalName$", $ManagingSystem)
$proxyInstance.AddProperty("$MPElement[Name='System!System.Entity']/DisplayName$", "$Target/Host/Property[Type='Windows!Microsoft.Windows.Computer']/NetworkName$")
$formatString = GetDateFormatString
$time = Get-Date -format $formatString
$proxyInstance.AddProperty("$MPElement[Name='NetAppSANtricity.Proxy']/LastUpdated$", $time)
$discoveryData.AddInstance($proxyInstance)

$arraysProcessed = 0

# If the Powershell version is not &gt;= 3.0, then skip everything else. We cannot get good data using Powershell 2.0
if ($v.Major -ge 3)
{

# Get all storage systems monitored by the agent
$allArrays = Invoke-RestMethod $baseUrl -Credential $cred
if ($allArrays.GetType().FullName -eq "System.String")
{
$allArrays = $javaScriptSerializer.DeserializeObject($allArrays)
}

foreach ($array in $allArrays)
{
# Create Array object
$arrayInstance = $discoveryData.CreateClassInstance("$MPElement[Name='NetAppSANtricity.StorageArray']$")
$private:friendlyName = ""
if ($array.name -ne $null)
{
$friendlyName = $array.name
}
else
{
$friendlyName = "Unnamed"
}
$arrayInstance.AddProperty("$MPElement[Name='NetAppSANtricity.StorageArray']/MonitoringSystem$", $ManagingSystem)
$arrayInstance.AddProperty("$MPElement[Name='System!System.Entity']/DisplayName$", $friendlyName)
$arrayInstance.AddProperty("$MPElement[Name='NetAppSANtricity.StorageArray']/friendlyName$", $friendlyName)
$arrayInstance.AddProperty("$MPElement[Name='NetAppSANtricity.StorageArray']/wwn$", $array.wwn)
$arrayInstance.AddProperty("$MPElement[Name='NetAppSANtricity.StorageArray']/status$", (GetStateStatusString $array.status))
$arrayInstance.AddProperty("$MPElement[Name='NetAppSANtricity.StorageArray']/ipAddress1$", $array.ip1)
$arrayInstance.AddProperty("$MPElement[Name='NetAppSANtricity.StorageArray']/ipAddress2$", $array.ip2)
$arrayInstance.AddProperty("$MPElement[Name='NetAppSANtricity.StorageArray']/model$", $array.model)
$arrayInstance.AddProperty("$MPElement[Name='NetAppSANtricity.StorageArray']/fwVersion$", $array.fwVersion)
$arrayInstance.AddProperty("$MPElement[Name='NetAppSANtricity.StorageArray']/nvsramVersion$", $array.nvsramVersion)
$arrayInstance.AddProperty("$MPElement[Name='NetAppSANtricity.StorageArray']/passwordSet$", (GetTrueFalseString $array.passwordSet))
$arrayInstance.AddProperty("$MPElement[Name='NetAppSANtricity.StorageArray']/hotSpareCount$", $array.hotSpareCount)
$arrayInstance.AddProperty("$MPElement[Name='NetAppSANtricity.StorageArray']/hostSparesUsed$", $array.hostSparesUsed)
$arrayInstance.AddProperty("$MPElement[Name='NetAppSANtricity.StorageArray']/chassisSerialNumber$", $array.chassisSerialNumber)
$discoveryData.AddInstance($arrayInstance)

# add 'hidden' relationship causing the health service on the
# managing computer to monitor the health of this StorageSubsystem

$healthSvc = $discoveryData.CreateClassInstance( "$MPElement[Name='SC!Microsoft.SystemCenter.HealthService']$" )
$healthSvc.AddProperty("$MPElement[Name='Windows!Microsoft.Windows.Computer']/PrincipalName$", $ManagingSystem )
$discoveryData.AddInstance($healthSvc)

$hsvcManagesSSubsystemRel = $discoveryData.CreateRelationshipInstance("$MPElement[Name='SC!Microsoft.SystemCenter.HealthServiceShouldManageEntity']$")
$hsvcManagesSSubsystemRel.Source = $healthSvc
$hsvcManagesSSubsystemRel.Target = $arrayInstance
$discoveryData.AddInstance($hsvcManagesSSubsystemRel)

# Create relationship between Array and the Proxy Agent
$relationshipInstance = $discoveryData.CreateRelationShipInstance("$MPElement[Name='NetAppSANtricity.ProxyArrayRelationship']$")
$relationshipInstance.Source = $proxyInstance
$relationshipInstance.Target = $arrayInstance
$discoveryData.AddInstance($relationshipInstance)

# Get StoragePool data for this array
$url = ""
$url = $baseUrl + $array.wwn + "/storage-pools/"
try
{
$allStoragePools = Invoke-RestMethod $url -Credential $cred
}
catch
{
# If the array is offline/unreachable then trying to get the storage-pools causes an error.
# The data in $allStoragePools will be leftover from the prior array, and using that is bad.
continue
}

if ($allStoragePools.GetType().FullName -eq "System.String")
{
$allStoragePools = $javaScriptSerializer.DeserializeObject($allStoragePools)
}

if ($allStoragePools)
{
# Create Storage Pools Group object to act as container for Storage Pools
$storagePoolGroupInstance = $discoveryData.CreateClassInstance("$MPElement[Name='NetAppSANtricity.StoragePoolsGroup']$")

# Adding properties that associate Storage Pools Group with its parent Storage Array
$storagePoolGroupInstance.AddProperty("$MPElement[Name='NetAppSANtricity.StoragePoolsGroup']/arrayWwn$", $array.wwn)
$storagePoolGroupInstance.AddProperty("$MPElement[Name='NetAppSANtricity.StoragePoolsGroup']/arrayName$", $friendlyName)
$storagePoolGroupInstance.AddProperty("$MPElement[Name='System!System.Entity']/DisplayName$", "Storage Pools")

$discoveryData.AddInstance($storagePoolGroupInstance)

# Create relationship between Storage Pool group and storage array
$relationshipInstance = $discoveryData.CreateRelationshipInstance("$MPElement[Name='NetAppSANtricity.StoragePoolsGroupRelationship']$")
$relationshipInstance.Source = $arrayInstance
$relationshipInstance.Target = $storagePoolGroupInstance
$discoveryData.AddInstance($relationshipInstance)

foreach ($storagePool in $allStoragePools)
{
# Create storage pool object
$poolInstance = $discoveryData.CreateClassInstance("$MPElement[Name='NetAppSANtricity.StoragePool']$")
$poolInstance.AddProperty("$MPElement[Name='System!System.Entity']/DisplayName$", $storagePool.label)
$poolInstance.AddProperty("$MPElement[Name='NetAppSANtricity.StoragePool']/offline$", (GetTrueFalseString $storagePool.offline))
$poolInstance.AddProperty("$MPElement[Name='NetAppSANtricity.StoragePool']/raidLevel$", (GetRaidString $storagePool.raidLevel))
$poolInstance.AddProperty("$MPElement[Name='NetAppSANtricity.StoragePool']/wwn$", $storagePool.worldWideName)
$poolInstance.AddProperty("$MPElement[Name='NetAppSANtricity.StoragePool']/state$", (GetStateStatusString $storagePool.state))
$poolInstance.AddProperty("$MPElement[Name='NetAppSANtricity.StoragePool']/usedSpace$", (GetFormattedSize $storagePool.usedSpace))
$poolInstance.AddProperty("$MPElement[Name='NetAppSANtricity.StoragePool']/totalRaidedSpace$", (GetFormattedSize $storagePool.totalRaidedSpace))
$poolInstance.AddProperty("$MPElement[Name='NetAppSANtricity.StoragePool']/raidStatus$", (GetStateStatusString $storagePool.raidStatus))
$poolInstance.AddProperty("$MPElement[Name='NetAppSANtricity.StoragePool']/freeSpace$", (GetFormattedSize $storagePool.freeSpace))
$poolInstance.AddProperty("$MPElement[Name='NetAppSANtricity.StoragePool']/storageArrayName$", $friendlyName)
$poolInstance.AddProperty("$MPElement[Name='NetAppSANtricity.StoragePool']/storageArrayWwn$", $array.wwn)
$poolInstance.AddProperty("$MPElement[Name='NetAppSANtricity.StoragePool']/volumeGroupRef$", $storagePool.volumeGroupRef)
$poolInstance.AddProperty("$MPElement[Name='NetAppSANtricity.StoragePool']/managingSystem$", $ManagingSystem)

# Add storage pool to discovery data
$discoveryData.AddInstance($poolInstance)

# Create relationship between storage pool and storage pool group
$relationshipInstance = $discoveryData.CreateRelationshipInstance("$MPElement[Name='NetAppSANtricity.StoragePoolRelationship']$")
$relationshipInstance.Source = $storagePoolGroupInstance
$relationshipInstance.Target = $poolInstance
$discoveryData.AddInstance($relationshipInstance)

#Adding health monitoring to the storage pool
$hsvcManagesSSubsystemRel = $discoveryData.CreateRelationshipInstance("$MPElement[Name='SC!Microsoft.SystemCenter.HealthServiceShouldManageEntity']$")
$hsvcManagesSSubsystemRel.Source = $healthSvc
$hsvcManagesSSubsystemRel.Target = $poolInstance
$discoveryData.AddInstance($hsvcManagesSSubsystemRel)

} # foreach ($storagePool in $allStoragePools)
} # if ($allStoragePools)

} # foreach ($array in $allArrays)

$arraysProcessed = $allArrays.Count

}

$logString = "Storage Array and Storage Pool Discovery Completed. Arrays processed: " + $arraysProcessed
$api.LogScriptEvent($ScriptName, $E_NBR_TRACE, $E_LVL_INFO, $logString)

# Send Discovery.Data to the output pipeline.
$discoveryData
</Script></ScriptBody>
<Parameters>
<Parameter>
<Name>sourceId</Name>
<Value>$MPElement$</Value>
</Parameter>
<Parameter>
<Name>managedEntityId</Name>
<Value>$Target/Id$</Value>
</Parameter>
</Parameters>
<TimeoutSeconds>420</TimeoutSeconds>
</DataSource>
</Discovery>