In the first part of my blog series about Service Monitoring I’ve described how Service Monitoring could be implemented en what parts of Service Monitoring are important. In the second part I’ve described the structure of Distributed Applications and how you can make your Distributed Applications dynamic. You can find Part 1 and Part 2 here. In this blogpost I want to focus on creating a distributed application and discovering monitoring objects using an external source. In my case the external source is an XML file.
If you want to create dynamic distributed applications you can use dynamic groups to achieve this. The solution I want to describe in this blogpost is not dynamic but give you control over which objects are added to the Distributed Application. With this solution you don’t need to edit the Distributed Application Management Packs, so we have the same advantages about making changes to the DA without entering in a not monitored state after the change.
In this solution we have a Management Pack with the following components:
- Class definitions for the Distributed Application
- Class definitions for the Component Groups
- Relationship definitions
- Discovery for the Distributed Application
- Discovery for the objects which need to be added to the component groups
- Health Rollup Monitors
Let’s start with defining the classes for the Distributed Application and the component groups:
<EntityTypes> <ClassTypes> <ClassType ID="DSN.Sessionbuilder.DA" Base="MSSL!Microsoft.SystemCenter.ServiceDesigner.GenericService" Accessibility="Public" Abstract="false" Hosted="false" Singleton="true" /> <ClassType ID="DSN.Sessionbuilder.DA.AllDatabases" Base="MSSL!Microsoft.SystemCenter.ServiceDesigner.ServiceComponentGroup" Accessibility="Public" Abstract="false" Hosted="false" Singleton="true" /> <ClassType ID="DSN.Sessionbuilder.DA.AllWebsites" Base="MSSL!Microsoft.SystemCenter.ServiceDesigner.ServiceComponentGroup" Accessibility="Public" Abstract="false" Hosted="false" Singleton="true" /> <ClassType ID="DSN.Sessionbuilder.DA.AllNLB" Base="MSSL!Microsoft.SystemCenter.ServiceDesigner.ServiceComponentGroup" Accessibility="Public" Abstract="false" Hosted="false" Singleton="true" /> </ClassTypes> </EntityTypes>
In the above XML code we define the Distributed Application based on ‘Microsoft.SystemCenter.ServiceDesigner.GenericService’ and Component Groups based on ‘Microsoft.SystemCenter.ServiceDesigner.ServiceComponentGroup’. The next step is to define the relationschips between the Distributed Application and the Components Groups:
</RelationshipType> <RelationshipType ID="DSN.Sessionbuilder.DA.Contains.DSN.Sessionbuilder.DA.AllNLB" Accessibility="Internal" Abstract="false" Base="System!System.Containment"> <Source ID="source" Type="DSN.Sessionbuilder.DA" /> <Target ID="target" Type="DSN.Sessionbuilder.DA.AllNLB" /> </RelationshipType> <RelationshipType ID="DSN.Sessionbuilder.DA.Contains.DSN.Sessionbuilder.DA.AllWebsites" Accessibility="Internal" Abstract="false" Base="System!System.Containment"> <Source ID="source" Type="DSN.Sessionbuilder.DA" /> <Target ID="target" Type="DSN.Sessionbuilder.DA.AllWebsites" /> </RelationshipType> <RelationshipType ID="DSN.Sessionbuilder.DA.Contains.DSN.Sessionbuilder.DA.AllDatabases" Accessibility="Internal" Abstract="false" Base="System!System.Containment"> <Source ID="source" Type="DSN.Sessionbuilder.DA" /> <Target ID="target" Type="DSN.Sessionbuilder.DA.AllDatabases" /> </RelationshipType>
Now we have defined the relationships between DA and component groups the next step is to define the relationship between the Components Groups and the class which can be discovered in the Component Group:
<RelationshipType ID="DSN.Sessionbuilder.DA.AllDatabases.Contains.Databases" Accessibility="Internal" Abstract="false" Base="System!System.Containment"> <Source ID="source" Type="DSN.Sessionbuilder.DA.AllDatabases" /> <Target ID="target" Type="MSSQL!Microsoft.SQLServer.Database" /> </RelationshipType> <RelationshipType ID="DSN.Sessionbuilder.DA.AllWebsites.Contains.Websites2012" Accessibility="Internal" Abstract="false" Base="System!System.Containment"> <Source ID="source" Type="DSN.Sessionbuilder.DA.AllWebsites" /> <Target ID="target" Type="IIS2012!Microsoft.Windows.InternetInformationServices.6.2.WebSite" /> </RelationshipType> <RelationshipType ID="DSN.Sessionbuilder.DA.AllNLB.Contains.NLBCLuster" Accessibility="Internal" Abstract="false" Base="System!System.Containment"> <Source ID="source" Type="DSN.Sessionbuilder.DA.AllNLB" /> <Target ID="target" Type="NLBLibrary!Microsoft.Windows.NetworkLoadBalancing.Cluster" /> </RelationshipType>
With above definitions we have defined all the classes and the relationships. Now it’s time to define the discoveries. The first discovery will discover the relationships between the DA and the Components Groups:
<Discovery ID="DSN.Sessionbuilder.DA.Discovery" Enabled="true" Target="DSN.Sessionbuilder.DA" ConfirmDelivery="false" Remotable="true" Priority="Normal"> <Category>Discovery</Category> <DiscoveryTypes /> <DataSource ID="DS" TypeID="SC!Microsoft.SystemCenter.GroupPopulator"> <RuleId>$MPElement$</RuleId> <GroupInstanceId>$Target/Id$</GroupInstanceId> <MembershipRules> <MembershipRule> <MonitoringClass>$MPElement[Name="DSN.Sessionbuilder.DA.AllDatabases"]$</MonitoringClass> <RelationshipClass>$MPElement[Name="DSN.Sessionbuilder.DA.Contains.DSN.Sessionbuilder.DA.AllDatabases"]$</RelationshipClass> </MembershipRule> <MembershipRule> <MonitoringClass>$MPElement[Name="DSN.Sessionbuilder.DA.AllWebsites"]$</MonitoringClass> <RelationshipClass>$MPElement[Name="DSN.Sessionbuilder.DA.Contains.DSN.Sessionbuilder.DA.AllWebsites"]$</RelationshipClass> </MembershipRule> <MembershipRule> <MonitoringClass>$MPElement[Name="DSN.Sessionbuilder.DA.AllNLB"]$</MonitoringClass> <RelationshipClass>$MPElement[Name="DSN.Sessionbuilder.DA.Contains.DSN.Sessionbuilder.DA.AllNLB"]$</RelationshipClass> </MembershipRule> </MembershipRules> </DataSource> </Discovery>
This Discovery will discover the membership of the component groups based on the relationships we defined earlier. The next and most important discovery is the discovery which discovers the objects:
<Discovery ID="DSN.Sessionbuilder.DA.Components.Discovery" Enabled="true" Target="SC!Microsoft.SystemCenter.AllManagementServersPool" ConfirmDelivery="false" Remotable="true" Priority="Normal"> <Category>Discovery</Category> <DiscoveryTypes> <DiscoveryClass TypeID="DSN.Sessionbuilder.DA.AllDatabases" /> <DiscoveryClass TypeID="DSN.Sessionbuilder.DA.AllWebsites" /> <DiscoveryClass TypeID="DSN.Sessionbuilder.DA.AllNLB" /> <DiscoveryClass TypeID="DSN.Sessionbuilder.DA.AllUE" /> <DiscoveryClass TypeID="MSSQL!Microsoft.SQLServer.Database" /> <DiscoveryClass TypeID="IIS2012!Microsoft.Windows.InternetInformationServices.6.2.ServerRole" /> <DiscoveryClass TypeID="IISCommon!Microsoft.Windows.InternetInformationServices.WebSite" /> <DiscoveryClass TypeID="NLBLibrary!Microsoft.Windows.NetworkLoadBalancing.Cluster" /> <DiscoveryClass TypeID="DSN.Sessionbuilder.UE.Session" /> <DiscoveryRelationship TypeID="DSN.Sessionbuilder.DA.AllDatabases.Contains.Databases" /> <DiscoveryRelationship TypeID="DSN.Sessionbuilder.DA.AllWebsites.Contains.Websites2012" /> <DiscoveryRelationship TypeID="DSN.Sessionbuilder.DA.AllNLB.Contains.NLBCLuster" /> <DiscoveryRelationship TypeID="DSN.Sessionbuilder.DA.AllUE.Contains.UE.Session" /> </DiscoveryTypes> <DataSource ID="DSN.Sessionbuilder.Components.Discovery.DS" TypeID="Windows!Microsoft.Windows.TimedPowerShell.DiscoveryProvider"> <IntervalSeconds>300</IntervalSeconds> <SyncTime /> <ScriptName>SessionbuilderComponentsDiscovery.ps1</ScriptName> <ScriptBody>$IncludeFileContent/Scripts/SessionbuilderComponentsDiscovery.ps1$</ScriptBody> <Parameters> <Parameter> <Name>sourceId</Name> <Value>$MPElement$</Value> </Parameter> <Parameter> <Name>managedEntityId</Name> <Value>$Target/Id$</Value> </Parameter> <Parameter> <Name>ServiceApp</Name> <Value>Sessionbuilder</Value> </Parameter> </Parameters> <TimeoutSeconds>300</TimeoutSeconds> <StrictErrorHandling>true</StrictErrorHandling> </DataSource> </Discovery>
Under Discovery types you need to define all objects which will be discovered by this discovery. This discovery will start the ‘SessionbuilderComponentsDiscovery.ps1’ script. This PowerShell script will do the actual discovery. In the Parameters section of the Discovery I added the mandatory parameters but also the name of the app which I want to discover. I you have multiple applications you probably want to have a possibility to pass the name of the application to the script.
The PowerShell script which will do the actual discovery will looks like:
# SessionbuilderComponentsDiscovery.ps1 # Written by Arjan Vroege. All rights reserved. param($SourceID, $ManagedEntityID, $ServiceApp) $scomapi = new-object -comObject "MOM.ScriptAPI" $DiscData = $scomapi.CreateDiscoveryData(0, $SourceID, $ManagedEntityID) $path = '\\CONTOSO-DC01\ServiceApp\' + $ServiceApp + '.xml' [xml]$content = Get-Content($path) if($content -ne $null) { }
The above script will create the discovery and will read the file. The If statement will check if the XML file is not empty. For each component group the following script section is added:
# Add Instance for the Database DA class $DB_DA_Instance = $DiscData.CreateClassInstance("$MPElement[Name='DSN.Sessionbuilder.DA.AllDatabases']$") $DB_DA_Instance.AddProperty("$MPElement[Name='System!System.Entity']/DisplayName$", "All Sessionbuilder databases") $DiscData.AddInstance($DB_DA_Instance) foreach ($db in $content.Application.Databases.Database) { $name = $db.name $server = $db.server $instance = $db.instance if(($name -ne "database") -and ($server -ne $null) -and ($instance -ne $null)) { #$scomapi.LogScriptEvent("SessionbuilderComponentsDiscovery.ps1",101,2, "Discovery was executed with the following name = $name, server = $server, instance = $Instance.") $DB_Instance = $DiscData.CreateClassInstance("$MPElement[Name='MSSQL!Microsoft.SQLServer.Database']$") $DB_Instance.AddProperty("$MPElement[Name='Windows!Microsoft.Windows.Computer']/PrincipalName$", $server) $DB_Instance.AddProperty("$MPElement[Name='MSSQL!Microsoft.SQLServer.ServerRole']/InstanceName$", $instance) $DB_Instance.AddProperty("$MPElement[Name='MSSQL!Microsoft.SQLServer.Database']/DatabaseName$", $name) $DiscData.AddInstance($DB_Instance) # Add Relationship class Database contains SQL Database $DB_DA_to_DB_Relation = $DiscData.CreateRelationshipInstance("$MPElement[Name='DSN.Sessionbuilder.DA.AllDatabases.Contains.Databases']$") $DB_DA_to_DB_Relation.Source = $DB_DA_Instance $DB_DA_to_DB_Relation.Target = $DB_Instance $DiscData.AddInstance($DB_DA_to_DB_Relation) } }
The above script will create the an instance of the Component Group class and will the create based on the following XML section the relationship between the component group and the monitoring object:
<databases> <database> <name>SessionBuilder</name> <server>CONTOSO-DB01.CONTOSO.LOCAL</server> <instance>MSSQLSERVER</instance> </database> </databases>
This will result in a component group with on Monitoring object (the database):
The sample Management Pack which can be downloaded at the end on this blogpost will have the following components in it:
- Class Definition for the Distributed Application and Component Groups
- Relationship definitions for the Component Groups
- Relationship definitions for a database, IIS webserver and NLB cluster monitoring object
- Discoveries
- SLO objectives for Availability and Performance of the Distributed Application.
You can download the sample Management Pack here.
In the last blog post of this series I want to describe the possibilities we have around dashboarding and how we can create dashboard to present the data we collect about service monitoring.
Please could you send me a link to download MP ?
Hi, Great Work. Is the MP still available?
Can you share it?
Thanks .
Hello, Can you please could you send me a link to download MP ?
Thanks!
Hello,
Could you re-share the MP?
Thanks