AMG Discovery

NetAppSANtricity.NetAppSANtricity.AMGDiscovery (Discovery)

Description for the new discovery.

Element properties:

TargetNetAppSANtricity.StorageArray
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.AMGDiscovery" Target="NetAppSANtricity.StorageArray" Enabled="true" ConfirmDelivery="false" Remotable="true" Priority="Normal">
<Category>Discovery</Category>
<DiscoveryTypes>
<DiscoveryClass TypeID="NetAppSANtricity.AMGPair"/>
<DiscoveryClass TypeID="NetAppSANtricity.AMGsGroup"/>
<DiscoveryClass TypeID="NetAppSANtricity.AMG"/>
</DiscoveryTypes>
<DataSource ID="DS" TypeID="Windows!Microsoft.Windows.TimedPowerShell.DiscoveryProvider">
<IntervalSeconds>3600</IntervalSeconds>
<SyncTime>06:30</SyncTime>
<ScriptName>AMGDiscovery.ps1</ScriptName>
<ScriptBody><Script>##############################################################################
# Copyright (c) 2015 NetApp Inc.
# All rights reserved.
#
# AMGDiscovery.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 GetAmgRoleString($value)
{
if ($value -eq "primary")
{
$result = "Primary"
}
elseif ($value -eq "secondary")
{
$result = "Secondary"
}
elseif ($value -eq "unknown")
{
$result = "Unknown"
}
else
{
$result = $value
}
return $result
}

function GetAmgRoleChangeProgressString($value)
{
if ($value -eq "none")
{
$result = "None"
}
elseif ($value -eq "pending")
{
$result = "Pending"
}
elseif ($value -eq "inprogress")
{
$result = "In Progress"
}
elseif ($value -eq "unknown")
{
$result = "Unknown"
}
else
{
$result = $value
}
return $result
}

function GetAmgSyncActivityString($value)
{
if ($value -eq "idle")
{
$result = "Idle"
}
elseif ($value -eq "active")
{
$result = "Active"
}
elseif ($value -eq "paused")
{
$result = "Paused"
}
elseif ($value -eq "userSuspended")
{
$result = "User Suspended"
}
elseif ($value -eq "internallySuspended")
{
$result = "Internally Suspended"
}
elseif ($value -eq "unknown")
{
$result = "Unknown"
}
else
{
$result = $value
}
return $result
}

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

function GetDateFromEpoch($epochTime)
{
$temp = ( [timezone]::CurrentTimeZone.ToLocalTime(([datetime]'1/1/1970').AddSeconds($epochTime)) )
$format = GetDateFormatString
return $temp.ToString($format)
}

function GetPercentageString($value)
{
return ("" + $value + "%")
}

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 StorageArray
#&gt;

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

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

$arrayWWN = '$Target/Property[Type="NetAppSANtricity.StorageArray"]/wwn$'
$arrayName = '$Target/Property[Type="NetAppSANtricity.StorageArray"]/friendlyName$'
$arraySystem = '$Target/Property[Type="NetAppSANtricity.StorageArray"]/MonitoringSystem$'

# 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)

try
{
# Get the AMGs for this array
$url = ""
$url = $baseUrl + $arrayWWN + "/async-mirrors/"
$allAmgs = Invoke-RestMethod $url -Credential $cred

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

# Get all the volumes in this array. This data is used to get the AMG pair name
$url = ""
$url = $baseUrl + $arrayWWN + "/volumes/"
$allVolumes = Invoke-RestMethod $url -Credential $cred
if ($allVolumes.GetType().FullName -eq "System.String")
{
$allVolumes = $javaScriptSerializer.DeserializeObject($allVolumes)
}

if ($allAmgs)
{
# Create AMGs Group object to act as container for AMGs
$amgGroupInstance = $discoveryData.CreateClassInstance("$MPElement[Name='NetAppSANtricity.AMGsGroup']$")

# Adding properties that associate AMGsGroup with its parent Storage Array
$amgGroupInstance.AddProperty("$MPElement[Name='NetAppSANtricity.AMGsGroup']/arrayWwn$", $arrayWWN)
$amgGroupInstance.AddProperty("$MPElement[Name='NetAppSANtricity.AMGsGroup']/arrayName$", $arrayName)
$amgGroupInstance.AddProperty("$MPElement[Name='System!System.Entity']/DisplayName$", "AMGs")

#Adding key properties of parent Storage Array
$amgGroupInstance.AddProperty("$MPElement[Name='NetAppSANtricity.StorageArray']/wwn$", $arrayWWN)
$amgGroupInstance.AddProperty("$MPElement[Name='NetAppSANtricity.StorageArray']/MonitoringSystem$", $arraySystem)

$discoveryData.AddInstance($amgGroupInstance)

foreach ($amg in $allAmgs)
{
# Create AMG object
$amgInstance = $discoveryData.CreateClassInstance("$MPElement[Name='NetAppSANtricity.AMG']$")
$amgInstance.AddProperty("$MPElement[Name='System!System.Entity']/DisplayName$", $amg.label)
$amgInstance.AddProperty("$MPElement[Name='NetAppSANtricity.AMG']/groupRef$", $amg.groupRef)
$amgInstance.AddProperty("$MPElement[Name='NetAppSANtricity.AMG']/worldWideName$", $amg.worldWideName)
$amgInstance.AddProperty("$MPElement[Name='NetAppSANtricity.AMG']/groupState$", (GetStateStatusString $amg.groupState))
$amgInstance.AddProperty("$MPElement[Name='NetAppSANtricity.AMG']/localRole$", (GetAmgRoleString $amg.localRole))
$amgInstance.AddProperty("$MPElement[Name='NetAppSANtricity.AMG']/remoteRole$", (GetAmgRoleString $amg.remoteRole))
$amgInstance.AddProperty("$MPElement[Name='NetAppSANtricity.AMG']/roleChangeProgress$", (GetAmgRoleChangeProgressString $amg.roleChangeProgress))
$amgInstance.AddProperty("$MPElement[Name='NetAppSANtricity.AMG']/syncIntervalMinutes$", $amg.syncIntervalMinutes)
$amgInstance.AddProperty("$MPElement[Name='NetAppSANtricity.AMG']/syncCompletionTimeAlertThresholdMinutes$", $amg.syncCompletionTimeAlertThresholdMinutes)
$amgInstance.AddProperty("$MPElement[Name='NetAppSANtricity.AMG']/recoveryPointAgeAlertThresholdMinutes$", $amg.recoveryPointAgeAlertThresholdMinutes)
$amgInstance.AddProperty("$MPElement[Name='NetAppSANtricity.AMG']/repositoryUtilizationWarnThreshold$", (GetPercentageString $amg.repositoryUtilizationWarnThreshold))
$amgInstance.AddProperty("$MPElement[Name='NetAppSANtricity.AMG']/syncActivity$", (GetAmgSyncActivityString $amg.syncActivity))
$amgInstance.AddProperty("$MPElement[Name='NetAppSANtricity.AMG']/orphanGroup$", (GetTrueFalseString $amg.orphanGroup))
$amgInstance.AddProperty("$MPElement[Name='NetAppSANtricity.AMG']/storageArrayName$", $arrayName)
$discoveryData.AddInstance($amgInstance)

# Create relationship between AMG and AMG Group
$relationshipInstance = $discoveryData.CreateRelationshipInstance("$MPElement[Name='NetAppSANtricity.AMGRelationship']$")
$relationshipInstance.Source = $amgGroupInstance
$relationshipInstance.Target = $amgInstance
$discoveryData.AddInstance($relationshipInstance)

#Create health service associated to amg
$hsvcManagesSSubsystemRel = $discoveryData.CreateRelationshipInstance("$MPElement[Name='SC!Microsoft.SystemCenter.HealthServiceShouldManageEntity']$")
$hsvcManagesSSubsystemRel.Source = $healthSvc
$hsvcManagesSSubsystemRel.Target = $amgInstance
$discoveryData.AddInstance($hsvcManagesSSubsystemRel)

# Get the AMG pairs for this AMG
$url = ""
$url = $baseUrl + $arrayWwn + "/async-mirrors/" + $amg.groupRef + "/pairs/"
$pairs = Invoke-RestMethod $url -Credential $cred
if ($pairs.GetType().FullName -eq "System.String")
{
$pairs = $javaScriptSerializer.DeserializeObject($pairs)
}

foreach ($pair in $pairs)
{
# Search for the volume labels corresponding to $pair.localVolume and $pair.remoteVolume to get their labels
$private:localVolumeName = ""
foreach($volume in $allVolumes)
{
if ($volume.volumeRef -eq $pair.localVolume)
{
$localVolumeName = $volume.label
break
}
}

# Create amg pair object
$amgPairInstance = $discoveryData.CreateClassInstance("$MPElement[Name='NetAppSANtricity.AMGPair']$")
$amgPairInstance.AddProperty("$MPElement[Name='System!System.Entity']/DisplayName$", $localVolumeName)
$amgPairInstance.AddProperty("$MPElement[Name='NetAppSANtricity.AMGPair']/localVolume$", $pair.localVolume)
$amgPairInstance.AddProperty("$MPElement[Name='NetAppSANtricity.AMGPair']/remoteVolume$", $pair.remoteVolume)
$amgPairInstance.AddProperty("$MPElement[Name='NetAppSANtricity.AMGPair']/memberState$", (GetStateStatusString $pair.memberState))
$amgPairInstance.AddProperty("$MPElement[Name='NetAppSANtricity.AMGPair']/lastRecoveryPointTime$", (GetDateFromEpoch $pair.lastRecoveryPointTime))
$amgPairInstance.AddProperty("$MPElement[Name='NetAppSANtricity.AMGPair']/overUtilizationWarnThreshold$", (GetTrueFalseString $pair.overUtilizationWarnThreshold))
$amgPairInstance.AddProperty("$MPElement[Name='NetAppSANtricity.AMGPair']/worldWideName$", $pair.worldWideName)
$amgPairInstance.AddProperty("$MPElement[Name='NetAppSANtricity.AMGPair']/repositoryFull$", (GetTrueFalseString $pair.repositoryFull))
$amgPairInstance.AddProperty("$MPElement[Name='NetAppSANtricity.AMGPair']/storageArrayName$", $arrayName)
$discoveryData.AddInstance($amgPairInstance)

# Create relationship between AMG pair and this AMG
$relationshipInstance = $discoveryData.CreateRelationshipInstance("$MPElement[Name='NetAppSANtricity.AMGPairRelationship']$")
$relationshipInstance.Source = $amgInstance
$relationshipInstance.Target = $amgPairInstance
$discoveryData.AddInstance($relationshipInstance)

#Create health service associated to amg pairs
$hsvcManagesSSubsystemRel = $discoveryData.CreateRelationshipInstance("$MPElement[Name='SC!Microsoft.SystemCenter.HealthServiceShouldManageEntity']$")
$hsvcManagesSSubsystemRel.Source = $healthSvc
$hsvcManagesSSubsystemRel.Target = $amgPairInstance
$discoveryData.AddInstance($hsvcManagesSSubsystemRel)

} # foreach ($pair in $pairs)

} # foreach ($amg in $amgs)
} # if ($amgs)

}
catch
{
# If the array is offline/unreachable then trying to get the AMGs causes an error.
}

if ( $Trace )
{
$logString = "AMG and AMG Pair Discovery for array: " + $arrayName + " Completed. AMGs processed: " + $amgs.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>