Drive Discovery

NetAppSANtricity.NetAppSANtricity.DriveDiscovery (Discovery)

Description for the new discovery.

Element properties:

TargetNetAppSANtricity.StoragePool
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.DriveDiscovery" Target="NetAppSANtricity.StoragePool" Enabled="true" ConfirmDelivery="false" Remotable="true" Priority="Normal">
<Category>Discovery</Category>
<DiscoveryTypes>
<DiscoveryClass TypeID="NetAppSANtricity.VolumesGroup"/>
<DiscoveryClass TypeID="NetAppSANtricity.Volume"/>
<DiscoveryClass TypeID="NetAppSANtricity.SnapshotVolume"/>
</DiscoveryTypes>
<DataSource ID="DS" TypeID="Windows!Microsoft.Windows.TimedPowerShell.DiscoveryProvider">
<IntervalSeconds>3600</IntervalSeconds>
<SyncTime>06:40</SyncTime>
<ScriptName>DriveDiscovery.ps1</ScriptName>
<ScriptBody><Script>##############################################################################
# Copyright (c) 2015 NetApp Inc.
# All rights reserved.
#
# DriveDiscovery.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 GetDriveTypeString($value)
{
if ($value -eq "fibre")
{
$result = "Fibre"
}
elseif ($value -eq "sas")
{
$result = "SAS"
}
elseif ($value -eq "scsi")
{
$result = "SCSI"
}
elseif ($value -eq "sata")
{
$result = "SATA"
}
elseif ($value -eq "unknown")
{
$result = "Unknown"
}
else
{
$result = $value
}
return $result
}

function GetDriveMediaTypeString($value)
{
if ($value -eq "hdd")
{
$result = "HDD"
}
elseif ($value -eq "ssd")
{
$result = "SSD"
}
elseif ($value -eq "all")
{
$result = "All"
}
elseif ($value -eq "unknown")
{
$result = "Unknown"
}
else
{
$result = $value
}
return $result
}

function GetRPM($value)
{
if ($value -ne 0)
{
return ("" + $value + " RPM")
}
else
{
return "N/A"
}
}

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 is currently Storage Pool. It will be easier to create relationships then
#&gt;

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

$arrayWWN = '$Target/Property[Type="NetAppSANtricity.StoragePool"]/storageArrayWwn$'
$arrayName = '$Target/Property[Type="NetAppSANtricity.StoragePool"]/storageArrayName$'

$poolWWN = '$Target/Property[Type="NetAppSANtricity.StoragePool"]/wwn$'
$poolName = '$Target/Property[Type="System!System.Entity"]/DisplayName$'
$poolVolGroupRef = '$Target/Property[Type="NetAppSANtricity.StoragePool"]/volumeGroupRef$'
$arraySystem = '$Target/Property[Type="NetAppSANtricity.StoragePool"]/managingSystem$'

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

# 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/"

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

# Create Drives Group object to act as container for Drives
$drivesGroupInstance = $discoveryData.CreateClassInstance("$MPElement[Name='NetAppSANtricity.DrivesGroup']$")

# Adding properties that associate DriveGroup with its parent StoragePool
$drivesGroupInstance.AddProperty("$MPElement[Name='NetAppSANtricity.DrivesGroup']/storagePoolWwn$", $poolWWN)
$drivesGroupInstance.AddProperty("$MPElement[Name='NetAppSANtricity.DrivesGroup']/storagePoolName$", $poolName)
$drivesGroupInstance.AddProperty("$MPElement[Name='System!System.Entity']/DisplayName$", "Drives")

#Add key properties of parent storage pool
$drivesGroupInstance.AddProperty("$MPElement[Name='NetAppSANtricity.StoragePool']/wwn$", $poolWWN)

$discoveryData.AddInstance($drivesGroupInstance)

# Get HwInventory for use with determining tray/drawer/slot information
$url = ""
$url = $baseUrl + $arrayWWN + "/hardware-inventory/"
$hwInventory = Invoke-RestMethod $url -Credential $cred
if ($hwInventory.GetType().FullName -eq "System.String")
{
$hwInventory = $javaScriptSerializer.DeserializeObject($hwInventory)
}
$hwTrays = $hwInventory.trays

# Get the drives that are associated with this Storage Pool
$url = ""
$url = $baseUrl + $arrayWWN + "/drives/"
$allDrives = Invoke-RestMethod $url -Credential $cred
if ($allDrives.GetType().FullName -eq "System.String")
{
$allDrives = $javaScriptSerializer.DeserializeObject($allDrives)
}

foreach ($drive in $allDrives)
{
if ($drive.currentVolumeGroupRef -eq $poolVolGroupRef)
{
# Loop through hwInventory/trays
foreach($hwTray in $hwTrays)
{
if ($hwTray.trayRef -eq $drive.physicalLocation.trayRef)
{
$foundTray = $hwTray
}
}
$trayLabel = "" + $foundTray.trayId + "/"
$slotLabel = $drive.physicalLocation.locationPosition
# if the componentType is a tray, then there are no drawers, and thus set it to 0
if ($drive.physicalLocation.locationParent.typedReference.componentType -eq "tray")
{
$drawerLabel = "0/"
}
elseif ($drive.physicalLocation.locationParent.typedReference.componentType -eq "drawer")
{
# Find drawer by looking at symbolRef
$symbolRef = $drive.physicalLocation.locationParent.typedReference.symbolRef
# Drawer # is the 21st # in the symbolRef - this is cheesy, fix it!
$symbolRef = $symbolRef.substring(21,1)
$drawerLabel = $symbolRef + "/"
}
$driveLabel = $trayLabel + $drawerLabel + $slotLabel

# Split the label up to get tray, drawer, and slot
$dts = $driveLabel + " (Tray/Drawer/Slot)"

# Create drive object
$driveInstance = $discoveryData.CreateClassInstance("$MPElement[Name='NetAppSANtricity.Drive']$")
$driveInstance.AddProperty("$MPElement[Name='System!System.Entity']/DisplayName$", $driveLabel)
$driveInstance.AddProperty("$MPElement[Name='NetAppSANtricity.Drive']/status$", (GetStateStatusString $drive.status))
$driveInstance.AddProperty("$MPElement[Name='NetAppSANtricity.Drive']/location$", $dts)
$driveInstance.AddProperty("$MPElement[Name='NetAppSANtricity.Drive']/manufacturer$", $drive.manufacturer)
$driveInstance.AddProperty("$MPElement[Name='NetAppSANtricity.Drive']/productID$", $drive.productID)
$driveInstance.AddProperty("$MPElement[Name='NetAppSANtricity.Drive']/softwareVersion$", $drive.softwareVersion)
$driveInstance.AddProperty("$MPElement[Name='NetAppSANtricity.Drive']/rawCapacity$", (GetFormattedSize $drive.rawCapacity))
$driveInstance.AddProperty("$MPElement[Name='NetAppSANtricity.Drive']/worldWideName$", $drive.worldWideName)
$driveInstance.AddProperty("$MPElement[Name='NetAppSANtricity.Drive']/phyDriveType$", (GetDriveTypeString $drive.phyDriveType))
$driveInstance.AddProperty("$MPElement[Name='NetAppSANtricity.Drive']/storageArrayName$", $arrayName)
$driveInstance.AddProperty("$MPElement[Name='NetAppSANtricity.Drive']/storagePoolName$", $poolName)
$discoveryData.AddInstance($driveInstance)

# Create relationship between drive and drives group
$relationshipInstance = $discoveryData.CreateRelationshipInstance("$MPElement[Name='NetAppSANtricity.DriveRelationship']$")
$relationshipInstance.Source = $drivesGroupInstance
$relationshipInstance.Target = $driveInstance
$discoveryData.AddInstance($relationshipInstance)

#Create health service associated to drive
$hsvcManagesSSubsystemRel = $discoveryData.CreateRelationshipInstance("$MPElement[Name='SC!Microsoft.SystemCenter.HealthServiceShouldManageEntity']$")
$hsvcManagesSSubsystemRel.Source = $healthSvc
$hsvcManagesSSubsystemRel.Target = $driveInstance
$discoveryData.AddInstance($hsvcManagesSSubsystemRel)
}
} # foreach ($drive in $allDrives)

if ( $Trace )
{
$logString = "Drive Discovery for array: " + $arrayName + " Completed. Drives processed: " + $allDrives.Count
$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>