By default, a resource type defined in a plugin is only required to implement the discovery and availability APIs. In other words, the majority of the code required to back that resource type will focus around finding resources on the system, connecting to them, and determining whether or not the resource is up and running.
Each resource type must have a corresponding code implementation of the discovery API. This implementation is scoped to a particular resource type and must understand how to find instances of that type (it is up to the discretion of the plugin writer as far as whether or not to discover both running and stopped resources).
The plugin can leverage process information on the machine provided by the plugin container if necessary. Metadata, in the plugin descriptor, is used to provide a mask on what processes on a per resource type basis to make accessible to the plugin at discovery time.
The other required API that must be implemented for each resource type is the general resource component API. Implementations of this interface will be started for each resource discovered. Outside of the start/stop methods (which are largely used to establish the initial connection to the resource), the main functionality exposed by this interface is the availability check.
Calls to the availability API will occur frequently for all inventoried resources in order to keep the user informed of the state of each resource. One best practice is for plugin writers to determine how to best utilize the start operation to cache any connections to the resource used by the availability check that may be costly.
In some cases, the discovery and availability features are enough. However, it's very likely that the plugin will want to take advantage of the much more rich features provided by the platform. To facilitate this, a plugin may take advantage of any of a number of subsystems made available through the plugin container. None of the additional subsystems are required to be supported, and any combination of them may be utilized depending on their applicability to the resource type in question. Keep in mind that this is per resource type; it is very likely that each resource type implemented in a single plugin may choose to utilize different combinations of subsystems.
The configuration subsystem allows an RHQ user to remotely view and edit a resource's configuration. The names and types of properties available for configuration on the resource are defined as metadata on the resource type in the plugin descriptor. The plugin code itself is responsible for communicating with the resource and actually applying any configuration changes triggered by the user.
The plugin writer can also indicate static conditions on each property that will be used as validation on the user input. For instance, if a property corresponding to a server's port is specified as configurable, conditions can be added to cause server-side validation to ensure it is a number in a specific range. Once the conditions are defined, there is no further coding necessary; the server will guarantee that updates to the configuration honor these conditions prior to sending the request to the plugin.
The metrics subsystem provides a means to query the plugin at user-scheduled intervals for various metrics on a specific resource. The names, types, units, and default collection interval are defined as metadata on the resource type in the plugin descriptor. Once the plugin descriptor defines the metric definitions, the plugin container provides the mechanism for enforcing the scheduled collection. The plugin code simply needs to understand how to connect to the resource and retrieve the current value for each metric defined.
The operations subsystem provides a framework for executing operations against a remote resource. The set of operations that can be executed on a resource are defined in the plugin descriptor's metadata for that resource type. Additionally, for each operation a set of parameters can optionally be indicated. When a user attempts to execute an operation that defines a set of parameters, the user interface will prompt for these values prior to submitting the request. The parameters are defined using the same metadata type as with the configuration subsystem, allowing the same forms of server-side validation as described above. Finally, the metadata for an operation can define a structure for the complex result type of the operation. Again, the configuration element is reused, allowing the operation to return a series of name/value pairs (in fact, even more complex results are possible due to the user of the configuration definition element).
The plugin container provides the framework for threading and timing out executions of operations. The plugin code itself need only contain the means to perform the actual operation execution on the resource for each defined operation.
For instance, many resources define "start" and "stop" operations for controlling the state of the resource. The plugin code contains whatever logic is necessary to perform the starting and stopping of the resource. The rest of the functionality, including the user interface for accepting user inputted parameter values, scheduling of operations to run in the future or recur, and server to agent communication of the request and response are all handled by the RHQ platform itself.
The content subsystem enhances the abilities of a resource type by defining a series of package types that may be deployed to corresponding resources. Packages typically refer to files deployed into a resource, but are not strictly limited to files. Packages may include applications installed on a server, libraries in use by a resource, or any other type of file that may be of interest on a particular resource.
The metadata for a package type, included in the plugin descriptor, includes the name of the package type, default discovery interval, and a categorization of the type. Additionally, a configuration definition element (as used in the configuration subsystem) can be specified to indicate a series of attributes that are specific only to that package type. For instance, if the license information of a package type is particularly relevant, it can be added as a property to this configuration definition and populated on package discovery.
The subsystem allows for the inventory. At scheduled intervals, the plugin container will request a snapshot of the packages on a resource. The server inventories information on these packages and makes it available to users.
Users can also deploy new packages to a resource. The plugin writer only needs to write code to place the package in the appropriate location on the resource. The platform provides the means for streaming the package bits remotely from the server and agent and will leverage whatever communication security that was previously set up for between them.
These two (related) subsystems allow a user to create and delete resources on a remote machine. As it is possible that certain resource types cannot be either created or deleted from a plugin, a flag in the resource type metadata indicates the correct functionality to present to the user (the createDeletePolicy flag). In other words, something like a database table would be marked as both able to be created and deleted, whereas the database installation itself would likely be marked as supporting neither.
There are two ways to create a resource. One approach is to request the user fill out the resource's configuration (the same that is accessible through the configuration subsystem). The other is to request the user upload a new package of a particular type as part of the create request. Both options are configured in the resource type's metadata and the choice of which to use will vary based on the nature of the resource in question.
The code implementation of a create request is responsible for taking whatever steps are necessary to have the resource physically created on the system. The plugin's only other responsibility is to return the resource key of the newly created resource. This key must be the same as if the resource had already existed and was returned through a discovery call.
The implementation of delete is simpler, simply removing the physical resource from the machine such that it will not be found on the next discovery. It is the discretion of the plugin writer to decide if that means actually deleting any files or simply disabling the resource in some capacity.
There is one small distinction that is worth noting. A resource is created by sending a request to its parent resource. When deleting a resource, however, the request is sent directly to the resource itself. This is important to realize when implementing a new plugin to be sure the code is put in the correct location.
|Experimental - not currently fully flushed out - discuss on rhq-dev mailing list if you have requirements you want to talk about|
This is to provide functionality that helps you support a managed resource. By "support", it means provide things that allow you better able to diagnose symptoms and problems. For example, you can take a snapshot report of a managed resource, allowing you to capture things like log files, data files and configuration files. With this in hand, you (or some support organization) can take a look at the information to further diagnose problems that are occurring in your managed resource.
A Resource type may include support for Resources being manually added to inventory via the GUI. This would allow Resources that could not be auto-discovered, either because they were offline or for various other reasons, to still be inventoried. The way manually discovery works is that the user chooses to manually add a Resource of a particular type and enters an initial plugin configuration for the Resource, then that plugin configuration is submitted to the plugin, which converts it to a Resource details object and returns that. The plugin container then adds the Resource to its inventory and reports it to the Server.