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
Comments
Anonymous
November 08, 2006
Thanks for this post Jakub. I still 've not try this out yet. Just wanted to check with u , After i 've installed the RC1, the SCOM Engine status is always uninitialised. when I open the console I see 2 "Required Configuration", saying that I must discover computers and also I must import management packs. As of now I don’t want the SCOM to manage other computer, I'm just exploring the functionalities only. But it seems the SCOM engine does not start unless I do these configurations. Is there any way I can by pass this and get the SCOM Server started? Once i get this initialised will try this sample and let u know how it goes. Thanks.Anonymous
November 09, 2006
I am not sure what you mean by the SCOM Engine status is uninitialzed. You don't need to discovery computers or import an new management packs to play around with things. These are just common configuration tasks that we highlight on the main administration page.Anonymous
November 09, 2006
After i install the RC1, for very long time i can not see any performance counter values in the console, so i was n't sure whether the system is running. I assumed that it needs some sort of initialisation. But yesterday i did a reinstall of my OS and then the RC1 again. After that , after a while i could see the performance values in the performance view. I'm not sure y the server was idle when i installed first time. Well, itz ok finally it is up and running. I was trying to import the management pack u have attached in this post. I ran into couple of errors. The errors related to the dependent MPs, Microsoft.Windows.Library and System.Library. In ur MP it was 6.0.0.0 in my RC1 it was 6.0.4655.0. I managed to correct it in XML point to the correct version. But i still could not find the "publicKeyToken". Then i used the cmdlet "get-managementpack" which i learned from ur collegue's SC command shell blog. It gave me the required public key token. And finally could import the MP. I will test-out the c# code as well and update u how it goes. BTW, why the "Required Tasks" keep telling me "Import MP" even though i 've already imported a MP? And last time i understand from u, that the RC1 will have an authoring console to import ICONS and assign to classes. I could not see them in the RC1. Is that available already or may be it is targeted for RC2? BTW, how to actually convert the icon image into the binary format in the xml, is it base64 encoding??Anonymous
November 10, 2006
Thanks for the heads up. I have updated the managemant pack so now it should import with the shipped RC1. The required tasks still being there sounds like a bug. The image data in an MP should be hexBinary. If you start with the right image size (16x16 or 80x80) it looks like you just have to convert it to hex. The authoring console shipped only to TAP customers for RC1 as we weren't able to get as much test coverage as we liked.Anonymous
November 12, 2006
Well, I just wrote a utility in Studio.NET to convert the image files to hex. I was just wondering, Why your sample to show the insertion of discovery data is written in .NET, where as you could just do the same in the VBS and bundle it together with the MP rite? Is it just for a demonstration or what???Anonymous
November 13, 2006
You can do it any way you like, this is just a blog about using the SDK, hence it showed how to do things that way. However, bundling it the MP, is not as easy as what I showed. I am not even sure what you would want to accomplish by doing this.Anonymous
November 13, 2006
The comment has been removedAnonymous
November 14, 2006
MP import will create a single instance for all singleton classes. Otherwise, you cannot do what you ask.Anonymous
November 14, 2006
I managed to modify your sample MP and add a script based discovery provider, to create instances from there. But i need to specify the "Computer" in the target.... <Discovery ID="My.Discovery" Enabled="true" Target="Windows!Microsoft.Windows.Server.Computer" > If i specify "SampleClass1HostedByComputer" as target, the script does not take effect. Once i use the "Computer" target, as i specified in the script , it creates instances under the "SampleClass1HostedByComputer". Do u know why it does not take effect when i specify "SampleClass1HostedByComputer"?Anonymous
November 15, 2006
Did you create any instances of SampleClass1HostedByComputer? If you want to create instance of SampleClass1HostedByComputer, you really need your discovery rule targetted to something other than the class itself (like computer), since you need an instance of a class for a rule to actually run. Take a look at the "How Stuff Works" post as I talk a little bit about how discovery works there.Anonymous
November 15, 2006
The comment has been removedAnonymous
November 15, 2006
I spoke with another developer on the team and the reply he gave me was: The recommendation is that you run your script on a long interval like every 24 hours (a user could always disable the rule after the script ran I suppose). Unless you provide a sync time the script will run immediately anyway and discovery data is only sent to the server if there is a change to it. Basically the only downside to running this continually is some CPU time on the agent.Anonymous
November 16, 2006
Thanks Jakub, for checking out the details for me. Infact, I was thinking the same thing, It is ok it consumes the CPU time, but the problem is i need to wait for atleast 24 Hours to get my instances created. Now I'm trying to find out is there a way i could write a script, which will disable itz own discovery rule after being executed for the first time.Anonymous
November 16, 2006
It should in fact run once immediately.Anonymous
November 16, 2006
I thought like that also but it did not run immediate. It will run immediate only if i configure the <SyncTime> tag to the next minute before i import the MP. But that is not practical to change the time when ever i'm importing the MP.Anonymous
November 17, 2006
Have you tried setting it to <SyncTime />? This should cause it to run immediately for discovery rules.Anonymous
November 19, 2006
Kool. It works fine now. I 've set it to longer intervals. And now i got all the instances i 've wanted. So after this i 've tried to create a memberModule called "InstanceFactory" and tried to wrap my code inside that. But so strange, now SCOM converts all the $..$ variables inside the script into actual GUIDs, which did not happen if i call the scriptProvider straight. So i rearrange the variables to make sure they are passed as correct values, but then it said "A monitoring host is unresponsive or has crashed. The status code for the host failure was 2164195371." Well, for the time being i'm not gonna use the memberModules, for my case, seems like i'm tweaking the SCOM too much :-)Anonymous
November 20, 2006
After i 've created the instances i can see them from the "Search Managed Objects" and also from the "Command Shell". But is there a way to find the "Relationship Instances" from the console??Anonymous
November 21, 2006
Not really. You can create a diagram view with your instances and that should show the relationships. Also via the command shell if you invoke the SDK you can browse relationships.Anonymous
December 03, 2006
After i insert the discovery data, is there a way, i can set the healthState to Green-Sucess by default for all those objects?Anonymous
December 04, 2006
No - that is a function of the health model you defined for your instances; you can't directly set state.Anonymous
June 27, 2007
In the last blog post , we read how we can change overrides via submitting discovery data for Microsoft.SystemCenter.CM.AEM.MonitorOverrideAnonymous
May 27, 2008
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 tAnonymous
June 05, 2008
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 tAnonymous
July 02, 2008
Jakub, I'm not all that familiar with discovery so excuse me if this is addressed somewhere in this blog or it's responses. I have a need to create classes for individual monitors to be able to put them in maintenance mode but there is not always a way to discover the objects on the managed server. Is it possible to create the class manually and then instantiate it for a given managed server via the SDK or other mechanism? Thanks.Anonymous
July 02, 2008
You could use the SDK for this, you just need to be careful to make sure that the instances you insert are managed by the server you want the rules and monitors to run on. By default, this is always the RMS, unless the instance is hosted by another instance running on the machine you want your monitor to run on or you explicitly add a HealthServiceManages relationship from your instance to the health service you want it to manage.Anonymous
February 01, 2011
Great stuff. But you drop a hint in your post that you can use this mechanism (the SDK) to delete objects through the managed connector, qoute "This can include additions, as well as deletions". However the sample shows how to add a full snapshot and to do a incremental update, an addition, How would I delete one monitored object?Anonymous
February 01, 2011
To delete, use the Remove() method on IncrementalMonitoringDiscoveryData.