Updated: The sample code (see attachment) has been updated for SCOM 2012 R2.
I had the opportunity to build a simple product connector for System Center Operations Manager 2007 last week. A product connector is used to forward alert information from OpsMgr to an external system. This post describes how I built the product connector and contains some sample code. This sample extends the code found on MSDN by wrapping it in a windows service.
Product connectors use the Operations Manager SDK to poll for alerts. The connector API has a built-in mechanism for marking processed alerts to prevent the connector from outputting the same alert every polling cycle. It also has a mechanism for controlling the number of alerts that are read during each polling cycle. Because of the polling approach, a connector must be hosted by something that can periodically wake up and perform the polling operation. The connector described here uses a service to host the polling logic.
Once you have installed a connector, the administrator must create a subscription that defines the alerts that are available to the connector. For more information on building and configuring product connectors, see http://msdn.microsoft.com/en-us/library/bb437511.aspx and http://blogs.msdn.com/jakuboleksy/archive/2008/01/09/scom-connector-quickstart-guide.aspx.
I simplified the connector that I built to create a small sample showing how to build an outbound connector. The sample was built using Visual Studio 2008 and written in c#. See the attached files for the complete sample.
This sample extends what you find on MSDN in the following ways:
- It is a Windows Service instead of a command line program. MSDN suggests that you create a windows service if you intend to run the connector continuously.
- The sample includes code for use by the service installer.
- The sample utilizes a thread timer to control the alert polling. The interval and startup delay are configurable via application settings.
- The sample writes alert information to an XML formatted text file.
The Installer Class
The project includes an installer class. The installer class will create the service and register the product connector using the Operations Manager SDK API. The uninstaller will do the reverse, as well as removing the subscriptions created for this connector.
You can install the service using the InstallUtil tool that is part of the .net framework. Look for this tool in the %windir%\Microsoft.NET\<.net version> folder. Use the /u option of InstallUtil To uninstall the service.
There are lots of names and descriptions to create when building a product connector. They are used for the service and for the product connector itself. Most are defined in the installer class. The service name is defined in the service class. You should update these names to be descriptive of your solution if you use this sample code.
The service is installed to run as local system by default. Consider changing this to use a less privileged account after installing the service. You can use the service control manager to change the credentials of the service after it is installed.
The service is installed with a run mode of ‘Automatic’. You must manually start the service after the installation, but it will start automatically after a system restart.
Every product connector must have a unique guid. There is a property on the service class that defines the guid for the sample. You should change this guid if you create a product connector based on this sample.
The Configuration File
I used the appsettings section in the app.config file for three settings:
- PollingIntervalMS – This determines how frequently the service will poll for new alerts (in milliseconds). You will need to find the correct tradeoff between polling overhead and latency for your application.
- StartupDelay – This allows you to specify a delay before starting the polling when the service first starts. I have found that if you attempt to connect and poll for alerts before the SDK is ready after a system restart, the connection will fail. A delay of a few minutes seems to be sufficient to avoid this problem.
- OutputFilePath – The full path for the output file where alerts are to be written.
The Management Group Connection
The service is written such that it expects to run on the RMS. It connects to the management group using the “localhost” identifier.
You Must Create a Subscription
The service won’t start outputting alerts to the file until you create a subscription. Use the Operations Console to do this. From the administrator view, select ‘Product Connectors’ from the tree view on the left. If you have installed the sample product connector, you should see it in the list of product connectors. Select it, and create a subscription for it just as you would for a notification. Note that the MSDN documentation states that a connector with no subscription will process all alerts. My experience was that the connector did not process any alerts until at least one subscription was created for it. Perhaps I was not waiting long enough?
The service is designed around a thread based timer. When the OnStart event runs, the timer is created using the interval and startup values from the configuration file.
A few things to note about the timer function. I designed it to use a ‘lazy’ approach to connecting to the management group. When the timer function first runs, it detects that it needs to connect. Subsequent runs will use the existing connection. If an error of some sort occurs while connecting or polling for alerts, the connection is set back to null so that a new one will be created when the timer next fires. I wasn’t sure if there was a performance benefit from holding onto the connection, but I assumed there was. This approach makes the service fairly robust, but may create lots of events in your application log if the connection or polling is persistently broken.
The WriteAlert Method
The sample defines a WriteAlert method that is called for each alert. The purpose of this method is to do the work of output the alert to your target system. In the sample, this method just writes the alert the output file as an XML fragment containing many of the alert property. There are many additional alert properties you might find useful in your connector.
The current WriteAlert method really only makes sense for demonstration purposes because it will result in an output file that grows continuously as alerts are processed. You will need to create a mechanism for rolling that file over or harvesting it in some way.
You will probably need to rewrite this function in your connector to format the alert as needed and to output to whatever device your external system requires.
You may also need to modify the OutputAlerts method to establish a connection your external device. This is the method that actually calls the WriteAlert method while walking over the alert collection.
The service will place events in the event log for any errors it encounters. You might consider setting up an Operations Manager rule to alert on these events. See the source code for specifics on event numbers. The event source will be the name of the service. Consider building a small MP to go along with your connector for the purpose of monitoring the connector.
The attachment to this post contains a zip file with the project used to build the service. The project contains references to both of the assemblies in the Program Files\System Center Operations Manager 2007\SDK Binaries folder.
Interesting Things in the Database
There are a few interesting columns in the AlertView view of the Operations Manager database that I have found useful in debugging connectors. They are ConnectorId and ConnectorStatus. The ConnectorId column will be populated with the guid for the connector that will process the alert. (I’m curious about what would happen if two connectors have subscriptions that cover the same alert). The ConnectorStatus column is used to track whether or not the alert has been processed yet by the connector. A value of 1 in this column indicates that the alert is pending processing; a value of 2 indicates that processing is complete. Since the sample doesn’t use the batch size version of the GetMonitoringAlerts method, you would expect all pending alerts that this connector subscribes to would be returned by that method.
Use of included sample code is subject to the terms specified at http://www.microsoft.com/info/cpyright.htm.
Next Steps For Sample Code Users
- Consider adding more error checking everywhere.
- Does your connector need to use the batching overloads of the GetMonitoringAlerts method?
- Update the assorted names (connector name, description and service name).
- Create a new GUID for your connector
- Update the WriteAlert function to output the alert in the format you desire.
- Consider building a small management pack to monitor your connector service.