.classpath | 36 modules/core/client-api/src/main/java/org/rhq/core/clientapi/server/configuration/ConfigurationServerService.java | 4 modules/core/dbutils/src/main/java/org/rhq/core/db/DatabaseType.java | 13 modules/core/dbutils/src/main/java/org/rhq/core/db/OracleDatabaseType.java | 15 modules/core/domain/pom.xml | 26 modules/core/domain/src/main/java/org/rhq/core/domain/configuration/ResourceConfigurationUpdate.java | 17 modules/core/domain/src/test/resources/arquillian.xml | 4 modules/core/util/src/main/java/org/rhq/core/util/StringUtil.java | 20 modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/inventory/resource/detail/ResourceTreeView.java | 24 modules/enterprise/server/appserver/src/main/scripts/rhq-container.build.xml | 1 modules/enterprise/server/itests-2/pom.xml | 18 modules/enterprise/server/itests-2/src/test/java/org/rhq/enterprise/client/security/test/JndiAccessTest.java | 2 modules/enterprise/server/itests-2/src/test/java/org/rhq/enterprise/client/util/ScriptTest.java | 81 + modules/enterprise/server/itests-2/src/test/java/org/rhq/enterprise/server/configuration/ConfigurationManagerBeanTest.java | 96 +- modules/enterprise/server/itests-2/src/test/java/org/rhq/enterprise/server/resource/test/ResourceStorageTest.java | 7 modules/enterprise/server/itests-2/src/test/java/org/rhq/enterprise/server/test/TestServerCommunicationsService.java | 7 modules/enterprise/server/itests-2/src/test/resources/arquillian.xml | 4 modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/configuration/ConfigurationManagerBean.java | 123 +- modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/configuration/ConfigurationManagerLocal.java | 7 modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/configuration/ConfigurationServerServiceImpl.java | 8 modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/core/AgentManagerLocal.java | 14 modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/core/comm/ServerCommunicationsService.java | 12 modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/core/comm/ServerCommunicationsServiceMBean.java | 17 modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/resource/ResourceManagerBean.java | 12 modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/rest/AlertHandlerBean.java | 35 modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/rest/BadArgumentException.java | 3 modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/rest/ResourceHandlerBean.java | 8 modules/enterprise/server/jar/src/test/java/org/rhq/enterprise/server/configuration/ConfigurationManagerBeanUnitTest.java | 10 modules/enterprise/server/jar/src/test/java/org/rhq/enterprise/server/util/CriteriaQueryTest.java | 9 modules/integration-tests/rest-api/src/test/java/org/rhq/modules/integrationTests/restApi/AlertTest.java | 301 ++++++ modules/integration-tests/rest-api/src/test/java/org/rhq/modules/integrationTests/restApi/GroupTest.java | 24 modules/integration-tests/rest-api/src/test/java/org/rhq/modules/integrationTests/restApi/ResourcesTest.java | 55 + modules/integration-tests/rest-api/src/test/java/org/rhq/modules/integrationTests/restApi/d/Availability.java | 64 + modules/plugins/jboss-as-7/src/main/java/org/rhq/modules/plugins/jbossas7/BaseServerComponent.java | 117 +- modules/plugins/jboss-as-7/src/main/resources/META-INF/rhq-plugin.xml | 7 modules/plugins/jboss-as-7/src/test/java/org/rhq/modules/plugins/jbossas7/itest/AbstractServerComponentTest.java | 1 modules/plugins/netservices/pom.xml | 468 ++++------ modules/plugins/netservices/src/main/java/org/rhq/plugins/netservices/HTTPNetServiceComponent.java | 214 +++- modules/plugins/netservices/src/main/java/org/rhq/plugins/netservices/HTTPNetServiceComponentConfiguration.java | 57 + modules/plugins/netservices/src/main/java/org/rhq/plugins/netservices/HTTPNetServiceDiscoveryComponent.java | 51 - modules/plugins/netservices/src/main/java/org/rhq/plugins/netservices/PingNetServiceComponent.java | 77 - modules/plugins/netservices/src/main/java/org/rhq/plugins/netservices/PingNetServiceDiscoveryComponent.java | 41 modules/plugins/netservices/src/main/resources/META-INF/rhq-plugin.xml | 37 modules/plugins/netservices/src/test/java/org/rhq/plugins/netservices/HTTPNetServiceDiscoveryComponentTest.java | 178 +++ modules/plugins/netservices/src/test/java/org/rhq/plugins/netservices/PingNetServiceDiscoveryComponentTest.java | 105 ++ modules/plugins/netservices/src/test/java/org/rhq/plugins/netservices/itest/HTTPNetServiceComponentTest.java | 162 +++ modules/plugins/netservices/src/test/java/org/rhq/plugins/netservices/itest/NetServiceComponentTest.java | 154 +++ modules/plugins/netservices/src/test/java/org/rhq/plugins/netservices/itest/PingNetServiceComponentTest.java | 98 ++ modules/plugins/netservices/src/test/resources/log4j.xml | 32 modules/plugins/rhq-server/src/main/resources/META-INF/rhq-plugin.xml | 7 50 files changed, 2253 insertions(+), 630 deletions(-)
New commits: commit bf664e0f63aabbd22b242450d0f673c4064c4215 Merge: 76458a3 b452250 Author: Simeon Pinder spinder@fulliautomatix.conchfritter.com Date: Thu Feb 21 14:49:53 2013 -0500
Merge branch 'track_master' into spinder/criteriaUsage
commit 76458a3ca5762cec0512e8ed6b607cdafeddf71a Author: Simeon Pinder spinder@fulliautomatix.conchfritter.com Date: Thu Feb 21 14:16:16 2013 -0500
Add integration test to exercise some CLI functionality specifically findResources.
diff --git a/modules/enterprise/server/itests-2/src/test/java/org/rhq/enterprise/client/security/test/JndiAccessTest.java b/modules/enterprise/server/itests-2/src/test/java/org/rhq/enterprise/client/security/test/JndiAccessTest.java index fabe6ae..8489f1d 100644 --- a/modules/enterprise/server/itests-2/src/test/java/org/rhq/enterprise/client/security/test/JndiAccessTest.java +++ b/modules/enterprise/server/itests-2/src/test/java/org/rhq/enterprise/client/security/test/JndiAccessTest.java @@ -272,7 +272,7 @@ public class JndiAccessTest extends AbstractEJB3Test { // } // }
- private ScriptEngine getEngine(Subject subject) throws ScriptException, IOException { + protected ScriptEngine getEngine(Subject subject) throws ScriptException, IOException { StandardBindings bindings = new StandardBindings(new PrintWriter(System.out), new LocalClient(subject));
PermissionCollection perms = new StandardScriptPermissions(); diff --git a/modules/enterprise/server/itests-2/src/test/java/org/rhq/enterprise/client/util/ScriptTest.java b/modules/enterprise/server/itests-2/src/test/java/org/rhq/enterprise/client/util/ScriptTest.java new file mode 100644 index 0000000..98ad38c --- /dev/null +++ b/modules/enterprise/server/itests-2/src/test/java/org/rhq/enterprise/client/util/ScriptTest.java @@ -0,0 +1,81 @@ +package org.rhq.enterprise.client.util; + +import java.io.IOException; +import java.util.Random; + +import javax.persistence.EntityManager; +import javax.script.ScriptEngine; +import javax.script.ScriptException; +import javax.transaction.HeuristicMixedException; +import javax.transaction.HeuristicRollbackException; +import javax.transaction.NotSupportedException; +import javax.transaction.RollbackException; +import javax.transaction.SystemException; + +import org.testng.annotations.Test; + +import org.rhq.core.domain.auth.Subject; +import org.rhq.core.domain.resource.Resource; +import org.rhq.core.domain.util.PageList; +import org.rhq.enterprise.client.security.test.JndiAccessTest; +import org.rhq.enterprise.server.util.LookupUtil; +import org.rhq.enterprise.server.util.SessionTestHelper; + +/**Exercise some of the methods available via cli an integration tests/using a running server. + + * @author Simeon Pinder + */ +@Test +public class ScriptTest extends JndiAccessTest { + + /** Exercise the ScriptUtil.findResoruces + * + * @throws ScriptException + * @throws IOException + * @throws NotSupportedException + * @throws SystemException + * @throws SecurityException + * @throws IllegalStateException + * @throws RollbackException + * @throws HeuristicMixedException + * @throws HeuristicRollbackException + */ + @Test + public void testScriptUtilFindResources() throws ScriptException, IOException, NotSupportedException, + SystemException, + SecurityException, IllegalStateException, RollbackException, HeuristicMixedException, + HeuristicRollbackException { + + //Instantiate ScriptEngine. + Subject overlord = LookupUtil.getSubjectManager().getOverlord(); + ScriptEngine engine = getEngine(overlord); + + //create resources to query. + getTransactionManager().begin(); + EntityManager entityMgr = getEntityManager(); + String tuid = "" + new Random().nextInt(); + String prefix = "CLI-TEST-" + tuid + "-"; + int resourceCount = 201; //assuming 200 per page at least 2 pages of results. + int[] resourceIds = new int[resourceCount]; + try { + System.out.println("-------- Creating " + resourceCount + " resource(s). This may take a while ...."); + long start = System.currentTimeMillis(); + for (int i = 0; i < resourceCount; i++) { + String name = prefix + i; + Resource r = SessionTestHelper.createNewResource(entityMgr, name); + resourceIds[i] = r.getId(); + } + entityMgr.flush(); + + System.out.println("----------- Created " + resourceCount + " resource(s) in " + + (System.currentTimeMillis() - start) + " ms."); + + //now get the Resources back by CLI + PageList<Resource> result = (PageList<Resource>) engine.eval("findResources('" + prefix + "');"); + assert result.size() == resourceCount : "Expected to get '" + resourceCount + + "' result(s) from across two pages but instead got '" + result.size() + "'."; + } finally { + getTransactionManager().rollback(); + } + } +}
commit b4522507d1a18a20cabff9cd2097c730c5d5f42e Author: Jay Shaughnessy jshaughn@redhat.com Date: Thu Feb 21 11:21:27 2013 -0500
This should allow us to run Arquillian's spawned AS7 instances (for domain and server jar itests) on non-default ports. This can be helpful in environments where you want to run multiple AS7 instances at the same time.
Arquillian will now inspect, through the AS7 management port (assumed to be on the local machine for now), to find out what ports it needs to deal with.
diff --git a/modules/core/domain/pom.xml b/modules/core/domain/pom.xml index 3eec8ad..21af6e4 100644 --- a/modules/core/domain/pom.xml +++ b/modules/core/domain/pom.xml @@ -235,6 +235,16 @@ <echo>Will now add test configuration to JBossAS config file: ${jboss.conf}</echo> <replace file="${jboss.conf}"> <replacefilter> + <replacetoken></extensions></replacetoken> + <replacevalue><![CDATA[ + </extensions> + + <!-- FOR RHQ TESTING --> + <system-properties> + <property name="jboss.socket.binding.port-offset" value="${jboss.socket.binding.port-offset}" /> + </system-properties>]]></replacevalue> + </replacefilter> + <replacefilter> <replacetoken></drivers></replacetoken> <replacevalue><![CDATA[ <!-- FOR RHQ TESTING --> @@ -681,6 +691,22 @@ <jboss.vm.args.debug>-Xrunjdwp:transport=dt_socket,address=8798,server=y,suspend=y</jboss.vm.args.debug> </properties> </profile> + + <!-- These two properties allow Arquillian to inspect AS7 through the mgmt port, to determine the ports it needs to interact + with when spawning the AS7 instance. This allows the AS7 to run on non-default ports. If these properties are not set (for + example, in settings.xml) then we must set the defaults here. The offset is then provided via the standalone.xml properties --> + <profile> + <id>arquillian-ports</id> + <activation> + <property> + <name>!jboss.socket.binding.port-offset</name> + </property> + </activation> + <properties> + <jboss.socket.binding.port-offset>0</jboss.socket.binding.port-offset> + <jboss.management.native.port>9999</jboss.management.native.port> + </properties> + </profile>
</profiles>
diff --git a/modules/core/domain/src/test/resources/arquillian.xml b/modules/core/domain/src/test/resources/arquillian.xml index 368ce23..d0744f3 100644 --- a/modules/core/domain/src/test/resources/arquillian.xml +++ b/modules/core/domain/src/test/resources/arquillian.xml @@ -21,6 +21,10 @@
<configuration> <property name="jbossHome">${jboss.unzip.location}</property> + <!-- These two properties allow Arquillian to inspect AS7 through the mgmt port, to determine the ports it needs + to interact with when spawning the AS7 instance. This allows the AS7 to run on non-default ports. --> + <property name="managementAddress">127.0.0.1</property> + <property name="managementPort">${jboss.management.native.port}</property> </configuration> </container>
diff --git a/modules/enterprise/server/itests-2/pom.xml b/modules/enterprise/server/itests-2/pom.xml index 5961627..49d79f5 100644 --- a/modules/enterprise/server/itests-2/pom.xml +++ b/modules/enterprise/server/itests-2/pom.xml @@ -91,6 +91,7 @@ <system-properties> <property name="project.version" value="${project.version}"/> <property name="rhq.server.content.filesystem" value="${jboss.unzip.location}/standalone/data/packagebits" /> + <property name="jboss.socket.binding.port-offset" value="${jboss.socket.binding.port-offset}" /> </system-properties>]]></replacevalue> </replacefilter>
@@ -741,5 +742,22 @@ <jboss.vm.args.debug>-Xrunjdwp:transport=dt_socket,address=8798,server=y,suspend=y</jboss.vm.args.debug> </properties> </profile> + + <!-- These two properties allow Arquillian to inspect AS7 through the mgmt port, to determine the ports it needs to interact + with when spawning the AS7 instance. This allows the AS7 to run on non-default ports. If these properties are not set (for + example, in settings.xml) then we must set the defaults here. The offset is then provided via the standalone.xml properties --> + <profile> + <id>arquillian-ports</id> + <activation> + <property> + <name>!jboss.socket.binding.port-offset</name> + </property> + </activation> + <properties> + <jboss.socket.binding.port-offset>0</jboss.socket.binding.port-offset> + <jboss.management.native.port>9999</jboss.management.native.port> + </properties> + </profile> + </profiles> </project> diff --git a/modules/enterprise/server/itests-2/src/test/resources/arquillian.xml b/modules/enterprise/server/itests-2/src/test/resources/arquillian.xml index 72f8bdc..ffaa79e 100644 --- a/modules/enterprise/server/itests-2/src/test/resources/arquillian.xml +++ b/modules/enterprise/server/itests-2/src/test/resources/arquillian.xml @@ -33,6 +33,10 @@ <configuration> <property name="jbossHome">${jboss.unzip.location}</property> <property name="javaVmArguments">${jboss.vm.args} ${jboss.vm.args.debug}</property> + <!-- These two properties allow Arquillian to inspect AS7 through the mgmt port, to determine the ports it needs + to interact with when spawning the AS7 instance. This allows the AS7 to run on non-default ports. --> + <property name="managementAddress">127.0.0.1</property> + <property name="managementPort">${jboss.management.native.port}</property> </configuration> </container> </arquillian>
commit 93fb46966bfce20ec918191ec78408d20ce6b010 Author: John Mazzitelli mazz@redhat.com Date: Thu Feb 21 10:35:59 2013 -0500
don't deprecate these methods - criteria is nice, but these specific methods are very efficient and can be used when we need to eek out as much performance as possible. no need to go through the criteria API just to get a single agent using very targeted WHERE conditions.
diff --git a/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/core/AgentManagerLocal.java b/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/core/AgentManagerLocal.java index 842d5d8..7e2c3b9 100644 --- a/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/core/AgentManagerLocal.java +++ b/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/core/AgentManagerLocal.java @@ -134,47 +134,51 @@ public interface AgentManagerLocal { /** * Given an agent name, this will look up and return the {@link Agent} with that name. If no agent with the given * name exists, <code>null</code> is returned. - * + * This method is very efficient if you want to find a single agent by its name. + * If you need to get more than one agent, you could use <code>findAgentsByCriteria</code>. + * * @param agentName * * @return the agent whose name matches the given name; <code>null</code> if there is no agent with the given name - * @deprecated Use <code>findAgentsByCriteria()</code> instead */ Agent getAgentByName(String agentName);
/** * Given an agent id, this will look up and return the {@link Agent} with that id. If no agent with the given * name exists, <code>null</code> is returned. + * This method is very efficient if you want to find a single agent by its ID. + * If you need to get more than one agent, you could use <code>findAgentsByCriteria</code>. * * @param agentId * * @return the agent whose id matches the given id; <code>null</code> if there is no agent with the given id - * @deprecated Use <code>findAgentsByCriteria()</code> instead */ Agent getAgentByID(int agentId);
/** * Given an agent token string, this will look up and return the {@link Agent} associated with that token. If the * given token is invalid, <code>null</code> is returned. + * This method is very efficient if you want to find a single agent by its token. + * If you need to get more than one agent, you could use <code>findAgentsByCriteria</code>. * * @param token the agent token * * @return the agent whose agent token matches the given token; <code>null</code> if there is no agent with the * given token - * @deprecated Use <code>findAgentsByCriteria()</code> instead */ Agent getAgentByAgentToken(String token);
/** * Given an agent's address and port, this will look up and return the {@link Agent} associated with that address * and port. If no agent is found, <code>null</code> is returned. + * This method is very efficient if you want to find a single agent by its endpoint. + * If you need to get more than one agent, you could use <code>findAgentsByCriteria</code>. * * @param address the address that the agent is bound to * @param port the port at the given address that the agent is listening on * * @return the agent to be known at the given address and port; <code>null</code> if there is no agent with the * given token - * @deprecated Use <code>findAgentsByCriteria()</code> instead */ Agent getAgentByAddressAndPort(String address, int port);
commit 6a2b2c0c8c19cc52cbf39ddee7c49ea9ad0a3de1 Author: Simeon Pinder spinder@fulliautomatix.conchfritter.com Date: Thu Feb 21 10:13:48 2013 -0500
Apply fixes for CriteriaQueryTest incorrectly using paging.
diff --git a/modules/enterprise/server/jar/src/test/java/org/rhq/enterprise/server/util/CriteriaQueryTest.java b/modules/enterprise/server/jar/src/test/java/org/rhq/enterprise/server/util/CriteriaQueryTest.java index faa14ad..2e1c897 100644 --- a/modules/enterprise/server/jar/src/test/java/org/rhq/enterprise/server/util/CriteriaQueryTest.java +++ b/modules/enterprise/server/jar/src/test/java/org/rhq/enterprise/server/util/CriteriaQueryTest.java @@ -73,7 +73,9 @@ public class CriteriaQueryTest { }
public void addPage(List<FakeEntity> entities) { - pages.add(new PageList<FakeEntity>(entities, totalSize, pc)); + int pageNumber = pages.size(); + pages + .add(new PageList<FakeEntity>(entities, totalSize, new PageControl(pageNumber, this.pc.getPageSize()))); }
@Override @@ -113,7 +115,8 @@ public class CriteriaQueryTest { queryExecutor.addPage(expected.subList(2, 4));
FakeEntityCriteria criteria = new FakeEntityCriteria(); - criteria.setPageControl(pc); + //spinder 2-20-13: DO NOT use criteria.setPageControl(pc) here as it causes ignore of pageNumber/pageSize + criteria.setPaging(pc.getPageNumber(), pc.getPageSize());
CriteriaQuery<FakeEntity, FakeEntityCriteria> query = new CriteriaQuery<FakeEntity, FakeEntityCriteria>( criteria, queryExecutor); @@ -164,7 +167,7 @@ public class CriteriaQueryTest {
//build criteria and attach pageControl FakeEntityCriteria criteria = new FakeEntityCriteria(); - //DO NOT use criteria.setPageControl(pc) here as it causes ignore of pageNumber/pageSize + //spinder 2-20-13:DO NOT use criteria.setPageControl(pc) here as it causes ignore of pageNumber/pageSize criteria.setPaging(pc.getPageNumber(), pc.getPageSize());
//?? So which pageControl has the right details? Criteria.pageControl? OR PageControl passed into the QueryExecutor.
commit e0ea2fd840197301df934d34088b419e97279d83 Author: Thomas Segismont tsegismo@redhat.com Date: Tue Feb 12 10:23:51 2013 +0100
netservices plugin strengthening
Added Unit tests for HTTPNetServiceDiscoveryComponent
Added HTTPNetServiceComponent itest and verified code coverage
Added Unit tests for PingNetServiceDiscoveryComponent
Added PingNetServiceComponent itest and verified code coverage
Implemented missing parts and cleaned up code
diff --git a/.classpath b/.classpath index 9af3a50..dd5d354 100644 --- a/.classpath +++ b/.classpath @@ -24,9 +24,9 @@ <classpathentry kind="src" path="modules/core/util/src/test/java"/> <classpathentry kind="src" path="modules/core/dbutils/src/main/java"/> <classpathentry kind="src" path="modules/core/dbutils/src/test/java"/> - <classpathentry kind="src" path="modules/core/native-system/src/main/java"/> - <classpathentry kind="src" path="modules/core/native-system/src/test/java"/> - <classpathentry kind="src" path="modules/core/native-system/src/test/resources"/> + <classpathentry kind="src" path="modules/core/native-system/src/main/java"/> + <classpathentry kind="src" path="modules/core/native-system/src/test/java"/> + <classpathentry kind="src" path="modules/core/native-system/src/test/resources"/> <classpathentry kind="src" path="modules/core/domain/src/main/java"/> <classpathentry kind="src" path="modules/core/domain/src/test/java"/> <classpathentry kind="src" path="modules/core/plugin-api/src/main/java"/> @@ -124,6 +124,9 @@ <classpathentry kind="src" path="modules/plugins/apache/src/test/resources"/> <classpathentry kind="src" path="modules/plugins/script/src/main/java"/> <classpathentry kind="src" path="modules/plugins/netservices/src/main/java"/> + <classpathentry kind="src" path="modules/plugins/netservices/src/main/resources"/> + <classpathentry kind="src" path="modules/plugins/netservices/src/test/java"/> + <classpathentry kind="src" path="modules/plugins/netservices/src/test/resources"/> <classpathentry kind="src" path="modules/plugins/ant-bundle/src/main/java"/> <classpathentry kind="src" path="modules/plugins/ant-bundle/src/test/java"/> <classpathentry kind="src" path="modules/plugins/ant-bundle/src/test/resources"/> @@ -178,11 +181,11 @@ <classpathentry kind="src" path="modules/core/arquillian-integration/container/src/test/java"/> <classpathentry kind="src" path="modules/core/arquillian-integration/container/src/test/resources"/> <classpathentry kind="src" path="modules/test-utils/src/main/java"/> - <classpathentry kind="src" path="modules/integration-tests/apache-plugin-test/src/test/java"/> - <classpathentry kind="src" path="modules/integration-tests/apache-plugin-test/src/test/resources"/> - <classpathentry kind="src" path="modules/integration-tests/jndi-access/jndi-access-test/src/test/java"/> - <classpathentry kind="src" path="modules/integration-tests/jndi-access/jndi-access-test/src/test/resources"/> - <classpathentry kind="src" path="modules/integration-tests/mod_cluster-plugin-test/src/test/java"/> + <classpathentry kind="src" path="modules/integration-tests/apache-plugin-test/src/test/java"/> + <classpathentry kind="src" path="modules/integration-tests/apache-plugin-test/src/test/resources"/> + <classpathentry kind="src" path="modules/integration-tests/jndi-access/jndi-access-test/src/test/java"/> + <classpathentry kind="src" path="modules/integration-tests/jndi-access/jndi-access-test/src/test/resources"/> + <classpathentry kind="src" path="modules/integration-tests/mod_cluster-plugin-test/src/test/java"/> <classpathentry kind="src" path="etc/samples/skeleton-plugin/src/main/java"/> <classpathentry kind="src" path="etc/samples/custom-serverplugin/src/main/java"/> <classpathentry kind="src" path="etc/samples/simplereport-serverplugin/src/main/java"/> @@ -336,9 +339,9 @@ <classpathentry exported="true" kind="var" path="M2_REPO/org/jboss/spec/javax/jms/jboss-jms-api_1.1_spec/1.0.0.Final/jboss-jms-api_1.1_spec-1.0.0.Final.jar"/> <classpathentry exported="true" kind="var" path="M2_REPO/org/jboss/spec/javax/interceptor/jboss-interceptors-api_1.1_spec/1.0.0.Final/jboss-interceptors-api_1.1_spec-1.0.0.Final.jar"/> <classpathentry exported="true" kind="var" path="M2_REPO/org/jboss/spec/javax/transaction/jboss-transaction-api_1.1_spec/1.0.0.Final/jboss-transaction-api_1.1_spec-1.0.0.Final.jar"/> - <classpathentry exported="true" kind="var" path="M2_REPO/org/jboss/remotingjmx/remoting-jmx/1.0.2.Final/remoting-jmx-1.0.2.Final.jar"/> - <classpathentry exported="true" kind="var" path="M2_REPO/javax/enterprise/cdi-api/1.0-SP4/cdi-api-1.0-SP4.jar" sourcepath="M2_REPO/javax/enterprise/cdi-api/1.0-SP4/cdi-api-1.0-SP4-sources.jar"/> - <classpathentry exported="true" kind="var" path="M2_REPO/javax/inject/javax.inject/1/javax.inject-1.jar" sourcepath="M2_REPO/javax/inject/javax.inject/1/javax.inject-1-sources.jar"/> + <classpathentry exported="true" kind="var" path="M2_REPO/org/jboss/remotingjmx/remoting-jmx/1.0.2.Final/remoting-jmx-1.0.2.Final.jar"/> + <classpathentry exported="true" kind="var" path="M2_REPO/javax/enterprise/cdi-api/1.0-SP4/cdi-api-1.0-SP4.jar" sourcepath="M2_REPO/javax/enterprise/cdi-api/1.0-SP4/cdi-api-1.0-SP4-sources.jar"/> + <classpathentry exported="true" kind="var" path="M2_REPO/javax/inject/javax.inject/1/javax.inject-1.jar" sourcepath="M2_REPO/javax/inject/javax.inject/1/javax.inject-1-sources.jar"/> <classpathentry exported="true" kind="var" path="M2_REPO/org/mozilla/rhino/1.7R4/rhino-1.7R4.jar"/> <classpathentry exported="true" kind="var" path="M2_REPO/org/picketbox/picketbox/4.0.7.Final/picketbox-4.0.7.Final.jar"/> <classpathentry exported="true" kind="var" path="M2_REPO/org/python/jython-standalone/2.5.2/jython-standalone-2.5.2.jar"/> @@ -346,9 +349,10 @@ <classpathentry exported="true" kind="var" path="M2_REPO/joda-time/joda-time/2.1/joda-time-2.1.jar"/> <classpathentry exported="true" kind="var" path="M2_REPO/org/apache/cassandra/cassandra-thrift/1.1.5/cassandra-thrift-1.1.5.jar"/> <classpathentry exported="true" kind="var" path="M2_REPO/org/hectorclient/hector-core/1.1-1/hector-core-1.1-1.jar"/> - <classpathentry exported="true" kind="var" path="M2_REPO/org/jboss/byteman/byteman-install/1.5.2/byteman-install-1.5.2.jar" sourcepath="M2_REPO/org/jboss/byteman/byteman-install/1.5.2/byteman-install-1.5.2-sources.jar"/> - <classpathentry exported="true" kind="var" path="M2_REPO/org/jboss/byteman/byteman-submit/1.5.2/byteman-submit-1.5.2.jar" sourcepath="M2_REPO/org/jboss/byteman/byteman-submit/1.5.2/byteman-submit-1.5.2-sources.jar"/> - <classpathentry exported="true" kind="var" path="M2_REPO/org/jboss/byteman/byteman-bmunit/1.5.2/byteman-bmunit-1.5.2.jar" sourcepath="M2_REPO/org/jboss/byteman/byteman-bmunit/1.5.2/byteman-bmunit-1.5.2-sources.jar"/> - <classpathentry exported="true" kind="var" path="JDK_HOME/lib/tools.jar"/> - <classpathentry kind="output" path="eclipse-classes"/> + <classpathentry exported="true" kind="var" path="M2_REPO/org/jboss/byteman/byteman-install/1.5.2/byteman-install-1.5.2.jar" sourcepath="M2_REPO/org/jboss/byteman/byteman-install/1.5.2/byteman-install-1.5.2-sources.jar"/> + <classpathentry exported="true" kind="var" path="M2_REPO/org/jboss/byteman/byteman-submit/1.5.2/byteman-submit-1.5.2.jar" sourcepath="M2_REPO/org/jboss/byteman/byteman-submit/1.5.2/byteman-submit-1.5.2-sources.jar"/> + <classpathentry exported="true" kind="var" path="M2_REPO/org/jboss/byteman/byteman-bmunit/1.5.2/byteman-bmunit-1.5.2.jar" sourcepath="M2_REPO/org/jboss/byteman/byteman-bmunit/1.5.2/byteman-bmunit-1.5.2-sources.jar"/> + <classpathentry exported="true" kind="var" path="M2_REPO/org/eclipse/jetty/aggregate/jetty-all/8.1.8.v20121106/jetty-all-8.1.8.v20121106.jar" sourcepath="M2_REPO/org/eclipse/jetty/aggregate/jetty-all/8.1.8.v20121106/jetty-all-8.1.8.v20121106-sources.jar"/> + <classpathentry exported="true" kind="var" path="JDK_HOME/lib/tools.jar"/> + <classpathentry kind="output" path="eclipse-classes"/> </classpath> diff --git a/modules/core/util/src/main/java/org/rhq/core/util/StringUtil.java b/modules/core/util/src/main/java/org/rhq/core/util/StringUtil.java index 59a09f2..21e81c4 100644 --- a/modules/core/util/src/main/java/org/rhq/core/util/StringUtil.java +++ b/modules/core/util/src/main/java/org/rhq/core/util/StringUtil.java @@ -39,6 +39,8 @@ public class StringUtil {
private static final Log log = LogFactory.getLog(StringUtil.class);
+ public static final String EMPTY_STRING = ""; + /** * @param source The source string to perform replacements on. * @param find The substring to find in source. @@ -119,7 +121,7 @@ public class StringUtil { * * @return The Iterator's elements in a user-friendly string format. */ - public static String iteratorToString(Iterator i, String delim) { + public static String iteratorToString(Iterator<?> i, String delim) { return iteratorToString(i, delim, ""); }
@@ -132,7 +134,7 @@ public class StringUtil { * * @return The Iterator's elements in a user-friendly string format. */ - public static String iteratorToString(Iterator i, String delim, String quoteChar) { + public static String iteratorToString(Iterator<?> i, String delim, String quoteChar) { Object elt = null; StringBuilder rstr = new StringBuilder(); String s; @@ -166,21 +168,21 @@ public class StringUtil { * * @return The List in a user-friendly string format. */ - public static String listToString(List list, String delim) { + public static String listToString(List<?> list, String delim) { if (list == null) { return "NULL"; }
- Iterator i = list.iterator(); + Iterator<?> i = list.iterator(); return iteratorToString(i, delim, null); }
- public static String collectionToString(Collection collection, String delim) { + public static String collectionToString(Collection<?> collection, String delim) { if (collection == null) { return "NULL"; }
- Iterator i = collection.iterator(); + Iterator<?> i = collection.iterator(); return iteratorToString(i, delim, null); }
@@ -191,11 +193,11 @@ public class StringUtil { * * @return The List in a user-friendly string format. */ - public static String listToString(List list) { + public static String listToString(List<?> list) { return listToString(list, ","); }
- public static String collectionToString(Collection collection) { + public static String collectionToString(Collection<?> collection) { return collectionToString(collection, ","); }
@@ -278,7 +280,7 @@ public class StringUtil { * * @return A string with objects in the list seperated by delim */ - public static String implode(List objs, String delim) { + public static String implode(List<?> objs, String delim) { StringBuilder buf = new StringBuilder(); int size = objs.size();
diff --git a/modules/plugins/netservices/pom.xml b/modules/plugins/netservices/pom.xml index 7805daa..4afa8a5 100644 --- a/modules/plugins/netservices/pom.xml +++ b/modules/plugins/netservices/pom.xml @@ -1,240 +1,236 @@ -<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd"> - - <modelVersion>4.0.0</modelVersion> - - <parent> - <groupId>org.rhq</groupId> - <artifactId>rhq-plugins-parent</artifactId> - <version>4.6.0-SNAPSHOT</version> - </parent> - - <groupId>org.rhq</groupId> - <artifactId>rhq-netservices-plugin</artifactId> - <packaging>jar</packaging> - - <name>RHQ Network Services Plugin</name> - <description> - A plugin for monitoring network services. - </description> - - <dependencies> - - <dependency> - <groupId>commons-httpclient</groupId> - <artifactId>commons-httpclient</artifactId> - <version>${commons-httpclient.version}</version> - </dependency> - <dependency> - <groupId>commons-codec</groupId> - <artifactId>commons-codec</artifactId> - <version>${commons-codec.version}</version> - </dependency> - - </dependencies> - - <build> - - <plugins> - - <plugin> - <artifactId>maven-dependency-plugin</artifactId> - <executions> - <execution> - <id>copy-dependency-jars</id> - <phase>process-resources</phase> - <goals> - <goal>copy</goal> - </goals> - <configuration> - <artifactItems> - <artifactItem> - <groupId>commons-httpclient</groupId> - <artifactId>commons-httpclient</artifactId> - <version>${commons-httpclient.version}</version> - </artifactItem> - <artifactItem> - <groupId>commons-codec</groupId> - <artifactId>commons-codec</artifactId> - <version>1.2</version> - </artifactItem> - </artifactItems> - <outputDirectory>${project.build.outputDirectory}/lib</outputDirectory> - </configuration> - </execution> - </executions> - </plugin> - - </plugins> - - </build> - - - <profiles> - <profile> - <id>integration-tests</id> - <activation> +<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd%22%3E + + <modelVersion>4.0.0</modelVersion> + + <parent> + <groupId>org.rhq</groupId> + <artifactId>rhq-plugins-parent</artifactId> + <version>4.6.0-SNAPSHOT</version> + </parent> + + <groupId>org.rhq</groupId> + <artifactId>rhq-netservices-plugin</artifactId> + <packaging>jar</packaging> + + <name>RHQ Network Services Plugin</name> + <description>A plugin for monitoring network services.</description> + + <dependencies> + + <dependency> + <groupId>commons-httpclient</groupId> + <artifactId>commons-httpclient</artifactId> + <version>${commons-httpclient.version}</version> + </dependency> + <dependency> + <groupId>commons-codec</groupId> + <artifactId>commons-codec</artifactId> + <version>${commons-codec.version}</version> + </dependency> + + <!-- Test dependencies --> + + <dependency> + <groupId>org.mockito</groupId> + <artifactId>mockito-core</artifactId> + <version>1.9.5</version> + <scope>test</scope> + </dependency> + + <dependency> + <groupId>org.eclipse.jetty.aggregate</groupId> + <artifactId>jetty-all</artifactId> + <version>8.1.8.v20121106</version> + <scope>test</scope> + </dependency> + + </dependencies> + + <build> + <plugins> + + <plugin> + <artifactId>maven-surefire-plugin</artifactId> + <configuration> + <excludes> + <exclude>org/rhq/plugins/netservices/itest/**</exclude> + </excludes> + <properties> <property> - <name>maven.test.skip</name> - <value>!true</value> + <name>listener</name> + <value>org.rhq.test.testng.StdoutReporter</value> </property> - </activation> - - <build> - <plugins> - - <!-- Integration testing voodoo to load and test this plugin with its plugin dependencies --> - <plugin> - <artifactId>maven-antrun-plugin</artifactId> - <executions> - <execution> - <phase>pre-integration-test</phase> - <configuration> - <target> - <echo>Setting up plugin dependencies for ${project.artifactId}-${project.version}.jar...</echo> - <property name="settings.localRepository" location="${user.home}/.m2/repository" /> - <mkdir dir="target/itest" /> - <mkdir dir="target/itest/plugins" /> - <mkdir dir="target/itest/lib" /> - <copy toDir="target/itest/plugins" flatten="true"> - <fileset dir="${project.build.directory}"> - <include name="${project.artifactId}-${project.version}.jar" /> - </fileset> - </copy> - <unzip dest="target/itest/lib"> - <fileset dir="${settings.localRepository}/org/hyperic/sigar-dist/${sigar.version}" includes="*.zip" /> - <patternset> - <include name="**/lib/sigar.jar" /> - <include name="**/lib/bcel*.jar" /> - <include name="**/lib/*.so" /> - <include name="**/lib/*.sl" /> - <include name="**/lib/*.dll" /> - <include name="**/lib/*.dylib" /> - </patternset> - </unzip> - <move todir="target/itest/lib" flatten="true"> - <fileset dir="target/itest/lib"> - <include name="**/lib/*" /> - </fileset> - </move> - <delete dir="target/itest/lib/hyperic-sigar-${sigar.version}" /> - </target> - </configuration> - <goals> - <goal>run</goal> - </goals> - </execution> - </executions> - </plugin> - - <plugin> - <artifactId>maven-surefire-plugin</artifactId> - <configuration> - <skip>true</skip> - </configuration> - <executions> - <execution> - <id>surefire-it</id> - <phase>integration-test</phase> - <goals> - <goal>test</goal> - </goals> - <configuration> - <skip>${maven.test.skip}</skip> - <excludedGroups>${rhq.testng.excludedGroups}</excludedGroups> - <useSystemClassLoader>false</useSystemClassLoader> - <argLine>${jacoco.integration-test.args} -Dorg.hyperic.sigar.path=${basedir}/target/itest/lib</argLine> - <!--<argLine>${jacoco.integration-test.args} -Dorg.hyperic.sigar.path=${basedir}/target/itest/lib -Xdebug -Xnoagent -Djava.compiler=NONE -Xrunjdwp:transport=dt_socket,address=8787,server=y,suspend=y</argLine>--> - <systemProperties> - <property> - <name>project.artifactId</name> - <value>${project.artifactId}</value> - </property> - <property> - <name>project.version</name> - <value>${project.version}</value> - </property> - </systemProperties> - </configuration> - </execution> - </executions> - </plugin> - - </plugins> - </build> - </profile> - - <profile> - <id>dev</id> - - <properties> - <rhq.rootDir>../../..</rhq.rootDir> - <rhq.containerDir>${rhq.rootDir}/${rhq.defaultDevContainerPath}</rhq.containerDir> - <rhq.deploymentDir>${rhq.containerDir}/${rhq.agentPluginDir}</rhq.deploymentDir> - </properties> - - <build> - <plugins> - - <plugin> - <artifactId>maven-antrun-plugin</artifactId> - <executions> - - <execution> - <id>deploy</id> - <phase>compile</phase> - <configuration> - <target> - <mkdir dir="${rhq.deploymentDir}" /> - <property name="deployment.file" location="${rhq.deploymentDir}/${project.build.finalName}.jar" /> - <echo>*** Updating ${deployment.file}...</echo> - <jar destfile="${deployment.file}" basedir="${project.build.outputDirectory}" /> - </target> - </configuration> - <goals> - <goal>run</goal> - </goals> - </execution> - - <execution> - <id>deploy-jar-meta-inf</id> - <phase>package</phase> - <configuration> - <target> - <property name="deployment.file" location="${rhq.deploymentDir}/${project.build.finalName}.jar" /> - <echo>*** Updating META-INF dir in ${deployment.file}...</echo> - <unjar src="${project.build.directory}/${project.build.finalName}.jar" dest="${project.build.outputDirectory}"> - <patternset><include name="META-INF/**" /></patternset> - </unjar> - <jar destfile="${deployment.file}" manifest="${project.build.outputDirectory}/META-INF/MANIFEST.MF" update="true"> - </jar> - </target> - </configuration> - <goals> - <goal>run</goal> - </goals> - </execution> - - <execution> - <id>undeploy</id> - <phase>clean</phase> - <configuration> - <target> - <property name="deployment.file" location="${rhq.deploymentDir}/${project.build.finalName}.jar" /> - <echo>*** Deleting ${deployment.file}...</echo> - <delete file="${deployment.file}" /> - </target> - </configuration> - <goals> - <goal>run</goal> - </goals> - </execution> - - </executions> - </plugin> - - </plugins> - </build> - </profile> - </profiles> + </properties> + <useSystemClassLoader>false</useSystemClassLoader> + <argLine>${jacoco.unit-test.args}</argLine> + </configuration> + </plugin> + + <plugin> + <artifactId>maven-antrun-plugin</artifactId> + <executions> + <execution> + <phase>pre-integration-test</phase> + <configuration> + <target> + <echo>Setting up itest plugin container...</echo> + <property name="settings.localRepository" location="${user.home}/.m2/repository" /> + <mkdir dir="target/itest/plugins" /> + <copy toDir="target/itest/plugins" flatten="true" verbose="true"> + <fileset dir="${settings.localRepository}/"> + <include name="org/rhq/rhq-platform-plugin/${project.version}/rhq-platform-plugin-${project.version}.jar" /> + </fileset> + <fileset dir="${project.build.directory}"> + <include name="${project.artifactId}-${project.version}.jar" /> + </fileset> + </copy> + </target> + </configuration> + <goals> + <goal>run</goal> + </goals> + </execution> + </executions> + </plugin> + + <plugin> + <artifactId>maven-failsafe-plugin</artifactId> + <configuration> + <skipTests>false</skipTests> + <skipITs>false</skipITs> + <includes> + <!-- only include integration tests; normal unit tests are handled above by surefire plugin --> + <include>org/rhq/plugins/netservices/itest/**/*Test.java</include> + </includes> + <properties> + <property> + <name>listener</name> + <value>org.rhq.test.testng.StdoutReporter</value> + </property> + </properties> + <useSystemClassLoader>false</useSystemClassLoader> + <argLine>${jacoco.integration-test.args}</argLine> + </configuration> + <executions> + <execution> + <goals> + <goal>integration-test</goal> + <goal>verify</goal> + </goals> + </execution> + </executions> + </plugin> + + <plugin> + <artifactId>maven-dependency-plugin</artifactId> + <executions> + <execution> + <id>copy-dependency-jars</id> + <phase>process-resources</phase> + <goals> + <goal>copy</goal> + </goals> + <configuration> + <artifactItems> + <artifactItem> + <groupId>commons-httpclient</groupId> + <artifactId>commons-httpclient</artifactId> + <version>${commons-httpclient.version}</version> + </artifactItem> + <artifactItem> + <groupId>commons-codec</groupId> + <artifactId>commons-codec</artifactId> + <version>1.2</version> + </artifactItem> + </artifactItems> + <outputDirectory>${project.build.outputDirectory}/lib</outputDirectory> + </configuration> + </execution> + </executions> + </plugin> + + </plugins> + </build> + + <profiles> + + <profile> + + <id>dev</id> + + <properties> + <rhq.rootDir>../../..</rhq.rootDir> + <rhq.containerDir>${rhq.rootDir}/${rhq.defaultDevContainerPath}</rhq.containerDir> + <rhq.deploymentDir>${rhq.containerDir}/${rhq.agentPluginDir}</rhq.deploymentDir> + </properties> + + <build> + <plugins> + + <plugin> + <artifactId>maven-antrun-plugin</artifactId> + <executions> + + <execution> + <id>deploy</id> + <phase>compile</phase> + <configuration> + <target> + <mkdir dir="${rhq.deploymentDir}" /> + <property name="deployment.file" location="${rhq.deploymentDir}/${project.build.finalName}.jar" /> + <echo>*** Updating ${deployment.file}...</echo> + <jar destfile="${deployment.file}" basedir="${project.build.outputDirectory}" /> + </target> + </configuration> + <goals> + <goal>run</goal> + </goals> + </execution> + + <execution> + <id>deploy-jar-meta-inf</id> + <phase>package</phase> + <configuration> + <target> + <property name="deployment.file" location="${rhq.deploymentDir}/${project.build.finalName}.jar" /> + <echo>*** Updating META-INF dir in ${deployment.file}...</echo> + <unjar src="${project.build.directory}/${project.build.finalName}.jar" dest="${project.build.outputDirectory}"> + <patternset> + <include name="META-INF/**" /> + </patternset> + </unjar> + <jar destfile="${deployment.file}" manifest="${project.build.outputDirectory}/META-INF/MANIFEST.MF" + update="true"> + </jar> + </target> + </configuration> + <goals> + <goal>run</goal> + </goals> + </execution> + + <execution> + <id>undeploy</id> + <phase>clean</phase> + <configuration> + <target> + <property name="deployment.file" location="${rhq.deploymentDir}/${project.build.finalName}.jar" /> + <echo>*** Deleting ${deployment.file}...</echo> + <delete file="${deployment.file}" /> + </target> + </configuration> + <goals> + <goal>run</goal> + </goals> + </execution> + + </executions> + </plugin> + + </plugins> + </build> + </profile> + </profiles>
</project> diff --git a/modules/plugins/netservices/src/main/java/org/rhq/plugins/netservices/HTTPNetServiceComponent.java b/modules/plugins/netservices/src/main/java/org/rhq/plugins/netservices/HTTPNetServiceComponent.java index 54d9256..42cbcee 100644 --- a/modules/plugins/netservices/src/main/java/org/rhq/plugins/netservices/HTTPNetServiceComponent.java +++ b/modules/plugins/netservices/src/main/java/org/rhq/plugins/netservices/HTTPNetServiceComponent.java @@ -1,6 +1,6 @@ /* * RHQ Management Platform - * Copyright (C) 2005-2008 Red Hat, Inc. + * Copyright (C) 2005-2013 Red Hat, Inc. * All rights reserved. * * This program is free software; you can redistribute it and/or modify @@ -19,14 +19,22 @@
package org.rhq.plugins.netservices;
-import java.text.SimpleDateFormat; +import java.net.MalformedURLException; +import java.net.URL; import java.util.Date; -import java.util.Locale; import java.util.Set; +import java.util.regex.Pattern; +import java.util.regex.PatternSyntaxException;
import org.apache.commons.httpclient.Header; import org.apache.commons.httpclient.HttpClient; +import org.apache.commons.httpclient.HttpMethodBase; +import org.apache.commons.httpclient.SimpleHttpConnectionManager; +import org.apache.commons.httpclient.UsernamePasswordCredentials; +import org.apache.commons.httpclient.auth.AuthScope; import org.apache.commons.httpclient.methods.GetMethod; +import org.apache.commons.httpclient.methods.HeadMethod; +import org.apache.commons.httpclient.util.DateUtil; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory;
@@ -39,43 +47,114 @@ import org.rhq.core.pluginapi.inventory.InvalidPluginConfigurationException; import org.rhq.core.pluginapi.inventory.ResourceComponent; import org.rhq.core.pluginapi.inventory.ResourceContext; import org.rhq.core.pluginapi.measurement.MeasurementFacet; -import org.rhq.core.pluginapi.operation.OperationFacet; -import org.rhq.core.pluginapi.operation.OperationResult; +import org.rhq.core.util.StringUtil;
/** * Monitoring of HTTP Servers * * @author Greg Hinkle */ -public class HTTPNetServiceComponent implements ResourceComponent, MeasurementFacet, OperationFacet { - private final Log log = LogFactory.getLog(this.getClass()); +public class HTTPNetServiceComponent implements ResourceComponent, MeasurementFacet {
- public static final String CONFIG_URL = "url"; - public static final String CONFIG_USER = "user"; - public static final String CONFIG_PASSWORD = "password"; - public static final String CONFIG_REALM = "realm"; + public static final class ConfigKeys {
- // One of { none, SSL, TLS } - public static final String CONFIG_SSL_PROTOCOL = "sslProtocol"; + private ConfigKeys() { + // Defensive + } + + public static final String URL = "url"; + public static final String USER = "user"; + public static final String PASSWORD = "password"; + public static final String REALM = "realm"; + public static final String METHOD = "method"; + public static final String FOLOW_REDIRECTS = "followRedirects"; + public static final String VALIDATE_RESPONSE_CODE = "validateResponseCode"; + public static final String VALIDATE_RESPONSE_PATTERN = "validateResponsePattern";
- // One of { HEAD, GET } - public static final String CONFIG_METHOD = "method"; - public static final String CONFIG_FOLOW_REDIRECTS = "followRedirects"; - public static final String CONFIG_RESPONSE_PATTERN = "responsePattern"; + } + + public static enum HttpMethod { + GET, HEAD + } + + private static final Log LOG = LogFactory.getLog(HTTPNetServiceComponent.class);
private ResourceContext resourceContext;
+ private Configuration pluginConfig; + + private HTTPNetServiceComponentConfiguration componentConfig; + + @Override public void start(ResourceContext resourceContext) throws InvalidPluginConfigurationException, Exception { this.resourceContext = resourceContext; - String url = resourceContext.getPluginConfiguration().getSimple(CONFIG_URL).getStringValue(); - if (!url.startsWith("http:") && !url.startsWith("https")) { - throw new InvalidPluginConfigurationException("Url not valid. Must start with 'http:' or 'https:'"); + pluginConfig = resourceContext.getPluginConfiguration(); + componentConfig = createComponentConfiguration(pluginConfig); + } + + /** + * Create a foram {@link HTTPNetServiceComponentConfiguration} instance with the supplied {@link Configuration}. + * May throw {@link InvalidPluginConfigurationException} if: + * <ul> + * <li>Url is empty, invalid, or pointing an non http/https resource</li> + * <li>Http method is not HEAD or GET</li> + * <li>If both content validation and HEAD method are configured</li> + * <li>If the content validation pattern is invalid</li> + * <ul> + * + * @param pluginConfig + * @return + * @throws InvalidPluginConfigurationException + */ + static HTTPNetServiceComponentConfiguration createComponentConfiguration(Configuration pluginConfig) { + + URL endPointUrl = null; + String configUrl = pluginConfig.getSimpleValue(ConfigKeys.URL, StringUtil.EMPTY_STRING); + if (StringUtil.isBlank(configUrl)) { + throw new InvalidPluginConfigurationException("Endpoint URL is not defined"); + } + try { + endPointUrl = new URL(configUrl); + } catch (MalformedURLException e) { + throw new InvalidPluginConfigurationException(configUrl + " is not a valid URL"); } + String protocol = endPointUrl.getProtocol(); + if (!protocol.equals("http") && !protocol.equals("https")) { + throw new InvalidPluginConfigurationException(configUrl + "does not point to an http(s) resource"); + } + + HttpMethod httpMethod = null; + String configMethod = pluginConfig.getSimpleValue(ConfigKeys.METHOD, StringUtil.EMPTY_STRING); + try { + httpMethod = HttpMethod.valueOf(configMethod); + } catch (IllegalArgumentException e) { + throw new InvalidPluginConfigurationException("Invalid http method: " + configMethod); + } + + Pattern responseValidationPattern = null; + String configValidateResponsePattern = pluginConfig.getSimpleValue(ConfigKeys.VALIDATE_RESPONSE_PATTERN); + if (configValidateResponsePattern != null) { + if (httpMethod.equals(HttpMethod.HEAD)) { + throw new InvalidPluginConfigurationException("Cannot validate response content with HEAD request"); + } + try { + responseValidationPattern = Pattern.compile(configValidateResponsePattern); + } catch (PatternSyntaxException e) { + throw new InvalidPluginConfigurationException("Invalid pattern: " + configValidateResponsePattern); + } + } + + return new HTTPNetServiceComponentConfiguration(endPointUrl, httpMethod, responseValidationPattern); }
+ @Override public void stop() { + resourceContext = null; + pluginConfig = null; + componentConfig = null; }
+ @Override public AvailabilityType getAvailability() { try { return getValuesOrAvailability(null, null) ? AvailabilityType.UP : AvailabilityType.DOWN; @@ -84,53 +163,60 @@ public class HTTPNetServiceComponent implements ResourceComponent, MeasurementFa } }
+ @Override public void getValues(MeasurementReport report, Set<MeasurementScheduleRequest> metrics) throws Exception { getValuesOrAvailability(report, metrics); }
- public boolean getValuesOrAvailability(MeasurementReport report, Set<MeasurementScheduleRequest> metrics) + private boolean getValuesOrAvailability(MeasurementReport report, Set<MeasurementScheduleRequest> metrics) throws Exception {
- try { - - Configuration config = resourceContext.getPluginConfiguration(); - - HttpClient httpClient = new HttpClient(); + SimpleHttpConnectionManager httpConnectionManager = new SimpleHttpConnectionManager(); + HttpClient client = new HttpClient(httpConnectionManager); + + String userName = pluginConfig.getSimpleValue(ConfigKeys.USER, StringUtil.EMPTY_STRING); + // Set credentials only if a user name is configured + if (StringUtil.isNotBlank(userName)) { + String password = pluginConfig.getSimpleValue(ConfigKeys.PASSWORD, StringUtil.EMPTY_STRING); + String realm = pluginConfig.getSimpleValue(ConfigKeys.REALM, AuthScope.ANY_REALM); + client.getState().setCredentials( + new AuthScope(componentConfig.getEndPointUrl().getHost(), componentConfig.getEndPointUrl().getPort(), + realm), new UsernamePasswordCredentials(userName, password)); + }
- GetMethod method = new GetMethod(config.getSimple(CONFIG_URL).getStringValue()); + HttpMethodBase method = null; + switch (componentConfig.getHttpMethod()) { + case GET: + method = new GetMethod(componentConfig.getEndPointUrl().toExternalForm()); + break; + case HEAD: + method = new HeadMethod(componentConfig.getEndPointUrl().toExternalForm()); + break; + default: + throw new RuntimeException("Unsupported http method: '" + componentConfig.getHttpMethod() + "'"); + } + Boolean followRedirects = pluginConfig.getSimple(ConfigKeys.FOLOW_REDIRECTS).getBooleanValue(); + method.setFollowRedirects(followRedirects == null ? false : followRedirects.booleanValue());
- method.setFollowRedirects(config.getSimple(CONFIG_FOLOW_REDIRECTS).getBooleanValue()); + try {
long start = System.currentTimeMillis(); - int responseCode = httpClient.executeMethod(method); + int responseCode = client.executeMethod(method); long connectTime = System.currentTimeMillis() - start;
- boolean success = !config.getSimple("validateResponseCode").getBooleanValue() + // Availability may depend on reponse code value + boolean success = !pluginConfig.getSimple(ConfigKeys.VALIDATE_RESPONSE_CODE).getBooleanValue() || (responseCode >= 200 && responseCode <= 299); - - String response = method.getResponseBodyAsString(); + // Availability may depend on reponse content matching a pattern + success = success + && (componentConfig.getResponseValidationPattern() == null || componentConfig + .getResponseValidationPattern().matcher(method.getResponseBodyAsString()).find());
long readTime = (System.currentTimeMillis() - start);
- // TODO: may need to allow plugin to configure the locale, but for this fixed string, make sure we - // ignore default locale, this works for english. - SimpleDateFormat sdf = new SimpleDateFormat("EEE, d MMM yyyy HH:mm:ss zzz", Locale.ENGLISH); Header dateHeader = method.getResponseHeader("Date"); - Date contentDate = dateHeader == null ? new Date(System.currentTimeMillis()) : sdf.parse(dateHeader.getValue()); - - // System.out.println("Success: " + success); - // System.out.println("Response: " + responseCode); - // System.out.println("Connect Time: " + connectTime); - // System.out.println("Read Time: " + readTime); - // System.out.println("Content Length: " + response.length()); - // System.out.println("Content Date: " + contentDate); - // System.out.println("Content Charset: " + method.getResponseCharSet()); - // System.out.println("Content Age: " + (System.currentTimeMillis() - contentDate.getTime())); - - // System.out.println("-----------------------"); - // for (Header header : method.getResponseHeaders()) { - // System.out.println(header.getName() + " = " + header.getValue()); - // } + Date contentDate = dateHeader == null ? new Date(System.currentTimeMillis()) : DateUtil + .parseDate(dateHeader.getValue());
if (metrics != null) { for (MeasurementScheduleRequest request : metrics) { @@ -139,7 +225,7 @@ public class HTTPNetServiceComponent implements ResourceComponent, MeasurementFa } else if (request.getName().equals("readTime")) { report.addData(new MeasurementDataNumeric(request, (double) readTime)); } else if (request.getName().equals("contentLength")) { - report.addData(new MeasurementDataNumeric(request, (double) response.length())); + report.addData(new MeasurementDataNumeric(request, (double) method.getResponseContentLength())); } else if (request.getName().equals("contentAge")) { report.addData(new MeasurementDataNumeric(request, (double) (System.currentTimeMillis() - contentDate.getTime()))); @@ -150,28 +236,14 @@ public class HTTPNetServiceComponent implements ResourceComponent, MeasurementFa return success;
} catch (Exception e) { - // e.printStackTrace(); - log.error(e); + LOG.error(e); + } finally { + // First release connection + method.releaseConnection(); + // Then force close + httpConnectionManager.closeIdleConnections(0); } return false; }
- // TODO GH: This really only makes sense to offer to go get the content if we can support long config content for responses bigger than 4k - public OperationResult invokeOperation(String name, Configuration parameters) throws InterruptedException, - Exception { - Configuration config = resourceContext.getPluginConfiguration(); - - HttpClient httpClient = new HttpClient(); - - GetMethod method = new GetMethod(config.getSimple(CONFIG_URL).getStringValue()); - - method.setFollowRedirects(config.getSimple(CONFIG_FOLOW_REDIRECTS).getBooleanValue()); - - int responseCode = httpClient.executeMethod(method); - - String response = method.getResponseBodyAsString(); - - OperationResult result = new OperationResult(response); - return result; - } } diff --git a/modules/plugins/netservices/src/main/java/org/rhq/plugins/netservices/HTTPNetServiceComponentConfiguration.java b/modules/plugins/netservices/src/main/java/org/rhq/plugins/netservices/HTTPNetServiceComponentConfiguration.java new file mode 100644 index 0000000..b28d03f --- /dev/null +++ b/modules/plugins/netservices/src/main/java/org/rhq/plugins/netservices/HTTPNetServiceComponentConfiguration.java @@ -0,0 +1,57 @@ +/* + * RHQ Management Platform + * Copyright (C) 2013 Red Hat, Inc. + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation version 2 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +package org.rhq.plugins.netservices; + +import java.net.URL; +import java.util.regex.Pattern; + +import org.rhq.plugins.netservices.HTTPNetServiceComponent.HttpMethod; + +/** + * @author Thomas Segismont + */ +class HTTPNetServiceComponentConfiguration { + + private URL endPointUrl; + + private HttpMethod httpMethod; + + private Pattern responseValidationPattern; + + public HTTPNetServiceComponentConfiguration(URL endPointUrl, HttpMethod httpMethod, + Pattern responseValidationPattern) { + this.endPointUrl = endPointUrl; + this.httpMethod = httpMethod; + this.responseValidationPattern = responseValidationPattern; + } + + public URL getEndPointUrl() { + return endPointUrl; + } + + public HttpMethod getHttpMethod() { + return httpMethod; + } + + public Pattern getResponseValidationPattern() { + return responseValidationPattern; + } + +} \ No newline at end of file diff --git a/modules/plugins/netservices/src/main/java/org/rhq/plugins/netservices/HTTPNetServiceDiscoveryComponent.java b/modules/plugins/netservices/src/main/java/org/rhq/plugins/netservices/HTTPNetServiceDiscoveryComponent.java index f0d693b..6b259b3 100644 --- a/modules/plugins/netservices/src/main/java/org/rhq/plugins/netservices/HTTPNetServiceDiscoveryComponent.java +++ b/modules/plugins/netservices/src/main/java/org/rhq/plugins/netservices/HTTPNetServiceDiscoveryComponent.java @@ -1,6 +1,6 @@ /* * RHQ Management Platform - * Copyright (C) 2005-2008 Red Hat, Inc. + * Copyright (C) 2005-2013 Red Hat, Inc. * All rights reserved. * * This program is free software; you can redistribute it and/or modify @@ -19,48 +19,37 @@
package org.rhq.plugins.netservices;
-import org.rhq.core.pluginapi.inventory.ResourceDiscoveryComponent; -import org.rhq.core.pluginapi.inventory.ResourceDiscoveryContext; -import org.rhq.core.pluginapi.inventory.InvalidPluginConfigurationException; +import java.util.Collections; +import java.util.Set; + +import org.rhq.core.domain.configuration.Configuration; import org.rhq.core.pluginapi.inventory.DiscoveredResourceDetails; +import org.rhq.core.pluginapi.inventory.InvalidPluginConfigurationException; import org.rhq.core.pluginapi.inventory.ManualAddFacet; -import org.rhq.core.domain.configuration.Configuration; - -import java.util.Set; -import java.util.Collections; -import java.net.URL; -import java.net.MalformedURLException; +import org.rhq.core.pluginapi.inventory.ResourceDiscoveryComponent; +import org.rhq.core.pluginapi.inventory.ResourceDiscoveryContext;
/** * @author Greg Hinkle */ public class HTTPNetServiceDiscoveryComponent implements ResourceDiscoveryComponent, ManualAddFacet { - public Set discoverResources(ResourceDiscoveryContext resourceDiscoveryContext) throws InvalidPluginConfigurationException, Exception { + + @Override + public Set discoverResources(ResourceDiscoveryContext resourceDiscoveryContext) + throws InvalidPluginConfigurationException, Exception { // We don't support auto-discovery. return Collections.emptySet(); }
+ @Override public DiscoveredResourceDetails discoverResource(Configuration config, - ResourceDiscoveryContext resourceDiscoveryContext) - throws InvalidPluginConfigurationException { - String configURL = config.getSimple(HTTPNetServiceComponent.CONFIG_URL).getStringValue(); - URL url; - try { - url = new URL(configURL); - } - catch (MalformedURLException e) { - throw new InvalidPluginConfigurationException("Property '" + HTTPNetServiceComponent.CONFIG_URL - + "' is not a valid URL."); - } - DiscoveredResourceDetails details = - new DiscoveredResourceDetails( - resourceDiscoveryContext.getResourceType(), - url.toExternalForm(), - url.toExternalForm(), - null, - null, - config, - null); + ResourceDiscoveryContext resourceDiscoveryContext) throws InvalidPluginConfigurationException { + // Get the component configuration. This call will also make configuration checks + HTTPNetServiceComponentConfiguration componentConfiguration = HTTPNetServiceComponent + .createComponentConfiguration(config); + String endPointUrl = componentConfiguration.getEndPointUrl().toExternalForm(); + DiscoveredResourceDetails details = new DiscoveredResourceDetails(resourceDiscoveryContext.getResourceType(), + endPointUrl, endPointUrl, null, null, config, null); return details; } } diff --git a/modules/plugins/netservices/src/main/java/org/rhq/plugins/netservices/PingNetServiceComponent.java b/modules/plugins/netservices/src/main/java/org/rhq/plugins/netservices/PingNetServiceComponent.java index f219e05..f416140 100644 --- a/modules/plugins/netservices/src/main/java/org/rhq/plugins/netservices/PingNetServiceComponent.java +++ b/modules/plugins/netservices/src/main/java/org/rhq/plugins/netservices/PingNetServiceComponent.java @@ -1,6 +1,6 @@ /* * RHQ Management Platform - * Copyright (C) 2005-2008 Red Hat, Inc. + * Copyright (C) 2005-2013 Red Hat, Inc. * All rights reserved. * * This program is free software; you can redistribute it and/or modify @@ -19,78 +19,93 @@
package org.rhq.plugins.netservices;
-import org.apache.commons.httpclient.Header; -import org.apache.commons.httpclient.HttpClient; -import org.apache.commons.httpclient.methods.GetMethod; +import java.net.InetAddress; +import java.net.UnknownHostException; +import java.util.Set; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; + import org.rhq.core.domain.configuration.Configuration; import org.rhq.core.domain.measurement.AvailabilityType; import org.rhq.core.domain.measurement.MeasurementDataNumeric; +import org.rhq.core.domain.measurement.MeasurementDataTrait; import org.rhq.core.domain.measurement.MeasurementReport; import org.rhq.core.domain.measurement.MeasurementScheduleRequest; -import org.rhq.core.domain.measurement.MeasurementDataTrait; import org.rhq.core.pluginapi.inventory.InvalidPluginConfigurationException; import org.rhq.core.pluginapi.inventory.ResourceComponent; import org.rhq.core.pluginapi.inventory.ResourceContext; import org.rhq.core.pluginapi.measurement.MeasurementFacet; -import org.rhq.core.pluginapi.operation.OperationFacet; -import org.rhq.core.pluginapi.operation.OperationResult; - -import java.text.SimpleDateFormat; -import java.util.Date; -import java.util.Set; -import java.net.InetAddress; -import java.net.Inet4Address; -import java.net.UnknownHostException; - +import org.rhq.core.util.StringUtil;
/** - * Monitoring of HTTP Servers + * Monitoring of IP addresses * * @author Greg Hinkle */ public class PingNetServiceComponent implements ResourceComponent, MeasurementFacet {
- public static final String CONFIG_ADDRESS = "address"; + public static final class ConfigKeys {
+ private ConfigKeys() { + // Defensive + } + + public static final String ADDRESS = "address"; + }
- private ResourceContext resourceContext; + private static final Log LOG = LogFactory.getLog(PingNetServiceComponent.class);
- public void start(ResourceContext resourceContext) throws InvalidPluginConfigurationException, Exception { - this.resourceContext = resourceContext; - String addressString = resourceContext.getPluginConfiguration().getSimple(CONFIG_ADDRESS).getStringValue(); + private static final int PING_TIMEOUT = 5000; + + private InetAddress address; + + @Override + public void start(@SuppressWarnings("rawtypes") + ResourceContext resourceContext) throws InvalidPluginConfigurationException, Exception { + address = createComponentConfiguration(resourceContext.getPluginConfiguration()); + } + + static InetAddress createComponentConfiguration(Configuration pluginConfig) + throws InvalidPluginConfigurationException { + String addressString = pluginConfig.getSimpleValue(ConfigKeys.ADDRESS, StringUtil.EMPTY_STRING); + if (StringUtil.isBlank(addressString)) { + throw new InvalidPluginConfigurationException("Address is not defined"); + } try { - InetAddress address = InetAddress.getByName(addressString); + return InetAddress.getByName(addressString); } catch (UnknownHostException uhe) { throw new InvalidPluginConfigurationException(uhe); } }
+ @Override public void stop() { + address = null; }
+ @Override public AvailabilityType getAvailability() { try { - String addressString = resourceContext.getPluginConfiguration().getSimple(CONFIG_ADDRESS).getStringValue(); - InetAddress address = InetAddress.getByName(addressString); - return address.isReachable(5000) ? AvailabilityType.UP : AvailabilityType.DOWN; + return address.isReachable(PING_TIMEOUT) ? AvailabilityType.UP : AvailabilityType.DOWN; } catch (Exception e) { + if (LOG.isWarnEnabled()) { + LOG.warn(address.getHostAddress() + " not reachable", e); + } return AvailabilityType.DOWN; } }
- + @Override public void getValues(MeasurementReport report, Set<MeasurementScheduleRequest> metrics) throws Exception { - String addressString = resourceContext.getPluginConfiguration().getSimple(CONFIG_ADDRESS).getStringValue(); - InetAddress address = InetAddress.getByName(addressString); - - for (MeasurementScheduleRequest request :metrics) { + for (MeasurementScheduleRequest request : metrics) { if (request.getName().equals("ipAddress")) { report.addData(new MeasurementDataTrait(request, address.getHostAddress())); } else if (request.getName().equals("hostName")) { report.addData(new MeasurementDataTrait(request, address.getCanonicalHostName())); } else if (request.getName().equals("responseTime")) { long start = System.currentTimeMillis(); - address.isReachable(5000); + address.isReachable(PING_TIMEOUT); report.addData(new MeasurementDataNumeric(request, (double) (System.currentTimeMillis() - start))); } } diff --git a/modules/plugins/netservices/src/main/java/org/rhq/plugins/netservices/PingNetServiceDiscoveryComponent.java b/modules/plugins/netservices/src/main/java/org/rhq/plugins/netservices/PingNetServiceDiscoveryComponent.java index 3f41a7e..da87c1b 100644 --- a/modules/plugins/netservices/src/main/java/org/rhq/plugins/netservices/PingNetServiceDiscoveryComponent.java +++ b/modules/plugins/netservices/src/main/java/org/rhq/plugins/netservices/PingNetServiceDiscoveryComponent.java @@ -1,6 +1,6 @@ /* * RHQ Management Platform - * Copyright (C) 2005-2008 Red Hat, Inc. + * Copyright (C) 2005-2013 Red Hat, Inc. * All rights reserved. * * This program is free software; you can redistribute it and/or modify @@ -19,40 +19,37 @@
package org.rhq.plugins.netservices;
-import org.rhq.core.pluginapi.inventory.ResourceDiscoveryComponent; -import org.rhq.core.pluginapi.inventory.ResourceDiscoveryContext; -import org.rhq.core.pluginapi.inventory.InvalidPluginConfigurationException; +import java.net.InetAddress; +import java.util.Collections; +import java.util.Set; + +import org.rhq.core.domain.configuration.Configuration; import org.rhq.core.pluginapi.inventory.DiscoveredResourceDetails; +import org.rhq.core.pluginapi.inventory.InvalidPluginConfigurationException; import org.rhq.core.pluginapi.inventory.ManualAddFacet; -import org.rhq.core.domain.configuration.Configuration; - -import java.util.Set; -import java.util.Collections; +import org.rhq.core.pluginapi.inventory.ResourceDiscoveryComponent; +import org.rhq.core.pluginapi.inventory.ResourceDiscoveryContext;
/** * @author Greg Hinkle */ public class PingNetServiceDiscoveryComponent implements ResourceDiscoveryComponent, ManualAddFacet { + + private static final String RESOURCE_NAME_PREFIX = "Ping "; + + @Override public Set discoverResources(ResourceDiscoveryContext resourceDiscoveryContext) - throws InvalidPluginConfigurationException, Exception { + throws InvalidPluginConfigurationException, Exception { // We don't support auto-discovery. return Collections.emptySet(); }
+ @Override public DiscoveredResourceDetails discoverResource(Configuration config, - ResourceDiscoveryContext resourceDiscoveryContext) - throws InvalidPluginConfigurationException { - String address = config.getSimple(PingNetServiceComponent.CONFIG_ADDRESS).getStringValue(); - // TODO: Validate the address is a valid host name or IP address. - DiscoveredResourceDetails details = - new DiscoveredResourceDetails( - resourceDiscoveryContext.getResourceType(), - address, - "Ping " + address, - null, - null, - config, - null); + ResourceDiscoveryContext resourceDiscoveryContext) throws InvalidPluginConfigurationException { + InetAddress address = PingNetServiceComponent.createComponentConfiguration(config); + DiscoveredResourceDetails details = new DiscoveredResourceDetails(resourceDiscoveryContext.getResourceType(), + address.getHostAddress(), RESOURCE_NAME_PREFIX + address.getHostAddress(), null, null, config, null); return details; } } \ No newline at end of file diff --git a/modules/plugins/netservices/src/main/resources/META-INF/rhq-plugin.xml b/modules/plugins/netservices/src/main/resources/META-INF/rhq-plugin.xml index b6b0cd3..16a48d5 100644 --- a/modules/plugins/netservices/src/main/resources/META-INF/rhq-plugin.xml +++ b/modules/plugins/netservices/src/main/resources/META-INF/rhq-plugin.xml @@ -11,30 +11,29 @@ <service name="HTTPService" discovery="HTTPNetServiceDiscoveryComponent" class="HTTPNetServiceComponent" - supportsManualAdd="true"> + supportsManualAdd="true" + description="HTTP Endpoint monitoring service">
<plugin-configuration> - <c:simple-property name="url"/> - <c:simple-property name="user" required="false"/> - <c:simple-property name="password" required="false"/> - <c:simple-property name="realm" required="false"/> - <c:simple-property name="validateResponseCode" type="boolean" default="false" - description="Codes in the 200-299 range are considered success"/> - <c:simple-property name="sslProtocol" default="none"> - <c:property-options> - <c:option value="none"/> - <c:option value="SSL"/> - <c:option value="TLS"/> - </c:property-options> - </c:simple-property> + <c:simple-property name="url" description="Http URL of the endpoint" /> + <c:simple-property name="user" required="false" + description="User name if http endpoint requires authentication." /> + <c:simple-property name="password" required="false" + description="Password if http endpoint requires authentication." /> + <c:simple-property name="realm" required="false" + description="Authentication Realm. By default user name and password will be used with any realm." /> <c:simple-property name="method" default="GET"> <c:property-options> <c:option value="HEAD"/> <c:option value="GET"/> </c:property-options> </c:simple-property> - <c:simple-property name="followRedirects" type="boolean" default="false"/> - <c:simple-property name="responsePattern" required="false"/> + <c:simple-property name="followRedirects" type="boolean" default="false" + description="Follow http redirects when contacting endpoints?" /> + <c:simple-property name="validateResponseCode" type="boolean" default="false" + description="Set this to true if response code should determine availability. Codes in the 200-299 range are considered success." /> + <c:simple-property name="validateResponsePattern" required="false" + description="If not empty, availability will depend on http response having content matching this (Java style) regular expression."/> </plugin-configuration>
<metric property="connectTime" units="milliseconds" displayType="summary" @@ -46,17 +45,17 @@ <metric property="contentAge" units="milliseconds" description="The declared age of the requested page"/>
- </service>
<service name="PingService" discovery="PingNetServiceDiscoveryComponent" class="PingNetServiceComponent" - supportsManualAdd="true"> + supportsManualAdd="true" + description="IP address ping service">
<plugin-configuration> - <c:simple-property name="address"/> + <c:simple-property name="address" description="IP address"/> </plugin-configuration>
<metric property="ipAddress" displayType="summary" dataType="trait" description="The ip address of the host"/> diff --git a/modules/plugins/netservices/src/test/java/org/rhq/plugins/netservices/HTTPNetServiceDiscoveryComponentTest.java b/modules/plugins/netservices/src/test/java/org/rhq/plugins/netservices/HTTPNetServiceDiscoveryComponentTest.java new file mode 100644 index 0000000..0745a34 --- /dev/null +++ b/modules/plugins/netservices/src/test/java/org/rhq/plugins/netservices/HTTPNetServiceDiscoveryComponentTest.java @@ -0,0 +1,178 @@ +/* + * RHQ Management Platform + * Copyright 2013, Red Hat Middleware LLC, and individual contributors + * as indicated by the @author tags. See the copyright.txt file in the + * distribution for a full listing of individual contributors. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation version 2 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +package org.rhq.plugins.netservices; + +import static org.mockito.Mockito.when; +import static org.testng.Assert.assertEquals; +import static org.testng.Assert.fail; + +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; +import org.testng.annotations.BeforeMethod; +import org.testng.annotations.Test; + +import org.rhq.core.domain.configuration.Configuration; +import org.rhq.core.domain.resource.ResourceType; +import org.rhq.core.pluginapi.inventory.DiscoveredResourceDetails; +import org.rhq.core.pluginapi.inventory.InvalidPluginConfigurationException; +import org.rhq.core.pluginapi.inventory.ResourceDiscoveryContext; +import org.rhq.plugins.netservices.HTTPNetServiceComponent.ConfigKeys; +import org.rhq.plugins.netservices.HTTPNetServiceComponent.HttpMethod; + +/** + * @author Thomas Segismont + */ +public class HTTPNetServiceDiscoveryComponentTest { + + private HTTPNetServiceDiscoveryComponent httpNetServiceDiscoveryComponent; + + private Configuration configuration; + + @Mock + private ResourceDiscoveryContext<?> resourceDiscoveryContext; + + @Mock + private ResourceType resourceType; + + @BeforeMethod(alwaysRun = true) + protected void setUp() throws Exception { + httpNetServiceDiscoveryComponent = new HTTPNetServiceDiscoveryComponent(); + configuration = new Configuration(); + configuration.setSimpleValue(ConfigKeys.URL, "http://www.myhost.com/pipo/molo"); + configuration.setSimpleValue(ConfigKeys.METHOD, HttpMethod.GET.name()); + configuration.setSimpleValue(ConfigKeys.VALIDATE_RESPONSE_PATTERN, "(ok|success)"); + MockitoAnnotations.initMocks(this); + when(resourceDiscoveryContext.getResourceType()).thenReturn(resourceType); + } + + @Test + public void testDiscoverResources() throws Exception { + // Manual add only, should always return empty set + assertEquals(0, httpNetServiceDiscoveryComponent.discoverResources(null).size()); + } + + @Test + public void testValidComponentConfiguration() { + try { + DiscoveredResourceDetails resourceDetails = httpNetServiceDiscoveryComponent.discoverResource( + configuration, resourceDiscoveryContext); + assertEquals(resourceDetails.getResourceType(), resourceType); + } catch (InvalidPluginConfigurationException e) { + fail("Component configuration should be valid", e); + } + } + + @Test + public void testMissingUrl() { + try { + configuration.remove(ConfigKeys.URL); + httpNetServiceDiscoveryComponent.discoverResource(configuration, resourceDiscoveryContext); + fail("Component configuration should be invalid"); + } catch (InvalidPluginConfigurationException e) { + assertEquals(e.getMessage(), "Endpoint URL is not defined"); + } + } + + @Test + public void testMalformedUrl() { + String configUrl = "pipomolo"; + try { + configuration.setSimpleValue(ConfigKeys.URL, configUrl); + httpNetServiceDiscoveryComponent.discoverResource(configuration, resourceDiscoveryContext); + fail("Component configuration should be invalid"); + } catch (InvalidPluginConfigurationException e) { + assertEquals(e.getMessage(), configUrl + " is not a valid URL"); + } + } + + @Test + public void testNotHttpOrHttpsUrl() { + String configUrl = "ftp://pipo.com/molo.zipo"; + try { + configuration.setSimpleValue(ConfigKeys.URL, configUrl); + httpNetServiceDiscoveryComponent.discoverResource(configuration, resourceDiscoveryContext); + fail("Component configuration should be invalid"); + } catch (InvalidPluginConfigurationException e) { + assertEquals(e.getMessage(), configUrl + "does not point to an http(s) resource"); + } + } + + @Test + public void testHttpsUrl() { + try { + configuration.setSimpleValue(ConfigKeys.URL, "https://www.myhost.com/pipo/molo"); + DiscoveredResourceDetails resourceDetails = httpNetServiceDiscoveryComponent.discoverResource( + configuration, resourceDiscoveryContext); + assertEquals(resourceDetails.getResourceType(), resourceType); + } catch (InvalidPluginConfigurationException e) { + fail("Component configuration should be valid", e); + } + } + + @Test + public void testInvalidHttpMethod() { + String configMethod = "DELETE"; + try { + configuration.setSimpleValue(ConfigKeys.METHOD, configMethod); + httpNetServiceDiscoveryComponent.discoverResource(configuration, resourceDiscoveryContext); + fail("Component configuration should be invalid"); + } catch (InvalidPluginConfigurationException e) { + assertEquals(e.getMessage(), "Invalid http method: " + configMethod); + } + } + + @Test + public void testHeadMethod() { + try { + configuration.setSimpleValue(ConfigKeys.METHOD, HttpMethod.HEAD.name()); + configuration.remove(ConfigKeys.VALIDATE_RESPONSE_PATTERN); + DiscoveredResourceDetails resourceDetails = httpNetServiceDiscoveryComponent.discoverResource( + configuration, resourceDiscoveryContext); + assertEquals(resourceDetails.getResourceType(), resourceType); + } catch (InvalidPluginConfigurationException e) { + fail("Component configuration should be valid", e); + } + } + + @Test + public void testUnableToValidateContentWithHeadRequest() { + try { + configuration.setSimpleValue(ConfigKeys.METHOD, HttpMethod.HEAD.name()); + httpNetServiceDiscoveryComponent.discoverResource(configuration, resourceDiscoveryContext); + fail("Component configuration should be invalid"); + } catch (InvalidPluginConfigurationException e) { + assertEquals(e.getMessage(), "Cannot validate response content with HEAD request"); + } + } + + @Test + public void testInvalidPatternSyntax() { + String configValidateResponsePattern = "(pipo"; + try { + configuration.setSimpleValue(ConfigKeys.VALIDATE_RESPONSE_PATTERN, configValidateResponsePattern); + httpNetServiceDiscoveryComponent.discoverResource(configuration, resourceDiscoveryContext); + fail("Component configuration should be invalid"); + } catch (InvalidPluginConfigurationException e) { + assertEquals(e.getMessage(), "Invalid pattern: " + configValidateResponsePattern); + } + } + +} diff --git a/modules/plugins/netservices/src/test/java/org/rhq/plugins/netservices/PingNetServiceDiscoveryComponentTest.java b/modules/plugins/netservices/src/test/java/org/rhq/plugins/netservices/PingNetServiceDiscoveryComponentTest.java new file mode 100644 index 0000000..961a81c --- /dev/null +++ b/modules/plugins/netservices/src/test/java/org/rhq/plugins/netservices/PingNetServiceDiscoveryComponentTest.java @@ -0,0 +1,105 @@ +/* + * RHQ Management Platform + * Copyright 2013, Red Hat Middleware LLC, and individual contributors + * as indicated by the @author tags. See the copyright.txt file in the + * distribution for a full listing of individual contributors. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation version 2 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +package org.rhq.plugins.netservices; + +import static org.mockito.Mockito.when; +import static org.testng.Assert.assertEquals; +import static org.testng.Assert.fail; + +import java.net.UnknownHostException; + +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; +import org.testng.annotations.BeforeMethod; +import org.testng.annotations.Test; + +import org.rhq.core.domain.configuration.Configuration; +import org.rhq.core.domain.resource.ResourceType; +import org.rhq.core.pluginapi.inventory.DiscoveredResourceDetails; +import org.rhq.core.pluginapi.inventory.InvalidPluginConfigurationException; +import org.rhq.core.pluginapi.inventory.ResourceDiscoveryContext; +import org.rhq.plugins.netservices.PingNetServiceComponent.ConfigKeys; + +/** + * @author Thomas Segismont + */ +public class PingNetServiceDiscoveryComponentTest { + + private PingNetServiceDiscoveryComponent pingNetServiceDiscoveryComponent; + + private Configuration configuration; + + @Mock + private ResourceDiscoveryContext<?> resourceDiscoveryContext; + + @Mock + private ResourceType resourceType; + + @BeforeMethod(alwaysRun = true) + protected void setUp() throws Exception { + pingNetServiceDiscoveryComponent = new PingNetServiceDiscoveryComponent(); + configuration = new Configuration(); + configuration.setSimpleValue(ConfigKeys.ADDRESS, "127.0.0.1"); + MockitoAnnotations.initMocks(this); + when(resourceDiscoveryContext.getResourceType()).thenReturn(resourceType); + } + + @Test + public void testDiscoverResources() throws Exception { + // Manual add only, should always return empty set + assertEquals(0, pingNetServiceDiscoveryComponent.discoverResources(null).size()); + } + + @Test + public void testValidComponentConfiguration() { + try { + DiscoveredResourceDetails resourceDetails = pingNetServiceDiscoveryComponent.discoverResource( + configuration, resourceDiscoveryContext); + assertEquals(resourceDetails.getResourceType(), resourceType); + } catch (InvalidPluginConfigurationException e) { + fail("Component configuration should be valid", e); + } + } + + @Test + public void testMissingAddress() { + try { + configuration.remove(ConfigKeys.ADDRESS); + pingNetServiceDiscoveryComponent.discoverResource(configuration, resourceDiscoveryContext); + fail("Component configuration should be invalid"); + } catch (InvalidPluginConfigurationException e) { + assertEquals(e.getMessage(), "Address is not defined"); + } + } + + @Test + public void testMalformedAddress() { + String configAddress = "pipomolo"; + try { + configuration.setSimpleValue(ConfigKeys.ADDRESS, configAddress); + pingNetServiceDiscoveryComponent.discoverResource(configuration, resourceDiscoveryContext); + fail("Component configuration should be invalid"); + } catch (InvalidPluginConfigurationException e) { + assertEquals(e.getCause().getClass(), UnknownHostException.class); + } + } + +} diff --git a/modules/plugins/netservices/src/test/java/org/rhq/plugins/netservices/itest/HTTPNetServiceComponentTest.java b/modules/plugins/netservices/src/test/java/org/rhq/plugins/netservices/itest/HTTPNetServiceComponentTest.java new file mode 100644 index 0000000..24b6644 --- /dev/null +++ b/modules/plugins/netservices/src/test/java/org/rhq/plugins/netservices/itest/HTTPNetServiceComponentTest.java @@ -0,0 +1,162 @@ +/* + * RHQ Management Platform + * Copyright 2013, Red Hat Middleware LLC, and individual contributors + * as indicated by the @author tags. See the copyright.txt file in the + * distribution for a full listing of individual contributors. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation version 2 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +package org.rhq.plugins.netservices.itest; + +import static org.testng.Assert.assertEquals; +import static org.testng.Assert.assertNotNull; +import static org.testng.Assert.assertTrue; + +import java.io.IOException; +import java.net.InetSocketAddress; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Map; +import java.util.Set; + +import javax.servlet.ServletException; +import javax.servlet.http.HttpServlet; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.eclipse.jetty.server.Server; +import org.eclipse.jetty.servlet.ServletContextHandler; +import org.eclipse.jetty.servlet.ServletHolder; +import org.testng.annotations.AfterClass; +import org.testng.annotations.BeforeClass; +import org.testng.annotations.Test; + +import org.rhq.core.domain.configuration.Configuration; +import org.rhq.core.domain.discovery.MergeResourceResponse; +import org.rhq.core.domain.measurement.AvailabilityType; +import org.rhq.core.domain.measurement.DataType; +import org.rhq.core.domain.measurement.MeasurementData; +import org.rhq.core.domain.measurement.MeasurementReport; +import org.rhq.core.domain.measurement.MeasurementScheduleRequest; +import org.rhq.core.pluginapi.inventory.ResourceComponent; +import org.rhq.plugins.netservices.HTTPNetServiceComponent; +import org.rhq.plugins.netservices.HTTPNetServiceComponent.ConfigKeys; +import org.rhq.plugins.netservices.HTTPNetServiceComponent.HttpMethod; + +/** + * @author Thomas Segismont + */ +public class HTTPNetServiceComponentTest extends NetServiceComponentTest { + + private static final Log LOG = LogFactory.getLog(NetServiceComponentTest.class); + + private static final String SERVICE_NAME = "HTTPService"; + + private static final String HTTP_HOST = "localhost"; + + private static final int HTTP_PORT = 31158; + + private static final int SERVLET_SLEEP = 1000; + + private Server jettyServer; + + private HTTPNetServiceComponent httpNetServiceComponent; + + @BeforeClass + public void startJetty() throws Exception { + LOG.info("Setting up Jetty test server"); + jettyServer = new Server(new InetSocketAddress(HTTP_HOST, HTTP_PORT)); + ServletContextHandler context = new ServletContextHandler(ServletContextHandler.SESSIONS); + context.setContextPath("/"); + jettyServer.setHandler(context); + @SuppressWarnings("serial") + HttpServlet testServlet = new HttpServlet() { + @Override + protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { + resp.getWriter().println("Test servlet request: success view"); + long start = System.currentTimeMillis(); + do { + try { + Thread.sleep(SERVLET_SLEEP); + } catch (InterruptedException e) { + } + } while (System.currentTimeMillis() - start < SERVLET_SLEEP); + } + }; + context.addServlet(new ServletHolder(testServlet), "/*"); + jettyServer.start(); + } + + @AfterClass + public void stopJetty() { + LOG.info("Shutting down Jetty test server"); + try { + if (jettyServer != null) { + jettyServer.stop(); + } + } catch (Exception ignore) { + } + } + + @Test(dependsOnMethods = "testPluginLoad") + public void testManualAdd() throws Exception { + Configuration configuration = new Configuration(); + configuration.setSimpleValue(ConfigKeys.URL, "http://" + HTTP_HOST + ":" + HTTP_PORT + "/pipo/molo"); + configuration.setSimpleValue(ConfigKeys.METHOD, HttpMethod.GET.name()); + configuration.setSimpleValue(ConfigKeys.VALIDATE_RESPONSE_CODE, "true"); + configuration.setSimpleValue(ConfigKeys.VALIDATE_RESPONSE_PATTERN, "success"); + MergeResourceResponse response = getInventoryManager().manuallyAddResource( + getPluginManager().getMetadataManager().getType(SERVICE_NAME, PLUGIN_NAME), getPlatform().getId(), + configuration, -1); + assertNotNull(response, "Manual add response is null"); + @SuppressWarnings("rawtypes") + ResourceComponent resourceComponent = getInventoryManager().getResourceContainer(response.getResourceId()) + .getResourceComponent(); + assertEquals(resourceComponent.getClass(), HTTPNetServiceComponent.class); + httpNetServiceComponent = (HTTPNetServiceComponent) resourceComponent; + } + + @Test(dependsOnMethods = "testManualAdd") + public void testAvailability() throws Exception { + assertEquals(httpNetServiceComponent.getAvailability(), AvailabilityType.UP); + } + + @Test(dependsOnMethods = "testAvailability") + public void testMeasurement() throws Exception { + MeasurementReport report = new MeasurementReport(); + Set<MeasurementScheduleRequest> metrics = new HashSet<MeasurementScheduleRequest>(); + int scheduleId = 1; + metrics.add(new MeasurementScheduleRequest(scheduleId++, "connectTime", 1000, true, DataType.MEASUREMENT)); + metrics.add(new MeasurementScheduleRequest(scheduleId++, "readTime", 1000, true, DataType.MEASUREMENT)); + metrics.add(new MeasurementScheduleRequest(scheduleId++, "contentLength", 1000, true, DataType.MEASUREMENT)); + metrics.add(new MeasurementScheduleRequest(scheduleId++, "contentAge", 1000, true, DataType.MEASUREMENT)); + httpNetServiceComponent.getValues(report, metrics); + Map<String, Object> datas = new HashMap<String, Object>(); + for (MeasurementData data : report.getNumericData()) { + datas.put(data.getName(), data.getValue()); + } + Double value = getMetric(datas, "connectTime"); + assertTrue(value > SERVLET_SLEEP); + value = getMetric(datas, "readTime"); + assertTrue(value > SERVLET_SLEEP); + value = getMetric(datas, "contentLength"); + assertTrue(value > 0); + value = getMetric(datas, "contentAge"); + assertTrue(value > 0); + } + +} diff --git a/modules/plugins/netservices/src/test/java/org/rhq/plugins/netservices/itest/NetServiceComponentTest.java b/modules/plugins/netservices/src/test/java/org/rhq/plugins/netservices/itest/NetServiceComponentTest.java new file mode 100644 index 0000000..503e359 --- /dev/null +++ b/modules/plugins/netservices/src/test/java/org/rhq/plugins/netservices/itest/NetServiceComponentTest.java @@ -0,0 +1,154 @@ +/* + * RHQ Management Platform + * Copyright 2013, Red Hat Middleware LLC, and individual contributors + * as indicated by the @author tags. See the copyright.txt file in the + * distribution for a full listing of individual contributors. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation version 2 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +package org.rhq.plugins.netservices.itest; + +import static org.mockito.Matchers.any; +import static org.mockito.Matchers.anyInt; +import static org.mockito.Mockito.when; +import static org.testng.Assert.assertEquals; +import static org.testng.Assert.assertNotNull; +import static org.testng.Assert.assertTrue; + +import java.io.File; +import java.util.Map; +import java.util.concurrent.atomic.AtomicInteger; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.mockito.Mockito; +import org.mockito.invocation.InvocationOnMock; +import org.mockito.stubbing.Answer; +import org.testng.annotations.AfterSuite; +import org.testng.annotations.BeforeSuite; +import org.testng.annotations.Test; + +import org.rhq.core.clientapi.server.discovery.DiscoveryServerService; +import org.rhq.core.domain.discovery.MergeResourceResponse; +import org.rhq.core.domain.resource.Resource; +import org.rhq.core.pc.PluginContainer; +import org.rhq.core.pc.PluginContainerConfiguration; +import org.rhq.core.pc.ServerServices; +import org.rhq.core.pc.inventory.InventoryManager; +import org.rhq.core.pc.plugin.FileSystemPluginFinder; +import org.rhq.core.pc.plugin.PluginEnvironment; +import org.rhq.core.pc.plugin.PluginManager; + +/** + * @author Thomas Segismont + */ +public abstract class NetServiceComponentTest { + + public static final String PLUGIN_NAME = "NetworkServices"; + + private static final Log LOG = LogFactory.getLog(NetServiceComponentTest.class); + + private static final AtomicInteger resourceIdGenerator = new AtomicInteger(Integer.MIN_VALUE / 2); + + private static PluginContainer pluginContainer; + + private static InventoryManager inventoryManager; + + private static Resource platform; + + private static PluginManager pluginManager; + + private static PluginEnvironment pluginEnvironment; + + protected PluginContainer getPluginContainer() { + return pluginContainer; + } + + protected InventoryManager getInventoryManager() { + return inventoryManager; + } + + protected Resource getPlatform() { + return platform; + } + + protected PluginManager getPluginManager() { + return pluginManager; + } + + protected PluginEnvironment getPluginEnvironment() { + return pluginEnvironment; + } + + @BeforeSuite + public static void startPluginContainer() throws Exception { + LOG.info("Setting up plugin container"); + File pluginDir = new File("target/itest/plugins"); + PluginContainerConfiguration containerConfig = new PluginContainerConfiguration(); + containerConfig.setPluginFinder(new FileSystemPluginFinder(pluginDir)); + containerConfig.setPluginDirectory(pluginDir); + containerConfig.setInsideAgent(false); + // netservices plugin has resources which can only be manually added so we have to mock server integration. + DiscoveryServerService discoveryServerService = Mockito.mock(DiscoveryServerService.class); + when(discoveryServerService.addResource(any(Resource.class), anyInt())).thenAnswer( + new Answer<MergeResourceResponse>() { + + @Override + public MergeResourceResponse answer(InvocationOnMock invocation) throws Throwable { + return new MergeResourceResponse(resourceIdGenerator.decrementAndGet(), false); + } + }); + ServerServices serverServices = new ServerServices(); + serverServices.setDiscoveryServerService(discoveryServerService); + containerConfig.setServerServices(serverServices); + pluginContainer = PluginContainer.getInstance(); + pluginContainer.setConfiguration(containerConfig); + pluginContainer.initialize(); + inventoryManager = pluginContainer.getInventoryManager(); + platform = inventoryManager.getPlatform(); + pluginManager = pluginContainer.getPluginManager(); + pluginEnvironment = pluginManager.getPlugin(PLUGIN_NAME); + } + + @AfterSuite + public static void stopPluginContainer() { + LOG.info("Shutting down plugin container"); + try { + if (pluginContainer != null) { + pluginContainer.shutdown(); + } + } catch (Exception ignore) { + } + } + + @Test + public static void testPluginLoad() { + assertNotNull(pluginEnvironment, "Plugin not loaded"); + assertEquals(pluginEnvironment.getPluginName(), PLUGIN_NAME); + } + + public static Double getMetric(Map<String, Object> datas, String metricName) { + assertTrue(datas.containsKey(metricName), metricName + " metric not found"); + assertTrue(datas.get(metricName).getClass().equals(Double.class), metricName + " metric value is not a Double"); + return (Double) datas.get(metricName); + } + + public static String getTrait(Map<String, Object> datas, String traitName) { + assertTrue(datas.containsKey(traitName), traitName + " trait not found"); + assertTrue(datas.get(traitName).getClass().equals(String.class), traitName + " traitName value is not a String"); + return (String) datas.get(traitName); + } + +} diff --git a/modules/plugins/netservices/src/test/java/org/rhq/plugins/netservices/itest/PingNetServiceComponentTest.java b/modules/plugins/netservices/src/test/java/org/rhq/plugins/netservices/itest/PingNetServiceComponentTest.java new file mode 100644 index 0000000..ea1a374 --- /dev/null +++ b/modules/plugins/netservices/src/test/java/org/rhq/plugins/netservices/itest/PingNetServiceComponentTest.java @@ -0,0 +1,98 @@ +/* + * RHQ Management Platform + * Copyright 2013, Red Hat Middleware LLC, and individual contributors + * as indicated by the @author tags. See the copyright.txt file in the + * distribution for a full listing of individual contributors. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation version 2 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +package org.rhq.plugins.netservices.itest; + +import static org.testng.Assert.assertEquals; +import static org.testng.Assert.assertNotNull; +import static org.testng.Assert.assertTrue; + +import java.util.HashMap; +import java.util.HashSet; +import java.util.Map; +import java.util.Set; + +import org.testng.annotations.Test; + +import org.rhq.core.domain.configuration.Configuration; +import org.rhq.core.domain.discovery.MergeResourceResponse; +import org.rhq.core.domain.measurement.AvailabilityType; +import org.rhq.core.domain.measurement.DataType; +import org.rhq.core.domain.measurement.MeasurementData; +import org.rhq.core.domain.measurement.MeasurementReport; +import org.rhq.core.domain.measurement.MeasurementScheduleRequest; +import org.rhq.core.pluginapi.inventory.ResourceComponent; +import org.rhq.core.util.StringUtil; +import org.rhq.plugins.netservices.PingNetServiceComponent; +import org.rhq.plugins.netservices.PingNetServiceComponent.ConfigKeys; + +/** + * @author Thomas Segismont + */ +public class PingNetServiceComponentTest extends NetServiceComponentTest { + + private static final String SERVICE_NAME = "PingService"; + + private static final String LOOPBACK = "127.0.0.1"; + + private PingNetServiceComponent pingNetServiceComponent; + + @Test(dependsOnMethods = "testPluginLoad") + public void testManualAdd() throws Exception { + Configuration configuration = new Configuration(); + configuration.setSimpleValue(ConfigKeys.ADDRESS, LOOPBACK); + MergeResourceResponse response = getInventoryManager().manuallyAddResource( + getPluginManager().getMetadataManager().getType(SERVICE_NAME, PLUGIN_NAME), getPlatform().getId(), + configuration, -1); + assertNotNull(response, "Manual add response is null"); + @SuppressWarnings("rawtypes") + ResourceComponent resourceComponent = getInventoryManager().getResourceContainer(response.getResourceId()) + .getResourceComponent(); + assertEquals(resourceComponent.getClass(), PingNetServiceComponent.class); + pingNetServiceComponent = (PingNetServiceComponent) resourceComponent; + } + + @Test(dependsOnMethods = "testManualAdd") + public void testAvailability() throws Exception { + assertEquals(pingNetServiceComponent.getAvailability(), AvailabilityType.UP); + } + + @Test(dependsOnMethods = "testAvailability") + public void testMeasurement() throws Exception { + MeasurementReport report = new MeasurementReport(); + Set<MeasurementScheduleRequest> metrics = new HashSet<MeasurementScheduleRequest>(); + int scheduleId = 1; + metrics.add(new MeasurementScheduleRequest(scheduleId++, "ipAddress", 1000, true, DataType.TRAIT)); + metrics.add(new MeasurementScheduleRequest(scheduleId++, "hostName", 1000, true, DataType.TRAIT)); + metrics.add(new MeasurementScheduleRequest(scheduleId++, "responseTime", 1000, true, DataType.MEASUREMENT)); + pingNetServiceComponent.getValues(report, metrics); + Map<String, Object> datas = new HashMap<String, Object>(); + for (MeasurementData data : report.getNumericData()) { + datas.put(data.getName(), data.getValue()); + } + for (MeasurementData data : report.getTraitData()) { + datas.put(data.getName(), data.getValue()); + } + assertEquals(getTrait(datas, "ipAddress"), LOOPBACK); + assertTrue(StringUtil.isNotBlank(getTrait(datas, "hostName"))); + assertTrue(getMetric(datas, "responseTime") >= 0); + } + +} diff --git a/modules/plugins/netservices/src/test/resources/log4j.xml b/modules/plugins/netservices/src/test/resources/log4j.xml new file mode 100644 index 0000000..4815936 --- /dev/null +++ b/modules/plugins/netservices/src/test/resources/log4j.xml @@ -0,0 +1,32 @@ +<?xml version="1.0" encoding="UTF-8"?> + +<!DOCTYPE log4j:configuration SYSTEM "log4j.dtd"> + +<!-- | For more configuration information and examples, see the Jakarta Log4j | website: http://jakarta.apache.org/log4j --> + +<log4j:configuration xmlns:log4j="http://jakarta.apache.org/log4j/%22%3E + + <appender name="CONSOLE" class="org.apache.log4j.ConsoleAppender"> + <param name="Target" value="System.out" /> + <param name="Threshold" value="INFO" /> + <layout class="org.apache.log4j.PatternLayout"> + <param name="ConversionPattern" value="%-5p %d{dd-MM HH:mm:ss,SSS} (%F:%M:%L) - %m%n" /> + </layout> + </appender> + + <appender name="FILE" class="org.apache.log4j.RollingFileAppender"> + <param name="File" value="target/test.log" /> + <param name="Append" value="false" /> + <param name="Threshold" value="DEBUG" /> + <layout class="org.apache.log4j.PatternLayout"> + <param name="ConversionPattern" value="%-5p %d{dd-MM HH:mm:ss,SSS} (%F:%M:%L) - %m%n" /> + </layout> + </appender> + + <root> + <level value="DEBUG" /> + <appender-ref ref="CONSOLE" /> + <appender-ref ref="FILE" /> + </root> + +</log4j:configuration>
commit b3b316f4b6761183fa75738008a94acc3bad918a Author: Heiko W. Rupp hwr@redhat.com Date: Thu Feb 21 15:16:37 2013 +0100
Add getAlerts4Definition, extend testing
diff --git a/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/rest/AlertHandlerBean.java b/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/rest/AlertHandlerBean.java index ce208a3..ce1ad76 100644 --- a/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/rest/AlertHandlerBean.java +++ b/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/rest/AlertHandlerBean.java @@ -45,6 +45,8 @@ import javax.ws.rs.core.UriBuilder; import javax.ws.rs.core.UriInfo;
import com.wordnik.swagger.annotations.Api; +import com.wordnik.swagger.annotations.ApiError; +import com.wordnik.swagger.annotations.ApiErrors; import com.wordnik.swagger.annotations.ApiOperation; import com.wordnik.swagger.annotations.ApiParam;
@@ -86,18 +88,40 @@ public class AlertHandlerBean extends AbstractRestBean { @GZIP @GET @Path("/") - @ApiOperation(value = "List all alerts", multiValueResponse = true, responseClass = "List<AlertRest>") + @ApiOperation(value = "List all alerts, possibly limiting by resource or alert definition, priority and start time", multiValueResponse = true, responseClass = "List<AlertRest>") + @ApiErrors({ + @ApiError(code = 406, reason = "There are 'resourceId' and 'definitionId' passed as query parameters"), + @ApiError(code = 406, reason = "Page size was 0"), + @ApiError(code = 406, reason = "Page number was < 1") + }) public Response listAlerts( - @ApiParam(value = "Page number", defaultValue = "1") @QueryParam("page") int page, + @ApiParam(value = "Page number") @QueryParam("page") @DefaultValue("1") int page, + @ApiParam(value = "Page size; use -1 for 'unlimited'") @QueryParam("size") @DefaultValue("100")int size, @ApiParam(value = "Limit to priority", allowableValues = "High, Medium, Low, All") @DefaultValue("All") @QueryParam("prio") String prio, @ApiParam(value = "Should full resources and definitions be sent") @QueryParam("slim") @DefaultValue("false") boolean slim, - @ApiParam( value = "If non-null only send alerts that have fired after this time, time is millisecond since epoch") @QueryParam("since") Long since, + @ApiParam(value = "If non-null only send alerts that have fired after this time, time is millisecond since epoch") @QueryParam("since") Long since, @ApiParam(value = "Id of a resource to limit search for") @QueryParam("resourceId") Integer resourceId, + @ApiParam(value = "If of an alert definition to search for") @QueryParam("definitionId") Integer definitionId, @Context UriInfo uriInfo, @Context HttpHeaders headers) {
+ if (resourceId!=null && definitionId!=null) { + throw new BadArgumentException("At most one of 'resourceId' and 'definitionId' may be given"); + } + if (size==0) + throw new BadArgumentException("size","Must not be 0"); + if (page<1) + throw new BadArgumentException("page","Must be >=1");
AlertCriteria criteria = new AlertCriteria(); - criteria.setPaging(page,20); // TODO implement linking to next page + + if (size==-1) { + PageControl pageControl = PageControl.getUnlimitedInstance(); + pageControl.setPageNumber(page); + criteria.setPageControl(pageControl); + } + else + criteria.setPaging(page-1, size); // TODO implement linking to next page + if (since!=null) { criteria.addFilterStartTime(since); } @@ -105,6 +129,9 @@ public class AlertHandlerBean extends AbstractRestBean { if (resourceId!=null) { criteria.addFilterResourceIds(resourceId); } + if (definitionId!=null) { + criteria.addFilterAlertDefinitionIds(definitionId); + }
if (!prio.equals("All")) { AlertPriority alertPriority = AlertPriority.valueOf(prio.toUpperCase()); diff --git a/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/rest/BadArgumentException.java b/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/rest/BadArgumentException.java index c07b4ce..cea84c2 100644 --- a/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/rest/BadArgumentException.java +++ b/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/rest/BadArgumentException.java @@ -32,7 +32,7 @@ public class BadArgumentException extends RuntimeException { private static final long serialVersionUID = 1L;
public BadArgumentException(String message) { - super("Bad parameter given: " + message); + super("Bad parameter(s) given: " + message); }
/** @@ -43,4 +43,5 @@ public class BadArgumentException extends RuntimeException { public BadArgumentException(String parameterName, String cause) { super("Parameter " + parameterName + " is bad: " + cause); } + } diff --git a/modules/integration-tests/rest-api/src/test/java/org/rhq/modules/integrationTests/restApi/AlertTest.java b/modules/integration-tests/rest-api/src/test/java/org/rhq/modules/integrationTests/restApi/AlertTest.java index 7e9fa70..aa56a46 100644 --- a/modules/integration-tests/rest-api/src/test/java/org/rhq/modules/integrationTests/restApi/AlertTest.java +++ b/modules/integration-tests/rest-api/src/test/java/org/rhq/modules/integrationTests/restApi/AlertTest.java @@ -27,11 +27,13 @@ import org.junit.Test; import org.rhq.modules.integrationTests.restApi.d.AlertCondition; import org.rhq.modules.integrationTests.restApi.d.AlertDefinition; import org.rhq.modules.integrationTests.restApi.d.AlertNotification; +import org.rhq.modules.integrationTests.restApi.d.Availability; import org.rhq.modules.integrationTests.restApi.d.Group;
import static com.jayway.restassured.RestAssured.delete; import static com.jayway.restassured.RestAssured.expect; import static com.jayway.restassured.RestAssured.given; +import static org.hamcrest.Matchers.contains; import static org.hamcrest.Matchers.instanceOf; import static org.hamcrest.Matchers.is; import static org.hamcrest.Matchers.iterableWithSize; @@ -115,7 +117,43 @@ public class AlertTest extends AbstractBase { .get("/alert/count") .xmlPath();
- int count = xmlPath.getInt("value.@value"); + xmlPath.getInt("value.@value"); + } + + @Test + public void testGetAlertByBadId() throws Exception { + given() + .header(acceptJson) + .pathParam("id",123) + .expect() + .statusCode(404) + .log().ifError() + .when() + .get("/alert/{id}"); + } + + @Test + public void testGetAlertConditionLogsByBadId() throws Exception { + given() + .header(acceptJson) + .pathParam("id",123) + .expect() + .statusCode(404) + .log().ifError() + .when() + .get("/alert/{id}/conditions"); + } + + @Test + public void testGetAlertNotificationLogsByBadId() throws Exception { + given() + .header(acceptJson) + .pathParam("id",123) + .expect() + .statusCode(404) + .log().everything() + .when() + .get("/alert/{id}/notifications"); }
@Test @@ -200,7 +238,7 @@ public class AlertTest extends AbstractBase { @Test public void testCreateDeleteBasicAlertDefinition() throws Exception {
- int definitionId = createEmptyAlertDefinition(); + int definitionId = createEmptyAlertDefinition(false);
cleanupDefinition(definitionId); } @@ -333,7 +371,7 @@ public class AlertTest extends AbstractBase { @Test public void testCreateDeleteAlertDefinitionWith1Condition() throws Exception {
- int definitionId = createEmptyAlertDefinition(); + int definitionId = createEmptyAlertDefinition(false);
// Now add a condition try { @@ -376,7 +414,7 @@ public class AlertTest extends AbstractBase { @Test public void testCreateDeleteAlertDefinitionWith2Conditions() throws Exception {
- int definitionId = createEmptyAlertDefinition(); + int definitionId = createEmptyAlertDefinition(false);
try { @@ -446,7 +484,7 @@ public class AlertTest extends AbstractBase { @Test public void testCreateDeleteAlertDefinitionWith1Notification() throws Exception {
- int definitionId = createEmptyAlertDefinition(); + int definitionId = createEmptyAlertDefinition(false);
// Now add a condition try { @@ -491,7 +529,7 @@ public class AlertTest extends AbstractBase { @Test public void testCRUDNotification() throws Exception {
- int definitionId = createEmptyAlertDefinition(); + int definitionId = createEmptyAlertDefinition(false);
// Now add a condition try { @@ -563,7 +601,7 @@ public class AlertTest extends AbstractBase { @Test public void testCRUDCondition() throws Exception {
- int definitionId = createEmptyAlertDefinition(); + int definitionId = createEmptyAlertDefinition(false);
// Now add a condition try { @@ -723,7 +761,7 @@ public class AlertTest extends AbstractBase { @Test public void testCreateDeleteAlertDefinitionWithUnknwonSender() throws Exception {
- int definitionId = createEmptyAlertDefinition(); + int definitionId = createEmptyAlertDefinition(false);
// Now add a condition try { @@ -802,7 +840,7 @@ public class AlertTest extends AbstractBase { @Test public void testCreateDeleteAlertDefinitionWith2Notifications() throws Exception {
- int definitionId = createEmptyAlertDefinition(); + int definitionId = createEmptyAlertDefinition(false);
// Now add a condition try { @@ -1049,7 +1087,7 @@ public class AlertTest extends AbstractBase { @Test public void testUpdateDefinition() throws Exception {
- int definitionId = createEmptyAlertDefinition(); + int definitionId = createEmptyAlertDefinition(false); try { AlertDefinition definition = given() @@ -1177,6 +1215,245 @@ public class AlertTest extends AbstractBase { cleanupDefinition(result.getId()); }
+ @Test + public void testCreateDeleteAlertDefinitionWith1ConditionAndFire() throws Exception { + + int definitionId = createEmptyAlertDefinition(true); + + // Now add a condition + try { + + AlertCondition alertCondition = new AlertCondition("AVAIL_GOES_UP","AVAILABILITY"); + given() + .header(acceptJson) + .contentType(ContentType.JSON) + .body(alertCondition) + .pathParam("defId",definitionId) + .expect() + .statusCode(201) + .log().ifError() + .when() + .post("/alert/definition/{defId}/conditions"); + + System.out.println("Definition created, waiting 60s for it to become active"); + + // Wait a while - see https://bugzilla.redhat.com/show_bug.cgi?id=830299 + Thread.sleep(60*1000); + + // Send a avail down/up sequence -> alert definition should fire + long now = System.currentTimeMillis(); + Availability a = new Availability(10001,now-2000,"DOWN"); + given() + .contentType(ContentType.JSON) + .pathParam("id", 10001) + .body(a) + .expect() + .statusCode(204) + .log().ifError() + .when() + .put("/resource/{id}/availability"); + + a = new Availability(10001,now-1000,"UP"); + given() + .contentType(ContentType.JSON) + .pathParam("id", 10001) + .body(a) + .expect() + .statusCode(204) + .log().ifError() + .when() + .put("/resource/{id}/availability"); + + // wait a little + Thread.sleep(5000); + + int alertId = + given() + .header(acceptJson) + .queryParam("definitionId",definitionId) + .queryParam("since", now - 3000) + .expect() + .statusCode(200) + .log().ifError() + .body("alertDefinition.name",contains("-x-test-definition")) + .body("",iterableWithSize(1)) + .when() + .get("/alert") + .body().jsonPath().getInt("id[0]"); + + System.out.println(alertId); + + // Find this alert by id and then its condition logs and notification logs + given() + .header(acceptJson) + .pathParam("id",alertId) + .log().everything() + .expect() + .statusCode(200) + .log().ifError() + .body("id",is(alertId)) + .when() + .get("/alert/{id}"); + + + given() + .header(acceptJson) + .pathParam("id", alertId) + .log().everything() + .expect() + .statusCode(200) + .log().ifError() + .body("",iterableWithSize(1)) + .when() + .get("/alert/{id}/conditions"); + + given() + .header(acceptJson) + .pathParam("id", alertId) + .expect() + .statusCode(200) + .log().ifError() + .body("",iterableWithSize(0)) + .when() + .get("/alert/{id}/notifications"); + + + } + + finally { + // delete the definition again + cleanupDefinition(definitionId); + } + } + + + @Test + public void testCreateDeleteAlertDefinitionWith1ConditionAndNotificationAndFire() throws Exception { + + int definitionId = createEmptyAlertDefinition(true); + + // Now add a condition + try { + + AlertCondition alertCondition = new AlertCondition("AVAIL_GOES_UP","AVAILABILITY"); + given() + .header(acceptJson) + .contentType(ContentType.JSON) + .body(alertCondition) + .pathParam("defId",definitionId) + .expect() + .statusCode(201) + .log().ifError() + .when() + .post("/alert/definition/{defId}/conditions"); + + AlertNotification notification = new AlertNotification("Direct Emails"); // short-name from server plugin descriptor + notification.getConfig().put("emailAddress", "root@eruditorium.org"); + + given() + .header(acceptJson) + .contentType(ContentType.JSON) + .body(notification) + .pathParam("defId", definitionId) + .log().everything() + .expect() + .statusCode(201) + .log().ifError() + .when() + .post("/alert/definition/{defId}/notifications"); + + + System.out.println("Definition created, waiting 60s for it to become active"); + + // Wait a while - see https://bugzilla.redhat.com/show_bug.cgi?id=830299 + Thread.sleep(60*1000); + + // Send a avail down/up sequence -> alert definition should fire + long now = System.currentTimeMillis(); + Availability a = new Availability(10001,now-2000,"DOWN"); + given() + .contentType(ContentType.JSON) + .pathParam("id", 10001) + .body(a) + .expect() + .statusCode(204) + .log().ifError() + .when() + .put("/resource/{id}/availability"); + + a = new Availability(10001,now-1000,"UP"); + given() + .contentType(ContentType.JSON) + .pathParam("id", 10001) + .body(a) + .expect() + .statusCode(204) + .log().ifError() + .when() + .put("/resource/{id}/availability"); + + // wait a little + Thread.sleep(5000); + + int alertId = + given() + .header(acceptJson) + .queryParam("definitionId",definitionId) + .queryParam("since", now - 3000) + .expect() + .statusCode(200) + .log().ifError() + .body("alertDefinition.name",contains("-x-test-definition")) + .body("",iterableWithSize(1)) + .when() + .get("/alert") + .body().jsonPath().getInt("id[0]"); + + System.out.println(alertId); + + // Find this alert by id and then its condition logs and notification logs + given() + .header(acceptJson) + .pathParam("id",alertId) + .expect() + .statusCode(200) + .log().ifError() + .body("id",is(alertId)) + .when() + .get("/alert/{id}"); + + + given() + .header(acceptJson) + .pathParam("id", alertId) + .log().everything() + .expect() + .statusCode(200) + .log().ifError() + .body("",iterableWithSize(1)) + .when() + .get("/alert/{id}/conditions"); + + given() + .header(acceptJson) + .pathParam("id", alertId) + .expect() + .statusCode(200) + .log().ifError() + .body("",iterableWithSize(1)) + .when() + .get("/alert/{id}/notifications"); + + + } + + finally { + // delete the definition again + cleanupDefinition(definitionId); + } + } + + private void cleanupDefinition(int definitionId) {
if (definitionId==0) @@ -1190,10 +1467,10 @@ public class AlertTest extends AbstractBase { .delete("/alert/definition/{id}"); }
- private int createEmptyAlertDefinition() { + private int createEmptyAlertDefinition(boolean enabled) { AlertDefinition alertDefinition = new AlertDefinition(); alertDefinition.setName("-x-test-definition"); - alertDefinition.setEnabled(false); + alertDefinition.setEnabled(enabled); alertDefinition.setPriority("LOW"); alertDefinition.setDampeningCategory("NONE");
diff --git a/modules/integration-tests/rest-api/src/test/java/org/rhq/modules/integrationTests/restApi/d/Availability.java b/modules/integration-tests/rest-api/src/test/java/org/rhq/modules/integrationTests/restApi/d/Availability.java new file mode 100644 index 0000000..fdacbb8 --- /dev/null +++ b/modules/integration-tests/rest-api/src/test/java/org/rhq/modules/integrationTests/restApi/d/Availability.java @@ -0,0 +1,64 @@ +/* + * RHQ Management Platform + * Copyright (C) 2005-2013 Red Hat, Inc. + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation version 2 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ + +package org.rhq.modules.integrationTests.restApi.d; + +/** + * Availability for testing + * @author Heiko W. Rupp + */ +public class Availability { + + long since; + String type; + int resourceId; + + public Availability() { + } + + public Availability(int resourceId, long since, String type) { + this.resourceId = resourceId; + this.since = since; + this.type = type; + } + + public int getResourceId() { + return resourceId; + } + + public void setResourceId(int resourceId) { + this.resourceId = resourceId; + } + + public long getSince() { + return since; + } + + public void setSince(long since) { + this.since = since; + } + + public String getType() { + return type; + } + + public void setType(String type) { + this.type = type; + } +}
commit ac5b2e13dbd2e3648169ddbbefb85a37eb2fdc35 Author: Heiko W. Rupp hwr@redhat.com Date: Wed Feb 20 20:55:25 2013 +0100
Add a get group by id case with valid id
diff --git a/modules/integration-tests/rest-api/src/test/java/org/rhq/modules/integrationTests/restApi/GroupTest.java b/modules/integration-tests/rest-api/src/test/java/org/rhq/modules/integrationTests/restApi/GroupTest.java index ce338bb..f6ffbe7 100644 --- a/modules/integration-tests/rest-api/src/test/java/org/rhq/modules/integrationTests/restApi/GroupTest.java +++ b/modules/integration-tests/rest-api/src/test/java/org/rhq/modules/integrationTests/restApi/GroupTest.java @@ -35,6 +35,7 @@ import org.rhq.modules.integrationTests.restApi.d.GroupDef; import static com.jayway.restassured.RestAssured.expect; import static com.jayway.restassured.RestAssured.given; import static org.hamcrest.CoreMatchers.hasItem; +import static org.hamcrest.Matchers.is; import static org.hamcrest.Matchers.iterableWithSize;
/** @@ -118,6 +119,20 @@ public class GroupTest extends AbstractBase { int groupId = jsonPath.get("[0].id"); assert groupId == createdId;
+ // Fetch id by id + given() + .pathParam("id",groupId) + .header(acceptJson) + .expect() + .statusCode(200) + .body("name",is(X_TEST_GROUP)) + .body("id",is(groupId)) + .body("explicitCount",is(0)) + .log().ifError() + .when() + .get("/group/{id}"); + + // delete the group again given() .pathParam("id",groupId) @@ -429,7 +444,6 @@ public class GroupTest extends AbstractBase { int id = Integer.parseInt(location.substring(location.lastIndexOf("/")+1));
try { - response = given() .header(acceptJson) .pathParam("id",id) @@ -472,7 +486,6 @@ public class GroupTest extends AbstractBase { list.add("resource.name"); gd.setExpression(list);
- Response response = given() .contentType(ContentType.JSON) .header("Accept","application/json") @@ -507,19 +520,18 @@ public class GroupTest extends AbstractBase {
String location = response.getHeader("Location"); - int defintionId = Integer.parseInt(location.substring(location.lastIndexOf("/")+1)); + int definitionId = Integer.parseInt(location.substring(location.lastIndexOf("/")+1));
try { // retrieve by id given() - .pathParam("id", defintionId) + .pathParam("id", definitionId) .expect() .statusCode(200) .when() .get("/group/definition/{id}");
// retrieve by query - Response resp = given() .queryParam("q", "-x-test-def") .expect() @@ -534,7 +546,7 @@ public class GroupTest extends AbstractBase { expect() .statusCode(204) .when() - .delete("/group/definition/" + defintionId); + .delete("/group/definition/" + definitionId); }
}
commit 2b908fa04815c7758e0486eb5e5055c6e13f1d15 Author: Stefan Negrea snegrea@redhat.com Date: Wed Feb 20 14:00:02 2013 -0600
[BZ 912478] Add managed server deployment as parent for the web subsystem resource type.
diff --git a/modules/plugins/jboss-as-7/src/main/resources/META-INF/rhq-plugin.xml b/modules/plugins/jboss-as-7/src/main/resources/META-INF/rhq-plugin.xml index 03dd318..2509073 100644 --- a/modules/plugins/jboss-as-7/src/main/resources/META-INF/rhq-plugin.xml +++ b/modules/plugins/jboss-as-7/src/main/resources/META-INF/rhq-plugin.xml @@ -8834,6 +8834,7 @@ <runs-inside> <parent-resource-type name="Deployment" plugin="&pluginName;"/> <parent-resource-type name="Subdeployment" plugin="&pluginName;"/> + <parent-resource-type name="ManagedServerDeployment" plugin="&pluginName;"/> </runs-inside>
<plugin-configuration>
commit 650d2c0b7c326c1528acf309ddb22e2792b6d65c Author: Simeon Pinder spinder@fulliautomatix.conchfritter.com Date: Wed Feb 20 14:03:52 2013 -0500
Clarify dirty read javadoc for test.
diff --git a/modules/enterprise/server/itests-2/src/test/java/org/rhq/enterprise/server/resource/test/ResourceStorageTest.java b/modules/enterprise/server/itests-2/src/test/java/org/rhq/enterprise/server/resource/test/ResourceStorageTest.java index f48d360..40b0623 100644 --- a/modules/enterprise/server/itests-2/src/test/java/org/rhq/enterprise/server/resource/test/ResourceStorageTest.java +++ b/modules/enterprise/server/itests-2/src/test/java/org/rhq/enterprise/server/resource/test/ResourceStorageTest.java @@ -221,9 +221,12 @@ public class ResourceStorageTest extends AbstractEJB3Test { }
/** Test creates a large number of resources and pages through them using CriteriaQuery. + * * NOTE: CriteriaQuery uses PageList instances underneath and are susceptible to dirty - * read issues if the total number of resources being parsed is i)very large or ii)processing - * each instance takes a significant amount of time. Ex. Begin parsing all resource types, + * read issues if the underlying dataset changes because the total number of resources being + * parsed is i)very large or ii)processing each instance takes a significant amount of + * time such that another action/process/object may have changed the original resources + * before resultset processing could be completed. Ex. Begin parsing all resource types, * while plugin update is removing some of those same types. * * @throws Exception
commit 68d2e82cc37e7109d5d989a58387b9e368b5f03a Author: Jirka Kremser jkremser@redhat.com Date: Wed Feb 20 19:16:56 2013 +0100
[BZ 913121 - Manual import from resource tree's context menu opens the create child child wizard instead] Both import and create option led to the openint the same wizzard. Also some typos in javadoc has been fixed.
diff --git a/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/inventory/resource/detail/ResourceTreeView.java b/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/inventory/resource/detail/ResourceTreeView.java index c38e77a..b4be93c 100644 --- a/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/inventory/resource/detail/ResourceTreeView.java +++ b/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/inventory/resource/detail/ResourceTreeView.java @@ -573,7 +573,7 @@ public class ResourceTreeView extends LocatableVLayout { Integer[] singletonChildTypes = getSingletonChildTypes(resourceType);
// To properly filter Create Child and Import menus we need existing singleton child resources. If the - // user has creat permission and the parent type has singleton child types and creatable or importable child + // user has created permission and the parent type has singleton child types and creatable or importable child // types, perform an async call to fetch the singleton children. if (canCreate && singletonChildTypes.length > 0 && (hasCreatableTypes || hasImportableTypes)) {
@@ -587,12 +587,14 @@ public class ResourceTreeView extends LocatableVLayout { public void onSuccess(PageList<Resource> singletonChildren) { if (hasCreatableTypes) { Map<String, ResourceType> displayNameMap = getDisplayNames(creatableChildTypes); - addMenu(MSG.common_button_create_child(), true, singletonChildren, resource, displayNameMap); + addMenu(MSG.common_button_create_child(), true, singletonChildren, resource, + displayNameMap, true); }
if (hasImportableTypes) { Map<String, ResourceType> displayNameMap = getDisplayNames(importableChildTypes); - addMenu(MSG.common_button_import(), true, singletonChildren, resource, displayNameMap); + addMenu(MSG.common_button_import(), true, singletonChildren, resource, displayNameMap, + false); }
resourceContextMenu.showContextMenu(); @@ -607,22 +609,22 @@ public class ResourceTreeView extends LocatableVLayout { } else if (canCreate && singletonChildTypes.length == 0 && (hasCreatableTypes || hasImportableTypes)) { if (hasCreatableTypes) { Map<String, ResourceType> displayNameMap = getDisplayNames(creatableChildTypes); - addMenu(MSG.common_button_create_child(), true, null, resource, displayNameMap); + addMenu(MSG.common_button_create_child(), true, null, resource, displayNameMap, true); }
if (hasImportableTypes) { Map<String, ResourceType> displayNameMap = getDisplayNames(importableChildTypes); - addMenu(MSG.common_button_import(), true, null, resource, displayNameMap); + addMenu(MSG.common_button_import(), true, null, resource, displayNameMap, false); }
resourceContextMenu.showContextMenu();
} else { if (!canCreate && hasCreatableTypes) { - addMenu(MSG.common_button_create_child(), false, null, null, null); + addMenu(MSG.common_button_create_child(), false, null, null, null, true); } if (!canCreate && hasImportableTypes) { - addMenu(MSG.common_button_import(), false, null, null, null); + addMenu(MSG.common_button_import(), false, null, null, null, false); }
resourceContextMenu.showContextMenu(); @@ -630,12 +632,12 @@ public class ResourceTreeView extends LocatableVLayout { }
private void addMenu(String name, boolean enabled, List<Resource> singletonChildren, Resource resource, - Map<String, ResourceType> displayNameMap) { + Map<String, ResourceType> displayNameMap, boolean isCreate) { MenuItem menu = new MenuItem(name); if (enabled) { Menu subMenu = new Menu(); - singletonChildren = (null == singletonChildren) ? new ArrayList() : singletonChildren; - Menu filteredSubMenu = checkForSingletons(singletonChildren, resource, displayNameMap, subMenu, true); + singletonChildren = (null == singletonChildren) ? new ArrayList<Resource>() : singletonChildren; + Menu filteredSubMenu = checkForSingletons(singletonChildren, resource, displayNameMap, subMenu, isCreate); menu.setSubmenu(filteredSubMenu); } else { menu.setEnabled(false); @@ -676,7 +678,7 @@ public class ResourceTreeView extends LocatableVLayout {
// omit the type's menu item if the singleton already exists, otherwise add the necessary click handler. // note: we omit as opposed to disable the menu item to match the behavior of the buttons in the Inventory - // -> Child Resources view, which has no facility to do the anologous disabling. + // -> Child Resources view, which has no facility to do the analogous disabling. if (!exists) { itemToAdd.addClickHandler(new ClickHandler() { public void onClick(MenuItemClickEvent event) {
commit b3d6756033305f1d6a02ebded33864c4303d3a10 Author: Jay Shaughnessy jshaughn@redhat.com Date: Wed Feb 20 09:37:52 2013 -0500
Add another test for the work done in Bug 912871.
diff --git a/modules/enterprise/server/itests-2/src/test/java/org/rhq/enterprise/server/configuration/ConfigurationManagerBeanTest.java b/modules/enterprise/server/itests-2/src/test/java/org/rhq/enterprise/server/configuration/ConfigurationManagerBeanTest.java index 0900ce6..7d0343b 100644 --- a/modules/enterprise/server/itests-2/src/test/java/org/rhq/enterprise/server/configuration/ConfigurationManagerBeanTest.java +++ b/modules/enterprise/server/itests-2/src/test/java/org/rhq/enterprise/server/configuration/ConfigurationManagerBeanTest.java @@ -78,11 +78,8 @@ public class ConfigurationManagerBeanTest extends AbstractEJB3Test { private Agent agent; private Subject overlord;
- /** - * Prepares things for the entire test class. - */ - //@BeforeClass don't use BeforeClass as Arquillian 1.0.2 invokes it on every test method - protected void beforeClass() { + @Override + protected void beforeMethod() throws Exception { // Make sure page control sorts so the latest config update is last (the default is for the latest to be first). configUpdatesPageControl = PageControl.getUnlimitedInstance(); // (ips, 04/01/10): Use createdTime, rather than id, to order by, since the id's are not guaranteed to be @@ -92,12 +89,6 @@ public class ConfigurationManagerBeanTest extends AbstractEJB3Test {
configurationManager = LookupUtil.getConfigurationManager(); resourceManager = LookupUtil.getResourceManager(); - overlord = LookupUtil.getSubjectManager().getOverlord(); - } - - @Override - protected void beforeMethod() throws Exception { - beforeClass();
prepareScheduler();
@@ -106,6 +97,8 @@ public class ConfigurationManagerBeanTest extends AbstractEJB3Test { agentServiceContainer.configurationService = testServices; agentServiceContainer.discoveryService = testServices;
+ overlord = LookupUtil.getSubjectManager().getOverlord(); + getTransactionManager().begin();
try { @@ -257,6 +250,87 @@ public class ConfigurationManagerBeanTest extends AbstractEJB3Test { }
@Test(enabled = ENABLE_TESTS) + public void testInProgressConfiguration() throws Exception { + int resourceId = newResource1.getId(); + + Subject overlord = LookupUtil.getSubjectManager().getOverlord(); + + // create 3 configs: config1 will be stored as current. config2 will be in progress, config3 should get + // blocked from updating by the inprogress update + Configuration configuration1 = new Configuration(); + configuration1.put(new PropertySimple("myboolean", "true")); + + Configuration configuration2 = new Configuration(); + configuration2.put(new PropertySimple("myboolean", "false")); + configuration2.put(new PropertySimple("mysleep", "7000")); + + Configuration configuration3 = new Configuration(); + configuration3.put(new PropertySimple("mysleep", "10000")); + + // make config1 the current + configurationManager.updateResourceConfiguration(overlord, resourceId, configuration1); + Thread.sleep(2000); // wait for the test agent to complete the request + + ResourceConfigurationUpdate history1; + history1 = configurationManager.getLatestResourceConfigurationUpdate(overlord, resourceId); + assert history1 != null; + PropertySimple myprop = history1.getConfiguration().getSimple("myboolean"); + assert myprop != null; + assert "true".equals(myprop.getStringValue()); + + // now update to config2 - the "agent" will sleep for a bit before it completes + // so we will have an INPROGRESS configuration for a few seconds before it goes to SUCCESS + configurationManager.updateResourceConfiguration(overlord, resourceId, configuration2); + + // now update to config3 - this should fail as you can't update while there is one in progress + try { + configurationManager.updateResourceConfiguration(overlord, resourceId, configuration3); + assert false : "Should have thrown an in progress exception"; + + } catch (ConfigurationUpdateStillInProgressException e) { + System.out.println("======> " + e); + + // make sure everything works as expected (like the above test) + + boolean inProgress = false; + boolean inProgressTested = false; + + do { + ResourceConfigurationUpdate history2 = configurationManager.getLatestResourceConfigurationUpdate( + overlord, resourceId); + inProgress = configurationManager.isResourceConfigurationUpdateInProgress(overlord, resourceId); + + if (inProgress) { + // history2 should be history1 since the update is not complete + assert history2 != null; + assert history2.getId() == history1.getId(); + myprop = history2.getConfiguration().getSimple("myboolean"); + assert myprop != null; + assert "true".equals(myprop.getStringValue()); + myprop = history2.getConfiguration().getSimple("mysleep"); // this wasn't in the first config + assert myprop == null; + // record that this test case ran, we expect it will if the agent delay is there + inProgressTested = true; + } else { + // update is complete, history 2 should be different + history2 = configurationManager.getLatestResourceConfigurationUpdate(overlord, resourceId); + assert history2 != null; + assert history2.getId() != history1.getId(); + myprop = history2.getConfiguration().getSimple("myboolean"); + assert myprop != null; + assert "false".equals(myprop.getStringValue()); + myprop = history2.getConfiguration().getSimple("mysleep"); + assert myprop.getLongValue() != null; + assert myprop.getLongValue().longValue() == 7000L; + } + } while (inProgress); + + } catch (Throwable t) { + assert false : "Should have thrown an in progress exception, not: " + t; + } + } + + @Test(enabled = ENABLE_TESTS) public void testDeleteType() throws Exception { // the purpose of this little test is to test an error condition I'm getting when attempting to delete // a resource type - just forces a run with before/afterMethod
commit 4385fbb69a2dfd9aced1f8802e9477dfb44860ae Author: Jay Shaughnessy jshaughn@redhat.com Date: Tue Feb 19 16:40:32 2013 -0500
[Bug 912871 - Perf: resource configuration update taking a lot of backend resources] Scalability work for resource config update. We already added concurrency limits that should throttle how many config updates the server gets hit with at one time but we also want to see if we can relieve the intense banging on the db and speed up the update time for each resource.
diff --git a/modules/core/domain/src/main/java/org/rhq/core/domain/configuration/ResourceConfigurationUpdate.java b/modules/core/domain/src/main/java/org/rhq/core/domain/configuration/ResourceConfigurationUpdate.java index c2d4767..69ebb9d 100644 --- a/modules/core/domain/src/main/java/org/rhq/core/domain/configuration/ResourceConfigurationUpdate.java +++ b/modules/core/domain/src/main/java/org/rhq/core/domain/configuration/ResourceConfigurationUpdate.java @@ -38,7 +38,7 @@ import org.rhq.core.domain.resource.Resource;
@DiscriminatorValue("resource") @Entity -@NamedQueries( { +@NamedQueries({ @NamedQuery(name = ResourceConfigurationUpdate.QUERY_FIND_ALL_IN_STATUS, query = "" // + "SELECT cu " // + " FROM ResourceConfigurationUpdate cu " // @@ -58,7 +58,8 @@ import org.rhq.core.domain.resource.Resource; + " WHERE icu.resource.id = res.id) " // + " ) " // + " )"), - @NamedQuery(name = ResourceConfigurationUpdate.QUERY_FIND_CURRENTLY_ACTIVE_CONFIG, query = "" // + // Note: Changes to this query should also be applied to QUERY_FIND_CURRENT_AND_IN_PROGRESS_CONFIGS, below. + @NamedQuery(name = ResourceConfigurationUpdate.QUERY_FIND_CURRENTLY_ACTIVE_CONFIG, query = "" // + "SELECT cu " // + " FROM ResourceConfigurationUpdate cu " // + " WHERE cu.resource.id = :resourceId " // @@ -67,6 +68,17 @@ import org.rhq.core.domain.resource.Resource; + " FROM ResourceConfigurationUpdate cu2 " // + " WHERE cu2.resource.id = :resourceId " // + " AND cu2.status = 'SUCCESS' ) "), + @NamedQuery(name = ResourceConfigurationUpdate.QUERY_FIND_CURRENT_AND_IN_PROGRESS_CONFIGS, query = "" // + + "SELECT cu " // + + " FROM ResourceConfigurationUpdate cu " // + + " WHERE cu.resource.id = :resourceId " // + + " AND ( ( cu.status = 'INPROGRESS' ) " // + + " OR ( cu.status = 'SUCCESS' " // + + " AND cu.modifiedTime = ( SELECT MAX(cu2.modifiedTime) " // + + " FROM ResourceConfigurationUpdate cu2 " // + + " WHERE cu2.resource.id = :resourceId " // + + " AND cu2.status = 'SUCCESS' ) " // + + " ) ) "), @NamedQuery(name = ResourceConfigurationUpdate.QUERY_FIND_LATEST_BY_RESOURCE_ID, query = "" // + "SELECT cu " // + " FROM ResourceConfigurationUpdate cu " // @@ -178,6 +190,7 @@ public class ResourceConfigurationUpdate extends AbstractResourceConfigurationUp public static final String QUERY_FIND_ALL_IN_STATUS = "ResourceConfigurationUpdate.findAllInStatus"; public static final String QUERY_FIND_ALL_BY_RESOURCE_ID = "ResourceConfigurationUpdate.findAllByResourceId"; public static final String QUERY_FIND_CURRENTLY_ACTIVE_CONFIG = "ResourceConfigurationUpdate.findCurrentlyActiveConfig"; + public static final String QUERY_FIND_CURRENT_AND_IN_PROGRESS_CONFIGS = "ResourceConfigurationUpdate.findCurrentAndInProgressConfigs"; public static final String QUERY_FIND_LATEST_BY_RESOURCE_ID = "ResourceConfigurationUpdate.findByLatestByResourceId"; public static final String QUERY_FIND_BY_GROUP_ID_AND_STATUS = "ResourceConfigurationUpdate.findByGroupIdAndStatus"; public static final String QUERY_FIND_BY_PARENT_UPDATE_ID_AND_STATUS = "ResourceConfigurationUpdate.findByParentUpdateIdAndStatus"; diff --git a/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/configuration/ConfigurationManagerBean.java b/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/configuration/ConfigurationManagerBean.java index 50e5fd4..04c15b7 100644 --- a/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/configuration/ConfigurationManagerBean.java +++ b/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/configuration/ConfigurationManagerBean.java @@ -89,7 +89,6 @@ import org.rhq.core.domain.resource.Resource; import org.rhq.core.domain.resource.ResourceError; import org.rhq.core.domain.resource.ResourceErrorType; import org.rhq.core.domain.resource.ResourceType; -import org.rhq.core.domain.resource.composite.ResourceComposite; import org.rhq.core.domain.resource.group.GroupCategory; import org.rhq.core.domain.resource.group.ResourceGroup; import org.rhq.core.domain.resource.group.composite.ResourceGroupComposite; @@ -487,9 +486,9 @@ public class ConfigurationManagerBean implements ConfigurationManagerLocal, Conf * is triggering save based on the semantics that we want to provide for configuration updates. * For the same reason, we pass null as the subject. */ - ResourceConfigurationUpdate update = this.configurationManager.persistNewResourceConfigurationUpdateHistory( - this.subjectManager.getOverlord(), resource.getId(), liveConfig, ConfigurationUpdateStatus.SUCCESS, null, - false); + ResourceConfigurationUpdate update = this.configurationManager + .persistResourceConfigurationUpdateInNewTransaction(this.subjectManager.getOverlord(), resource.getId(), + liveConfig, ConfigurationUpdateStatus.SUCCESS, null, false);
// resource.setResourceConfiguration(liveConfig.deepCopy(false)); resource.setResourceConfiguration(liveConfig.deepCopyWithoutProxies()); @@ -1248,8 +1247,9 @@ public class ConfigurationManagerBean implements ConfigurationManagerLocal, Conf return resourceConfigurationUpdate; }
- ResourceConfigurationUpdate newUpdate = configurationManager.persistNewResourceConfigurationUpdateHistory( - subject, resourceId, configToUpdate, ConfigurationUpdateStatus.INPROGRESS, subject.getName(), false); + ResourceConfigurationUpdate newUpdate = configurationManager + .persistResourceConfigurationUpdateInNewTransaction(subject, resourceId, configToUpdate, + ConfigurationUpdateStatus.INPROGRESS, subject.getName(), false); executeResourceConfigurationUpdate(newUpdate); return newUpdate; } @@ -1307,9 +1307,9 @@ public class ConfigurationManagerBean implements ConfigurationManagerLocal, Conf // configuration. // TODO: Consider synchronizing to avoid the condition where someone calls this method twice quickly in two // different tx's, which would put two updates in INPROGRESS and cause havoc. - ResourceConfigurationUpdate newUpdate = configurationManager.persistNewResourceConfigurationUpdateHistory( - subject, resourceId, newResourceConfiguration, ConfigurationUpdateStatus.INPROGRESS, subject.getName(), - false); + ResourceConfigurationUpdate newUpdate = configurationManager + .persistResourceConfigurationUpdateInNewTransaction(subject, resourceId, newResourceConfiguration, + ConfigurationUpdateStatus.INPROGRESS, subject.getName(), false);
executeResourceConfigurationUpdate(newUpdate);
@@ -1382,91 +1382,83 @@ public class ConfigurationManagerBean implements ConfigurationManagerLocal, Conf
@Override @TransactionAttribute(TransactionAttributeType.REQUIRES_NEW) - public ResourceConfigurationUpdate persistNewResourceConfigurationUpdateHistory(Subject subject, int resourceId, - Configuration newConfiguration, ConfigurationUpdateStatus newStatus, String newSubject, + public ResourceConfigurationUpdate persistResourceConfigurationUpdateInNewTransaction(Subject subject, + int resourceId, Configuration newConfiguration, ConfigurationUpdateStatus newStatus, String newSubject, boolean isPartofGroupUpdate) throws ResourceNotFoundException, ConfigurationUpdateStillInProgressException { - // get the resource that we will be updating - Resource resource = resourceManager.getResourceById(subject, resourceId);
- // make sure the user has the proper permissions to do this - if (!authorizationManager.hasResourcePermission(subject, Permission.CONFIGURE_WRITE, resource.getId())) { - throw new PermissionException("User [" + subject.getName() - + "] does not have permission to modify configuration for resource [" + resource + "]"); - } + ResourceConfigurationUpdate current = null; + String errorMessage = null;
- // see if there was a previous update request and make sure it isn't still in progress - List<ResourceConfigurationUpdate> previousRequests = resource.getResourceConfigurationUpdates(); + // for efficiency, in one query fetch IN_PROGRESS and/or the current update + Query query = entityManager + .createNamedQuery(ResourceConfigurationUpdate.QUERY_FIND_CURRENT_AND_IN_PROGRESS_CONFIGS); + query.setParameter("resourceId", resourceId); + List<?> updates = query.getResultList(); + for (Object result : updates) { + current = (ResourceConfigurationUpdate) result; + + if (ConfigurationUpdateStatus.INPROGRESS == current.getStatus()) { + // A previous update is still in progress for this Resource. If this update is part of a group + // update, persist it with FAILURE status, so it is still listed as part of the group history. + // Otherwise, throw an exception that can bubble up to the GUI. + if (isPartofGroupUpdate) { + newStatus = ConfigurationUpdateStatus.FAILURE; + errorMessage = "Resource configuration Update was aborted because an update request for the Resource was already in progress.";
- String errorMessage = null; - if (previousRequests != null) { - for (ResourceConfigurationUpdate previousRequest : previousRequests) { - if (previousRequest.getStatus() == ConfigurationUpdateStatus.INPROGRESS) { - // A previous update is still in progresss for this Resource. If this update is part of a group - // update, persist it with FAILURE status, so it is still listed as part of the group history. - // Otherwise, throw an exception that can bubble up to the GUI. - if (isPartofGroupUpdate) { - newStatus = ConfigurationUpdateStatus.FAILURE; - errorMessage = "Resource configuration Update was aborted because an update request for the Resource was already in progress."; - } else { - // NOTE: If you change this to another exception, make sure you change getLatestResourceConfigurationUpdate(). - throw new ConfigurationUpdateStillInProgressException( - "Resource [" - + resource - + "] has a resource configuration update request already in progress - please wait for it to finish: " - + previousRequest); - } + } else { + // NOTE: If you change this to another exception, make sure you change getLatestResourceConfigurationUpdate(). + throw new ConfigurationUpdateStillInProgressException( + "Resource [" + + resourceId + + "] has a resource configuration update request already in progress - please wait for it to finish: " + + current); } } }
- ResourceConfigurationUpdate current; + Resource resource = null; + + if (null != current) { + // Always persist a group update because each member must have an update. Otherwise, only persist a + // single resource update if it has changed. + if (!isPartofGroupUpdate) { + Configuration currentConfiguration = current.getConfiguration(); + Hibernate.initialize(currentConfiguration.getMap()); + if (currentConfiguration.equals(newConfiguration)) { + return null; + } + }
- // Get the latest configuration as known to the server (i.e. persisted in the DB). - try { - Query query = entityManager - .createNamedQuery(ResourceConfigurationUpdate.QUERY_FIND_CURRENTLY_ACTIVE_CONFIG); - query.setParameter("resourceId", resourceId); - current = (ResourceConfigurationUpdate) query.getSingleResult(); resource = current.getResource(); - } catch (NoResultException nre) { - current = null; // The resource hasn't been successfully configured yet. - }
- // If this update is not part of an group update, don't bother persisting a new entry if the Configuration - // hasn't changed. If it's part of an group update, persist a new entry no matter what, so the group - // update isn't missing any member updates. - if (!isPartofGroupUpdate && current != null) { - Configuration currentConfiguration = current.getConfiguration(); - Hibernate.initialize(currentConfiguration.getMap()); - if (currentConfiguration.equals(newConfiguration)) { - return null; - } + } else { + // make sure the resource exists + resource = resourceManager.getResourceById(subject, resourceId); }
- //Configuration zeroedConfiguration = newConfiguration.deepCopy(false); Configuration zeroedConfiguration = newConfiguration.deepCopyWithoutProxies();
- // create our new update request and assign it to our resource - its status will initially be "in progress" + // create our new update request and assign it to our resource - its status will initially be INPROGRESS ResourceConfigurationUpdate newUpdateRequest = new ResourceConfigurationUpdate(resource, zeroedConfiguration, newSubject); - newUpdateRequest.setStatus(newStatus); - if (newStatus == ConfigurationUpdateStatus.FAILURE) { + + if (ConfigurationUpdateStatus.FAILURE == newStatus) { newUpdateRequest.setErrorMessage(errorMessage); }
entityManager.persist(newUpdateRequest); - if (current != null) { - if (newStatus == ConfigurationUpdateStatus.SUCCESS) { - // If this is the first configuration update since the resource was imported, don't alert + + // No need to alert on the first configuration update, only on subsequent change + if (null != current) { + if (ConfigurationUpdateStatus.SUCCESS == newStatus) { notifyAlertConditionCacheManager("persistNewResourceConfigurationUpdateHistory", newUpdateRequest); } }
resource.addResourceConfigurationUpdates(newUpdateRequest);
- // agent and childResources fields are LAZY - force them to load, because the caller will need them. - Hibernate.initialize(resource.getChildResources()); + // provide the agent while we have the entity, it's typically needed by the caller Hibernate.initialize(resource.getAgent());
return newUpdateRequest; diff --git a/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/configuration/ConfigurationManagerLocal.java b/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/configuration/ConfigurationManagerLocal.java index f5b28ee..85c1247 100644 --- a/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/configuration/ConfigurationManagerLocal.java +++ b/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/configuration/ConfigurationManagerLocal.java @@ -188,7 +188,7 @@ public interface ConfigurationManagerLocal extends ConfigurationManagerRemote { * {@link #getLatestResourceConfigurationUpdate(Subject, int)} and * {@link #scheduleGroupResourceConfigurationUpdate}. * - * @param subject + * @param subject ASSUMES CONFIGURE_WRITE perm for resource in question, no authz checks in this method. * @param resourceId * @param newConfiguration * @param newStatus @@ -196,10 +196,11 @@ public interface ConfigurationManagerLocal extends ConfigurationManagerRemote { * * @param isPartofGroupUpdate * @return the persisted Resource Configuration update, or null if the specified Configuration is identical to the - * currently persisted Configuration + * currently persisted Configuration. Note, on success the normally lazy-loaded + * ResourceConfigurationUpdate.resource.agent will be provided. */ @Nullable - ResourceConfigurationUpdate persistNewResourceConfigurationUpdateHistory(Subject subject, int resourceId, + ResourceConfigurationUpdate persistResourceConfigurationUpdateInNewTransaction(Subject subject, int resourceId, Configuration newConfiguration, ConfigurationUpdateStatus newStatus, String newSubject, boolean isPartofGroupUpdate) throws ResourceNotFoundException, ConfigurationUpdateStillInProgressException;
diff --git a/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/configuration/ConfigurationServerServiceImpl.java b/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/configuration/ConfigurationServerServiceImpl.java index a36f35d..be32c53 100644 --- a/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/configuration/ConfigurationServerServiceImpl.java +++ b/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/configuration/ConfigurationServerServiceImpl.java @@ -43,8 +43,8 @@ public class ConfigurationServerServiceImpl implements ConfigurationServerServic SubjectManagerLocal subjectManager = LookupUtil.getSubjectManager();
int configUpdateId = response.getConfigurationUpdateId(); - ResourceConfigurationUpdate configUpdate = configurationManager.getResourceConfigurationUpdate(subjectManager - .getOverlord(), configUpdateId); + ResourceConfigurationUpdate configUpdate = configurationManager.getResourceConfigurationUpdate( + subjectManager.getOverlord(), configUpdateId);
if (configUpdate != null) { Resource resource = configUpdate.getResource(); @@ -67,7 +67,7 @@ public class ConfigurationServerServiceImpl implements ConfigurationServerServic SubjectManagerLocal subjectManager = LookupUtil.getSubjectManager();
Subject overlord = subjectManager.getOverlord(); - ResourceConfigurationUpdate update = configurationManager.persistNewResourceConfigurationUpdateHistory( + ResourceConfigurationUpdate update = configurationManager.persistResourceConfigurationUpdateInNewTransaction( overlord, resourceId, resourceConfiguration, ConfigurationUpdateStatus.SUCCESS, null, false);
if (update == null) { @@ -76,7 +76,7 @@ public class ConfigurationServerServiceImpl implements ConfigurationServerServic return; }
- Configuration configuration = update.getConfiguration().deepCopy(false); // clone the config, zeroing out ids + Configuration configuration = update.getConfiguration().deepCopy(false); // clone the config, zeroing out ids configurationManager.setResourceConfiguration(resourceId, configuration); // now set it as the current config on the Resource } } diff --git a/modules/enterprise/server/jar/src/test/java/org/rhq/enterprise/server/configuration/ConfigurationManagerBeanUnitTest.java b/modules/enterprise/server/jar/src/test/java/org/rhq/enterprise/server/configuration/ConfigurationManagerBeanUnitTest.java index d51798d..d29ad16 100644 --- a/modules/enterprise/server/jar/src/test/java/org/rhq/enterprise/server/configuration/ConfigurationManagerBeanUnitTest.java +++ b/modules/enterprise/server/jar/src/test/java/org/rhq/enterprise/server/configuration/ConfigurationManagerBeanUnitTest.java @@ -149,7 +149,7 @@ public class ConfigurationManagerBeanUnitTest extends JMockTest {
allowing(entityMgr).find(Resource.class, fixture.resourceId); will(returnValue(fixture.resource));
- oneOf(configurationMgrLocal).persistNewResourceConfigurationUpdateHistory(fixture.subject, + oneOf(configurationMgrLocal).persistResourceConfigurationUpdateInNewTransaction(fixture.subject, fixture.resourceId, fixture.configuration, INPROGRESS, fixture.subject.getName(), fixture.isPartOfGroupUpdate); will(returnValue(expectedUpdate)); @@ -191,7 +191,7 @@ public class ConfigurationManagerBeanUnitTest extends JMockTest { oneOf(authorizationMgr).hasResourcePermission(fixture.subject, CONFIGURE_WRITE, fixture.resourceId); will(returnValue(true));
- oneOf(configurationMgrLocal).persistNewResourceConfigurationUpdateHistory(fixture.subject, + oneOf(configurationMgrLocal).persistResourceConfigurationUpdateInNewTransaction(fixture.subject, fixture.resourceId, fixture.configuration, INPROGRESS, fixture.subject.getName(), fixture.isPartOfGroupUpdate); will(returnValue(expectedUpdate)); @@ -252,7 +252,7 @@ public class ConfigurationManagerBeanUnitTest extends JMockTest { oneOf(configAgentService).validate(fixture.configuration, fixture.resourceId, FROM_STRUCTURED); inSequence(configUdpate);
- oneOf(configurationMgrLocal).persistNewResourceConfigurationUpdateHistory(fixture.subject, + oneOf(configurationMgrLocal).persistResourceConfigurationUpdateInNewTransaction(fixture.subject, fixture.resourceId, fixture.configuration, INPROGRESS, fixture.subject.getName(), fixture.isPartOfGroupUpdate); will(returnValue(expectedUpdate)); @@ -302,7 +302,7 @@ public class ConfigurationManagerBeanUnitTest extends JMockTest { oneOf(configAgentService).merge(fixture.configuration, fixture.resourceId, FROM_RAW); will(returnValue(translatedConfig)); inSequence(configUdpate);
- oneOf(configurationMgrLocal).persistNewResourceConfigurationUpdateHistory(fixture.subject, + oneOf(configurationMgrLocal).persistResourceConfigurationUpdateInNewTransaction(fixture.subject, fixture.resourceId, translatedConfig, INPROGRESS, fixture.subject.getName(), fixture.isPartOfGroupUpdate); will(returnValue(expectedUpdate)); @@ -350,7 +350,7 @@ public class ConfigurationManagerBeanUnitTest extends JMockTest { oneOf(authorizationMgr).hasResourcePermission(fixture.subject, CONFIGURE_WRITE, fixture.resourceId); will(returnValue(true));
- oneOf(configurationMgrLocal).persistNewResourceConfigurationUpdateHistory(fixture.subject, fixture.resourceId, + oneOf(configurationMgrLocal).persistResourceConfigurationUpdateInNewTransaction(fixture.subject, fixture.resourceId, fixture.configuration, INPROGRESS, fixture.subject.getName(), fixture.isPartOfGroupUpdate); will(returnValue(expectedUpdate));
commit 3005a262a20961e6c8583e02953d9af1501d8c68 Author: John Mazzitelli mazz@redhat.com Date: Tue Feb 19 13:56:03 2013 -0500
[BZ 912525] add new concurrency limit for configuration updates
diff --git a/modules/core/client-api/src/main/java/org/rhq/core/clientapi/server/configuration/ConfigurationServerService.java b/modules/core/client-api/src/main/java/org/rhq/core/clientapi/server/configuration/ConfigurationServerService.java index caa1a91..e9e5b36 100644 --- a/modules/core/client-api/src/main/java/org/rhq/core/clientapi/server/configuration/ConfigurationServerService.java +++ b/modules/core/client-api/src/main/java/org/rhq/core/clientapi/server/configuration/ConfigurationServerService.java @@ -23,6 +23,7 @@ package org.rhq.core.clientapi.server.configuration;
import org.rhq.core.communications.command.annotation.Asynchronous; +import org.rhq.core.communications.command.annotation.LimitedConcurrency; import org.rhq.core.domain.configuration.Configuration; import org.rhq.core.domain.configuration.ConfigurationUpdateStatus; import org.rhq.core.domain.configuration.Property; @@ -31,6 +32,8 @@ import org.rhq.core.domain.configuration.Property; * Interface that allows an agent to provide information about a resource's configuration. */ public interface ConfigurationServerService { + String CONCURRENCY_LIMIT_CONFIG_UPDATE = "rhq.server.concurrency-limit.configuration-update"; + /** * The agent will notify the server when a configuration update request has been completed by calling this method. * @@ -65,6 +68,7 @@ public interface ConfigurationServerService { * @param resourceConfiguration the newly detected configuration */ @Asynchronous(guaranteedDelivery = true) + @LimitedConcurrency(CONCURRENCY_LIMIT_CONFIG_UPDATE) void persistUpdatedResourceConfiguration(int resourceId, Configuration resourceConfiguration);
} \ No newline at end of file diff --git a/modules/enterprise/server/appserver/src/main/scripts/rhq-container.build.xml b/modules/enterprise/server/appserver/src/main/scripts/rhq-container.build.xml index f7f781e..544dfbf 100644 --- a/modules/enterprise/server/appserver/src/main/scripts/rhq-container.build.xml +++ b/modules/enterprise/server/appserver/src/main/scripts/rhq-container.build.xml @@ -557,6 +557,7 @@ rhq.server.concurrency-limit.content-report=5 rhq.server.concurrency-limit.content-download=5 rhq.server.concurrency-limit.measurement-report=10 rhq.server.concurrency-limit.measurement-schedule-request=10 +rhq.server.concurrency-limit.configuration-update=10
# Content Local Filesystem Repository rhq.server.content.filesystem=${jboss.server.data.dir}/packagebits diff --git a/modules/enterprise/server/itests-2/src/test/java/org/rhq/enterprise/server/test/TestServerCommunicationsService.java b/modules/enterprise/server/itests-2/src/test/java/org/rhq/enterprise/server/test/TestServerCommunicationsService.java index 0a1c625..7ed7ffd 100644 --- a/modules/enterprise/server/itests-2/src/test/java/org/rhq/enterprise/server/test/TestServerCommunicationsService.java +++ b/modules/enterprise/server/itests-2/src/test/java/org/rhq/enterprise/server/test/TestServerCommunicationsService.java @@ -142,6 +142,13 @@ public class TestServerCommunicationsService implements TestServerCommunications public void setMeasurementScheduleRequestConcurrencyLimit(Integer maxConcurrency) { }
+ public Integer getConfigurationUpdateConcurrencyLimit() { + return 1; + } + + public void setConfigurationUpdateConcurrencyLimit(Integer maxConcurrency) { + } + public Boolean getMaintenanceModeAtStartup() { return Boolean.FALSE; } diff --git a/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/core/comm/ServerCommunicationsService.java b/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/core/comm/ServerCommunicationsService.java index 9c7909e..0d88020 100644 --- a/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/core/comm/ServerCommunicationsService.java +++ b/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/core/comm/ServerCommunicationsService.java @@ -45,6 +45,7 @@ import mazz.i18n.Logger; import org.jboss.remoting.InvokerLocator; import org.jboss.util.StringPropertyReplacer;
+import org.rhq.core.clientapi.server.configuration.ConfigurationServerService; import org.rhq.core.clientapi.server.content.ContentServerService; import org.rhq.core.clientapi.server.discovery.DiscoveryServerService; import org.rhq.core.clientapi.server.measurement.MeasurementServerService; @@ -645,6 +646,17 @@ public class ServerCommunicationsService implements ServerCommunicationsServiceM }
@Override + public Integer getConfigurationUpdateConcurrencyLimit() { + return getServiceContainer().getConcurrencyManager().getConfiguredNumberOfPermitsAllowed( + ConfigurationServerService.CONCURRENCY_LIMIT_CONFIG_UPDATE); + } + + @Override + public void setConfigurationUpdateConcurrencyLimit(Integer maxConcurrency) { + setConcurrencyLimit(ConfigurationServerService.CONCURRENCY_LIMIT_CONFIG_UPDATE, maxConcurrency, true); + } + + @Override public Boolean getMaintenanceModeAtStartup() { InputStream inputStream = null; Boolean flag; diff --git a/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/core/comm/ServerCommunicationsServiceMBean.java b/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/core/comm/ServerCommunicationsServiceMBean.java index 9c8c993..5d4c319 100644 --- a/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/core/comm/ServerCommunicationsServiceMBean.java +++ b/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/core/comm/ServerCommunicationsServiceMBean.java @@ -340,6 +340,23 @@ public interface ServerCommunicationsServiceMBean extends ServiceContainerMetric void setMeasurementScheduleRequestConcurrencyLimit(Integer maxConcurrency);
/** + * Gets the concurrency limit for configuration updates. This is the amount of new configuration updates that the server + * will allow to be processed concurrently. A configuration update is something the agent originates when it needs to + * let the server know when a resource's configuration has changed. + * + * @return number of concurrent calls allowed + */ + Integer getConfigurationUpdateConcurrencyLimit(); + + /** + * Sets the new concurrency limit for configuration updates. This new number is the amount of configuration updates + * that the server will allow to be processed concurrently. + * + * @param maxConcurrency + */ + void setConfigurationUpdateConcurrencyLimit(Integer maxConcurrency); + + /** * Returns <code>true</code> if the server should always start up in maintenance mode. * If <code>false</code>, the server will startup in the same state it was in when it * was shutdown. diff --git a/modules/plugins/rhq-server/src/main/resources/META-INF/rhq-plugin.xml b/modules/plugins/rhq-server/src/main/resources/META-INF/rhq-plugin.xml index 84289ad..ee3fbd1 100644 --- a/modules/plugins/rhq-server/src/main/resources/META-INF/rhq-plugin.xml +++ b/modules/plugins/rhq-server/src/main/resources/META-INF/rhq-plugin.xml @@ -616,6 +616,13 @@ required="true" activationPolicy="immediate" description="Number of measurement schedule requests that can be processed concurrently; if zero or less, there is no limit" /> + <c:simple-property + name="ConfigurationUpdateConcurrencyLimit" + displayName="Configuration Update Concurrency Limit" + type="integer" + required="true" + activationPolicy="immediate" + description="Number of configuration updates originating from agents that can be processed concurrently; if zero or less, there is no limit" /> </c:group> <c:group name="ha"
commit 532c73f05d278ef150056370ad84e4f12eb0de36 Author: Heiko W. Rupp hwr@redhat.com Date: Tue Feb 19 17:02:19 2013 +0100
Follow the recent changes in availability handling and add another test.
diff --git a/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/rest/ResourceHandlerBean.java b/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/rest/ResourceHandlerBean.java index 8142f17..ec42c3c 100644 --- a/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/rest/ResourceHandlerBean.java +++ b/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/rest/ResourceHandlerBean.java @@ -31,6 +31,8 @@ import java.util.UUID;
import javax.ejb.EJB; import javax.ejb.Stateless; +import javax.ejb.TransactionAttribute; +import javax.ejb.TransactionAttributeType; import javax.interceptor.Interceptors; import javax.persistence.EntityManager; import javax.persistence.PersistenceContext; @@ -356,6 +358,7 @@ public class ResourceHandlerBean extends AbstractRestBean { @PUT @Path("/{id}/availability") @ApiOperation("Set the current availability of the passed resource") + @TransactionAttribute(TransactionAttributeType.NEVER) public void reportAvailability(@ApiParam("Id of the resource to update") @PathParam("id") int resourceId, @ApiParam(value= "New Availability setting", required = true) AvailabilityRest avail) { if (avail.getResourceId() != resourceId) @@ -368,11 +371,12 @@ public class ResourceHandlerBean extends AbstractRestBean {
// According to jshaughn, plaforms must not be set to DISABLED, so catch this case here. if (resource.getResourceType().getCategory()==ResourceCategory.PLATFORM && at==AvailabilityType.DISABLED) { - throw new BadArgumentException("Availabilty","Platforms must not be set to DISABLED"); + throw new BadArgumentException("Availability","Platforms must not be set to DISABLED"); }
+ Agent agent = agentMgr.getAgentByResourceId(caller,resourceId);
- AvailabilityReport report = new AvailabilityReport(true, resource.getAgent().getName()); + AvailabilityReport report = new AvailabilityReport(true, agent.getName()); Availability availability = new Availability(resource, avail.getSince(), at); report.addAvailability(availability);
diff --git a/modules/integration-tests/rest-api/src/test/java/org/rhq/modules/integrationTests/restApi/ResourcesTest.java b/modules/integration-tests/rest-api/src/test/java/org/rhq/modules/integrationTests/restApi/ResourcesTest.java index 6899995..27bf5a2 100644 --- a/modules/integration-tests/rest-api/src/test/java/org/rhq/modules/integrationTests/restApi/ResourcesTest.java +++ b/modules/integration-tests/rest-api/src/test/java/org/rhq/modules/integrationTests/restApi/ResourcesTest.java @@ -220,6 +220,61 @@ public class ResourcesTest extends AbstractBase { }
@Test + public void testCreatePlatformUpdateAvailabilityAndRemove() throws Exception { + + Resource resource = new Resource(); + resource.setResourceName("dummy-test"); + resource.setTypeName("Linux"); + + Response response = + given() + .header(acceptXml) + .contentType(ContentType.JSON) + .body(resource) + .expect() + .statusCode(201) + .log().ifError() + .when() + .post("/resource/platforms"); + + XmlPath xmlPath = response.xmlPath(); + Node resource1 = xmlPath.get("resource"); + Node platformIdNode = resource1.get("resourceId"); + String platformId = platformIdNode.value(); + + try { + long now = System.currentTimeMillis()-100; + given().body("{"since":" + now + ","type":"DOWN","resourceId":" + platformId + "}") + .header("Content-Type","application/json") + .header("Accept","application/json") + .pathParam("id",platformId) + .expect() + .statusCode(HttpStatus.SC_NO_CONTENT) + .log().ifError() + .when().put("/resource/{id}/availability"); + + now += 50; + given().body("{"since":" + now + ","type":"UP","resourceId":" + platformId + "}") + .header("Content-Type","application/json") + .header("Accept","application/json") + .pathParam("id",platformId) + .expect() + .statusCode(HttpStatus.SC_NO_CONTENT) + .log().ifError() + .when().put("/resource/{id}/availability"); + + + } + + finally { + given().pathParam("id", platformId) + .expect().statusCode(HttpStatus.SC_NO_CONTENT) + .when().delete("/resource/{id}"); + } + + } + + @Test public void testCreatePlatformOLDAndRemove() throws Exception {
Response response =
commit 7189891da688fc90f5b3b5dc78a6706f1cd57060 Author: Thomas Segismont tsegismo@redhat.com Date: Mon Feb 18 19:39:10 2013 +0100
BZ911172 - Creating mail server fails with EAP 6.1.0.DR4 if outbound-socket-binding-ref is not filled
Mail server outbound-socket-binding-ref now mandatory in UI
diff --git a/modules/plugins/jboss-as-7/src/main/resources/META-INF/rhq-plugin.xml b/modules/plugins/jboss-as-7/src/main/resources/META-INF/rhq-plugin.xml index ba4fe29..03dd318 100644 --- a/modules/plugins/jboss-as-7/src/main/resources/META-INF/rhq-plugin.xml +++ b/modules/plugins/jboss-as-7/src/main/resources/META-INF/rhq-plugin.xml @@ -11670,7 +11670,7 @@ </plugin-configuration>
<resource-configuration> - <c:simple-property name="outbound-socket-binding-ref" required="false" type="string" readOnly="false" description="Outbound Socket binding to SMTP server"> + <c:simple-property name="outbound-socket-binding-ref" required="true" type="string" readOnly="false" description="Outbound Socket binding to SMTP server"> <c:option-source target="configuration" expression="*1/remote-destination-outbound-socket-binding=name:type=SocketBindingGroup"/> </c:simple-property> <c:simple-property name="password" required="false" type="string" readOnly="false" description="Password to authenticate on server"/> @@ -11694,7 +11694,7 @@ </plugin-configuration>
<resource-configuration> - <c:simple-property name="outbound-socket-binding-ref" required="false" type="string" readOnly="false" description="Outbound Socket binding to IMAP server"> + <c:simple-property name="outbound-socket-binding-ref" required="true" type="string" readOnly="false" description="Outbound Socket binding to IMAP server"> <c:option-source target="configuration" expression="*1/remote-destination-outbound-socket-binding=name:type=SocketBindingGroup"/> </c:simple-property> <c:simple-property name="password" required="false" type="string" readOnly="false" description="Password to authenticate on server"/> @@ -11718,7 +11718,7 @@ </plugin-configuration>
<resource-configuration> - <c:simple-property name="outbound-socket-binding-ref" required="false" type="string" readOnly="false" description="Outbound Socket binding to POP3 server"> + <c:simple-property name="outbound-socket-binding-ref" required="true" type="string" readOnly="false" description="Outbound Socket binding to POP3 server"> <c:option-source target="configuration" expression="*1/remote-destination-outbound-socket-binding=name:type=SocketBindingGroup"/> </c:simple-property> <c:simple-property name="password" required="false" type="string" readOnly="false" description="Password to authenticate on server"/>
commit 3dfeb0200b33373de0e9899f659b76c8d27a8648 Author: Thomas Segismont tsegismo@redhat.com Date: Tue Feb 19 11:07:16 2013 +0100
Fix AS7 plugin itest failures due to misuse of context.getNativeProcess
diff --git a/modules/plugins/jboss-as-7/src/main/java/org/rhq/modules/plugins/jbossas7/BaseServerComponent.java b/modules/plugins/jboss-as-7/src/main/java/org/rhq/modules/plugins/jbossas7/BaseServerComponent.java index dcf21d3..42c19ba 100644 --- a/modules/plugins/jboss-as-7/src/main/java/org/rhq/modules/plugins/jbossas7/BaseServerComponent.java +++ b/modules/plugins/jboss-as-7/src/main/java/org/rhq/modules/plugins/jbossas7/BaseServerComponent.java @@ -51,6 +51,7 @@ import org.rhq.core.pluginapi.util.ProcessExecutionUtility; import org.rhq.core.pluginapi.util.StartScriptConfiguration; import org.rhq.core.system.ProcessExecution; import org.rhq.core.system.ProcessExecutionResults; +import org.rhq.core.system.ProcessInfo; import org.rhq.core.system.SystemInfo; import org.rhq.core.util.PropertiesFileUpdate; import org.rhq.modules.plugins.jbossas7.helper.HostConfiguration; @@ -69,8 +70,8 @@ import org.rhq.modules.plugins.jbossas7.json.Result; * @author Heiko W. Rupp * @author Ian Springer */ -public abstract class BaseServerComponent<T extends ResourceComponent<?>> extends BaseComponent<T> - implements MeasurementFacet { +public abstract class BaseServerComponent<T extends ResourceComponent<?>> extends BaseComponent<T> implements + MeasurementFacet {
private static final String SEPARATOR = "\n-----------------------\n";
@@ -88,9 +89,8 @@ public abstract class BaseServerComponent<T extends ResourceComponent<?>> extend
serverPluginConfig = new ServerPluginConfiguration(pluginConfiguration); connection = new ASConnection(serverPluginConfig.getHostname(), serverPluginConfig.getPort(), - serverPluginConfig.getUser(), serverPluginConfig.getPassword()); - @SuppressWarnings("UnusedDeclaration") - AvailabilityType avail = getAvailability(); + serverPluginConfig.getUser(), serverPluginConfig.getPassword()); + getAvailability(); logFileEventDelegate = new LogFileEventResourceComponentHelper(context); logFileEventDelegate.startLogFileEventPollers(); startScriptConfig = new StartScriptConfiguration(pluginConfiguration); @@ -127,7 +127,7 @@ public abstract class BaseServerComponent<T extends ResourceComponent<?>> extend private void validateServerAttributes() throws InvalidPluginConfigurationException { // Validate the base dir (e.g. /opt/jboss-as-7.1.1.Final/standalone). File runtimeBaseDir; - File baseDir=null; + File baseDir = null; try { String runtimeBaseDirString = readAttribute(getEnvironmentAddress(), getBaseDirAttributeName()); // Canonicalize both paths before comparing them! @@ -142,12 +142,12 @@ public abstract class BaseServerComponent<T extends ResourceComponent<?>> extend log.error("Failed to validate base dir for " + getResourceDescription() + ".", e); } if ((runtimeBaseDir != null) && (baseDir != null)) { - if(!runtimeBaseDir.equals(baseDir)) { + if (!runtimeBaseDir.equals(baseDir)) { throw new InvalidPluginConfigurationException("The server listening on " - + serverPluginConfig.getHostname() + ":" + serverPluginConfig.getPort() - + " has base dir [" + runtimeBaseDir + "], but the base dir we expected was [" + baseDir - + "]. Perhaps the management hostname or port has been changed for the server with base dir [" - + baseDir + "]."); + + serverPluginConfig.getHostname() + ":" + serverPluginConfig.getPort() + " has base dir [" + + runtimeBaseDir + "], but the base dir we expected was [" + baseDir + + "]. Perhaps the management hostname or port has been changed for the server with base dir [" + + baseDir + "]."); } }
@@ -161,9 +161,9 @@ public abstract class BaseServerComponent<T extends ResourceComponent<?>> extend } if (runtimeMode != null) { String mode = getMode().name(); - if(!runtimeMode.equals(mode)) { - throw new InvalidPluginConfigurationException("The original mode discovered for this AS7 server was " + - getMode() + ", but the server is now reporting its mode is [" + runtimeMode + "]."); + if (!runtimeMode.equals(mode)) { + throw new InvalidPluginConfigurationException("The original mode discovered for this AS7 server was " + + getMode() + ", but the server is now reporting its mode is [" + runtimeMode + "]."); } }
@@ -171,8 +171,8 @@ public abstract class BaseServerComponent<T extends ResourceComponent<?>> extend JBossProductType runtimeType; try { String runtimeTypeString = readAttribute("product-name"); - runtimeType = (runtimeTypeString != null && !runtimeTypeString.isEmpty()) ? - JBossProductType.getValueByProductName(runtimeTypeString) : JBossProductType.AS; + runtimeType = (runtimeTypeString != null && !runtimeTypeString.isEmpty()) ? JBossProductType + .getValueByProductName(runtimeTypeString) : JBossProductType.AS; } catch (Exception e) { runtimeType = null; log.error("Failed to validate product type for " + getResourceDescription() + ".", e); @@ -180,8 +180,9 @@ public abstract class BaseServerComponent<T extends ResourceComponent<?>> extend if (runtimeType != null) { JBossProductType type = serverPluginConfig.getProductType(); if (runtimeType != type) { - throw new InvalidPluginConfigurationException("The original product type discovered for this AS7 server was " - + type + ", but the server is now reporting its product type is [" + runtimeType + "]."); + throw new InvalidPluginConfigurationException( + "The original product type discovered for this AS7 server was " + type + + ", but the server is now reporting its product type is [" + runtimeType + "]."); } } } @@ -225,7 +226,7 @@ public abstract class BaseServerComponent<T extends ResourceComponent<?>> extend
List<String> errors = validateStartScriptPluginConfigProps(); if (!errors.isEmpty()) { - OperationResult result = new OperationResult(); + OperationResult result = new OperationResult(); setErrorMessage(result, errors); return result; } @@ -279,9 +280,17 @@ public abstract class BaseServerComponent<T extends ResourceComponent<?>> extend
if (hostPort.isLocal) { // lets be paranoid here - while (context.getNativeProcess() != null && context.getNativeProcess().priorSnaphot() != null - && context.getNativeProcess().priorSnaphot().isRunning() - && count++ <= 20) { + for (; count <= 20; count++) { + ProcessInfo processInfo = context.getNativeProcess(); + if (processInfo == null) { + // Process not found, so it died, that's fine + break; + } + if (!processInfo.priorSnaphot().isRunning()) { + // Process info says process is no longer running, that's fine + break; + } + // Process is still running, wait a second and check again try { Thread.sleep(1000); // Wait 1s } catch (InterruptedException e) { @@ -314,7 +323,7 @@ public abstract class BaseServerComponent<T extends ResourceComponent<?>> extend String startScriptPrefix = startScriptConfig.getStartScriptPrefix(); File startScriptFile = getStartScriptFile(); ProcessExecution processExecution = ProcessExecutionUtility.createProcessExecution(startScriptPrefix, - startScriptFile); + startScriptFile);
List<String> arguments = processExecution.getArguments(); if (arguments == null) { @@ -352,7 +361,8 @@ public abstract class BaseServerComponent<T extends ResourceComponent<?>> extend if (results.getError() != null) { operationResult.setErrorMessage(results.getError().getMessage()); } else if (results.getExitCode() != null) { - operationResult.setErrorMessage("Start failed with error code " + results.getExitCode() + ":\n" + results.getCapturedOutput()); + operationResult.setErrorMessage("Start failed with error code " + results.getExitCode() + ":\n" + + results.getCapturedOutput()); } else { // Try to connect to the server - ping once per second, timing out after 20s. boolean up = waitForServerToStart(); @@ -368,7 +378,7 @@ public abstract class BaseServerComponent<T extends ResourceComponent<?>> extend }
private boolean isManuallyAddedServer(OperationResult operationResult, String operation) { - if (pluginConfiguration.get("manuallyAdded")!=null) { + if (pluginConfiguration.get("manuallyAdded") != null) { operationResult.setErrorMessage(operation + " is not enabled for manually added servers"); return true; } @@ -410,8 +420,8 @@ public abstract class BaseServerComponent<T extends ResourceComponent<?>> extend Map<String, String> startScriptEnv = startScriptConfig.getStartScriptEnv(); if (startScriptEnv.isEmpty()) { errors.add("No start script environment variables are set. At a minimum, PATH should be set " - + "(on UNIX, it should contain at least /bin and /usr/bin). It is recommended that " - + "JAVA_HOME also be set, otherwise the PATH will be used to find java."); + + "(on UNIX, it should contain at least /bin and /usr/bin). It is recommended that " + + "JAVA_HOME also be set, otherwise the PATH will be used to find java."); }
return errors; @@ -438,7 +448,7 @@ public abstract class BaseServerComponent<T extends ResourceComponent<?>> extend int count = 0; while (!up) { Operation op = new ReadAttribute(new Address(), "release-version"); - try{ + try { Result res = getASConnection().execute(op); if (res.isSuccess()) { // If op succeeds, server is not down up = true; @@ -478,7 +488,7 @@ public abstract class BaseServerComponent<T extends ResourceComponent<?>> extend */ protected OperationResult postProcessResult(String name, Result res) { OperationResult operationResult = new OperationResult(); - if (res==null) { + if (res == null) { operationResult.setErrorMessage("No result received from server"); return operationResult; } @@ -490,29 +500,29 @@ public abstract class BaseServerComponent<T extends ResourceComponent<?>> extend * reading, this is a good sign. */ if (!res.isSuccess()) { - if (res.getRhqThrowable()!=null && (res.getRhqThrowable() instanceof ConnectException || res.getRhqThrowable().getMessage().equals("Connection refused"))) { + if (res.getRhqThrowable() != null + && (res.getRhqThrowable() instanceof ConnectException || res.getRhqThrowable().getMessage() + .equals("Connection refused"))) { operationResult.setSimpleResult("Success"); - log.debug("Got a ConnectionRefused for operation " + name + " this is considered ok, as the remote server sometimes closes the communications channel before sending a reply"); + log.debug("Got a ConnectionRefused for operation " + + name + + " this is considered ok, as the remote server sometimes closes the communications channel before sending a reply"); } if (res.getFailureDescription().contains("Socket closed")) { // See https://issues.jboss.org/browse/AS7-4192 operationResult.setSimpleResult("Success"); - log.debug("Got a 'Socket closed' result from AS for operation " + name ); - } - else + log.debug("Got a 'Socket closed' result from AS for operation " + name); + } else operationResult.setErrorMessage(res.getFailureDescription()); - } - else { + } else { operationResult.setSimpleResult("Success"); } - } - else { + } else { if (res.isSuccess()) { - if (res.getResult()!=null) + if (res.getResult() != null) operationResult.setSimpleResult(res.getResult().toString()); else operationResult.setSimpleResult("-None provided by server-"); - } - else + } else operationResult.setErrorMessage(res.getFailureDescription()); } return operationResult; @@ -525,8 +535,9 @@ public abstract class BaseServerComponent<T extends ResourceComponent<?>> extend OperationResult result = new OperationResult();
PropertySimple remoteProp = pluginConfig.getSimple("manuallyAdded"); - if (remoteProp!=null && remoteProp.getBooleanValue()!= null && remoteProp.getBooleanValue()) { - result.setErrorMessage("This is a manually added server. This operation can not be used to install a management user. Use the server's 'bin/add-user.sh'"); + if (remoteProp != null && remoteProp.getBooleanValue() != null && remoteProp.getBooleanValue()) { + result + .setErrorMessage("This is a manually added server. This operation can not be used to install a management user. Use the server's 'bin/add-user.sh'"); return result; }
@@ -537,7 +548,8 @@ public abstract class BaseServerComponent<T extends ResourceComponent<?>> extend
File baseDir = serverPluginConfig.getBaseDir(); if (baseDir == null) { - result.setErrorMessage("'" + ServerPluginConfiguration.Property.BASE_DIR + "' plugin config prop is not set."); + result.setErrorMessage("'" + ServerPluginConfiguration.Property.BASE_DIR + + "' plugin config prop is not set."); return result; }
@@ -562,14 +574,13 @@ public abstract class BaseServerComponent<T extends ResourceComponent<?>> extend PropertiesFileUpdate propsFileUpdate = new PropertiesFileUpdate(propertiesFile.getPath()); userAlreadyExisted = propsFileUpdate.update(user, encryptedPassword); } catch (Exception e) { - throw new RuntimeException("Failed to update management users properties file [" + propertiesFile + "].", - e); + throw new RuntimeException("Failed to update management users properties file [" + propertiesFile + "].", e); }
String verb = (userAlreadyExisted) ? "updated" : "added"; result.setSimpleResult("Management user [" + user + "] " + verb + "."); log.info("Management user [" + user + "] " + verb + " for " + context.getResourceType().getName() - + " server with key [" + context.getResourceKey() + "]."); + + " server with key [" + context.getResourceKey() + "].");
context.getAvailabilityContext().requestAvailabilityCheck(); context.getInventoryContext().requestDeferredChildResourcesDiscovery(); @@ -588,7 +599,7 @@ public abstract class BaseServerComponent<T extends ResourceComponent<?>> extend public void getValues(MeasurementReport report, Set<MeasurementScheduleRequest> requests) throws Exception { Set<MeasurementScheduleRequest> skmRequests = new HashSet<MeasurementScheduleRequest>(requests.size()); Set<MeasurementScheduleRequest> leftovers = new HashSet<MeasurementScheduleRequest>(requests.size()); - for (MeasurementScheduleRequest request: requests) { + for (MeasurementScheduleRequest request : requests) { String requestName = request.getName(); if (requestName.equals("startTime")) { collectStartTimeTrait(report, request); @@ -681,14 +692,14 @@ public abstract class BaseServerComponent<T extends ResourceComponent<?>> extend op.includeRuntime(true); ComplexResult res = getASConnection().executeComplex(op); if (res.isSuccess()) { - Map<String,Object> props = res.getResult(); + Map<String, Object> props = res.getResult();
- for (MeasurementScheduleRequest request: skmRequests) { + for (MeasurementScheduleRequest request : skmRequests) { String requestName = request.getName(); String realName = requestName.substring(requestName.indexOf(':') + 1); - String val=null; + String val = null; if (props.containsKey(realName)) { - val = getStringValue( props.get(realName) ); + val = getStringValue(props.get(realName)); }
if ("null".equals(val)) { @@ -699,7 +710,7 @@ public abstract class BaseServerComponent<T extends ResourceComponent<?>> extend else log.debug("Value for " + realName + " was 'null' and no replacement found"); } - MeasurementDataTrait data = new MeasurementDataTrait(request,val); + MeasurementDataTrait data = new MeasurementDataTrait(request, val); report.addData(data); } } else { diff --git a/modules/plugins/jboss-as-7/src/test/java/org/rhq/modules/plugins/jbossas7/itest/AbstractServerComponentTest.java b/modules/plugins/jboss-as-7/src/test/java/org/rhq/modules/plugins/jbossas7/itest/AbstractServerComponentTest.java index f6f1502..7aa92b6 100644 --- a/modules/plugins/jboss-as-7/src/test/java/org/rhq/modules/plugins/jbossas7/itest/AbstractServerComponentTest.java +++ b/modules/plugins/jboss-as-7/src/test/java/org/rhq/modules/plugins/jbossas7/itest/AbstractServerComponentTest.java @@ -62,6 +62,7 @@ public abstract class AbstractServerComponentTest extends AbstractJBossAS7Plugin private static final Map<String, String> EAP6_VERSION_TO_AS7_VERSION_MAP = new HashMap<String, String>(); static { EAP6_VERSION_TO_AS7_VERSION_MAP.put("6.0.0", "7.1.2.Final-redhat-1"); + EAP6_VERSION_TO_AS7_VERSION_MAP.put("6.0.1", "7.1.3.Final-redhat-4"); }
private static final String RELEASE_VERSION_TRAIT_NAME = "_skm:release-version";
commit 43a268f07024873ad666fb3fda5713199f163dde Author: Jay Shaughnessy jshaughn@jshaughn.csb Date: Mon Feb 18 14:09:31 2013 -0500
Fix resource bulk delete when the resource is a member of groups, on oracle. The issue is that a native Query is used that returns resource group ids and since Oracle represents integers as Number, it actually returns a BigDecimal, not an Integer, for the Ids. Deal with it in the generic way we deal with DB type differences.
diff --git a/modules/core/dbutils/src/main/java/org/rhq/core/db/DatabaseType.java b/modules/core/dbutils/src/main/java/org/rhq/core/db/DatabaseType.java index fb62e4c..9e141a8 100644 --- a/modules/core/dbutils/src/main/java/org/rhq/core/db/DatabaseType.java +++ b/modules/core/dbutils/src/main/java/org/rhq/core/db/DatabaseType.java @@ -274,6 +274,19 @@ public abstract class DatabaseType { }
/** + * Get the Integer representation of the number type supplied by the db vendor for an integer field value. + * The default implementation simply applies a cast to the passed in number and is appropriate for DB types + * that support a native integer field type (like Postgres). Other db types should override this method + * (like Oracle). + * + * @param number + * @return + */ + public Integer getInteger(Object number) { + return (Integer) number; + } + + /** * Fill out a <code>PreparedStatement</code> correctly with a boolean. * * @param bool the boolean you want diff --git a/modules/core/dbutils/src/main/java/org/rhq/core/db/OracleDatabaseType.java b/modules/core/dbutils/src/main/java/org/rhq/core/db/OracleDatabaseType.java index 9dcbb89..15ee0af 100644 --- a/modules/core/dbutils/src/main/java/org/rhq/core/db/OracleDatabaseType.java +++ b/modules/core/dbutils/src/main/java/org/rhq/core/db/OracleDatabaseType.java @@ -18,6 +18,7 @@ */ package org.rhq.core.db;
+import java.math.BigDecimal; import java.sql.Connection; import java.sql.PreparedStatement; import java.sql.ResultSet; @@ -46,6 +47,7 @@ public abstract class OracleDatabaseType extends DatabaseType { * * @see DatabaseType#getVendor() */ + @Override public String getVendor() { return VENDOR; } @@ -55,10 +57,23 @@ public abstract class OracleDatabaseType extends DatabaseType { * * @see DatabaseType#getBooleanValue(boolean) */ + @Override public String getBooleanValue(boolean bool) { return bool ? "1" : "0"; }
+ /* (non-Javadoc) + * @see org.rhq.core.db.DatabaseType#getInteger(java.lang.Object) + * + * Oracle stores integer fields as Numbers and returns a BigDecimal. It is assumed <code>number</code> is actually + * an integer value, otherwise precision will be lost in this conversion. + */ + @Override + public Integer getInteger(Object number) { + BigDecimal intField = (BigDecimal) number; + return intField.intValue(); + } + /** * For Oracle databases, the boolean parameter will actually be of type "int" with a value of 0 or 1. * diff --git a/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/resource/ResourceManagerBean.java b/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/resource/ResourceManagerBean.java index 384a432..d3fd1ee 100644 --- a/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/resource/ResourceManagerBean.java +++ b/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/resource/ResourceManagerBean.java @@ -45,6 +45,7 @@ import org.apache.commons.logging.LogFactory; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable;
+import org.rhq.core.db.DatabaseType; import org.rhq.core.db.DatabaseTypeFactory; import org.rhq.core.domain.alert.Alert; import org.rhq.core.domain.alert.AlertCondition; @@ -499,7 +500,10 @@ public class ResourceManagerBean implements ResourceManagerLocal, ResourceManage // In other words, the implicit resources of a group have no impact on the group type (compatible/mixed). Query nativeQuery = entityManager.createNativeQuery(ResourceGroup.QUERY_GET_GROUP_IDS_BY_RESOURCE_IDS); nativeQuery.setParameter("resourceIds", resourceIds); - List<Integer> groupIds = nativeQuery.getResultList(); + // Note that different DB vendors return different types for IDs because the representation + // is different at the storage layer. This is an em native query so we need to handle the differences. + // Postgres will return an Integer, but Oracle returns a BigDecimal, etc. + List<?> rs = nativeQuery.getResultList();
String[] nativeQueriesToExecute = new String[] { // ResourceGroup.QUERY_DELETE_EXPLICIT_BY_RESOURCE_IDS, // unmap from explicit groups @@ -514,9 +518,13 @@ public class ResourceManagerBean implements ResourceManagerLocal, ResourceManage }
// update the resource type of affected groups by calling setResouceType() - for (int groupId : groupIds) { + DatabaseType dbType = DatabaseTypeFactory.getDefaultDatabaseType(); + Integer groupId = null; + for (int i = 0, size = rs.size(); i < size; ++i) { try { + groupId = dbType.getInteger(rs.get(i)); resourceGroupManager.setResourceType(groupId); + } catch (ResourceGroupDeleteException rgde) { log.warn("Unable to change resource type for group with id [" + groupId + "]", rgde); }
rhq-commits@lists.fedorahosted.org