Advanced Management Plugin System
Overview
RHQ has a plugin development API called the Advanced Management Plugin System (AMPS).
AMPS has been built from the ground up to provide a easy-to-use yet powerful way to write, deploy and update plugins.
 | Here are links to the SVN repository pointing to the source for the different APIs that plugin developers will need to use:
|
Getting Started Quickly
If you want to get started quickly and dive right in writing your own custom plugin, we suggest beginning with the custom-plugin maven module skeleton. This includes a maven pom with dependencies defined, a starter set of resource components and a minimal rhq-plugin.xml plugin descriptor. This maven module can be found at http://svn.rhq-project.org/repos/rhq/trunk/etc/samples/skeleton-plugin. If you want to manage your own product through a JMX interface only, you might even be able to start off with the much simpler "custom-jmx-plugin" - it doesn't require any Java code to be written, just modify the plugin descriptor to refer to custom JMX MBeans you want to access. See http://svn.rhq-project.org/repos/rhq/trunk/etc/custom-jmx-plugin for more.
We still recommend that you come back to this page and read it to fully understand AMPS.
AMPS Modules
There are five main "parts", or modules, that make up AMPS:
- Plugin Container (module core/plugin-container)
- Provides the main manager that contains all the plugins and the objects that manage them
- Runs inside the RHQ Agent
- The plugin writer does not need to be concerned with the classes in this module
- Plugin Components (module core/plugin-api)
- When the term "public AMPS API" is used, it typically refers to the interfaces in this module
- Contains component interfaces whose implementations will represent objects in the managed system
- Contains the interfaces for all facets a plugin can support (e.g. Measurement, Operation, Configuration, etc)
- Is simply an interface API - no implementations
- The plugin writer will write plugin components that implement these interfaces
- Domain Objects (module core/domain)
- Contains all the individual domain object POJOS - things like Resource, ResourceType, Configuration, etc.
- All other parts of the plugin system use the domain objects to model the managed system
- Plugins (module plugins)
- The out-of-box plugins that JBoss ON ships with
- These are the individual plugins that are loaded by the Plugin Container
- Each plugin provides the ability to manage a particular product
- The plugins implement one or more "components" from the Plugin Components module
- Look at the source code of these plugins to learn how to properly write plugins
- Native System (module core/native-system)
- Provides low-level JNI/native access to operating system information
- Allows you to get information from the OS process table to determine what things are running
- Allows you to execute external programs
- Provides metrics on operating system level details such as machine memory usage, CPU utilization, etc.
- Provides a Java-only fallback API for those platforms that currently do not have a JNI library available
How the AMPS modules integrate
The RHQ Agent provides the means by which the Plugin Container gets configured and initialized/shutdown. It is the agent's job to start the Plugin Container whereas its the Plugin Container's job to start the plugins. From the plugin writer's point of view, in order to deploy a new plugin, all that needs to be done is write a valid deployment descriptor and write the appropriate components that will communicate with the managed resource. Once the RHQ Agent and its Plugin Container is initialized, they can be considered a black box. The Plugin Container will handle all the classloading, threading, and running of the plugins.
Plugin Container Module
The Plugin Container is the subsystem deployed within the RHQ Agent that loads and manages all of the plugins. It is to be considered by the plugin writer almost as if it is a non-existing entity. The plugin writer never explicitly interacts with the plugin container or its internal managers. The Plugin Container isn't technically part of the public AMPS API - there are no classes or interfaces within the Plugin Container module that the plugin writer has to implement or use. Now that you know what the Plugin Container is, you can forget about it - you do not need to know any details of it if you just want to write plugins.
Plugins Module
A plugin's job is to manage and monitor one or more "products" - where a product can be a hardware box, a framework, embedded software or an external server or anything else that can be "managed". JBossAS application server is considered a "product"; JBoss ON ships with a JBossAS plugin to manage them. Apache Web Server, Hibernate, JBoss Portal and JGroups are all examples of "products" that can be managed by RHQ plugins. A "product" consists of one or more managed resources (or resources for short). Resources can be categorized as one of two generic types - servers or services. For example, the JBossAS "product" consists of a JBossAS server resource which has many service resources as children, such as Data Source services, JMS Queue/Topic services, EJB Session Bean services and more. From this point forward, the term "resource" will be used in lieu of the term "product" since a set of "resource" objects is how a plugin models a product and is, therefore, the more appropriate term to use.
At its core, a plugin consists of a single jar file that contains component classes and an XML plugin descriptor file. The plugin descriptor provides the metadata that describes everything about the plugin and the resources it can manage. This includes the resource names and versions, plugin configuration that enables the plugin to connect to the resource and resource configuration that configure the resource's internal components.
Plugin Descriptor
A plugin descriptor is an XML file that follows a well-defined XML Schema definition. A plugin writer needs to understand the descriptor schema and the concepts it models, because it is through the definitions within this plugin descriptor that the product's management interfaces can be exposed through JBoss ON.
A plugin descriptor defines some or all of the following:
- the names and versions of the resources (i.e. a product's servers and services) that are supported by the plugin
- plugin configuration that define the settings the plugin components use to connect to the managed resources
- a set of metrics (aka measurement definitions) that define the types of data the managed resources emit. This is the data that JBoss ON uses to monitor the resource
- a set of operations that can be invoked to manipulate managed resources. "start" and "stop" are the two most common operations a plugin would want to expose, thus allowing a user to start or stop a managed resource
- resource configuration that define the actual configuration of the managed resources (which is different than the plugin configuration; plugin configuration tells the plugin components how to connect/talk to the managed resource whereas resource configuration is the actual configuration settings of the managed resource itself)
- child resources (that is, the descriptor can define a hierarchy of resource types where one resource of one resource type can be considered the parent of other resources of another type). JBossAS and their Data Source services are a prime example of this - a JBossAS server resource is of type "JBossAS Server" - it has child service resources of type "JBossAS Data Source Service".
Please see the AMPS-Plugin Descriptor page for more information.
Plugin Components
At the heart of the public AMPS API are "plugin components" that the plugin writer implements. There are two basic types of components - a ResourceDiscoveryComponent and a ResourceComponent, which are described in the sections below. In effect, the plugin writer needs to only write (or reuse, if appropriate) these two component implementations for each type of resource that is to be supported.
 | It is recommended that you read the javadocs for all classes within the public AMPS API (i.e. the core/plugin-api module). All interfaces are javadoced to help explain further what it is a plugin writer needs to implement in order to complete a fully functioning plugin. The public AMPS API javadoc is considered part of the public AMPS documentation and a more detailed extension to this documentation page. |
ResourceDiscoveryComponent
The discovery component is an implementation written by the plugin writer that performs the discovery of the actual managed resources. The discovery component's job is to scan the platform (that is, the machine the agent/plugin container/plugin is running on) and to report back what it finds. A discovery component is only responsible for finding resources that it directly is in charge of managing. That is to say, a JBossAS plugin discovery component is not responsible for discovering all Apache Web Servers - it only needs to find JBossAS resources (leave the discovery of Apache Web Servers to the Apache plugin).
A discovery component will be told to go hunt for resources at an appropriate time by the Plugin Container. When the Plugin Container asks the discovery component to go discover more resources, it will send in a ResourceDiscoveryContext object to the discovery component. This context contains all the information the component needs to perform its duties of finding and creating new resources. The discovery context is also used to inject resources into the discovery component, in the case where the Plugin Container was able to discover new resources on behalf of the discovery component. A Plugin Container can only auto-discover resources if the appropriate metadata is supplied to it via the plugin's descriptor.
Resource Component
A resource component is a plugin abstraction that represents an actual managed resource. A resource component is stateful whose lifecycle is managed by the Plugin Container.
The Plugin Container will start and stop a resource component at the appropriate times. When a resource component is started, it typically connects to its underlying resource (the managed resource it represents) and maintains that connection until it is stopped by the Plugin Container (this is an implementation detail that a plugin writer is free to change). A resource component implementation provides a way for the Plugin Container to ask for the availability of the managed resource ("is this resource up? or has it gone down?") and to access optional functionality facets that a plugin writer chooses to expose. More on facets below.
Plugin Component Facets
A "facet" is simply an optional piece of functionality that a plugin writer chooses to expose to the Plugin Container and ultimately to the JBoss ON system as a whole. A plugin writer is free to have his resource components implement some, all or none of these facets (obviously, the more facets that are implemented and exposed, the more powerful and useful the plugins become).
MeasurementFacet
This facet exposes the capability for the component to collect measurement data from the managed resource and to report that data back to the server. For a measurement facet to work, the plugin must define one or more metric definitions for the resource component's resource type in the plugin descriptor. The resource component does not have to concern itself with how to schedule measurement collections and when it should collect the data. The only thing the MeasurementFacet requires the resource component to do is go out to the actual managed resource and collect the requested data. The Plugin Container will manage all measurement collection schedules and will only call into the resource component's MeasurementFacet when the time is appropriate and it will only ask for the metrics that need to be collected at that time.
The measurement facet is what provides the graphs of measurement data that you see in the JBoss ON GUI Console.
ConfigurationFacet
This facet provides the ability for a resource component to modify the configuration of the actual managed resource. When a resource component implements this facet, it is saying it has the capability to get the current configuration of the managed resource as well as be able to change it. As an example, the JBossAS Data Source Service resource component implements the ConfigurationFacet because it can report back to the user what the current settings are of that data source (e.g. its JDBC driver, its JNDI name, its connection pool size, etc) and it can allow the user to change those settings.
OperationFacet
This facet allows the resource component to perform operations (aka control actions) on the managed resource itself. This allows, for example, the JBossAS Server resource component to provide the capability to start and stop the JBossAS server. Other examples of operations are being able to clear a connection pool for a data source, or ask a resource to empty a data cache. Whatever the managed resource can be told to do, a resource component can expose that as an operation to the JBoss ON user.
ResourceFactoryFacet
Some resource components can support the creation and deletion of child resources (for example, a resource component representing the JBossAS server can create and delete JBossAS data source services by creating and deleting *-ds.xml files). This facet exposes this functionality.
ContentFacet
Resources may have content associated with them including deployed software or software parts and other content. This system can be used to inventory these software parts and to install and remove them. Examples of deployed content are RPMs on Linux, EARs and WAR applications or libraries and deployment files on JBoss Application Server. Plugins can support arbitrary types of content with this system
Resources may have additional files (aka "content") associated with it - configuration files, deployment files, etc. Those resources that have associated content can implement the ContentFacet to help create, delete and manage that content.
Domain Objects
Domain Objects are the building blocks of the AMPS management system. They include the basic pieces of the management inventory such as resources, resource types, configuration data, et. al.
Resource and ResourceType
Resource represents a single entity in inventory - it can be a platform, server or service. The semantics of what a platform, server or service is can be vague - as such, a Resource object encapsulates any resource no matter what categorization it is under. ResourceCategory is an enumeration that is associated with each Resource and indicates if the Resource is considered a platform, server or service. ResourceType represents types of resource instances that can be added to inventory.
ResourceTypes are defined by plugin descriptors. As you add more plugins to the plugin container, your system can understand and manage more types of resources. ResourceTypes are added to your system when you deploy new plugins. For example, deploy the JBossAS plugin and you can now manage JBossAS servers. Introduce the Tomcat plugin, and you can now manage Tomcast servers, in addition to those JBossAS servers.
Resources represent individual instances of managed products and are added to your system when they are auto-discovered by your plugins and imported, or manually created via the RHQ GUI Console.
Platform/Server/Service and Resource Hierarchy
Plugin descriptors not only define the ResourceTypes that it understands, but it also organizes those types in a hierarchy. For example, a JBossAS EJB Service only runs inside of a JBossAS Server, thus, the JBossAS EJB Service ResourceType is a child type of the JBossAS Server ResourceType.
Plugins can hardcode their hierarchy directly in its descriptor by nesting <service> definitions inside <server> or other <service> definitions. You can also use one of the models of AMPS-Plugin Extensions to enhance and extend existing resource types from other plugin definitions.
Configuration
Configuration is one of the larger APIs inside of the Domain Object module. It defines a highly extensible set of configuration settings that is associated with any resource. Configuration is so versatile, it is used in many places in JBoss ON where a set of configuration properties are required - such as plugin configuration to define how a plugin component can connect to a particular resource and operation parameters to define what arguments need to be passed when invoking a resource's operation.
Identity
Identity is a critical part of writing plugins to model and manage products. The plugin writer must deliver consistent identities for inventory elements that meet the uniqueness requirements and are consistent between discoveries. The resource keys are the critical part of a plugin developers efforts. They must be able to reliably and uniquely identify a resource under varying conditions and have to be a natural key that can be detected any time a discovery is run with regard to past discoveries. Keys do not have to be globally unique, but only unique to the according to the rules below.
Resource: Resources are unique to their parent, resource key, and resource type
Package Type: Package Types are unique to their parent resource and name.
As an example, you can have a Postgres Server resource that has a child database resource with a key of "RHQ" as well as a child user resource with a key of "RHQ" because they are different types. Different plugins can not step on each other as the plugin is part of the definition of the type and two plugins may even define the same type though this is not recommended to avoid confusion. It is recommended that you keep keys simple (such as the Database name of "RHQ") and depend on it being a child of a specific parent for further uniqueness in the hierarchy. This allows you to have two "Database" resources with a key of "RHQ" as long as they are children of two different Postgres Server resources.
Native System Information Access
All plugins have access to a set of native libraries that allow plugin components to ask the underlying operating system for details about the machine on which the plugin is running. Some of these features are not available on all hardware and OS platforms - only those platforms that have the native libraries available will be able to support all features described below. However, for those platforms that do not have the native libraries available, there will still be a limited feature set available.
SystemInfoFactory and SystemInfo
The plugins will have access to a SystemInfo object that is specific to the hardware/OS platform on which the plugin is running. Once a plugin obtains a SystemInfo object from its context (either ResourceDiscoveryContext or ResourceContext), it can make calls to that object which will call down into the native libraries to obtain the requested data from the operating system. If there are no native libraries available, the SystemInfo will be backed with a pure Java implementation of some, but not all, of the methods defined in the SystemInfo interface (see the JavaSystemInfo implementation of that interface). The methods that are not supported by the pure Java implementation will throw an UnsupportedOperationException.
ProcessInfoQuery
One interesting feature the SystemInfo interface provides is the ability to probe the operating system's process table. This is useful for your ResourceDiscoveryComponent implementations because they can scan the list of running processes and try to determine if it can auto-detect a managed resource that it is tasked to discover.
Through the use of the ProcessInfoQuery object, you can find processes that match a given set of criteria, defined by the Process Info Query Language (PIQL). You can even set pre-defined PIQL queries in your plugin's descriptor via the process-scan tag to have the plugin container scan the process table on behalf of your plugin.
Process Information Query Language (PIQL, pronounced "pickle")
 | Rather than repeat already documented information, refer to ProcessInfoQuery to learn more about the syntax and usage of PIQL. |
Plugin Extensions and Dependencies
Normally, the plugins that you write are independent from other plugins - in fact, during runtime, they are isolated from other plugin jars via separate classloaders. However, there are instances where you need to have one plugin depend on another, for either their class definitions or resource type definitions. For example, if your product's management interface uses JMX, you could have your product's plugin depend on the JMX plugin in order to be able to re-use the EMS functionality provided by the JMX plugin. An other example is the case where a Tomcat server is embedded in a JBossAS server - the JBossAS plugin can depend on the Tomcat plugin so the JBossAS discovery component classes can extend the Tomcat discovery component classes.
To have one plugin extend another, you provide one or more depends elements to the <plugin> element within the plugin descriptor. A depends element defines a plugin that the defining plugin depends on. A dependent plugin will be deployed after all of the plugins it depends on have already been deployed.
There are two different ways you can extend other plugins and their resource types: the Embedded Extension Model and Injection Extension Model. They provide slightly different functionality and have different semantics - why you would use one over the other is described in more detail in the AMPS-Plugin Extensions page. Please refer to that page for more information on how you can extend other plugins and their resource types.
Prepare the RHQ Server to use your custom plugin
Once you've built a plugin, put your custom plugin .jar inside the RHQ Server at:
jbossas/server/default/deploy/rhq.ear/rhq-downloads/rhq-plugins
That's all you need to do. If the server is already running, in a few seconds it will auto-detect the new plugin (or, if you overwrote an existing plugin, it'll detect the updated plugin). At this point, your agents are free to download the new/updated plugin.
Prepare the RHQ Agent to use your custom plugin
Once you deployed your new custom plugin on the server, you can have your agents download the new plugin. If the agent already has an older version of your plugin, it can update itself by pulling down the new plugin and overwritting the old one with it.
If the agent has not been started yet, all you need to do is start it. By default, the agent will automatically update its plugins at startup (there is a configuration setting that disables this feature; if you are interested, see the agent-configuration.xml for the rhq.agent.update-plugins-at-startup configuration preference).
If the agent is already started, you can execute the "plugins update" prompt command. This will shutdown the plugin container, pull down any plugins that have been updated on the server, then restart the plugin container.