> setconfig as7plugin.verbose=true > pc stop > pc start
The plugin can output verbose debugging of the connection data with the AS7.
To enable this you can use the following at the agent prompt.
> setconfig as7plugin.verbose=true > pc stop > pc start
The messages then go to the agent log.
JDBC drivers must (in domain mode) be deployed to all server groups that are used by the profile where a data source is to be added to.
Module loaded JDBC drivers are not supported yet.
The management tree of AS7 is very rich in the sense of number of resources. As RHQ resources are "fat", it makes sense to not use a RHQ resource for AS7-resources that only serve as configuration entities. One example are socket bindings, where the socket-binding-group has a number of individual socket-binding resources as children (for each binding one child). In RHQ-land this would map to a list of maps.
As the individual bindings are individual resources in AS7, there needs to be a way to tell the RHQ config subsystem where to pull the data from. This is done by the mechanism of <c:group name=X> where X conveys the information where to search.
In addition while reading that list of maps via recursive :read-resource is easy, writing back is not, as the configuration does not know that the list of map needs to go to children and how to identify the children.
Sometimes the AS7 code is organized in a way that only a single child resource is applicable. This can be achieved via
<c:group name="child:root-logger=root"> <c:simple-prop.... </c:group>
or
<c:group name="child:root-logger=root"> <c:map-prop.... </c:group>
This assumes that the child already exists.
If the child consists of runtime information, you can add a star * to the end of the group name like
<c:group name="child:core-service=server-environment*" displayName="..."> <c:simple-property name="base-dir" readOnly="true" ... />
In this case all embedded properties should be read-only.
In the case of e.g. subsystem=web,virtual-host=*,sso=configuration the sso=configuration node does not exist by default. In this case the
map-construct must be used:
<c:group name="child:sso=configuration" ...> <c:map-property name="*Configuration+" readOnly="false" required="false"> <c:simple-property name="cache-container" ... >
The map-property itself must be marked as non-requied so that reading a non-existing sso=configuration child does not harm
The map-property name must start with an asterisk (*)
The map-property name must end with a plus sign (+) to indicate that the sso=configuration child may be created
<c:simple-property name="secure" required="false" type="boolean".../> <c:group name="child:ssl=configuration:enabled=secure=true" displayName="SSL Configuration"> <c:map-property name="*Configuration+" ... > <c:simple-property name="ca-certificate-file" required="false" ... />
The ssl=configuration child is only valid if the value of the property secure is set to true - otherwise the child must not
exist. So the group name child:ssl=configuration:enabled=secure=true not only encodes the name of the node (as in the previous section), but
also a condition expression in the form of result=property=value so meaning that enabled=secure=true the group is enabled if the simple property (at configuration level) with the name secure has a value of true.
In conjunction with the '+' sign on the map name (this map is the only content of the group), it also means that the path of sso=configuration is created when the group is enabled and will be removed when the group is not enabled.
For this purpose there is a c:group with a special name 'children:socket-binding' meaning that the properties contained
are child (AS7)resources of type socket-binding
<c:group name="children:socket-binding" displayName="Individual socket bindings"> <c:list-property name="*" displayName="Bindings"> <c:map-property name="binding">
The embedded list element uses a name of '*' to indicate that the return value of the :read-children is actually the contained map and not a list. See also below.
IF there are more groups that contain such lists, each list name needs to be different, so it is possible to use multiple names by adding a suffix as in "*2" as seen in the next example:
<c:group name="children:system-property" displayName="System-properties"> <c:list-property name="*2" displayName="Properties" required="false" readOnly="true"> <c:map-property name="*:pname" displayName="Name" readOnly="true"> <c:simple-property name="pname" displayName="Property-Name" readOnly="true"/> <c:simple-property name="value" displayName="Value"/> </c:map-property> </c:list-property> </c:group>
Above example has another special. As the resource object on AS7 for ( this may become the default ) has no attribute for the name of the property - as this can be inferred from the address - the name of the property is added as a map element with name 'pname'. The special expression "*:pname" on the name of the embedded map tells us that the attribute 'pname' should be filled with the name of the AS7-resource as deducted from the address.
This is an extension of the earlier 'group' case
<c:group name="children:childType:name" displayName="Path"> <c:list-property name="*3" displayName="Path" readOnly="true"> <c:map-property name="*" displayName="Entry" readOnly="true"> <c:simple-property name="name" required="true" type="string" readOnly="false"/> <c:simple-property name="path" required="true" type="string" readOnly="false"/> </c:map-property> </c:list-property> </c:group>
Here the properties are not on the AS7-resource itself, but on the children with type 'childType'. In order to modify and write back the entries, the value of the sub-address (childType=value) needs to be determined. This is taken from the property with the name that matches the third component of children:childType:name, in this case from the attribute name.
<c:group name="children:system-property:name+" displayName="System-properties"> <c:list-property name="*2" displayName="Properties" required="false" readOnly="false"> <c:map-property name="*:name" displayName="Name" readOnly="true"> <c:simple-property name="name" displayName="Property-Name" readOnly="true"/> <c:simple-property name="value" displayName="Value"/> </c:map-property> </c:list-property> </c:group>
System properties are child resources of / in AS7 and need to be added as such. This is indicated with the + sing in the group's name attribute. The property name is used in the path as key for the new resource's name. A map of (name=foo,value=bar) translates to /system-property=foo:add(value=bar). Updates of the property's value can then be done via a :write-attribtue operation.
<c:group name="children:xa-datasource-properties:key+-" displayName="XA Datasource Properties"> <c:list-property name="*2" displayName="Properties" required="false" readOnly="false"> <c:map-property name="*:key" displayName="Name" readOnly="false"> <c:simple-property name="key" displayName="Property-Name" readOnly="false"/> <c:simple-property name="value" displayName="Value" readOnly="false"/> </c:map-property> </c:list-property> </c:group>
Here the xa-datasource-properties are child resources of the xa-datasource in AS7. In order to update them, it is needed that they are first removed and then re-added. This is indicated by the minus in "...key+-" in the name attribute of the group.
This is an even more special case of the previous one.
AS7 now allows to supply properties in the form ${foo.bar:1234} be set for fields that would normally e.g. be integer fields (like port numbers). In addition simple integer values are accepted as well. read-resource-description shows the following in this case:
[domain@localhost:9999 socket-binding-group=standard-sockets] ./socket-binding=http:read-resource-description { "outcome" => "success", "result" => { "description" => "Configuration information for a socket.", "attributes" => { "port" => { *"type" => INT,* "description" => "Number of the port to which the socket should be bound.", *"expressions-allowed" => true,* "nillable" => false, "min" => 0L, "max" => 65535L, "access-type" => "read-write", "storage" => "configuration", "restart-required" => "all-services" },
As the rhq plugin descriptor can only hold the "int" type, we need to signal the presence of expressions-allowed=true differently. This is done by appending :expr to the name of a simple property:
<c:simple-property name="port:expr" displayName="Port" type="string" />
As the GUI needs to be told to allow for entering of expressions as well, the type needs to be string and can't be int. See also BZ 800070
Sometimes AS7 returns json in the form
{ "result" : { "connector":{"in-vm":null} } }
where the property is "connector" and its value is a map. In RHQ Configuration, we need to model this as a map of simple properties. To tell the configuration code to map this map of simple to above json, we mark the map name with :collapsed :
<c:map-property name="connector:collapsed" displayName="Connector"> <c:simple-property name="name:0" displayName="Name" description="Connector name" required="true"/> <c:simple-property name="backup:1" displayName="Backup" description="Backup connector name"/> </c:map-property>
You can see another special thing in this example: as the code may return the properties in the MropertyMap in arbitrary order, we need to determine what is key want what is value. This is done by appending ':0' and ':1:' to the property names.
In many cases there is a link between resources. For example the interface in a SocketBindingGroup is one of the ones found with ResourceType=Network Interface. In the plugin descriptor, this can be expressed like this:
<c:simple-property name="interface" description="Name of the interface required="false"> <c:option-source target="resource" expression="type='Network Interface' plugin=jboss-as-7" expressionScope="baseResource"/> </c:simple-property>
The expression is a search query like in the search bar in the UI. If a type has a space in its name, the name needs to be surrounded by single quotes as shown above.
The above expression line lists resources (their names) that match the expression.
The expressionScope attribute defines a scope for expression searches. Its value must be one of unlimited or baseResource (it defaults to unlimited). unlimited means that search results may include any resource in the inventory. baseResource narrows down results to the resources sharing the same top level server or service.
In the next example, the target are (resource)configuration entries:
<c:simple-property name="socket-binding"> <c:option-source target="configuration" expression="*/socket-binding=name:type=SocketBindingGroup"/> </c:simple-property>
The server first looks for resources of type 'SocketBindingGroup'. Within the results it takes the resource-configuration and then takes the list property with name '*' and in the resulting map with name 'socket-binding' it returns the value of the map property with name 'name'
It may be needed to exclude a map in a list of maps from update activity. For example <c:group name="children:path:name+" displayName="Path"> contains both entries that are computed on the AS7-server and may not be updated at all (server will complain) and others that are user defined and may be updated as usual. This means, that the list can not be made read-only on a global scale.
Ignoring the immutable entries can be done in code by
map.setErrorMessage(ConfigurationWriteDelegate.LOGICAL_REMOVED);
For example have a look at org.rhq.modules.plugins.jbossas7.StandaloneASComponent#updateResourceConfiguration
you can add :ignore to the name:
<c:simple-property name="wildcard:ignore"
Writing the property will ignore it, reading will not find it on the AS7-Server and it will thus not be filled.
It is the responsibility of the methods implementing ConfigurationFacet and CreateChildResourceFacet to provide
the appropriate data.
The as7 plugin has a little tool Domain2Descriptor that is able to create snippets for the rhq plugin descriptor. A small wrapper shell script d2d.sh sets up the class path and calls the java tool - you probably need to tune d2d.sh for your need.
Example call looks like this:
$ ./d2d.sh -Urhqadmin:rhqadmin -p profile=full-ha/subsystem=ee <c:list-property name="global-modules" description="A [...]" > <c:simple-property name="global-modules" /> </c:list-property> <c:simple-property name="ear-subdeployments-isolated" required="false" type="boolean" readOnly="false" defaultValue="false" description="Flag indicating whether each [..]"/>
or
./d2d.sh -Urhqadmin:rhqadmin -p profile=full-ha/subsystem=web virtual-server <c:simple-property name="enable-welcome-root" required="false" type="boolean" readOnly="false" defaultValue="false" description="Whether or [..]"/> <c:simple-property name="default-web-module" required="false" type="string" readOnly="false" defaultValue="ROOT.war" description="The web module [..]"/> <c:list-property name="alias" description="The virtual server aliases" > <c:simple-property name="alias" /> </c:list-property> <c:simple-property name="name" required="false" type="string" readOnly="true" description="A unique [..]"/>
To use the tool, as7 must be running.
With -U you pass in the user:pass for the as7 server. Next are the options (see below) and then either the full path the as7 tree to a certain resource (1st example) or the base path to its parent and the type of the children (2nd example). The 2nd case applies when no child exists yet.
Options are -p for resource-config, -m for metrics and -o for operations; Operations of course still need their code counterpart.
Integration tests are defined in the 'itest' profile in modules/plugins/jboss-as-7/pom.xml. The profile is not active by default, since the tests take several minutes(varies with setup) or so to run (and longer on the initial run, since they have to download and unzip the AS7 or EAP6 dist zipfile).
To run the integration tests, enable the 'as7.itest' profile:
mvn verify -DskipTests=false -Pas7.itest
By default, the integration tests will run against the latest successful AS7 master build from Jenkins. To run the tests against a different version of AS7 or EAP6, specify the version via the 'as7.version' system property.
To run the integration tests against AS 7.1.1.Final, use:
mvn verify -DskipTests=false -Pas7.itest -Das7.version=7.1.1.Final
To run the integration tests against EAP 6.0.0.Beta1, use:
mvn verify -DskipTests=false -Pas7.itest -Das7.version=6.0.0.Beta1 -Das7.url=file:///tmp/jboss-eap-6.0.0.Beta1.zip
Note, for EAP6, you also need to specify the URL of the EAP6 dist zipfile via the 'as7.url' system property.
The first time the tests are run against a particular version, the zipfile for that version will be saved under /tmp and will remain there after maven exits. On subsequent runs, if the saved zipfile is newer than the remote zipfile, it will be used, rather than downloading the zip file again.
To speed up test runs during development i)run only the integration tests and ii) run only a specific batch of integration tests you should use the -DskipTests and -Dit.test options for example to only run the SecurityModuleOptionsTest.* operations. See more details on integration test granularity but be aware of 'priority' values with @Test, used to define dependencies between specific tests, when defining greater granularity. Additionally you may consider disabling 'post-integration-test' deletion temporarily in the pom during complex test creation to examine the affected AS7 instances before the next test run.
mvn verify -DskipTests=true -Pas7.itest -Das7.version=6.0.0.Beta1 -Das7.url=file:///tmp/jboss-eap-6.0.0.Beta1.zip -Dit.test=SecurityModuleOptionsTest
To remotely debug the integration tests, add -Ditest.debug to the mvn command line, e.g.:
mvn verify -DskipTests=false -Pas7.itest -Ditest.debug
Also check out this video on vimeo where Ian explains the setup of the modules and tests.