SCOM Advanced Authoring: TCP Port Monitoring

It’s been long time since I blogged about SCOM Authoring. Following the Blog Post on PowerShell Discovery from CSV File I got numerous feedback from fellow techies to complete the TCP Port Monitoring MP with monitors and rules. One of our friend even has created an MP which he has blogged out here. Anyways, I thought it would be good to finish what I started with detailed explanation. Better Late than Never! When we start talking about creating Custom Monitors and Rules in SCOM, we must understand how they are structured. Monitors: Each Monitor is based on a Monitor Type where you define the number of states (two or three) and their criteria along with necessary modules. Rules: Rules are built on top of modules directly. To understand about modules, please take a minute to go through the WIKI article. Coming back to the scenario, now we must build 4 Monitors and 1 Rule.

  • TCP Unreachable Monitor
  • TCP Timeout Monitor
  • DNS Resolution Monitor
  • Connection Refused Monitor
  • Connection Time Performance Collection Rule

This means, we must build 4 Monitor Types on top of which 4 Monitors can be created. For all 4 Monitors and 1 Rule, the Data Source is same (i.e., Synthetic Transaction to test port connectivity). So, we will start with creating a Data Source following with 4 Monitor Types and finally our 4 Monitors and a Rule.

Data Source

Below is the XML fragment for the Data Source Module. We use System.SimpleScheduler Data Source module and “Microsoft.SystemCenter.SyntheticTransactions.TCPPortCheckProbe” probe action module to create composite Data Source. As discussed in previous blog posts, we promote the fields that are customizable such as “IntervalSeconds”, “SyncTime”,”ServerName” and “Port”.

 <DataSourceModuleType ID="GKLab.TCP.Port.Monitoring.Monitoring.DataSource" Accessibility="Internal" Batching="false">
        <Configuration>
          <xsd:element minOccurs="1" name="IntervalSeconds" type="xsd:integer" />
          <xsd:element minOccurs="1" name="SyncTime" type="xsd:string" />
          <xsd:element minOccurs="1" name="ServerName" type="xsd:string" />
          <xsd:element minOccurs="1" name="Port" type="xsd:integer" />
        </Configuration>
        <OverrideableParameters>
          <OverrideableParameter ID="IntervalSeconds" Selector="$Config/IntervalSeconds$" ParameterType="int" />
        </OverrideableParameters>
        <ModuleImplementation Isolation="Any">
          <Composite>
            <MemberModules>
              <DataSource ID="DS" TypeID="System!System.SimpleScheduler">
                <IntervalSeconds>$Config/IntervalSeconds
lt;/IntervalSeconds> 
                <SyncTime>$Config/SyncTime
lt;/SyncTime> 
              </DataSource>
              <ProbeAction ID="Probe" TypeID="MicrosoftSystemCenterSyntheticTransactionsLibrary!Microsoft.SystemCenter.SyntheticTransactions.TCPPortCheckProbe">
                <ServerName>$Config/ServerName
lt;/ServerName> 
                <Port>$Config/Port
lt;/Port> 
              </ProbeAction>
            </MemberModules>
            <Composition>
              <Node ID="Probe">
                <Node ID="DS" />
              </Node>
            </Composition>
          </Composite>
        </ModuleImplementation>
        <OutputType>MicrosoftSystemCenterSyntheticTransactionsLibrary!Microsoft.SystemCenter.SyntheticTransactions.TCPPortCheckData</OutputType>
      </DataSourceModuleType>

Monitor Type

Next, we will create 4 monitor types. Each Monitor Type has two states. We will use the Data Source created above and define two conditions which will correspond to two states of Monitor Type. Below is code for Connection Refused Monitor Type. If StatusCode from Data Source equals 2147952461 then the monitor state will be ConnectionRefusedFailure which will be mapped to Critical health of monitor. If not, monitor state will be NoConnectionRefusedFailure which will be mapped to Success health of monitor. Refer attached XML for other three Monitor Types.

<UnitMonitorType ID="GKLab.TCP.Port.Monitoring.MonitorType.ConnectionRefused" Accessibility="Internal">
        <MonitorTypeStates>
          <MonitorTypeState ID="ConnectionRefusedFailure" NoDetection="false" />
          <MonitorTypeState ID="NoConnectionRefusedFailure" NoDetection="false" />
        </MonitorTypeStates>
        <Configuration>
          <xsd:element minOccurs="1" name="IntervalSeconds" type="xsd:integer" />
          <xsd:element minOccurs="1" name="SyncTime" type="xsd:string" />
          <xsd:element minOccurs="1" name="ServerName" type="xsd:string" />
          <xsd:element minOccurs="1" name="Port" type="xsd:integer" />
          <xsd:element minOccurs="1" name="TimeWindowInSeconds" type="xsd:integer" />
          <xsd:element minOccurs="1" name="NoOfRetries" type="xsd:integer" />
        </Configuration>
        <OverrideableParameters>
          <OverrideableParameter ID="IntervalSeconds" Selector="$Config/IntervalSeconds$" ParameterType="int" />
        </OverrideableParameters>
        <MonitorImplementation>
          <MemberModules>
            <DataSource ID="DS" TypeID="GKLab.TCP.Port.Monitoring.Monitoring.DataSource">
              <IntervalSeconds>$Config/IntervalSeconds
lt;/IntervalSeconds> 
              <SyncTime>$Config/SyncTime
lt;/SyncTime> 
              <ServerName>$Config/ServerName
lt;/ServerName> 
              <Port>$Config/Port
lt;/Port> 
            </DataSource>
            <ProbeAction ID="PassThrough" TypeID="System!System.PassThroughProbe" />
            <ConditionDetection ID="ConditionOK" TypeID="System!System.ExpressionFilter">
              <Expression>
                <SimpleExpression>
                  <ValueExpression>
                    <XPathQuery Type="UnsignedInteger">StatusCode</XPathQuery>
                  </ValueExpression>
                  <Operator>NotEqual</Operator>
                  <ValueExpression>
                    <Value Type="UnsignedInteger">2147952461</Value>
                  </ValueExpression>
                </SimpleExpression>
              </Expression>
            </ConditionDetection>
            <ConditionDetection ID="ConditionFailure" TypeID="System!System.ExpressionFilter">
              <Expression>
                <SimpleExpression>
                  <ValueExpression>
                    <XPathQuery Type="UnsignedInteger">StatusCode</XPathQuery>
                  </ValueExpression>
                  <Operator>Equal</Operator>
                  <ValueExpression>
                    <Value Type="UnsignedInteger">2147952461</Value>
                  </ValueExpression>
                </SimpleExpression>
              </Expression>
            </ConditionDetection>
            <ConditionDetection ID="Consolidator" TypeID="System!System.ConsolidatorCondition">
              <Consolidator>
                <ConsolidationProperties />
                <TimeControl>
                  <WithinTimeSchedule>
                    <Interval>$Config/TimeWindowInSeconds
lt;/Interval> 
                  </WithinTimeSchedule>
                </TimeControl>
                <CountingCondition>
                  <Count>$Config/NoOfRetries
lt;/Count> 
                  <CountMode>OnNewItemTestOutputRestart_OnTimerSlideByOne</CountMode>
                </CountingCondition>
              </Consolidator>
            </ConditionDetection>
          </MemberModules>
          <RegularDetections>
            <RegularDetection MonitorTypeStateID="ConnectionRefusedFailure">
              <Node ID="Consolidator">
                <Node ID="ConditionFailure">
                  <Node ID="DS" />
                </Node>
              </Node>
            </RegularDetection>
            <RegularDetection MonitorTypeStateID="NoConnectionRefusedFailure">
              <Node ID="ConditionOK">
                <Node ID="DS" />
              </Node>
            </RegularDetection>
          </RegularDetections>
          <OnDemandDetections>
            <OnDemandDetection MonitorTypeStateID="ConnectionRefusedFailure">
              <Node ID="ConditionFailure">
                <Node ID="PassThrough" />
              </Node>
            </OnDemandDetection>
            <OnDemandDetection MonitorTypeStateID="NoConnectionRefusedFailure">
              <Node ID="ConditionOK">
                <Node ID="PassThrough" />
              </Node>
            </OnDemandDetection>
          </OnDemandDetections>
        </MonitorImplementation>
      </UnitMonitorType>

Monitors

Finally, the Monitors. The Monitor is targeted to the custom Class we created earlier – GKLab.TCP.Port.Monitoring.Class which hosts the instances from the CSV file. The Target Instance data is passed as configuration to the Monitor (refer <Configuration> tag) and the Alert parameters are defined. Notice the health state mapping with MonitorTypeStateId which we defined earlier in Monitor Types. Refer attached XML for other three Monitors.

<UnitMonitor ID="GKLab.TCP.Port.Monitoring.Monitor.ConnectionRefused" Accessibility="Internal" Enabled="true" Target="GKLab.TCP.Port.Monitoring.Class" ParentMonitorID="Health!System.Health.AvailabilityState" Remotable="true" Priority="Normal" TypeID="GKLab.TCP.Port.Monitoring.MonitorType.ConnectionRefused" ConfirmDelivery="true">
        <Category>Custom</Category>
        <AlertSettings AlertMessage="GKLab.TCP.Port.Monitoring.Monitor.ConnectionRefused_AlertMessageResourceID">
          <AlertOnState>Error</AlertOnState>
          <AutoResolve>true</AutoResolve>
          <AlertPriority>Normal</AlertPriority>
          <AlertSeverity>Error</AlertSeverity>
          <AlertParameters>
            <AlertParameter1>$Target/Property[Type="GKLab.TCP.Port.Monitoring.Class"]/Port
lt;/AlertParameter1> 
            <AlertParameter2>$Target/Property[Type="GKLab.TCP.Port.Monitoring.Class"]/ServerName
lt;/AlertParameter2> 
            <AlertParameter3>$Target/Host/Property[Type="Windows!Microsoft.Windows.Computer"]/PrincipalName
lt;/AlertParameter3> 
          </AlertParameters>
        </AlertSettings>
        <OperationalStates>
          <OperationalState ID="UIGeneratedOpStateIdde249d72023f429ab12b926b5bc21ca4" MonitorTypeStateID="ConnectionRefusedFailure" HealthState="Error" />
          <OperationalState ID="UIGeneratedOpStateId86f579e32c97416b824528157ecd2c71" MonitorTypeStateID="NoConnectionRefusedFailure" HealthState="Success" />
        </OperationalStates>
        <Configuration>
          <IntervalSeconds>300</IntervalSeconds>
          <SyncTime>00:00</SyncTime>
          <ServerName>$Target/Property[Type="GKLab.TCP.Port.Monitoring.Class"]/ServerName
lt;/ServerName> 
          <Port>$Target/Property[Type="GKLab.TCP.Port.Monitoring.Class"]/Port
lt;/Port> 
          <TimeWindowInSeconds>$Target/Property[Type="GKLab.TCP.Port.Monitoring.Class"]/TimeWindowInSeconds
lt;/TimeWindowInSeconds> 
          <NoOfRetries>$Target/Property[Type="GKLab.TCP.Port.Monitoring.Class"]/NoOfRetries
lt;/NoOfRetries> 
        </Configuration>
      </UnitMonitor>

Rules:

Like the Monitors, we need target Rule to the custom Class. We need to define the Data Source and relevant modules based on whether the rule is alerting or non-alerting rule. Since we are building a performance collection rule, we ought to use Performance!System.Performance.DataGenericMapper to map the performance data collected and Write Action modules to write the collected data to Ops DB and Ops DW DB.

<Rules>
      <Rule ID="GKLab.TCP.Port.Monitoring.Rule.ConnectionTime" Enabled="true" Target="GKLab.TCP.Port.Monitoring.Class" ConfirmDelivery="true" Remotable="true" Priority="Normal" DiscardLevel="100">
        <Category>PerformanceCollection</Category>
        <DataSources>
          <DataSource ID="DS" TypeID="GKLab.TCP.Port.Monitoring.Monitoring.DataSource">
            <IntervalSeconds>300</IntervalSeconds>
            <SyncTime>00:00</SyncTime>
            <ServerName>$Target/Property[Type="GKLab.TCP.Port.Monitoring.Class"]/ServerName
lt;/ServerName> 
            <Port>$Target/Property[Type="GKLab.TCP.Port.Monitoring.Class"]/Port
lt;/Port> 
          </DataSource>
        </DataSources>
        <ConditionDetection ID="PerfMapper" TypeID="Performance!System.Performance.DataGenericMapper">
          <ObjectName>TCP Port Check</ObjectName>
          <CounterName>Connection Time</CounterName>
          <InstanceName>$Data/ServerName$:$Data/Port
lt;/InstanceName> 
          <Value>$Data/ConnectionTime
lt;/Value> 
        </ConditionDetection>
        <WriteActions>
          <WriteAction ID="WriteToDB" TypeID="SC!Microsoft.SystemCenter.CollectPerformanceData" />
          <WriteAction ID="WriteToDW" TypeID="SystemCenter!Microsoft.SystemCenter.DataWarehouse.PublishPerformanceData" />
        </WriteActions>
      </Rule>
    </Rules>

Wrap Up:

Finally add missing xml fragments for Folders, Views, String Resources and Language Pack elements. You can download the final XML here. For any SCOM Monitoring requirements, please feel free to add a comment. Happy SCOMing!

One thought on “SCOM Advanced Authoring: TCP Port Monitoring

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.