Discovering and monitoring SNMP tables [SNMP MP Chap 5] #scom #sysctr


It has been a while since I first wrote about SNMP monitoring with OpsMgr. In my last installment I left open the chance to build a more sophisticated module to better manage tables, since I didn’t receive many requests I left the chance on the table, until today. The bad guy that pushed me to go down this road is my fellow MVP Stanislav Zhelyazkov, we embarked in a project to monitor some Kemp devices. After all this time, I had to reread my post series especially regarding tables and it has been an unpleasant experience. Too complex and error prone.

So here I am announcing the QND.SNMP.Library (https://qndsnmp.codeplex.com/) downloadable on Technet Gallery. I published the project on Codeplex with the final goal to add more and more devices.

In this first release the library addresses SNMP tables discovering and monitoring, currently we have the following limitations:

          All the data is returned as String, numeric values are casted using the EN-US locale

          The SNMPv3 Context property is not used. This means SNMPv3 works perfectly until you have devices using Context property.

From http://tools.ietf.org/html/rfc5343

An SNMP context is a collection of management information accessible

by an SNMP entity.  An item of management information may exist in

more than one context and an SNMP entity potentially has access to

many contexts [RFC3411].  A context is identified by the snmpEngineID

value of the entity hosting the management information (also called a

contextEngineID) and a context name that identifies the specific

context (also called a contextName).

          The library has been tested with v2 and v3 devices

          The library currently supports simple tables (not nested ones)

The library uses an external SNMP engine for SNMP GET and WALK (https://sharpsnmplib.codeplex.com/) the management pack distributes the SharpSnmpLib.dll assembly.

The library exposes 3 modules:

          QND.SNMP.GetTable.DS – this data source returns a set of property bags with all the content of the table. Used in monitoring scenarios.

          QND.SNMP.TableDiscovery.DS – this is a filtered discovery provider to enumerate, filter and discover table entries

          QND.SNMP.GetTable.PT – this is the core module for table enumeration. It’s a public probe type that can be composed as you like

The official documentation for the modules is on the CodePlex project site. In this post I just want to show how the complex discovery and monitoring structure I detailed in https://nocentdocent.wordpress.com/2013/06/25/device-components-discovery-snmp-mp-chap-4-scom-sysctr/ is dramatically simplified with the module.

The three way discovery for disks can now be accomplished in just one step, and the monitoring part can now use cookdown walking the table just once instead of once for every disk.

Disk Discovery workflow in one step

<Discovery ID=Progel.LibraEsva.Disk.Discovery Enabled=true ConfirmDelivery=false Remotable=true Priority=Normal Target=Progel.LibraEsva.Device>

<Category>Discovery</Category>

<DiscoveryTypes>

   <DiscoveryClass TypeID=Progel.LibraEsva.Disk />

</DiscoveryTypes>

<DataSource ID=DS TypeID=Progel.LibraEsva.Disk.Discovery.MT>

   <IntervalSeconds>43200</IntervalSeconds>

   <SyncTime />

   <Timeout>3500</Timeout>

   <Port>$Target/Property[Type=”Network!System.NetworkManagement.Node”]/PortNumber$</Port>

   <IP>$Target/Property[Type=”Network!System.NetworkManagement.Node”]/SNMPAddress$</IP>           

<CommunityString>$RunAs[Name=”Network!System.NetworkManagement.Snmp.MonitoringAccount”]/CommunityString$$Target/Property[Type=”Network!System.NetworkManagement.Node”]/VirtualCommunitySuffix$</CommunityString>

   <Version>$Target/Property[Type=”Network!System.NetworkManagement.Node”]/SNMPVersion$</Version>

   <DeviceKey>$Target/Property[Type=”Network!System.NetworkManagement.Node”]/DeviceKey$</DeviceKey>

   <TraceLevel>2</TraceLevel>

   <ProbeTimeoutSeconds>300</ProbeTimeoutSeconds>

</DataSource>

</Discovery>

 

The data source module used by the discovery is based on QND.SNMP.TableDiscovery.DS where the bulk of the code is SNMP parameters copy and paste and data mapping to create the disk instances. As you can read the TableDiscovery DS implements a filter that can be natively used to filter out not needed instances, I highlighted the relevant code:

Disk discovery data source

      <DataSourceModuleType ID=Progel.LibraEsva.Disk.Discovery.MT Accessibility=Public Batching=false>

        <Configuration>

          <xsd:element minOccurs=1 name=IntervalSeconds type=xsd:integer />

          <xsd:element minOccurs=0 name=SyncTime type=xsd:string />

          <xsd:element minOccurs=0 maxOccurs=1 name=Timeout type=xsd:unsignedInt default=500 />

          <xsd:element minOccurs=0 maxOccurs=1 name=Port type=xsd:unsignedInt default=161 />

          <xsd:element name=IP type=xsd:string />

          <xsd:element name=CommunityString type=xsd:string />

          <xsd:element minOccurs=0 maxOccurs=1 name=Version type=xsd:string />

          <xsd:element minOccurs=1 name=DeviceKey type=xsd:string />

          <xsd:element minOccurs=0 name=TraceLevel type=xsd:integer default=2 xmlns:xsd=http://www.w3.org/2001/XMLSchema />

          <xsd:element minOccurs=0 name=ProbeTimeoutSeconds type=xsd:integer default=300 xmlns:xsd=http://www.w3.org/2001/XMLSchema />

        </Configuration>

        <OverrideableParameters>

          <OverrideableParameter ID=IntervalSeconds Selector=$Config/IntervalSeconds$ ParameterType=int />

          <OverrideableParameter ID=SyncTime Selector=$Config/SyncTime$ ParameterType=string />

          <OverrideableParameter ID=Timeout Selector=$Config/IntervalSeconds$ ParameterType=int />

          <OverrideableParameter ID=TraceLevel Selector=$Config/TraceLevel$ ParameterType=int />

          <OverrideableParameter ID=ProbeTimeoutSeconds Selector=$Config/ProbeTimeoutSeconds$ ParameterType=int />

        </OverrideableParameters>

        <ModuleImplementation Isolation=Any>

          <Composite>

            <MemberModules>

              <DataSource ID=GetDisks TypeID=QSNMP!QND.SNMP.TableDiscovery.DS>

                <NoOfRetries>3</NoOfRetries>

                <Timeout>$Config/Timeout$</Timeout>

                <Port>$Config/Port$</Port>

                <SNMPv3UserName>$RunAs[Name=”Network!System.NetworkManagement.SnmpV3.MonitoringAccount”]/UserName$</SNMPv3UserName>

                <SNMPv3AuthProtocol>$RunAs[Name=”Network!System.NetworkManagement.SnmpV3.MonitoringAccount”]/AuthenticationProtocol$</SNMPv3AuthProtocol>

                <SNMPv3AuthPassword>$RunAs[Name=”Network!System.NetworkManagement.SnmpV3.MonitoringAccount”]/AuthenticationKey$</SNMPv3AuthPassword>

                <SNMPv3PrivProtocol>$RunAs[Name=”Network!System.NetworkManagement.SnmpV3.MonitoringAccount”]/PrivacyProtocol$</SNMPv3PrivProtocol>

                <SNMPv3PrivPassword>$RunAs[Name=”Network!System.NetworkManagement.SnmpV3.MonitoringAccount”]/PrivacyKey$</SNMPv3PrivPassword>

                <SNMPv3ContextName>$RunAs[Name=”Network!System.NetworkManagement.SnmpV3.MonitoringAccount”]/ContextName$</SNMPv3ContextName>

                <IP>$Config/IP$</IP>

                <CommunityString>$Config/CommunityString$</CommunityString>

                <Version>$Config/Version$</Version>

                <TableOID>.1.3.6.1.2.1.25.2.3.1</TableOID> This is the table starting OID

                <TableIndex>1</TableIndex> This is the table entry OID for the index i.e. TableOID.TableIndex

                <TraceLevel>$Config/TraceLevel$</TraceLevel>

                <ScriptTimeoutSeconds>$Config/ProbeTimeoutSeconds$</ScriptTimeoutSeconds>

                <IntervalSeconds>$Config/IntervalSeconds$</IntervalSeconds>

                <SyncTime>$Config/SyncTime$</SyncTime>

                <Filter> Here we filter for disks only

                  <SimpleExpression>

                    <ValueExpression>

                      <XPathQuery Type=String>Property[@Name=’.1.3.6.1.2.1.25.2.3.1.2′]</XPathQuery>

                    </ValueExpression>

                    <Operator>Equal</Operator>

                    <ValueExpression>

                      <Value>.1.3.6.1.2.1.25.2.1.4</Value>

                    </ValueExpression>

                  </SimpleExpression>

                </Filter>

                <ClassId>$MPElement[Name=’Progel.LibraEsva.Disk’]$</ClassId>

                <InstanceSettings> From here on we’re just mapping the returned property bags to the proper fields

                  <Settings>

                    <Setting>

                      <Name>$MPElement[Name=’Network!System.NetworkManagement.Node’]/DeviceKey$</Name>

                      <Value>$Config/DeviceKey$</Value>

                    </Setting>

                    <Setting>

                      <Name>$MPElement[Name=’Network!System.NetworkManagement.LogicalDevice’]/Key$</Name>

                      <Value>Disk-.1.3.6.1.2.1.25.2.3.1.1.$Data/Property[@Name=’Index’]$</Value>

                    </Setting>

                    <Setting>

                      <Name>$MPElement[Name=’Network!System.NetworkManagement.Disk’]/Removable$</Name>

                      <Value>false</Value>

                    </Setting>

                    <Setting>

                      <Name>$MPElement[Name=’Network!System.NetworkManagement.LogicalDevice’]/Index$</Name>

                      <Value>$Data/Property[@Name=”Index”]$</Value>

                    </Setting>

                    <Setting>

                      <Name>$MPElement[Name=’Network!System.NetworkManagement.LogicalDevice’]/Description$</Name>

                      <Value>$Data/Property[@Name=’.1.3.6.1.2.1.25.2.3.1.3′]$</Value>

                    </Setting>

                    <Setting>

                      <Name>$MPElement[Name=’System!System.Entity’]/DisplayName$</Name>

                      <Value>Disk – $Data/Property[@Name=’.1.3.6.1.2.1.25.2.3.1.3′]$</Value>

                    </Setting>

                    <Setting>

                      <Name>$MPElement[Name=’Network!System.NetworkManagement.Disk’]/Capacity$</Name>

                      <Value>$Data/Property[@Name=’.1.3.6.1.2.1.25.2.3.1.5′]$</Value>

                    </Setting>

                    <Setting>

                      <Name>$MPElement[Name=’Progel.LibraEsva.Disk’]/AllocationUnitSize$</Name>

                      <Value>$Data/Property[@Name=’.1.3.6.1.2.1.25.2.3.1.4′]$</Value>

                    </Setting>

                  </Settings>

                </InstanceSettings>

              </DataSource>

            </MemberModules>

            <Composition>

              <Node ID=GetDisks />

            </Composition>

          </Composite>

        </ModuleImplementation>

        <OutputType>System!System.Discovery.Data</OutputType>

      </DataSourceModuleType>

 

The new disk monitor uses QND.SNMP.GetTable.DS as its data source, the data source doesn’t have the device index in its parameters so it can be cooked down by the HealthService logic, the monitor can then filter just the property bag instance needed and do all the math that it needs. Again the peculiarities are highlighted in the code.

Disk free space Unit Monitor Type

<UnitMonitorType ID=Progel.LibraEsva.DiskFreeSpace.MT Accessibility=Internal>

<MonitorTypeStates>

  <MonitorTypeState ID=AboveThreshold NoDetection=false />

  <MonitorTypeState ID=UnderThreshold NoDetection=false />

</MonitorTypeStates>

<Configuration>

  <xsd:element minOccurs=1 name=IntervalSeconds type=xsd:integer xmlns:xsd=http://www.w3.org/2001/XMLSchema />

  <xsd:element minOccurs=0 name=SyncTime type=xsd:string xmlns:xsd=http://www.w3.org/2001/XMLSchema />

  <xsd:element minOccurs=0 maxOccurs=1 name=Timeout type=xsd:unsignedInt default=500 xmlns:xsd=http://www.w3.org/2001/XMLSchema />

  <xsd:element minOccurs=0 maxOccurs=1 name=Port type=xsd:unsignedInt default=161 xmlns:xsd=http://www.w3.org/2001/XMLSchema />

  <xsd:element name=IP type=xsd:string xmlns:xsd=http://www.w3.org/2001/XMLSchema />

  <xsd:element name=CommunityString type=xsd:string xmlns:xsd=http://www.w3.org/2001/XMLSchema />

  <xsd:element minOccurs=0 maxOccurs=1 name=Version type=xsd:string xmlns:xsd=http://www.w3.org/2001/XMLSchema />

  <xsd:element minOccurs=1 name=LogicalDeviceIndex type=xsd:string xmlns:xsd=http://www.w3.org/2001/XMLSchema />

  <xsd:element minOccurs=1 name=Threshold type=xsd:integer xmlns:xsd=http://www.w3.org/2001/XMLSchema />

  <xsd:element minOccurs=1 name=NumberOfSamples type=xsd:integer xmlns:xsd=http://www.w3.org/2001/XMLSchema />

  <xsd:element minOccurs=0 name=TraceLevel type=xsd:integer default=2 xmlns:xsd=http://www.w3.org/2001/XMLSchema />

  <xsd:element minOccurs=0 name=ProbeTimeoutSeconds type=xsd:integer default=300 xmlns:xsd=http://www.w3.org/2001/XMLSchema />

</Configuration>

<OverrideableParameters>

  <OverrideableParameter ID=IntervalSeconds Selector=$Config/IntervalSeconds$ ParameterType=int />

  <OverrideableParameter ID=SyncTime Selector=$Config/SyncTime$ ParameterType=string />

  <OverrideableParameter ID=Timeout Selector=$Config/IntervalSeconds$ ParameterType=int />

  <OverrideableParameter ID=Threshold Selector=$Config/Threshold$ ParameterType=int />

  <OverrideableParameter ID=NumberOfSamples Selector=$Config/NumberOfSamples$ ParameterType=int />

  <OverrideableParameter ID=TraceLevel Selector=$Config/TraceLevel$ ParameterType=int />

  <OverrideableParameter ID=ProbeTimeoutSeconds Selector=$Config/ProbeTimeoutSeconds$ ParameterType=int />

</OverrideableParameters>

<MonitorImplementation>

  <MemberModules>

    <DataSource ID=DS TypeID=QSNMP!QND.SNMP.GetTable.DS>

      <NoOfRetries>3</NoOfRetries>

      <Timeout>$Config/Timeout$</Timeout>

      <Port>$Config/Port$</Port>

      <SNMPv3UserName>$RunAs[Name=”Network!System.NetworkManagement.SnmpV3.MonitoringAccount”]/UserName$</SNMPv3UserName>

      <SNMPv3AuthProtocol>$RunAs[Name=”Network!System.NetworkManagement.SnmpV3.MonitoringAccount”]/AuthenticationProtocol$</SNMPv3AuthProtocol>

      <SNMPv3AuthPassword>$RunAs[Name=”Network!System.NetworkManagement.SnmpV3.MonitoringAccount”]/AuthenticationKey$</SNMPv3AuthPassword>

      <SNMPv3PrivProtocol>$RunAs[Name=”Network!System.NetworkManagement.SnmpV3.MonitoringAccount”]/PrivacyProtocol$</SNMPv3PrivProtocol>

      <SNMPv3PrivPassword>$RunAs[Name=”Network!System.NetworkManagement.SnmpV3.MonitoringAccount”]/PrivacyKey$</SNMPv3PrivPassword>

      <SNMPv3ContextName>$RunAs[Name=”Network!System.NetworkManagement.SnmpV3.MonitoringAccount”]/ContextName$</SNMPv3ContextName>

      <IP>$Config/IP$</IP>

      <CommunityString>$Config/CommunityString$</CommunityString>

      <Version>$Config/Version$</Version>

      <TableOID>.1.3.6.1.2.1.25.2.3.1</TableOID> Tabel entry point and Index dimension

      <TableIndex>1</TableIndex>

      <TraceLevel>$Config/TraceLevel$</TraceLevel>

      <ScriptTimeoutSeconds>$Config/ProbeTimeoutSeconds$</ScriptTimeoutSeconds>

      <IntervalSeconds>$Config/IntervalSeconds$</IntervalSeconds>

      <SyncTime>$Config/SyncTime$</SyncTime>

    </DataSource>

    <ConditionDetection ID=FilterIndex TypeID=System!System.ExpressionFilter> Condition detection to get just the needed property bag

      <Expression>

        <SimpleExpression>

          <ValueExpression>

            <XPathQuery Type=String>Property[@Name=’Index’]</XPathQuery>

          </ValueExpression>

          <Operator>Equal</Operator>

          <ValueExpression>

            <Value>$Config/LogicalDeviceIndex$</Value>

          </ValueExpression>

        </SimpleExpression>

      </Expression>

    </ConditionDetection>

 

Hope this new module can ease SNMP monitoring MPs.

Let me know.

  • Daniele This posting is provided “AS IS” with no warranties, and confers no rights.
Advertisements
  1. #1 by Brian MIller on December 20, 2017 - 6:32 pm

    Hello,

    I am working on creating a management pack that monitors emc isilon quotas. The discovery is failing with this error message, any ideas?

    The constructor for the managed module type “Microsoft.EnterpriseManagement.Modules.PowerShell.PowerShellProbeActionModule” threw an exception. This module was running in rule “CSI.Isilon.Monitoring.Quota.Discovery” running for instance “Pad-Isilon2-1″ with id:”{B023A970-53A6-67EA-10B5-4F85619B107F}” in management group “CSI-Int”.

    The exception text is:
    Microsoft.EnterpriseManagement.HealthService.ModuleException: Failed to parse module configuration, please see inner exception for details. —> System.Xml.XmlException: ‘EndElement’ is an invalid XmlNodeType. Line 225, position 652.
    at System.Xml.XmlReader.ReadElementString(String name)
    at Microsoft.EnterpriseManagement.Modules.PowerShell.PowerShellProbeActionModule.ReadParametersXml(XmlReader reader)
    at Microsoft.EnterpriseManagement.Modules.PowerShell.PowerShellProbeActionModule..ctor(ModuleHost`1 moduleHost, XmlReader configuration, Byte[] previousState)
    — End of inner exception stack trace —
    at Microsoft.EnterpriseManagement.Modules.PowerShell.PowerShellProbeActionModule..ctor(ModuleHost`1 moduleHost, XmlReader configuration, Byte[] previousState)

    Thank You,
    Brian

    • #2 by Daniele Grandini on December 22, 2017 - 11:17 am

      do you have any optional param in your powershell script that you’re not explicitly passing in?

      • #3 by Brian MIller on December 22, 2017 - 11:28 am

        Hello,

        Thank you for your quick reply, yes that was the problem, i did not create the snmpv3 tags as we are only using snmpv2.

        Thank You,

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

%d bloggers like this: