Friday, May 30, 2008

Writing a RHQ plugin Part 5

Welcome back

As promised in the last part, I will talk a little bit more about the Facets of a plugin. But before we come to this, I want to show you how to detect physical processes on a machine via process scans. And last but least, I'm gonna talk a little bit about the skeleton plugin -- basically a plugin template that you can use to write your own plugins.

Using Process scans for discovery



Often when you want to discover resources, they are not virtual like the remote http servers in our examples, but processes on the local machine. The RHQ agent offers through its SIGAR library to query the process table in order to detect those resources. As you may have guessed, this involves the plugin descriptor, so lets have a look at this first before going to the discovery component

Process-scans in the plugin descriptor



As you have seen in part 2, each of platform/server/service can have <proces-scan> elements. The element itself is empty, but has two required attributes: name and query. Name just names this specific scan method. Query is the intersting part. It is a string written in PIQL (Process Info Query Language), which is documented in the JavaDoc to its class. I don't want to go into detail here and just show two queries. Visit the page just mentioned to learn more.

Query 1: find a JBossAS



process|basename|match=^java.*,arg|org.jboss.Main|match=.*


We want to query for a process, whose name is starting with java and which has an argument of org.jboss.Main -- a JBoss Server. The matching entry from ps is:

hrupp 2035 0.0 -1.5 724712 30616 p7 S+ 9:49PM 0:01.61 java
-Dprogram.name=run.sh -Xms128m -Xmx512m -Dsun.rmi.dgc.client.gcInterval=3600000
-Dsun.rmi.dgc.server.gcInterval=3600000 -Djboss.platform.mbeanserver
-Djava.endorsed.dirs=/devel/jboss-4.0.5.GA/lib/endorsed
-classpath /devel/jboss-4.0.5.GA/bin/run.jar:/lib/tools.jar
org.jboss.Main -c minimal


Query 2: find a process by its pid



Here the program id is stored in a file in a well known place


process|pidfile|match=/etc/product/lock.pid


PIQL will take the pid from /etc/product/lock.pid and search for a process with that id


Discovery component revisited



Ok, now that we have seen what we can do with the <process-scan> in the plugin descriptor, lets see how we can process that info. And .. as you may have alreay expected this is again very simple:


List<ProcessScanResult> autoDiscoveryResults =
context.getAutoDiscoveredProcesses();
for (ProcessScanResult result : autoDiscoveryResults) {
ProcessInfo procInfo = result.getProcessInfo();
....
// as before
DiscoveredResourceDetails detail =
new DiscoveredResourceDetails(
resourceType, key, name, null,
description, childConfig, procInfo
);
result.add(detail);
}


So basically you jut need to obtain the list of resources discovered by process scan (autodiscovered as opposed to a manual add) and create the DiscoveredResourceDetails as before. You can use ProcessInfo to get more information about the process and to even decide not to include it in the list of autodiscovered resources (imagine, the PIQL query would have looked for processes where the name starts with post. This would apply to postgres and postmaster. Here you could still filter the ones you really want.


A few more Facets



We have seen the MeasurementFacet in the previous articles. In this section I will briefly mention the other kinds of facets, so that you can get an idea what plugins are capable to do.

ConfigurationFacet



This facet indicats that the plugin is able to read and write the configuration of a managed resource. It goes hand in hand with <resource-configuration> in the plugin descriptor.

OperationFacet



An operation allows you to invoke functionality on the managed resource. This could be a restart operation or whatever you want to invoke on a target. Operations are described in <operation> elements in the plugin descriptor. They can have argument and return values.

ContentFacet



This facet allows the uploading content like files or archives into the managed resource. That way it is possible to centrally manage software distribution into managed resources. There exists a <content> element as counterpart.

The skeleton plugin



The skeleton plugin is a stub to get you started writing a plugin. So instead of copying an existing project like we did in the first place, you can take the skeleton, rename a few things on it and start with writing the plugin. It comes with a plugin descriptor that is filled with comments and also skeletons for the class files.
It is not yet complete, but expect it to be downloadable within the next few days. And if you are all nice to my colleague Jason, he will write a little installer for it, so a few of he manual steps can just be skipped :)


Plugin community


The RHQ wiki now hosts a plugin community page that shows available plugins:
RHQ Plugin Community.
Check it out for any updates about plugin related information - including lists of new plugins.

The end


Ok, that's it. I hope you have enjoyed the posts in the series. I am looking to forward to see you using RHQ and writing great plugins for it.

Please provide feedback - here or at the RHQ forums.

And join us in #rhq on irc.freenode.net




Part 1
Part 2
Part 3
Part 4

Small steps and bicycling

While Marlene did her first steps already some weeks ago, she wasn't to enthusiastic about. But since last weekend she is really 'running' around, enjoying walking on two feet wherever she can. This is really great.

Orlando on the other hand is now since yesterday able to ride a bicycle freely without any help and without stabilizer wheels. He still needs to practice some more before we can leave him into the wild, but its a great achievement too.

Wednesday, May 28, 2008

Reminder: Stuttgart SIG-JBoss meeting about jBPM

This is a reminder about the upcoming Stuttgart SIG-JBoss meeting.




The meeting is about Business process simulation with JBoss jBPM. Bernd Rücker will introduce into jBPM and Business Process Simulation.

The meeting will take place on Jun 5 at 7pm in the premises of Red Hat Germany.

You can read the full (German) announcement on the web site of the Stuttgart
Java User Group (JUGS)

Sunday, May 18, 2008

Writing a RHQ plugin Part 4

Welcome back to the fourth part of the trilogy :)

In the last three parts we have been building our first RHQ plugin. This was working great, but hardcoding the target URL is not really elegant. In this posting I will show you how to make the target URLs configurable from the GUI.

To do this we need to reshuffle things a little:
We will have a generic Server 'HttpCheck' that servers as parent for the individual http-servers that we want to monitor. Those will live as Services under that Server. In the Server inventory we will add the possibility to manually add new http servers on the go.



As you may have already guessed, most of this is done in the plugin descriptor. We also need some small code changes, but those are mostly to separate the concerns of the various files. Lets start with the changed plugin descriptor

Changed plugin descriptor



The boilerplate code is the same as before and will thus not be shown again.


<server name="HttpCheck"
description="Httpserver pinging"
discovery="HttpDiscoveryComponent"
class="HttpComponent">


I have changed the name of the Server to HttpCheck, as this is nicer in the GUI. Now the interesting part starts:


<service name="HttpServer"
discovery="HttpServiceDiscoveryComponent"
class="HttpServiceComponent"
description="One remote Http Server"
supportsManualAdd="true"
>


Here we introduce a Service as child of the above Server. It has its own Plugin Component and Discovery classes (the name of the classes reflect that they belong to this Service). Technically they could have gone into the existing classes, but this way it is more obvious who does what. The attribute supportsManualAdd tells RHQ that those HttpServer Services can be added by the operator in the GUI - just what we want.


<plugin-configuration>
<c:simple-property name="url"
type="string"
required="true" />
</plugin-configuration>


The plugin-configuration tells RHQ that this service can be configured with one simple property, the URL of the remote, which is required. I'll talk a bit more about properties in a minute.

Last but not least, we have moved the two metrics into the service tag (so I don't show them in detail again:


<metric property="responseTime" ...
 
<metric property="status" ...
</service>
</server>


A word about configuration and properties



The configuration type presented here, can be used in two forms within a plugin descriptor: plugin-configuration and resource-configuration. Check the structure diagram in part 2 to see where they belong.

A configuration can consist of a number of sub-elements - notably properties that are children of the abstract configurationType. This is described below.


(Diagram created with http://x2svg.sf.net/)

In addition it is possible to group properties together in the group element. The GUI will show those in their own collapsable section. Allowed child elements of group are one description element and instances of the abstract configuration-property. Templates allow you to preset some configuration properties, so the user has only to fill in stuff that is needed or that they want to change. The template itself is of the configuration type and thus no shown again.

Properties



Properties allow you to specify individual apsects of a configuration. There are three types of properties:

  • simple-property: for one key value pair, as shown above

  • map-property: for a bunch of key value pairs, following the java.util.Map concept

  • list-property: for a list of properties.




(Diagram created with http://x2svg.sf.net/)


As you can see from the structural diagram, it is possible to nest configuration properties within list-property and map-property elements to compose more complex configurations.

If we would want to allow our Services to add multiple remote servers with properties of 'host', 'port', 'protocol' it could look like this:


<plugin-configuration>
<c:list-property name="Servers">
<c:map-property name="OneServer">
<c:simple-property name="host"/>
<c:simple-property name="port">
<c:integer-constraint
minimum="0"
maximum="65535"/>
</c:simple-property>
<c:simple-property name="protocol">
<c:property-options>
<c:option value="http" default="true"/>
<c:option value="https"/>
</c:property-options>
</c:simple-property>
</c:map-property>
</c:list-property>
</plugin-configuration>


This example also shows a few more possibilities we have here:
The port has a constraint so, the GUI can validate the input being between 0 and 2^16-1. For the protocol, we offer the user a drop down list / radio buttons to choose the protocol from. It defaults to 'http', as indicated on the option element.

Change in discovery components



These changes are - as already indicated - more or less just for clarity reasons and to clearly separate out the concerns of each component.

Server level: HttpDiscoveryComponent



The HttpDiscoveryComponent from part 3 of the series only got some minor changes to cater for the change in naming, so I am not showing it here - have a look at the provided sources archive for details.

Service level: HttpServiceDiscoveryComponent



The HttpServiceDiscoveryComponent is more interesting, as we no longer have the hard coded keys, but we get the URL passed in from the GUI when the user is adding a new one.

public class HttpServiceDiscoveryComponent
implements ResourceDiscoveryComponent<HttpServiceComponent>
{
public Set<DiscoveredResourceDetails> discoverResources
(ResourceDiscoveryContext<HttpServiceComponent> context)
throws InvalidPluginConfigurationException, Exception
{
Set<DiscoveredResourceDetails> result =
new HashSet<DiscoveredResourceDetails>();
ResourceType resourceType = context.getResourceType();


This basically the same code that we already know. The interesting part starts now:


List<Configuration> childConfigs =
context.getPluginConfigurations();
for (Configuration childConfig : childConfigs) {
String key = childConfig.getSimpleValue("url", null);
if (key == null)
throw new InvalidPluginConfigurationException(
"No URL provided");


We get a list of plugin configurations passed from the context through which we loop
to determine the passed parameters. As we have only one - the url - this is simple.
If there is no url provided provided we complain (actually that should never happen, as we
marked the property as required in the plugin descriptor above).


String name = key;
String description = "Http server at " + key;
DiscoveredResourceDetails detail =
new DiscoveredResourceDetails(
resourceType, key, name, null,
description, childConfig, null
);
result.add(detail);
}
return result;
}


The remainder is the same as we know it already from the previous part.


Change in plugin components



The change in plugin components in basically that the old HttpComponent got
renamed to HttpServiceComponent and that we have a new "pseudo" HttpComponent on server level.

Server level - HttpComponent



Ok, this one is - as just described - a dummy implementation, as it just provides
placeholder methods from the ResourceComponent interface.


public AvailabilityType getAvailability() {
return AvailabilityType.UP;
}


We set the Availability to being always UP so the component can successfully start. We leave the other two methods just as empty implementations.

Service level - HttpServiceComponent



As indicated this is more or less the old HttpComponent except for one change:


public void start(ResourceContext context)
throws InvalidPluginConfigurationException, Exception
{
url = new URL(context.getResourceKey());
// Provide an initial status, so
// getAvailability() returns up
status = "200";
}


We are now setting the URL when the component is starting be reading it from the passed ResourceContext.

Building the plugin



The updated plugin can be built as shown in the previous part by calling mvn -Pdev install in the root of plugin source tree.

There is currently as of RHQ 1.0 a drawback though: Changes like those above may not be recognized by the system (or worse even throw an Exception in the server at plugin update time) - in this case you have to clean out the database and start with an empty one. We are looking into fixing this.

Summary



You have just seen, how easy it is to pass plugin configuration parameters from the GUI to a plugin by expressing the parameters in the plugin descriptor. Our plugin is now able to have an arbitrary number of child services that each monitor a different remote http server. The changes needed are basically a few more lines of XML and a little bit more Java code.

The sources are again available as zip archive. Just install it like the previous one (overwrite the previous one).

In the next posting I will talk a little more about the OperationFacet and the ConfigurationFacet and will show an example around using process scans for discovery of servers and services.


 


Part 1
Part 2
Part 3
Part 5








Technorati Tags:
, ,

OS X Gui package added to x2svg

For all of us OS X guys, it is always somewhat lame when the favorite app doesn't live in /Applications and can't just be double clicked (Ok, I admit, I love OS X because of its command line and its Unix internals).

So I just created an application bundle of the gui version of x2svg and uploaded it to SourceForge.

Just open the disk image and double click on x2svg.app

Enjoy :-)

Forums enabled for x2svg

I have enabled the forums fuctionality for x2svg in the hope for feedback from the community.

While this is not (yet) the top downloaded project at SourceForge, there are users out there and are using the program - I want to hear from you!

And in case you have missed it - Version 1.2 has been released with a lot of new functionality and fixes over previous versions.
Check the changelog at http://x2svg.sourceforge.net/changes.html.

Wednesday, May 14, 2008

Writing a RHQ plugin Part 3

Welcome to the third article in the "Writing a RHQ plugin" series.

In the last post I was talking about the plugin descriptor, discovery component and the plugin component. Today we will see the project structure, some code and how to build and run our plugin.

Remember: for the start we just have a very simple version of the plugin. We will perhaps enhance it in a future posting.

First let's talk about the project structure in the file system.

The RHQ project structure



To make things easier, we will host this plugin just within the RHQ tree. So go and check out RHQ from
http://svn.rhq-project.org/repos/rhq . Build the project as described on the build page on the wiki. After that is done, we will start to add our plugin into modules/plugins/.

Directory layout



Create the following directory structure:




Add modules/plugins/httptest/src/main/java to the build path in your IDE.

The classes within org.rhq.plugins.httptest form the plugin discovery component and plugin comonent and will be described below.


Maven pom


RHQ is a mavenized project, thus we need to supply a pom file. Easiest is to just grab another pom, copy it over to the root of the plugin subtree and change at least the artifactId:


<groupId>org.rhq</groupId>
<artifactId>rhq-httptest-plugin</artifactId>
<packaging>jar</packaging>
 
<name>RHQ HttpTest Plugin</name>
<description>A plugin to monitor http servers</description>


Please note that this only defines the pom for this subtree - it will not add this to the global project. To do this, you need to add the httptest plugin to the parent pom at the modules/plugins/ level:

  <modules>
<module>platform</module>
...
<module>postgres</module>
<module>httptest</module>
</modules>



The artifacts



We will now look at the individual three artifacts that make up a plugin. The directory tree above shows where they are located.

Plugin discovery component



First we start with discovering our server. This is relatively simple and directly
follows the description in the previous part.


public class HttpDiscoveryComponent implements
ResourceDiscoveryComponent
{
public Set discoverResources(ResourceDiscoveryContext context)
throws InvalidPluginConfigurationException, Exception
{
Set<DiscoveredResourceDetails> result =
new HashSet<DiscoveredResourceDetails>();
 
String key = "http://localhost:7080/"; // Jon server
String name = key;
String description = "Http server at " + key;
Configuration configuration = null;
ResourceType resourceType = context.getResourceType();
DiscoveredResourceDetails detail =
new DiscoveredResourceDetails(resourceType,
key, name, null, description,
configuration, null
);
 
result.add(detail);
 
return result;
}
}


Again it is extremely important that the key is/stays the same for each discovery performed!

Plugin component



So the next part is the plugin component to do the work


public class HttpComponent implements ResourceComponent,
MeasurementFacet
{
URL url; // remote server url
long time; // response time from last collection
String status; // Status code from last collection

As we want to monitor stuff, we need to implement the MeasurementFacet with the getValues() method (see below).

But first we implement two of the methods from ResourceComponent. The first returns the availability of the remote server. We check if the status is null or 500 and return DOWN, otherwise UP.

public AvailabilityType getAvailability()
{
if (status == null || status.startsWith("5"))
return AvailabilityType.DOWN;
return AvailabilityType.UP;
}

One needs to be careful here, as the discovery will not happen as long as this method is returning DOWN. So we provide a valid start value in the start() method from the ResourceComponent:

public void start(ResourceContext context) throws
InvalidPluginConfigurationException, Exception
{
url = new URL("http://localhost:7080/");
// Provide an initial status,
// so getAvailability() returns UP
status = "200"; so getAvailability() returns up
}

Analogous to start() there is a stop() method, that can be used to clean up resources, which we leave empty and don't show it here.

This leads us to getValues() from the MeasurementFacet:


public void getValues(MeasurementReport report,
Set<MeasurementScheduleRequest> metrics)
throws Exception
{
getData();
// Loop over the incoming requests and
// fill in the requested data
for (MeasurementScheduleRequest request : metrics)
{
if (request.getName().equals("responseTime")) {
report.addData(new MeasurementDataNumeric(
request, new Double(time)));
} else if (request.getName().equals("status")) {
report.addData(new MeasurementDataTrait
(request, status));
}
}
}

We get data from the remote and then loop over the incoming request to see which metric is wanted and fill it in. Depending on the type we need to wrap it into the correct MeasurementData* class.
This leaves the implementation of getData():

private void getData()
{
HttpURLConnection con = null;
int code = 0;
try {
con = (HttpURLConnection) url.openConnection();
con.setConnectTimeout(1000);
long now = System.currentTimeMillis();
con.connect();
code = con.getResponseCode();
long t2 = System.currentTimeMillis();
time = t2 - now;
} catch (Exception e) {
e.printStackTrace();
}
if (con != null)
con.disconnect();
 
status = String.valueOf(code);
}


This is nothing fancy again. Just open a URL connection, take the time it takes to connect, get the status code and we are done. Of course, this could be optimized, but for this article I wanted to use a simple solution.

Plugin descriptor



The plugin descriptor is where everything is glued together. First we start off with some "boiler plate" code:

<?xml version="1.0" encoding="UTF-8" ?>
<plugin name="HttpTest"
displayName="HttpTest plugin"
package="org.rhq.plugins.httptest"
version="2.0"
description="Monitoring of http servers"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="urn:xmlns:rhq-plugin"
xmlns:c="urn:xmlns:rhq-configuration">


The package attribute predefines the Java package for Java class names that appear later in the descriptor.

   <server name="HttpServer"
discovery="HttpDiscoveryComponent"
class="HttpComponent"
description="Http Server"
>


We define our plugin as a Server. From the intuition it could be a Service, but Services can't just live on their own so we choose a server here. The attribute class denotes the plugin component and discovery the discovery component. If you have specified the package above, you can just use the class name without prefix.

    <metric property="responseTime"
displayName="Response Time"
measurementType="dynamic"
units="milliseconds"
displayType="summary"/>

<metric property="status"
displayName="Status Code"
dataType="trait"
displayType="summary"/>
</server>
</plugin>


Now the two metrics. With all the knowledge you have now, they are nothing special anymore.
Again, responseTime is modeled as numerical data, while the status is modeled as trait. This could have been done differently, but is done here for educational purposes :-)


Ready, steady, go ...



To compile the plugin, go to the root of the plugin tree and do
mvn -Pdev install
The dev mode allows maven to automatically deploy the plugin to a server instance as described on the Advanced Built Notes page on the RHQ-Wiki.

When the server is running or starting up, you will see a line like this in the server log:


21:49:31,874 INFO [ProductPluginDeployer] Deploying ON plugin HttpTest (HttpTest plugin)


The next step is to make the plugin available to the agent. Remember that the agent is usually pulling plugins from the server when it is starting up. So if you have not yet started the agent, there is nothing to do for you. If the agent is already started, you can issue plugins update at the command prompt to update them to the latest versions of the server.

If you now log into the GUI, go to the resource browser and click on 'Servers', you can see the server discovered by our plugin:



Clicking on the server name or the little 'M'onitor icon leads you to the indicator charts, where you can see the response time values:



When you click on the Metric Data subtab, you can see the raw data for the server:



On the top you see the numerical ResponseTime data, and in the lower section the server status as trait as expected.

Summary



Congratulations, you just wrote your first RHQ plugin, that can also be used in JBoss ON 2.0. Writing a plugin consists of three parts: Discovery, Plugin Component and plugin descriptor. The agent with its plugin container is providing you with all the infrastructure to talk to the server, scheduling of metric gathering, scheduling of discovery etc. This means that you can fully concentrate on the business code of your plugin. RHQ just does the rest.

I have made the source code of those articles available as zip archive, that you can unpack in the modules/plugins/ directory.

I want to stop here for now. I will perhaps extend this on how to make the configuration flexible instead of hardcoding the server url. I also kept a third type of measurement data a secret, that I might be talking about some more.

Please provide feedback - either as comment to these articles or in the RHQ forums.

Here are again the references to the other articles in this series:


Part 1
Part 2
Part 4
Part 5








Technorati Tags:
, ,

Tuesday, May 13, 2008

If your JBossAS does not want to redeploy embedded war archives ...

JBossAS has since I remember a cool feature called Hot-Deploy. When you want to deploy an archive (EJB-Jar, Webarchive or else), you just throw it into the deploy/ directory of the server config. JBossAS will detected (by default within 5 secs) and deploy it. Same if you have updated an existing archive.
To just force a redploy, you can just touch the archive.

JBossAS has a second cool feature around this: exploded archives. Here you don't need to zip up the archive to deploy it, but you can just deploy a flat directory hierarchy (which of course needs to follow the required archive structure). To redeploy a changed archive, you don't touch the archive directory, but the descriptor file in it (e.g. web.xml for a .war archive).

Now lets imagine you want to update a few files (like struts config) in an exploded .war within a .ear. You'd expect to just touch the web.xml file of the war an be done. But sometimes this just does not work. If this is the case, but normal redeploys of e.g. the ear work, then go and check deploy/jboss-web.deployer/context.xml

This needs to read:


<Context cookies="true" crossContext="true" reloadable="true">


After changing this, restart the JBossAS and the redeploy of the embedded war will work.

x2svg new release x2svg-1.2

Project x2svg just released the final 1.2 version.



Changes in release 1.2 since the last beta are:

  • Pass debug flag to the parsers.

  • Add the possibility in the GUI to pass parser specific options to
    the parser (SF fr#1956587).

  • Allow parsing of attributes and element comments. It depends on the
    individual parser if this is supported (SF FR#1940442). As this is still
    somewhat experimental, it is turned off by default.

  • Pull ant.lib into lib/, so the IDE can use this one.

  • Allow parsing of types in the XSD parser (SF FR#1947079).

  • Lot of cleanup and smaller fixes.



Browse the full changelog to see all changes in earlier versions.

You can download it from Sourceforge

Please provide feeback:


Help is always welcome.





Friday, May 09, 2008

Writing a RHQ plugin Part 2

In the last post I showed the general architecture of RHQ and where plugins live. So we can now start writing one.

The scenario revisited



Our plugin should be able to connect to a http server, issue a HEAD request on the base url (e.g.
http://localhost/) and return the http return code as trait and the time it took as numeric data (see below).



To make things easier for the purpose of this series of postings, we will have the agent running on the machine the RHQ server lives on and we will just try to get data from the Servers http connector at port 7080 (the default port).

What do we need ?



In order to write our plugin we basically need three things

  • A plugin descriptor. This contains metadata about the plugin: which metrics should be collected, what operations does it support etc.

  • A discovery component. This part discovers the actual resource(s) and delivers them to the Inventory.

  • A plugin component. This component executes operations and gathers the measurement data etc.



So lets have a look into those three parts.

Plugin descriptor



The plugin descriptor is described by an XML Schema that you can find in svn. The basic structure is as follows:




(Click for pdf version), Graphic done with http://x2svg.sf.net/

The desciptor consists of a few sections. First you can express dependencies to other plugins. This is allows reuse of existing plugins and is useful when you e.g. want to write a plugin that itself needs the JMX plugin, so that it can do its work.

The next are a row of platform/server/service sections. Each of those can have the same (XML-)content as the platform that is shown as an example - they are all of the same (XML-) data type (as a platform/server/service) as each is a kind of resource type, as you already know from the first part.

Example:

<service name="CheckHttp">
<metric property="responseTime"
description="How long did it take to connect"
displayType="Summary"
displayName="Time to get the response"
units="ms"
/>
</service>


The name of a <service> and the other ResourceTypes (platform, server) must be unique for a plugin. So it is not allowed to have two services named "CheckHttp" within our example plugin, but you could write a Tomcat5 and a separate Tomcat6 plugin that both have a service with the name "connector".

For the start we are especially interested in one of the sub elements: metric for our example plugin, so I will describe this here in a little more detail. For all other tags refer to the XML Schema that has a lot of comments.

Metric



This is a simple element with a bunch of attributes and no child tags. You have already seen an example above.
Attributes of it are:

property: name of this metric. Can be obtained in the code via getName()
  • description: A human readable description of the metric

  • displayName: The name that gets displayed

  • dataType: Type of metric (numeric / trait /...)

  • units: The measurement units for numerical dataType

  • displayType: if set to "summary", the metric will show at the indicator charts and collected by default

  • defaultOn: Shall this metric collected by default

  • measurementType: what characteristics do the numerical values have (trends up, trends down, dynamic). The system will for trends* metrics, automatically create additional per minute metrics.



For the sample plugin we will use a metric with numerical dataType for the response time and a dataType of trait for the Status code. Traits are meant to be data values that only rarely change like OS version, IP Address of an ethernet interface or the hostname. RHQ is intelligent enough to only store changed traits to conserve space.

Discovery component



The discovery component will be called by the InventoryManager in the agent to discover resources. This can be done by a process table scan (e.g. for the Postgres plugin) or by any other means (if your plugin wants to look for JMX-based resources, then it can just query the MBeanServer. Well, actually there is a JMX-Plugin that can do that for you in clever ways).

The most important thing here is that the Discovery component must return the same unique key each time for the same resource.

The DiscoveryComponent needs to implement org.rhq.core.pluginapi.inventory.ResourceDiscoveryComponent and you need to implement discoverResources().
The usual code block that you will see in discoverResources() is:


Set<DiscoveredResourceDetails> result = new HashSet<DiscoveredResourceDetails>();
for ( ... ) {
...
DiscoveredResourceDetails detail = new DiscoveredResourceDetails(
context.getResourceType(),
uniqueResourceKey,
resourceName,
resourceVersion,
description,
configuration, // can be null if no confi
processInfo);
result.add(detail);
}
return result;


Basically the context passed in gives you a lot of information, that you can use to discover the resource and create a DiscoveredResourceDetails object per discovered resource. The list of result objects is then returned to the caller. Simple - eh?

Plugin component



The plugin component is the part of the plugin that does the work after the discovery has finished.
For each of the "basic functions" in the plugin descriptor, it needs to implement an appropriate Facet:












Descriptor elementFacet
<metric> MeasurementFacet
<operation> OperationFacet
.....


Each Facet has its own methods to implement. In the case of the MeasurementFacet this is e.g. getValues(MeasurementReport report, Set metrics). The report passed in is where you add your results. The metrics is a list of metrics for which data should be gathered. This can be all ouf your definied <metric>s at once or only a few of them - this depends on the schedules the user configured in the GUI.




Ok, that's it for now. In the next post we will do some coding and get our plugin to work.




Part 1
Part 3
Part 4
Part 5







Technorati Tags:
, ,


Thursday, May 08, 2008

Sample app of my ejb3 book updated (German)

I have just updated the sample app + installation guide of the sample app from my ejb3 book to use JBoss 4.2.2.GA. This makes the installation much simpler. I also removed a few issues from various places.

You can the updated description on the books web page.

Remember, even as there is the free PDF version of the book, it still can be ordered in print.

Wednesday, May 07, 2008

Writing a RHQ plugin Part 1

Red Hat and Hyperic released Project RHQ in the open in February. Meanwhile we released the first GA version of RHQ together with JBossON 2.0 at JavaOne 2008.

This post and the next few will try to show how to write your own plugins for RHQ.
As an example scenario the plugin will try to reach a http server, see if the base URL is available and return the status code + the time it took to reach it.

General architecture of RHQ



Before we go into detailed plugin writing, I first want to show the general architecture of RHQ and its plugin system.

RHQ follows a hub and spoke approach: A central server (or cluster) processes data coming in from agents. The data is stored in a database connected to the server. Users / admin can look at the data and trigger operations through a web-based GUI on the server



Agents do not have a fixed functionality, but can be extended through plugins which we will see below. Usually there is one agent running per machine with resources to manage. The RHQ server itself is able to run an agent embedded in the server. This is mostly for demo and test scenarios, but it is well able to monitor the server machine.

Server services



The server hosts a number of services like

  • It has a view on the complete Inventory

  • It processes incoming measurement data

  • It triggers alerts to be sent

  • It triggers operations on managed resources

  • It hosts the graphical user interface

  • It hosts the user management

  • ...



Some of those services are reflected in the agent like inventory syncing, gathering of measurement data or running operations on a managed resource, while alert processing or hosting of the GUI is purely on the server.

Agent architecture



The agent is sort of a container that hosts some common functionality like the communication interface with the server, logging, starting and stopping of plugins or reading configuration files. In addition to this, it hosts plugin containers, who host the actual plugins. When you write a plugin, you talk to the plugin container.



The agent is in addition to the plugin containers also hosting common service like the communication with the RHQ server, logging or the handling of the command line and interactive command prompt.


Central functionality: Inventory



The central functionality of RHQ is the inventory. Each resource that you want to manage or monitor must be present in that inventory. RHQ has mechanisms to autodetect and also manually add resources. We'll come back to that later when we are talking about implementing plugins.

Each org.rhq.core.domain.resource.Resource has a certain org.rhq.core.domain.resource.ResourceCategory:


  • Platform: This is basically a host where things run on

  • Server: Things like database server, JBossAS instance or the RHQ agent

  • Service: (Fine grained) Services offered by a server



The ResourceCategory is sort of hierarchic as you can see on the next image:



A platform hosts servers, a server can host other servers and services and a service can host other services. In theory it is also possible that a platform is hosting other platforms.
As an example: you have a Red Hat Linux platform, which hosts the RHQ Agent and JBossAS as a server. This AS it self is hosting a Tomcat server. Both JBossAS and Tomcat themselves are hosting services like JMS or Connectors.
So at the end this will result in a tree of resources with the Linux platform as its root.

In addition to the category each Resource also is of a certain org.rhq.core.domain.resource.ResourceType. For a platform this might e.g. "Max OS X", "Red Hat Linux", "Debian Linux" etc. Or the JBossAS and Tomcat from above are both of category Server, but have different ResourceType.

The RHQ wiki has an overview of the inventory db schema.



Ok, that's it for now. As a homework, check out the documentation at the RHQ wiki and the source code from the RHQ svn

Greg Hinkle also put a high level overview of the plugin system online.

Joseph Marques has written an article about things to consider before writing a plugin and will soon write a second part of it (actually it is already online).





Part 2
Part 3
Part 4
Part 5







Technorati Tags:
, ,


Tuesday, May 06, 2008

JBossON 2.0 and RHQ 1.0 released

After a lot of work JBossON 2.0 was released today together with RHQ 1.0 at JavaOne conference.

You can read the press release at:

Yahoo

Red Hat

This is a great release and it feels great that over a year of hard work finally fell into place. There are no real release notes for RHQ, but you can browse the release notes created by JIRA at jira.rhq-project.org.

I wrote already about a few of the new features and I am planning on writing soon about developing own plugins for RHQ and JBossON.

If you want to meet the team, join us on #rhq at irc.freenode.net.

Greg from the JBossON team will also be around at JavaOne - you can probably meet him at the JBoss booth.

My colleague Jason Dobies also has an article about the release.


Friday, May 02, 2008

JPA 2 first draft is out

The counterpart to the EJB 3.1 spec, the Java Persistence API 2.0 spec has just published a first public draft at JSR 317.
There have been so many changes to the spec since JPA 1.0 (JSR 220) that I don't want to mention them here.
Mike Keith has recently written an article that describes some of them.

Like in JPA 1.0, JBoss has contributed a lot to the stuff. Both Gavin King and Emmanuel Bernard were very active in this update.

But check them out by yourself at the JSR 317 spec page.