Inserting Discovery Data

We've gone over how to drive state and insert operational data for existing entities, but how do you insert your own objects into the system? That's what this post will briefly touch on, as well as providing sample code (below) and a management pack to use (attached) with the code.

Discovery data insertion via the SDK revolves around connectors as discovery sources. In order to insert data, you first need to create a connector with the system that all the data you insert will be associated with. This allows us to control the lifetime of the discovery data as a function of the lifetime of the connector.

Once the connector is setup, you can use one of two modes for insertion; Snapshot or Incremental. Snapshot discovery indicates to the system that for this particular connector (read: discovery source), this is the definite snapshot of everything it has discovered. It will essentially delete anything that was previously discovered, and treat this snapshot as authoritative. Incremental, as the name would indicate, simply merges the existing discovery data with the discovery information provided in the incremental update. This can include additions, as well as deletions.

Users can insert CustomMonitoringObjects and CustomMonitoringRelationshipObjects which, once inserted, map to MonitoringObjects and MonitoringRelationshipObjects. In order to insert either, you have to provide, at a minimum, the key values for objects, and the source and target for relationships. When dealing with a hosting relationship, the key values of the host must also be populated as part of the CustomMonitoringObject and no explicit CustomMonitoringRelationshipObject needs to be created. The example below should guide you through this.

A quick discussion on managed vs. unmanaged instances. Our system will only run workflows against instances that are managed. The discovery process I talked about in the last post will insert "managed" data. Top-level instances (computers for instance) are inserted via the install agent APIs in the SDK and result in managed computers. It is also possible for rules to insert discovery data, however, this data will not be managed unless hosted by a managed instance.

In order to be able to target workflows to your newly created instances and have them actually run, DiscoveryDataIsManaged needs to be set to true on the ConnectorInfo object when creating the connector. Alternatively, if you insert an instance as hosted by a managed instance, that instance will also be managed. For the former case, all workflows would run on the primary management server, while the latter would have them all running on the health service that manages the host. If something is not managed, you can still insert events and performance data about it, although the workflow that collects these will need to targeted against something other than the class of the instance. State change information would not be available for non-managed instances.

using System;

using Microsoft.EnterpriseManagement;

using Microsoft.EnterpriseManagement.Configuration;

using Microsoft.EnterpriseManagement.ConnectorFramework;

using Microsoft.EnterpriseManagement.Monitoring;

 

namespace Jakub_WorkSamples

{

    partial class Program

    {

        static void InsertDiscoveryData()

        {

            // Connect to the sdk service on the local machine

            ManagementGroup localManagementGroup = new ManagementGroup("jakubo-test");

 

            // Get the connnector framework administration object

            ConnectorFrameworkAdministration connectorFrameworkAdministration =

                localManagementGroup.GetConnectorFrameworkAdministration();

 

            // Create a connector

            ConnectorInfo info = new ConnectorInfo();

            info.Name = "TestConnector";

            info.DisplayName = "Test connector for discovery data";

            MonitoringConnector connector = connectorFrameworkAdministration.Setup(info);

 

            // First create an instance of SampleClassiHostedByComputer and

            // SampleClass2HostedBySampleClass1   

            // Find a computer

            MonitoringObject computer = localManagementGroup.GetMonitoringObjects(

                localManagementGroup.GetMonitoringClass(

                SystemMonitoringClass.WindowsComputer))[0];

 

            // Get the SampleClassiHostedByComputer class

            MonitoringClass sampleClass1HostedByComputer =

                localManagementGroup.GetMonitoringClasses(

                "SampleClass1HostedByComputer")[0];

 

            // Get the SampleClass2HostedBySampleClass1 class

            MonitoringClass sampleClass2HostedBysampleClass1 =

                localManagementGroup.GetMonitoringClasses(

                "SampleClass2HostedBySampleClass1")[0];

 

            // Get the key properties for each

            MonitoringClassProperty keyPropertyForSampleClass1 =

                (MonitoringClassProperty)sampleClass1HostedByComputer.

                PropertyCollection["KeyProperty1"];

            MonitoringClassProperty keyPropertyForSampleClass2 =

                (MonitoringClassProperty)sampleClass2HostedBysampleClass1.

                PropertyCollection["KeyProperty1SecondClass"];

 

            // Create the CustomMonitoringObjects to represent the new instances

            CustomMonitoringObject sampleClass1HostedByComputerInstance =

                new CustomMonitoringObject(sampleClass1HostedByComputer);

            CustomMonitoringObject sampleClass2HostedBysampleClass1Instance =

                new CustomMonitoringObject(sampleClass2HostedBysampleClass1);

 

            // Set the key property value for the first instance

            sampleClass1HostedByComputerInstance.SetMonitoringPropertyValue(

                keyPropertyForSampleClass1, "MySampleInstance1");

 

            // Set the key property values for the second instance, which includes the

            // key property values of the host in order to populate the hosting relationship

            sampleClass2HostedBysampleClass1Instance.SetMonitoringPropertyValue(

                keyPropertyForSampleClass1, "MySampleInstance1");

            sampleClass2HostedBysampleClass1Instance.SetMonitoringPropertyValue(

                keyPropertyForSampleClass2, "MySampleInstance2");

 

            // In order to populate the hosting relationship, you need to also set

            // the key properties of the host. This will automatically create the hosting

            // relationship and is in fact the only way to create one programmatically.

            foreach (MonitoringClassProperty property in computer.GetMonitoringProperties())

            {

                if (property.Key)

                {

                    sampleClass1HostedByComputerInstance.SetMonitoringPropertyValue(

                        property, computer.GetMonitoringPropertyValue(property));

 

                    // Even though the relationship between

                    // sampleClass1HostedByComputerInstance and the computer is already

                    // defined, we need to add this key property to

                    // sampleClass2HostedBysampleClass1Instance as the entire hosting

                    // hierarchy is what uniquely identifies the instance. Without this,

                    // we wouldn't know "where" this instance exists and where it should be

                    // managed.

                    sampleClass2HostedBysampleClass1Instance.SetMonitoringPropertyValue(

                        property, computer.GetMonitoringPropertyValue(property));

                }

            }

 

            // Let's insert what we have so far

            // We'll use Snapshot discovery to indicate this is a full snapshot of

            // all the discovery data this connector is aware of.

            SnapshotMonitoringDiscoveryData snapshot = new SnapshotMonitoringDiscoveryData();

            snapshot.Include(sampleClass1HostedByComputerInstance);

            snapshot.Include(sampleClass2HostedBysampleClass1Instance);

            snapshot.Commit(connector);

 

            // Let's retrieve the objects and ensure they were created

            MonitoringObject sampleClass1HostedByComputerMonitoringObject =

                localManagementGroup.GetMonitoringObject(

                sampleClass1HostedByComputerInstance.Id.Value);

            MonitoringObject sampleClass2HostedBySampleClass1MonitoringObject =

                localManagementGroup.GetMonitoringObject(

                sampleClass2HostedBysampleClass1Instance.Id.Value);

 

            // Now we create a relationship that isn't hosting

            MonitoringRelationshipClass computerContainsSampleClass2 =

                localManagementGroup.GetMonitoringRelationshipClasses(

                "ComputerContainsSampleClass2")[0];

 

            // Create the custom relationship object

            CustomMonitoringRelationshipObject customRelationship =

                new CustomMonitoringRelationshipObject(computerContainsSampleClass2);

 

            // Do an incremental update to add the relationship.

            IncrementalMonitoringDiscoveryData incrementalAdd =

                new IncrementalMonitoringDiscoveryData();

            customRelationship.SetSource(computer);

            customRelationship.SetTarget(sampleClass2HostedBySampleClass1MonitoringObject);

            incrementalAdd.Add(customRelationship);

            incrementalAdd.Commit(connector);

 

            // Make sure the relationship was inserted

            MonitoringRelationshipObject relationshipObject =

                localManagementGroup.GetMonitoringRelationshipObject(

                customRelationship.Id.Value);

 

            // Cleanup the connector. This should remove all the discovery data.

            connectorFrameworkAdministration.Cleanup(connector);

        }

    }

}

 

ConnectorDiscoveryData.Sample.xml