MomResources.org, a great site run by one of our MVPs, has posted all the lab documents from MMS. These are a GREAT resource for everything that is SCOM 2007. Download them here.
I put together and presented a short demostration on the SDK at MMS on Monday. I think it went over well and was a short glimspe on some of the power of the SDK. I wanted to make my demo available so here it is. Let me know if there are any issues with it.
We are almost done here, and a lot of folks are heading to MMS next week for the official launch of System Center Operations Manager 2007. I will be there next week so I probably won't post until I get back. I hope to see some of you there!
Monitoring objects are the instances that are discovered in SCOM. They are identified by unique values for key properties as defined by the class(es) that they are as well as the key properties of their host, if applicable. Their identity is solidified by the first non-abstract class in the objects class hierarchy, even though there may still exist a hierarchy of non-abstract classes that derive from this class. For instance, a computer is defined by its System.Computer class, even though it is also a System.Windows.Computer and potentially a MyCompany.SpecialComputer, both of which derive from System.Computer. It is important to note that these additional non-abstract classes do not in any way change the identity of the object itself and can be thought of as roles.
Since a monitoring object is a representation of an instantiated class, it really represents a meta-object in a way. Early on, we were trying to figure out if we want strongly typed monitoring objects, such as Computer or Server, but for the most part decided against it, with a few exceptions to SCOM specific classes like ManagementServer. Given that, the MonitoringObject, in it's most basic form, is a property bag of values for all the class(es) properties of the object as well as the objects host(s).
When we store monitoring objects in the database, they are stored in two places. We have a general store where common attributes of all monitoring objects are maintained, such as Name, Id and class list (what classes the object is) and a dynamically generated view per identifying class that gets populated with class values. As such, all SDK methods that return MonitoringObject must make at least two queries to construct the object. If the response is heterogeneous in object class, there are even more queries performed. This fact and it's performance implications led to the SDK exposing a full MonitoringObject that represents the property bag as mentioned above as well as a stripped PartialMonitoringClass that includes all the same functionality as MonitoringObject, but does not include any property values or property value related methods. Any method returning PartialMonitoringObject will always perform a single database query and thus is the recommended approach when working with these objects, unless the properties are necessary. The only additional method on MonitoringObject that is not on PartialMonitoringObject is:
public object GetMonitoringPropertyValue(MonitoringClassProperty property)
Please note that this method can be used properties of the monitoring object itself, or any key properties of any host class.
Before diving into all the various ways to query for monitoring objects, I wanted to go through some of features of the object (both MonitoringObject and PartialMonitoringObject) itself. First, there is a public event available on the object:
public event EventHandler<MonitoringObjectMembershipChangedEventArgs> OnRelatedEntitiesChanged
This event will get signaled any time any object in the containment hierarchy of the current object is changed. The event includes the Id of the object whose contained members changed, but does NOT include what objects actually changed; a query would need to be performed to get contained objects and compare accordingly.
The object also contains the following properties for quick reference without needing a full Monitoring Object
public string Name
public string Path
public string DisplayName
public string FullName
public bool IsManaged
public DateTime LastModified
public HealthState HealthState
public DateTime? StateLastModified
public bool IsAvailable
public DateTime? AvailabilityLastModified
public bool InMaintenanceMode
public DateTime? MaintenanceModeLastModified
public ReadOnlyCollection<Guid> MonitoringClassIds
public Guid LeastDerivedNonAbstractMonitoringClassId
Name is the key value(s) of the monitoring object, while DisplayName is the same as name unless a friendly display name was specified by the discovery source via the DisplayName property defined on the System.Entity class. Path is the concatenated names of the hosts, while FullName is the uniquely identifying full name of the current instance, including name, path and class name. The HealthState of the System.EntityHealth monitor for the object is populated, as is the currently IsAvailable property (which is a function of the health service that is currently monitoring this object being available) and whether or not the object is in maintenance mode. IsManaged is always true and is not used. The MonitoringClassIds are all the non-abstract classes this object is, and the LeastDerivedNonAbstractMonitoringClassId is what it says it is, namely the class that brings in the identity of the object, just with a really long name :-).
There are a ton of methods on this object, that I will leave that for you to browse through. I will go through some as the topics come up with future posts.
Now, how do you get this objects? Well, first, let's go over MonitoringObjectGenericCriteria and MonitoringObjectCriteria. MonitoringObjectGenericCriteria allows you to query by generic properties shared across all monitoring objects. This is the list of properties you can use:
MonitoringObjectCriteria uses the same properties and allows you to query for monitoring objects by specific property values, as defined on the class(es) of the objects (such as PrincipalName on Computer), however, you can NOT use non-abstract classes. Note that when querying by MonitoringObjectCriteria, MonitoringObject instances are always returned as we have to make a query on both tables in the database anyway.
What follows is an overview of the methods that are available for retrieving MonitoringObject(s) and PartialMonitoringObject(s). I won't go over all of them as hopefully the docs/Intellisense can help you find what you need.
These are methods that accept criteria as accessible on the ManagementGroup object:
public ReadOnlyCollection<MonitoringObject> GetMonitoringObjects(MonitoringObjectGenericCriteria criteria)
public ReadOnlyCollection<MonitoringObject> GetMonitoringObjects(MonitoringObjectCriteria criteria)
public ReadOnlyCollection<MonitoringObject> GetMonitoringObjects(ICollection<MonitoringObjectCriteria> criteriaCollection)
public ReadOnlyCollection<PartialMonitoringObject> GetPartialMonitoringObjects(MonitoringObjectGenericCriteria criteria)
These are methods that accept criteria as accessible on the monitoring object instance itself. TraversalDepth can be OneLevel or Recursive and determines whether we return immediately contained instances, or all contained instances:
public ReadOnlyCollection<MonitoringObject> GetRelatedMonitoringObjects(MonitoringObjectGenericCriteria criteria, TraversalDepth traversalDepth)
public ReadOnlyCollection<PartialMonitoringObject> GetRelatedPartialMonitoringObjects(MonitoringObjectGenericCriteria criteria, TraversalDepth traversalDepth)
These methods allow you to specify a class as your criteria, including abstract classes, and are found on ManagementGroup (similar methods are available on MonitoringObject with TraversalDepth as a parameter):
public ReadOnlyCollection<MonitoringObject> GetMonitoringObjects(MonitoringClass monitoringClass)
public ReadOnlyCollection<PartialMonitoringObject> GetPartialMonitoringObjects(MonitoringClass monitoringClass)
For getting related objects for multiple instances (the UI State View uses these methods), ManagementGroup allows you to get related object to a collection of objects by class, relationship type or MonitoringObjectCriteria (MonitoringObject also has similar methods for a single object):
public Dictionary<T, ReadOnlyCollection<MonitoringObject>> GetRelatedMonitoringObjects<T>(ICollection<T> monitoringObjects, MonitoringClass monitoringClass, TraversalDepth traversalDepth) where T : PartialMonitoringObject
public Dictionary<T, ReadOnlyCollection<MonitoringObject>> GetRelatedMonitoringObjects<T>(ICollection<T> monitoringObjects, MonitoringObjectCriteria criteria, TraversalDepth traversalDepth) where T : PartialMonitoringObject
public Dictionary<T, ReadOnlyCollection<MonitoringObject>> GetRelatedMonitoringObjects<T>(ICollection<T> monitoringObjects, MonitoringRelationshipClass relationshipClass, TraversalDepth traversalDepth) where T : PartialMonitoringObject
public Dictionary<T, ReadOnlyCollection<PartialMonitoringObject>> GetRelatedPartialMonitoringObjects<T>(ICollection<T> monitoringObjects, MonitoringClass monitoringClass, TraversalDepth traversalDepth) where T : PartialMonitoringObject
public Dictionary<T, ReadOnlyCollection<PartialMonitoringObject>> GetRelatedPartialMonitoringObjects<T>(ICollection<T> monitoringObjects, MonitoringRelationshipClass relationshipClass, TraversalDepth traversalDepth) where T : PartialMonitoringObject
This list isn't exhaustive, but it's pretty close. If you have any particular scenarios that you are confused about with regard to these methods and how best to accomplish a particular query, shoot me an email or post a comment. Also note that MonitoringRelationship is another class that has a source MonitoringObject and a target MonitoringObject included in the class itself and provides another convenient way to retrieve monitoring objects, but that is for another post.
I added a link to http://www.authormps.com. This is a site maintained by a co-worker geared towards management pack authors. It is in its early stages, but should prove to be an excellent resource for management pack authoring.
Since the SDK uses WCF under the covers for communicating with the SDK service, users of the SDK must play nice with it when it comes to thread pool utilization. WCF works a bit differently than it would appear from programmatically using it; namely all the calls are asynchronous and the reply is actually processed on a different thread than the method invocation thread. This poses an interesting problem: what if there are not threads to service the reply? A coworker of mine ran into this issue and needless to say, it stalemated his application. He enqueued a bunch of task execution methods onto the threadpool and all of them woke up and submitted their tasks. The replies could not be processed (and in this particular case, there is actually a separate client-callback method that needs to be processed), so they all appeared to just hang, even though the server showed no signs of the calls being blocked. Well, they weren't; they were just done, but unable to retrieve the reply. Longer story short, don't use all your threads to do remote SDK calls.