Undiscovering with Multiple Discoveries

I am going to include this issue in a video in the Discovery series I’ve been putting out (Script Discoveries is in the works right now), and we’ll probably get some more detail on this in the Authoring Guide.  I wanted to write up a quick blog entry to get the information out there quick though and also give some deep information as to the inner workings of discovery.  This is actually an issue that’s been nagging at me for a bit, and I just got final confirmation on exactly how it works from our developers.  I‘m going to give quite a bit of detail here, so if you just want the high level summary answer, go ahead and scroll to the bottom.

The issue is when you have multiple discoveries for a particular class and want to undiscover an object.  Undiscover simply means that the object no longer exists and should be removed.  SCOM assumes that an object should be undiscovered when the discovery that first discovered it returns data that doesn’t include the object.  For example, you might have a script discovery that discovers databases.  When that discovery runs, it finds 10 databases, and SCOM creates an object for each.  You then delete one of the databases.  The next time that the discovery runs, SCOM receives the discovery data with 9 databases in it, figures out which one is missing, and goes and and deletes the object for that database (or “undiscovers” it).

If you just have a single discovery for that class, then that’s exactly how the undiscovery works.  What if you had two separate discoveries for the class though?  The basic description that we tend to give is that each discovery must run and undiscover that object before it’s actually removed.  To understand why this is, SCOM creates a RefCount on an object when it’s discovered.  If another discovery discovers the same object, it will increment the RefCount by one.  When a discovery undiscovers an object, it decrements its RefCount by one.  Only when the RefCount hits zero, is the object actually removed. 

Let’s consider a couple of cases where you might have multiple discoveries for a single class:

  1. You have two different discoveries each discovering unique properties of the class.  Maybe you can get some properties through the registry but need a script for other properties. 
  2. You have a script discovery to create containment relationships from the original object.  For example, you might discover a top level object from the registry, and then you target that class with a script discovery that discovers some application components that are contained by the top level class.  To create a containment relationship in a discovery script, you have to create instances of the source and destination class.  Technically, you’re rediscovering the class that was already discovered.

The question for both of these scenarios is whether we need both of the discoveries to run and to undiscover a particular object for it to go away. 

Consider #1 supposing that each discovery used the same target.  The first discovery runs, creates the object, and sets the RefCount to 1.  The second discovery runs, and increments the RefCount to 2.  If the application is removed though, then the next time each discovery runs, they each decrement the RefCount by 1.  It hits 0 after each runs, and the object is removed.

But now consider #2.  The RefCount for the discovered object would be 2 since both discoveries would increment it.  Suppose the application is then uninstalled.  The registry discovery runs decrements the RefCount down to 1.  The script discovery goes ahead and runs (because its target object still exists), but it’s not checking whether the application is installed or not – it’s just happily creating containment relationships.  So the RefCount stays at 1, and the object essentially lives forever. 

Fortunately, SCOM knows how to identify this kind of circular reference.  If the class being discovered is the target of the discovery, then the RefCount is not incremented.  This means that when the first discovery runs, it decrements the RefCount to 0, and the object goes away.  The second discovery never runs because there is no object for it to run against.

To summarize this rule:  If one of the discoveries uses the class being discovered as its target, than that discovery will not have to run for the object to be undiscovered. If both discoveries use any other class than the one being discovered, then they both need to undiscover the object.

This is good, because #2 is actually a common scenario.  Without that added bit of logic baked into SCOM, it would be quite the headache as the discovery for the containment relationships would have to recreate some of the initial discovery’s logic in order to determine if the object should still exist.  Thanks to that extra logic though, we don’t have to worry about it.