How to make an Operations Manager Resource Pool Host your Custom Class

About 6 months ago I created a sample management pack after being asked how one could have their custom class hosted by a resource pool. If you’re running synthetic transactions against websites, databases, remote systems, etc… it would be nice to use a resource pool rather than an agent watcher to run these transactions. It is also nice to be able to target different instances of objects (multiple web sites) using a single monitor and simply targeting the resource pool directly would require multiple monitors. Having a resource pool host a class in which multiple instances of that class are discovered solves this problem.

This management pack is a very simple example that creates a resource pool, class, and discovers instances of that class – but no monitoring exists. It is really just a framework that can be used to create your own management pack applicable to your scenario.

To test the management pack in your lab do the following:

  • Create a the file called machines.txt and place it in your c:\temp directory on all the management servers that you want in your resource pool
  • Populate the machines.txt file with real or fake machines on separate lines:

image

  • Import the attached management pack
 <?xml version="1.0" encoding="utf-8"?>
<ManagementPack SchemaVersion="2.0" ContentReadable="true" xmlns:xsd="https://www.w3.org/2001/XMLSchema">
  <Manifest>
    <Identity>
      <ID>Custom.Example.AgentlessMonitoring</ID>
      <Version>1.0.0.11</Version>
    </Identity>
    <Name>CustomResourcePool</Name>
    <References>
      <Reference Alias="SC">
        <ID>Microsoft.SystemCenter.Library</ID>
        <Version>7.0.8427.0</Version>
        <PublicKeyToken>31bf3856ad364e35</PublicKeyToken>
      </Reference>
      <Reference Alias="Windows">
        <ID>Microsoft.Windows.Library</ID>
        <Version>7.5.8501.0</Version>
        <PublicKeyToken>31bf3856ad364e35</PublicKeyToken>
      </Reference>
      <Reference Alias="System">
        <ID>System.Library</ID>
        <Version>7.5.8501.0</Version>
        <PublicKeyToken>31bf3856ad364e35</PublicKeyToken>
      </Reference>
    </References>
  </Manifest>
  <TypeDefinitions>
    <EntityTypes>
      <ClassTypes>
        <ClassType ID="Custom.Example.AgentlessMonitoring.MyPool" Accessibility="Public" Abstract="false" Base="SC!Microsoft.SystemCenter.ManagementServicePool" Hosted="false" Singleton="true" Extension="false" />
        <ClassType ID="Custom.Example.AgentlessMonitoring.MyDevice" Accessibility="Public" Abstract="false" Base="System!System.ApplicationComponent" Hosted="false" Singleton="false" Extension="false">
          <Property ID="DeviceName" Type="string" AutoIncrement="false" Key="true" CaseSensitive="false" MaxLength="256" MinLength="0" Required="false" Scale="0" />
        </ClassType>
      </ClassTypes>
    </EntityTypes>
    <ModuleTypes>
      <DataSourceModuleType ID="Custom.Example.AgentlessMonitoring.DataSource.MyPool" Accessibility="Public" Batching="false">
        <Configuration>
          <xsd:element name="IntervalSeconds" type="xsd:integer" xmlns:xsd="https://www.w3.org/2001/XMLSchema" />
        </Configuration>
        <OverrideableParameters>
          <OverrideableParameter ID="IntervalSeconds" Selector="$Config/IntervalSeconds$" ParameterType="int" />
        </OverrideableParameters>
        <ModuleImplementation Isolation="Any">
          <Composite>
            <MemberModules>
              <DataSource ID="Scheduler" TypeID="System!System.Discovery.Scheduler">
                <Scheduler>
                  <SimpleReccuringSchedule>
                    <Interval>$Config/IntervalSeconds$</Interval>
                    <SyncTime />
                  </SimpleReccuringSchedule>
                  <ExcludeDates />
                </Scheduler>
              </DataSource>
              <ConditionDetection ID="Mapper" TypeID="System!System.Discovery.ClassSnapshotDataMapper">
                <ClassId>$MPElement[Name="SC!Microsoft.SystemCenter.ManagementServicePoolWatcher"]$</ClassId>
                <InstanceSettings>
                  <Settings>
                    <Setting>
                      <Name>$MPElement[Name="SC!Microsoft.SystemCenter.ManagementServicePoolWatcher"]/PoolId$</Name>
                      <Value>$Target/Id$</Value>
                    </Setting>
                    <Setting>
                      <Name>$MPElement[Name="SC!Microsoft.SystemCenter.ManagementServicePoolWatcher"]/PoolName$</Name>
                      <Value>$Target/Property[Type="System!System.Entity"]/DisplayName$</Value>
                    </Setting>
                    <Setting>
                      <Name>$MPElement[Name="System!System.Entity"]/DisplayName$</Name>
                      <Value>$Target/Property[Type="System!System.Entity"]/DisplayName$ Watcher</Value>
                    </Setting>
                  </Settings>
                </InstanceSettings>
              </ConditionDetection>
            </MemberModules>
            <Composition>
              <Node ID="Mapper">
                <Node ID="Scheduler" />
              </Node>
            </Composition>
          </Composite>
        </ModuleImplementation>
        <OutputType>System!System.Discovery.Data</OutputType>
      </DataSourceModuleType>
    </ModuleTypes>
  </TypeDefinitions>
  <Monitoring>
    <Discoveries>
      <Discovery ID="Custom.Example.AgentlessMonitoring.Discovery.MyDevicesManagedByMyPool" Enabled="true" Target="Custom.Example.AgentlessMonitoring.MyPool" ConfirmDelivery="true" Remotable="true" Priority="Normal">
        <Category>Discovery</Category>
        <DiscoveryTypes>
          <DiscoveryRelationship TypeID="SC!Microsoft.SystemCenter.ManagementActionPointShouldManageEntity" />
        </DiscoveryTypes>
        <DataSource ID="DS" TypeID="SC!Microsoft.SystemCenter.GroupPopulator">
          <RuleId>$MPElement$</RuleId>
          <GroupInstanceId>$Target/Id$</GroupInstanceId>
          <MembershipRules>
            <MembershipRule>
              <MonitoringClass>$MPElement[Name="Custom.Example.AgentlessMonitoring.MyDevice"]$</MonitoringClass>
              <RelationshipClass>$MPElement[Name="SC!Microsoft.SystemCenter.ManagementActionPointShouldManageEntity"]$</RelationshipClass>
            </MembershipRule>
          </MembershipRules>
        </DataSource>
      </Discovery>
      <Discovery ID="Custom.Example.AgentlessMonitoring.Discovery.MyDevice" Enabled="true" Target="Custom.Example.AgentlessMonitoring.MyPool" ConfirmDelivery="true" Remotable="true" Priority="Normal">
        <Category>Discovery</Category>
        <DiscoveryTypes>
          <DiscoveryClass TypeID="Custom.Example.AgentlessMonitoring.MyDevice" />
        </DiscoveryTypes>
        <DataSource ID="DS" TypeID="Windows!Microsoft.Windows.TimedPowerShell.DiscoveryProvider">
          <IntervalSeconds>14400</IntervalSeconds>
          <SyncTime />
          <ScriptName>TxtFileDiscovery.ps1</ScriptName>
          <ScriptBody><![CDATA[$sFile = 'c:\temp\machines.txt'
$sResourcePoolName = 'My Custom Agentless Monitoring Resource Pool'

$oAPI = New-Object -ComObject 'MOM.ScriptAPI'
$oDiscoveryData = $oAPI.CreateDiscoveryData(0, '$MPElement$', '$Target/Id$')
foreach ($line in [System.IO.File]::ReadLines($sFile))
{
  #Discover the Device
  $oInstance = $oDiscoveryData.CreateClassInstance("$MPElement[Name='Custom.Example.AgentlessMonitoring.MyDevice']$")
  $oInstance.AddProperty("$MPElement[Name='System!System.Entity']/DisplayName$", $line)
  $oInstance.AddProperty("$MPElement[Name='Custom.Example.AgentlessMonitoring.MyDevice']/DeviceName$", $line)
  $oDiscoveryData.AddInstance($oInstance)
}

$oDiscoveryData]]></ScriptBody>
          <TimeoutSeconds>300</TimeoutSeconds>
        </DataSource>
      </Discovery>
      <Discovery ID="Custom.Example.AgentlessMonitoring.Discovery.MyPool" Enabled="true" Target="Custom.Example.AgentlessMonitoring.MyPool" ConfirmDelivery="false" Remotable="true" Priority="Normal">
        <Category>Discovery</Category>
        <DiscoveryTypes>
          <DiscoveryClass TypeID="SC!Microsoft.SystemCenter.ManagementServicePoolWatcher">
            <Property TypeID="System!System.Entity" PropertyID="DisplayName" />
            <Property PropertyID="PoolId" />
            <Property PropertyID="PoolName" />
          </DiscoveryClass>
        </DiscoveryTypes>
        <DataSource ID="DS" TypeID="Custom.Example.AgentlessMonitoring.DataSource.MyPool">
          <IntervalSeconds>86400</IntervalSeconds>
        </DataSource>
      </Discovery>
    </Discoveries>
  </Monitoring>
  <LanguagePacks>
    <LanguagePack ID="ENU" IsDefault="true">
      <DisplayStrings>
        <DisplayString ElementID="Custom.Example.AgentlessMonitoring.MyPool">
          <Name>My Custom Agentless Monitoring Resource Pool</Name>
        </DisplayString>
        <DisplayString ElementID="Custom.Example.AgentlessMonitoring.MyDevice">
          <Name>My Custom Agentless Device</Name>
        </DisplayString>
        <DisplayString ElementID="Custom.Example.AgentlessMonitoring.MyDevice" SubElementID="DeviceName">
          <Name>Device Name</Name>
        </DisplayString>
        <DisplayString ElementID="Custom.Example.AgentlessMonitoring.DataSource.MyPool">
          <Name>My Custom Resource Pool Watcher Discovery Data Source</Name>
        </DisplayString>
        <DisplayString ElementID="Custom.Example.AgentlessMonitoring.DataSource.MyPool" SubElementID="IntervalSeconds">
          <Name>Interval Seconds</Name>
        </DisplayString>
        <DisplayString ElementID="Custom.Example.AgentlessMonitoring.Discovery.MyDevicesManagedByMyPool">
          <Name>My Custom Agentless Monitoring Pool to Device Relationship Discovery</Name>
        </DisplayString>
        <DisplayString ElementID="Custom.Example.AgentlessMonitoring.Discovery.MyDevice">
          <Name>My Custom Agentless Monitoring Device Discovery</Name>
        </DisplayString>
        <DisplayString ElementID="Custom.Example.AgentlessMonitoring.Discovery.MyPool">
          <Name>My Custom Agentless Monitoring Pool Discovery</Name>
        </DisplayString>
        <DisplayString ElementID="Custom.Example.AgentlessMonitoring">
          <Name>Custom Agentless Monitoring</Name>
        </DisplayString>
      </DisplayStrings>
      <KnowledgeArticles></KnowledgeArticles>
    </LanguagePack>
  </LanguagePacks>
</ManagementPack>
  • If you want, change the “My Custom Agentless Monitoring Resource Pool” to manual and modify the membership to include the management servers you placed the machines.txt file on

image

  • Restart the health services on the management servers if needed, otherwise you should see the instances discovered:

image

 

If these were real devices, websites, databases, etc… then I could create a monitor which targets the “My Custom Agentless Device” class that would run synthetic transactions, from the resource pool, to each remote device on an interval. Each object then maintains its own health state and there is a level of redundancy since the transaction is being run from within a resource pool.

Custom.Example.AgentlessMonitoring.renametoxml