Managing Tomcat 7 by extending the JEE Application Server MPs (Part 2 of 2)
In the previous posting, I detailed that Tomcat provides an interface for starting and stopping applications. I gave synopis of the configuration changes necessary to do this as well. In this post I will detail how to write a Management Pack to run these tasks from the SCOM Console.
Goal
Create an MP with a set of tasks in SCOM console to allow the user with the click of a button to remotely start and stop a deployed Tomcat 7 applications.
Gap
Credential information must be supplied to the Manager application and to execute the commands the context path to the application is needed.
For instance, to start an application a HTTP GET needs to be made similar to https://localhost:8080/manager/text/start?path=/examples
. By default the JEE application class does not have this information.
Solution
Create a new management pack that will extend the Microsoft.JEE.Tomcat.7.Application class from the Microsoft.JEE.Tomcat.7.mp. This class is actually an extension on the Microsoft.JEE.Application class found in the Microsoft.JEE.Library.mp. Both classes have just three attributes:
- Application Name
- J2EE Type
- Object Name
The new object needs an additional property: Context Path. As highlighted above, this is the path to the deployed application.
The MP XML for the new Class would look like:
<ClassType ID="Contoso.JEE.Tomcat.Seven.Application" Abstract="false"
Accessibility="Public" Hosted="true"
Base="Tomcat7!Microsoft.JEE.Tomcat.7.Application">
<Property ID="ContextPath" Type="string" CaseSensitive="true" Length="260" MinLength="0" />
</ClassType>
The next step is to create a discovery that will target instances of the Tomcat 7 application class. Below is the blob of XML. The interesting parts are that it targets the Tomcat 7 Application class. It uses a datasource from the Microsoft.JEE.Library.mp that does some filtering, and there is a "complex" XPath. The targeting needs to be a the Tomcat 7 class because the URL needed is Tomcat 7 specific. The DataSource will take a given JMX query and return the results and as XML. Since the returned data is cast to XML, the third piece of the XPath comes into play. This discovery is run against each Tomcat 7 JEE Application. It uses the XPath to locate the XML node of the correct MBean type (aka org.apache.catalina.mbeans.ContextMBean) and the object name of the current application.
Note: I realize this is a brief description, if someone wants more info let me know in the comments and I'll do another post. There is much to be said about authoring MPs. :)
<!-- Discover Additional Tomcat Properties for a WebModule -->
<Discovery ID="Contoso.JEE.Tomcat.Seven.Application.Discovery"
Target="Tomcat7!Microsoft.JEE.Tomcat.7.Application" Remotable="true" Enabled="true">
<Category>Discovery</Category>
<DiscoveryTypes>
<DiscoveryClass TypeID="Contoso.JEE.Tomcat.Seven.Application" />
</DiscoveryTypes>
<DataSource ID="DS" TypeID="JEE!Microsoft.JEE.Discovery.MBeansWithXPath.DataSource">
<ComputerName>$Target/Host/Property[Type="JEE!Microsoft.JEE.ApplicationServer.Monitored.Instance"]/HostName$</ComputerName>
<Protocol>$Target/Host/Property[Type="JEE!Microsoft.JEE.ApplicationServer.Monitored.Instance"]/Protocol$</Protocol>
<Port>$Target/Host/Property[Type="JEE!Microsoft.JEE.ApplicationServer.Monitored.Instance"]/Port$</Port>
<BaseURL />
<JMXQuery>Catalina:j2eeType=WebModule,*</JMXQuery>
<AdditionalArguments>&MaxDepth=1</AdditionalArguments>
<!-- Interval currently set to four hours -->
<IntervalSeconds>14400</IntervalSeconds>
<TimeoutSeconds>300</TimeoutSeconds>
<XPath>MBeans/MBean[@Name='org.apache.catalina.mbeans.ContextMBean' and @objectName='$Target/Property[Type="JEE!Microsoft.JEE.Application"]/ObjectName$'] </XPath>
<ClassId>$MPElement[Name="Contoso.JEE.Tomcat.Seven.Application"]$</ClassId>
<InstanceSettings>
<Settings>
<!-- These properties are for the Tomcat Configuration -->
<Setting>
<Name>$MPElement[Name="JEE!Microsoft.JEE.ApplicationServer.Instance"]/Id$</Name>
<Value>$Target/Host/Host/Property[Type="JEE!Microsoft.JEE.ApplicationServer.Instance"]/Id$</Value>
</Setting>
<Setting>
<Name>$MPElement[Name="JEE!Microsoft.JEE.ApplicationServer.Instance"]/HostName$</Name>
<Value>$Target/Host/Host/Property[Type="JEE!Microsoft.JEE.ApplicationServer.Instance"]/HostName$</Value>
</Setting>
<!-- The following properties are defined for the Application -->
<Setting>
<Name>$MPElement[Name="JEE!Microsoft.JEE.Application"]/ApplicationName$</Name>
<Value>$Target/Property[Type="JEE!Microsoft.JEE.Application"]/ApplicationName$</Value>
</Setting>
<Setting>
<Name>$MPElement[Name="JEE!Microsoft.JEE.Application"]/j2eeType$</Name>
<Value>$Target/Property[Type="JEE!Microsoft.JEE.Application"]/j2eeType$</Value>
</Setting>
<Setting>
<Name>$MPElement[Name="JEE!Microsoft.JEE.Application"]/ObjectName$</Name>
<Value>$Target/Property[Type="JEE!Microsoft.JEE.Application"]/ObjectName$</Value>
</Setting>
<!-- The Contoso property of Context Path needed to do the starts/stops-->
<Setting>
<Name>$MPElement[Name="Contoso.JEE.Tomcat.Seven.Application"]/ContextPath$</Name>
<Value>$Data/MBeans/MBean[@Name='org.apache.catalina.mbeans.ContextMBean' and @objectName='$Target/Property[Type="JEE!Microsoft.JEE.Application"]/ObjectName$']/Properties/Property[@Name='path']$</Value>
</Setting>
</Settings>
</InstanceSettings>
</DataSource>
</Discovery>
Now that there is a discovery in place, the next step is to write some tasks that target these new classes for starting/stopping the applications. That would look something like below. Of course you will notice that this is rather simple (or so it would seem) because I have abstracted all of the magic into the Contoso.JEE.Tomcat.Seven.HttpGet.UrlProbe.GetRequestBody.ProbeAction (which I am not showing). The short version is that the (unshown) ModuleType calls the URLProbe module from the Microsoft.SystemCenter.WebApplication.Library.mp. It is rather long, but essentially it is a module for making HTTP calls.
<Tasks>
<!-- Reload an existing Tomcat Application via: -->
<!-- http(s)://{hostname}:{portnumber}/manager/text/reload?path={context_path} -->
<Task ID="Contoso.JEE.Tomcat.Seven.Restart.Task" Accessibility="Public"
Enabled="true" Target="Contoso.JEE.Tomcat.Seven.Application" Remotable="true">
<Category>Maintenance</Category>
<ProbeAction ID="Probe" TypeID="Contoso.JEE.Tomcat.Seven.HttpGet.UrlProbe.GetRequestBody.ProbeAction">
<ComputerName>$Target/Host/Property[Type="JEE!Microsoft.JEE.ApplicationServer.Monitored.Instance"]/HostName$</ComputerName>
<Protocol>$Target/Host/Property[Type="JEE!Microsoft.JEE.ApplicationServer.Monitored.Instance"]/Protocol$</Protocol>
<Port>$Target/Host/Property[Type="JEE!Microsoft.JEE.ApplicationServer.Monitored.Instance"]/Port$</Port>
<URL>/manager/text/reload?path=$Target/Property[Type="Contoso.JEE.Tomcat.Seven.Application"]/ContextPath$</URL>
<TimeoutSeconds>10</TimeoutSeconds>
</ProbeAction>
</Task>
<!-- Start an existing Tomcat Application via: -->
<!-- http(s)://{hostname}:{portnumber}/manager/text/start?path={context_path} -->
<Task ID="Contoso.JEE.Tomcat.Seven.Start.Task" Accessibility="Public"
Enabled="true" Target="Contoso.JEE.Tomcat.Seven.Application" Remotable="true">
<Category>Maintenance</Category>
<ProbeAction ID="Probe" TypeID="Contoso.JEE.Tomcat.Seven.HttpGet.UrlProbe.GetRequestBody.ProbeAction">
<ComputerName>$Target/Host/Property[Type="JEE!Microsoft.JEE.ApplicationServer.Monitored.Instance"]/HostName$</ComputerName>
<Protocol>$Target/Host/Property[Type="JEE!Microsoft.JEE.ApplicationServer.Monitored.Instance"]/Protocol$</Protocol>
<Port>$Target/Host/Property[Type="JEE!Microsoft.JEE.ApplicationServer.Monitored.Instance"]/Port$</Port>
<URL>/manager/text/start?path=$Target/Property[Type="Contoso.JEE.Tomcat.Seven.Application"]/ContextPath$</URL>
<TimeoutSeconds>10</TimeoutSeconds>
</ProbeAction>
</Task>
<!-- Stop an existing Tomcat Application via: -->
<!-- http(s)://{hostname}:{portnumber}/manager/text/stop?path={context_path} -->
<Task ID="Contoso.JEE.Tomcat.Seven.Stop.Task" Accessibility="Public"
Enabled="true" Target="Contoso.JEE.Tomcat.Seven.Application" Remotable="true">
<Category>Maintenance</Category>
<ProbeAction ID="Probe" TypeID="Contoso.JEE.Tomcat.Seven.HttpGet.UrlProbe.GetRequestBody.ProbeAction">
<ComputerName>$Target/Host/Property[Type="JEE!Microsoft.JEE.ApplicationServer.Monitored.Instance"]/HostName$</ComputerName>
<Protocol>$Target/Host/Property[Type="JEE!Microsoft.JEE.ApplicationServer.Monitored.Instance"]/Protocol$</Protocol>
<Port>$Target/Host/Property[Type="JEE!Microsoft.JEE.ApplicationServer.Monitored.Instance"]/Port$</Port>
<URL>/manager/text/stop?path=$Target/Property[Type="Contoso.JEE.Tomcat.Seven.Application"]/ContextPath$</URL>
<TimeoutSeconds>10</TimeoutSeconds>
</ProbeAction>
</Task>
</Tasks>
Finally, let's not forget that a new set of credentials are needed to access the Manager application.
<SecureReferences>
<SecureReference ID="Contoso.JEE.Tomcat.Seven.PrivilegedAccount"
Accessibility="Public"
Context="System!System.Entity"/>
</SecureReferences>
Deployment
Good news: I have done all of this work for you. All you need to do is import the attached MP and add the appropriate credential information.
In SCOM Console, go to Administration > Run As Configuration > Accounts and choose the task to Create Run As Account. Create a new Basic Authentication Run As Account with credentials that are appropriate for your Tomcat 7 instance(s).
Next go to Administration > Run As Configuration > Profiles, select the Privileged Tomcat 7.x Account, and right-click and choose Properties. Associate the Account create above with the Profile.
Now all that is necessary is for the discovery to occur. Due the internals of how SCOM works, this will occur one application at a time (recall that I mentioned above that the discovery needs to run for each application). When the discovery has occured you will three tasks for a selected application.
Now you can stop and start applications with one-click from SCOM Console!
Update on March 14th, 2012: Uploaded different management pack b/c I had mistakenly attached the wrong file.