JBoss Community Archive (Read Only)

RHQ 4.9

Design - Configuration synchronization

Configuration synchronization

The RHQ servers usually share a lot of configuration in a staged environment. The goal of this feature is to help keep the individual RHQ servers similarly configured.

Synchronized entities

The first version of the configuration synchronization is fairly limited and only includes support for synchronizing the system settings (as seen in Administration - System Settings) and metric templates. These two features were picked because they are the easiest to implement and thus this new feature can be showcased without possibly huge changes required to support synchronizing other types of entities. The main problem with synchronization lies in the fact that most of the configuration is either directly or indirectly tied to the inventory, which is obviously going to differ between the installations and therefore some kind of mapper would have to be introduced to support synchronizing those.

Invocation

Export

The synchronization is exclusively driven from the CLI, there is no UI available for it. It is assumed that the user that invokes the below commands has sufficient privleges in the RHQ server to read (during the export) and update (during the import) the synchronized entities. Currently, the user needs MANAGE_SETTINGS privilege to export/import both the system settings and metric templates.

To export the configuration of an RHQ server, connect to it using the CLI and invoke the following command:

var ex = SynchronizationManager.exportAllSubsystems();

This will produce an object that contains the export bytes along with some potential notes from the exporters of individual subystems or error messages.

To save the export to a file, type:

saveBytesToFile(ex.exportFile, 'export.xml.gz');

As you can guess by the extension, the export file is a GZIPped xml file. This means that the users are free to modify the XML before it is imported into another RHQ server. This can become useful if the administrator knows about some intentional differences between the installations and does not want them to disappear.

Import

The import takes the previously saved export file and tries to import it to an RHQ server. Besides the actual exported data, the export file also contains output of validators, which are run before the actual import and check that the target RHQ installation is able to import the data and that the data is internally consistent (note that the import requires the presence of all the validators that are needed for import of given subsystem but because the user is free to modify the export file, s/he can also modify the settings of the validators in there. This is potentially very dangerous but very powerful, if the "user knows what s/he's doing.").

The way the synchronizers process the export file can be configured. Each synchronizer provides a configuration definition that describes what kind of settings it accepts. At export time, this configuration definition along with the defalt values is persisted to the export file itself. But it is also possible to get the import configuration definitions of all available synchronizers before the import on the "target" RHQ installlation.

To import the exported server configuration, one can issue:

var data = getFileBytes('export.xml.gz');
SynchronizationManager.importAllSubsystems(data, null);

The null argument means that the import will run with the configuration as specified in the export file itself. If the export file doesn't include any configuration, the default configuration values are used. To see what is the default configuration of a synchronizer, one can type:

//you can get the config definition of a single synchronizer like so:
var configDef = SynchronizationManager.getImportConfigurationDefinition('org.rhq.enterprise.server.sync.SystemSettingsSynchronizer')

//or you can pick a definition from the list of import config definitions of all synchronizers
var configDefs = SynchronizationManager.importConfigurationDefinitionOfAllSynchronizers
configDef = configDefs.get(0)

pretty.print(configDef.configurationDefinition.defaultTemplate.configuration)

A non-null configuration to the importAllSubSystems method has precedence over the inlined configuration from the export file.

To create an import configuration manually, you need to create instances of the ImportConfiguration objects and initialize them with the correct settings. The basics of that process are described in one of the following paragraphs.

Inlined Import Configuration

The easiest way of modifying the import configuration is to directly edit the export file and modify the inlined default-configuration elements that are present for each synchronizer (i.e. inside the entities elements). The content of the default-configuration element is governed by the urn:xmlns:rhq-configuration-instance namespace. The XSD is available in $RHQ_HOME/jbossas/server/default/deploy/rhq.ear/lib/rhq-enterprise-server-xml-schemas-$RHQ_VERSION.jar!/rhq-configuration-instance.xsd. You can take a quick look at the latest version of that file in RHQ's source code.

The default-configuration contents is refered to as a "configuration instance". It is a combination of the configuration definition (i.e. the format and description of the possible values in the configuration) with the configuration values themselves. This enables the system to describe both the structure and contents of the default configuration, including short descriptions, directly in the export file so that it is easily consumable for both the human and automated editor. The configuration instance format basically "extends" the format of configuration definition that is used in many places in RHQ. For example the both agent and server RHQ plugins use configuration definitions to describe their configuration possibilities. This makes the use of the configuration instance easy for anyone familiar with configuration definitions. The XSD schema provides the full details of the configuration instance specification. For clarity, let's walk through some basic examples here (these examples are synthetic and only illustrate the usage of the configuration instance concept. The paragraphs further below include the concrete default configurations of the synchronizers):

Simple values

ci is assumed to be the namespace prefix for urn:xmlns:rhq-configuration-instance.

<default-configuration>
    <ci:simple-property value='42' name='my-property' type='integer'>
        <c:description>my-property is the answer to the ultimate question.</c:description>
    </ci:simple-property>
</default-configuration>

As you can see, a simple property in a configuration instance is basically a normal simple-property definition augmented with the value attribute that means exactly that - a value for that property.

Lists of values
<default-configuration>
    <ci:list-property name="my-list">
        <c:simple-property name="element" type="string"/>
        <ci:values>
           <ci:simple-value value="a"/>
           <ci:simple-value value="b"/>
           <ci:simple-value value="c"/>
        </ci:values>
    </ci:list-property>
</default-configuration>

In here, you can see a list called "list". The format of the its values is specified by the <c:simple-property> definition. I.e. the definition of that list specifies that it can contain only simple properties (all called "element") that will have values of type string. The next element - <ci-values> - lists the values of the list. Each value is a simple-value, i.e. a value of a simple property, and has a value.
In the above example we therefore defined the list "my-list" to contain simple properties of type string and this list is going to have 3 elements by default (these are going to be simple properties with values a, b and c).

Maps of values
<default-configuration>
    <ci:map-property name="my-map">
        <c:simple-property name="prop1" type="integer"/>
        <c:simple-property name="prop2" type="string"/>
        <c:simple-property name="prop3" type"boolean"/>
        <ci:values>
            <ci:simple-value property-name="prop1" value="1"/>
            <ci:simple-value property-name="prop2" value="abc"/>
            <ci:simple-value property-name="prop3" value="true"/>
        </ci:values>
    </ci:map-property>
</default-configuration>

A map is a set of different properties addressed by their names. The <c:simple-property> elements define what can be put into the map - they are the definition of that map. The <simple-value> elements then specify the values of the properties in the map (unlike in the list, that specifies only a single "member" definition, the map defines multiple and therefore property-name attributes are necessary for the values to be assigned to the appropriate properties).

Tables of values (aka lists of maps)

To create a table of values, it is very common in RHQ plugins to define a list of maps. The property names in the map define the columns in the table and the individual maps in the list act for each row in the table.

<default-configuration>
    <ci:list-property name="table">
        <c:map-property name="row">
            <c:simple-property name="column1" type="integer"/>
            <c:simple-property name="column2" type="boolean"/>
            <c:simple-property name="column3" type="string"/>
        </c:map-property>
        <ci:values>
            <ci:map-value>
               <ci:simple-value property-name="column1" value="1"/>
               <ci:simple-value property-name="column2" value="true"/>
               <ci:simple-value property-name="column3" value="a"/>
            </ci:map-value>
            <ci:map-value>
               <ci:simple-value property-name="column1" value="2"/>
               <ci:simple-value property-name="column2" value="true"/>
               <ci:simple-value property-name="column3" value="b"/>
            </ci:map-value>
            <ci:map-value>
               <ci:simple-value property-name="column1" value="3"/>
               <ci:simple-value property-name="column2" value="false"/>
               <ci:simple-value property-name="column3" value="c"/>
            </ci:map-value>
        </ci:values>
    </ci:list-property>
</default-configuration>

As in the previous examples, the c: elements specify the format - i.e. configuration definition, while the elements inside <ci:values> specify the values that conform to that definition.

Default Import Configuration of System Settings Synchronizer
<default-configuration>
    <ci:simple-property value="AGENT_MAX_QUIET_TIME_ALLOWED, ENABLE_AGENT_AUTO_UPDATE, ENABLE_DEBUG_MODE, ENABLE_EXPERIMENTAL_FEATURES, 
CAM_DATA_PURGE_1H, CAM_DATA_PURGE_6H, CAM_DATA_PURGE_1D, CAM_DATA_MAINTENANCE, DATA_REINDEX_NIGHTLY, RT_DATA_PURGE, ALERT_PURGE, EVENT_PURGE, 
TRAIT_PURGE, AVAILABILITY_PURGE, CAM_BASELINE_FREQUENCY, CAM_BASELINE_DATASET" type="string" name="propertiesToImport">
        <c:description>The names of the properties that should be imported. Note that these are the INTERNAL names as used in the RHQ database</c:description>
    </ci:simple-property>
</default-configuration>

The configuration of the system settings synchronizer comprises of a single simple property that contains a comma-separated list of names of the individual system settings properties to be imported.

Default Import Configuration of Metric Templates Synchronizer
<default-configuration>
    <ci:simple-property value="false" type="boolean" name="updateAllSchedules">
        <c:description>If set to true, all the metric templates will update all the existing schedules on corresponding resources.</c:description>
    </ci:simple-property>
    <ci:list-property name="metricUpdateOverrides">
        <c:description>Per metric settings</c:description>
        <c:map-property summary="false" required="true" readOnly="false" name="metricUpdateOverride">
            <c:simple-property type="string" summary="false" required="true" readOnly="false" name="metricName">
                <c:description>The name of the metric</c:description>
            </c:simple-property>
            <c:simple-property type="string" summary="false" required="true" readOnly="false" name="resourceTypeName">
                <c:description>The name of the resource type defining the metric</c:description>
            </c:simple-property>
            <c:simple-property type="string" summary="false" required="true" readOnly="false" name="resourceTypePlugin">
                <c:description>The name of the plugin defining the resource type that defines the metric</c:description>
            </c:simple-property>
            <c:simple-property type="boolean" summary="false" required="true" readOnly="false" name="updateSchedules">
                <c:description>Whether to update the schedules of this metric on existing resources</c:description>
            </c:simple-property>
        </c:map-property>
    </ci:list-property>
</default-configuration>

The updateAllSchedules defaults to false and specifies whether all metric schedules should be updated or not while updating the metric templates. Note that if this is set to true, the metricUpdateOverrides have no effect.

If updateAllSchedules is set to false, one can still set some of the metric schedules to be updated along with the templates by specifically listing them in this list.

In the example below, the default configuration has been modified to only update resource metric schedules of the "Free Memory" metric on the JBoss AS5 servers inventoried:

<default-configuration>
    <ci:simple-property value="false" type="boolean" name="updateAllSchedules" />
    <ci:list-property name="metricUpdateOverrides">
        <c:map-property summary="false" required="true" readOnly="false" name="metricUpdateOverride">
            <c:simple-property type="string" summary="false" required="true" readOnly="false" name="metricName" />
            <c:simple-property type="string" summary="false" required="true" readOnly="false" name="resourceTypeName" />
            <c:simple-property type="string" summary="false" required="true" readOnly="false" name="resourceTypePlugin" />
            <c:simple-property type="boolean" summary="false" required="true" readOnly="false" name="updateSchedules" />
        </c:map-property>
        <ci:values>
           <ci:map-value>
               <ci:simple-value name="metricName" value="MCBean|ServerInfo|*|freeMemory"/>
               <ci:simple-value name="resourceTypeName" value="JBoss AS Server"/>
               <ci:simple-value name="resourceTypePlugin" value="JBossAS5"/>
               <ci:simple-value name="updateSchedules" value="true"/>
           </ci:map-value>
        </ci:values>
    </ci:list-property>
</default-configuration>

Programmatic Import Configuration

As mentioned above, the import of the export file can be configured. The first step to configure the import is, as mentioned above, to review the import configuration definitions provided by the individual synchronizers:

var definitions = SynchronizationManager.importConfigurationDefinitionOfAllSynchronizers;

This method returns a list of ImportConfigurationDefinition objects. Each such object has the synchronizerClassName property which identifies the synchronizer that provides that definition and a configurationDefinition property that contains the actual configuration definition of the import configuration expected by that particular synchronizer.

The configuration definition has a default template defined, from which it is possible to obtain the default configuration object for given synchronizer:

var systemSettingsImportConfigurationDefinition = definitions.get(0) //the index depends on what's in the definitions (obtained in the above code example)
//alternatively, you can directly obtain the definition for a known synchronizer using the method below
var systemSettingsImportConfigurationDefinition = SynchronizationManager.getImportConfigurationDefinition('org.rhq.enterprise.server.sync.SystemSettingsSynchronizer')

var configurationObject = systemSettingsImportConfigurationDefinition.configurationDefinition.defaultTemplate.createConfiguration()

//the configurationObject has class org.rhq.core.domain.configuration.Configuration
//javadocs are here: http://docs.redhat.com/docs/en-US/JBoss_Operations_Network/2.4/html/API_Guides/domain/org/rhq/core/domain/configuration/Configuration.html
//you can use its API to modify the configuration before you use it further
//This comment block is expanded with some concrete examples in the paragraphs below.

var systemSettingsImportConfiguration = new ImportConfiguration(systemSettingsImportConfigurationDefinition.synchronizerClassName, configurationObject)
var allConfigs = new java.util.ArrayList()
allConfigs.add(systemSettingsImportConfiguration)

//data is obtained from the export file on the file system in the same way as above
SynchronizationManager.importAllSubsystems(data, allConfigs)
System settings configuration example

As you can see in the default import configuration of system settings, the sole property in that configuration defines the comma-separated list of system settings names that should be imported. All other settings are ignored during the import. Note that not all settings are imported by default - for example the CAM_BASE_URL is ignored because overwriting the URL by which an RHQ server is known to the agents is not generally a thing one would want to do on import.

Expading on the previous CLI code example, one would change the configuration on the CLI command line like this:

var defaultSettingsToImport = configurationObject.getSimple('propertiesToImport').stringValue
configurationObject.getSimple('propertiesToImport').setValue(defaultSettingsToImport + ', CAM_BASE_URL')

This would add the base url to the list of imported system settings.

Metric templates configuration example

First thing is that by default, importing the metric templates DOES NOT update the schedules of the corresponding metrics on individual resources. Secondly, the configuration provides a way to either update all schedules of all resources of all metric templates (by setting the updateAllSchedules property to true) or that it is possible to specify which concrete metric templates should update the schedules of corresponding metrics on resources (by filling up the list metricUpdateOverrides).

Code examples for the above follow:

//to make the import update all the schedules on all resources for all metric templates
configurationObject.getSimple('updateAllSchedules').setBooleanValue(true)

//if updateAllSchedules is false, one can still update the schedules of some metric templates
//for example the below code will cause the schedules of "Free Memory" metric on the inventoried JBoss AS 5 servers
//be updated with the collection interval stored in the export file.
var updateList = new PropertyList('metricUpdateOverrides')
var update = new PropertyMap('metricUpdateOverride')
update.put(new PropertySimple('metricName', 'MCBean|ServerInfo|*|freeMemory'))
update.put(new PropertySimple('resourceTypeName', 'JBossAS Server'))
update.put(new PropertySimple('resourceTypePlugin', 'JBossAS5'))
update.put(new PropertySimple('updateSchedules', 'true'))

updateList.add(update)

configurationObject.put(updateList)

Future directions

It would be great if we could add support for more RHQ subsystems but this is going to require some kind of a resource mapping tool. That is of course not impossible but will require some serious thinking to make it usable.

JBoss.org Content Archive (Read Only), exported from JBoss Community Documentation Editor at 2020-03-13 08:10:40 UTC, last content change 2013-09-18 19:41:11 UTC.