Jaa


Working with Management Pack Templates

Management pack templates provide a powerful way to create single or a collection of management pack objects. Essentially, you author the fragment of a management pack you want created, with some missing values that become configuration to your template, and upon execution of the template the missing values are provided and the finished management pack object(s) are materialized and imported.

Templates show up in the UI under the Authoring pane. In order for your own custom template to show up there, you need to create a folder for it and place the template in the folder as a folder item. It will show up without the folder, but won't work quite right. Enabling executing the template via the UI is outside the scope of this post, but should be eventually available as a tutorial on www.authormps.com.

I've attached a sample management pack that essentially recreates the instance group template we use for creating groups.

If you take a look at the template defined there, you will see that the configuration section is very similar to other management pack elements. The configuration schema here specifies what values must be provided to the template processor.

The second section is the references for the actual template. The references refer to the references section of the management pack the template is in, by alias. There is one special alias defined, 'Self', which refers to the management pack the template is in.

Finally, under the implementation section is the fragment of the management pack you want your template to create. You can have the configuration values replace any part of the implementation by referring to the values via the $TemplateConfig/<configuration variable name>$ format.

In the templates management pack you will also notice that I put the sample templates in a newly created folder. This will ensure the UI behaves properly with any template output I produce. What happens is that the template output can be placed in a folder, and the UI will treat these folders as individual instances of execution of the template, such that they can be managed as homogenous units, even though they may have created a wide variety of management pack objects.

The code below runs my template using the SDK.

First you will notice that I need to get the management pack the template is in and the template itself. I need the management pack for two reasons. First, I need a management pack to run the template against; all the objects produced by the template will be placed in this management pack. Second, I need this particular management pack because it is not sealed and thus any templates defined in it, must be run against it. If you seal the management pack that contains the template, you can run it against any non-sealed management pack.

Next, I have to build the configuration for my template. This is just XML that matches the schema of my template. You will also notice that within my configuration I have to referenced some management packs. This will be reflected by adding additional references as a parameter to processing the template. Note that if I want to use references that already exist in the management pack the template output will be put in, these aliases must match the already existing aliases for the same management packs.

Finally, when I process my template, I provide additional information that will be used to name the folder the template output is put into. This is optional, but required if you want the output to show up in the UI and want to be able to delete it easily (by deleting everything in this folder). The method actually returns the folder the output was put in.

 using System;
using System.Collections.ObjectModel;
using System.Text;
using System.Xml;
using Microsoft.EnterpriseManagement;
using Microsoft.EnterpriseManagement.Configuration;

namespace Jakub_WorkSamples
{
    partial class Program
    {
        static void ProcessTemplate()
        {
            // Connect to the local management group
            ManagementGroup localManagementGroup = new ManagementGroup("localhost");

            // Get template management pack. This is where we will store out template output since 
            // the sample template management pack is not sealed and the output needs to be 
            // in the same management pack as the template in this case.
            ManagementPack templateManagementPack =
                localManagementGroup.GetManagementPacks(
                "Template.Sample")[0];

            // Get the template you want to process
            MonitoringTemplate sampleTemplate = 
                localManagementGroup.GetMonitoringTemplates(
                    new MonitoringTemplateCriteria("Name = 'Sample.Template'"))[0];

            // Populate the configuration for the template
            string formula =
               @"<MembershipRule>
                <MonitoringClass>$MPElement[Name=""Windows!Microsoft.Windows.Computer""]$</MonitoringClass>
                <RelationshipClass>$MPElement[Name=""InstanceGroup!Microsoft.SystemCenter.InstanceGroupContainsEntities""]$</RelationshipClass>
                </MembershipRule>";
            
            StringBuilder stringBuilder = new StringBuilder();
            XmlWriter configurationWriter = XmlWriter.Create(stringBuilder);
            configurationWriter.WriteStartElement("Configuration");
            configurationWriter.WriteElementString("Namespace", "Sample.Namespace");
            configurationWriter.WriteElementString("TypeName", "MyClass");
            configurationWriter.WriteElementString("LocaleId", "ENU");
            configurationWriter.WriteElementString("GroupDisplayName", "My Class");
            configurationWriter.WriteElementString("GroupDescription", "My Class Description");
            configurationWriter.WriteStartElement("MembershipRules");
            configurationWriter.WriteRaw(formula);
            configurationWriter.WriteEndElement();
            configurationWriter.WriteEndElement();
            configurationWriter.Flush();

            // Get the management packs for references
            ManagementPack windowsManagementPack = localManagementGroup.
                GetManagementPack(SystemManagementPack.Windows);
            ManagementPack instanceGroupManagementPack = localManagementGroup.
                GetManagementPack(SystemManagementPack.Group);
            ManagementPackReferenceCollection newReferences =
                new ManagementPackReferenceCollection();
            newReferences.Add("Windows", windowsManagementPack);
            newReferences.Add("InstanceGroup", instanceGroupManagementPack);

            templateManagementPack.ProcessMonitoringTemplate(sampleTemplate,
                stringBuilder.ToString(),
                newReferences,
                "MyTemplateRunFolder",
                "My Template Run",
                "This is the folder for my sample template output");
        }
    }
}

Template.Sample.xml

Comments

  • Anonymous
    April 25, 2007
    Hi Jakub, There are two questions:
  1. Could you give a sample of writing a UnitMonitor to monitor a SDK event based heartbeat? Background: I wrote a connector. The connector will "InsertCustomMonitoringEvent" at regular time interval (i.e., PublisherName=abc; EventNumber=9001 or 9002). I have a "FirstEventRaised/SecondEventRaised" kind of monitor working already, but still couldn't figure out how to write a heartbeat monitor. i.e., in 5 minites if I don't receive 9001/9002 sdk inserted event, heartbeat goes to error state; if I receive any 9001/9002 sdk event, I reset the state and reset the 5-minute timer.
  2. How to use SDK to write an instance based overrides? The UnitMonitor has to target a class (i.e., Connector class), in UI you can override properties for a particular instance. I export the UI defined overrides, and find out it has "ContextInstance" points to a GUID. But this GUID is not the ID of that instance. How can I get this GUID through program? Basically I would like my monitor to be disabled for Connector class. And I will enable it for my connetor when I install my connector. Steve
  • Anonymous
    April 26, 2007
    Regarding #1, I will have to get back to you. I am not an expert on all the various things you can do with a management pack so I will have to ask someone else on my team. For #2, the ContextInstance is AN instance, although it may not be the instance you are expecting. It can be any instance in our system as it just gives context for the override. Creating the instance based override simply requires setting the ContextInstance to be the Id of the MonitoringObject you want the override to apply in. Although not necessary, I usually set the Context in this can to be the class of the instance. If you want a monitor disabled for the Connector class you should create a ManagementPackMonitorPropertyOverride for the Enabled property, set the value to "0" I believe and the Context should be your Connector class or if you don't have one, the generic connector class.

  • Anonymous
    April 26, 2007
    For #2 the ideal way is to discover my own connector class so that my monitor can target on my class. But the connector is created by SDK's "cfa.Setup(cinfo, connectorId)". Although I have a prefix for my connector, I don't know how to write a MP to discover my class. Any ideas?

  • Anonymous
    April 26, 2007
    What you would have to do is write your own class that derives from the system connector class and then discover an instance of this class, most easily using the discovery data api. If you take a look at my inserting discovery data post, it will show you an example of how to do this.

  • Anonymous
    April 26, 2007
    Great! That is exactly what I need. Thanks.

  • Anonymous
    April 30, 2007
    Any update on #1, regarding a heartbeat monitor?

  • Anonymous
    April 30, 2007
    Ok, so I don't have a full example, but I have something to get you started. If you look at the Microsoft.Windows.Library (you'll need to export it using the SDK or Monad since it's sealed) there is a monitor type defined there that was use for missing event monitors in the product; it's called "Microsoft.Windows.MissingEventLogSingleEventLog2StateMonitorType". This monitor type uses the base event provider which just reads from the event log, but you should be able to change it to use the SDK event data source. This should get you started; I am trying to track down an example of using the consolidator condition detection.

  • Anonymous
    April 30, 2007
    So your best bet maybe to create one of these in the UI under the authoring section using the wizard, and look at the output there. I can't find any samples that would be better than that.

  • Anonymous
    April 30, 2007
    Thanks.