.classpath | 24 modules/core/native-system/src/main/java/org/rhq/core/system/AggregateProcessInfo.java | 13 modules/core/native-system/src/main/java/org/rhq/core/system/ProcessInfo.java | 457 ++++++++-- modules/core/native-system/src/test/java/org/rhq/core/system/ProcessInfoRefreshIntervalTest.java | 175 +++ modules/core/native-system/src/test/resources/org/rhq/core/system/bash-watch-echo.sh | 7 modules/core/native-system/src/test/resources/org/rhq/core/system/win-watch-echo.bat | 5 modules/core/plugin-api/src/main/java/org/rhq/core/pluginapi/inventory/ResourceContext.java | 24 modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/admin/topology/AgentDatasource.java | 7 modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/admin/topology/AgentDatasourceField.java | 3 modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/admin/topology/AgentDetailView.java | 15 modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/dashboard/DashboardsView.java | 2 modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/inventory/resource/detail/ResourceDetailView.java | 4 modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/inventory/resource/detail/inventory/ResourceAgentView.java | 216 ++++ modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/inventory/resource/detail/inventory/ResourceResourceAgentView.java | 193 ---- modules/enterprise/gui/coregui/src/main/resources/org/rhq/enterprise/gui/coregui/client/MessageConstants.properties | 4 modules/enterprise/gui/coregui/src/main/resources/org/rhq/enterprise/gui/coregui/client/Messages.properties | 1 modules/enterprise/gui/coregui/src/main/resources/org/rhq/enterprise/gui/coregui/client/Messages_de.properties | 1 modules/enterprise/gui/coregui/src/main/resources/org/rhq/enterprise/gui/coregui/client/Messages_ja.properties | 1 modules/enterprise/gui/coregui/src/main/resources/org/rhq/enterprise/gui/coregui/client/Messages_ko.properties | 86 + modules/enterprise/gui/coregui/src/main/resources/org/rhq/enterprise/gui/coregui/client/Messages_pt.properties | 1 modules/enterprise/gui/coregui/src/main/resources/org/rhq/enterprise/gui/coregui/client/Messages_ru.properties | 87 + modules/enterprise/gui/coregui/src/main/resources/org/rhq/enterprise/gui/coregui/client/Messages_zh.properties | 1 modules/integration-tests/apache-plugin-test/src/test/java/org/rhq/plugins/apache/util/ApacheExecutionUtil.java | 9 modules/plugins/cassandra/src/main/java/org/rhq/plugins/cassandra/CassandraNodeComponent.java | 11 modules/plugins/hadoop/src/main/java/org/rhq/plugins/hadoop/HadoopServerComponent.java | 70 - modules/plugins/jboss-as-5/pom.xml | 17 modules/plugins/mysql/src/main/java/org/rhq/plugins/mysql/MySqlComponent.java | 2 modules/plugins/platform/src/main/java/org/rhq/plugins/platform/ProcessComponent.java | 27 modules/plugins/sshd/src/main/java/org/rhq/plugins/sshd/OpenSSHDComponent.java | 43 29 files changed, 1120 insertions(+), 386 deletions(-)
New commits: commit d26cf3d099aa0c42c79ca097cc8b1c63db3b0c25 Merge: 52b4fd7 8e27a3a Author: John Sanda jsanda@redhat.com Date: Fri Jan 25 10:58:35 2013 -0500
Merge branch 'master' into feature/cassandra-backend
Conflicts: .classpath
diff --cc .classpath index 375538e,9af3a50..41e047a --- a/.classpath +++ b/.classpath @@@ -345,14 -343,12 +353,16 @@@ <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"/> <classpathentry exported="true" kind="var" path="M2_REPO/com/wordnik/swagger-annotations_2.9.1/1.1.1-SNAPSHOT/swagger-annotations_2.9.1-1.1.1-20121031.024335-6.jar"/> - <classpathentry exported="true" kind="var" path="JDK_HOME/lib/tools.jar"/> <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 kind="var" path="M2_REPO/org/apache/cassandra/cassandra-thrift/1.2.0-beta2/cassandra-thrift-1.2.0-beta2.jar"/> + <classpathentry exported="true" kind="var" path="M2_REPO/org/hectorclient/hector-core/1.1-1/hector-core-1.1-1.jar"/> + <classpathentry kind="var" path="M2_REPO/org/apache/cassandra/cassandra-all/1.2.0-beta2/cassandra-all-1.2.0-beta2.jar"/> + <classpathentry kind="var" path="M2_REPO/com/datastax/cassandra/cassandra-driver-core/0.1.0-SNAPSHOT/cassandra-driver-core-0.1.0-SNAPSHOT.jar"/> + <classpathentry kind="var" path="M2_REPO/org/apache/thrift/libthrift/0.7.0/libthrift-0.7.0.jar"/> + <classpathentry kind="var" path="M2_REPO/commons-cli/commons-cli/1.2/commons-cli-1.2.jar"/> + <classpathentry kind="var" path="M2_REPO/com/google/guava/guava/12.0/guava-12.0.jar"/> + <classpathentry kind="output" path="eclipse-classes"/> </classpath>
commit 8e27a3acaf35b70ed191b6890cdfd1cc482d82b8 Author: John Sanda jsanda@redhat.com Date: Fri Jan 25 10:43:53 2013 -0500
make sure we clean up when downloading jboss distro
The ant script that downloads the jboss distro could time out leaving a corrupt zip file in the tmp dir. This would cause the build to fail and was also causing subsequent CI builds to fail. Once again, doing tear down in the set up fixes the problem.
diff --git a/modules/plugins/jboss-as-5/pom.xml b/modules/plugins/jboss-as-5/pom.xml index 2474eec..9c71f33 100644 --- a/modules/plugins/jboss-as-5/pom.xml +++ b/modules/plugins/jboss-as-5/pom.xml @@ -473,6 +473,21 @@ <target> <property name="as5.zipfile" location="${java.io.tmpdir}${file.separator}jboss-as-${as5.version}.zip"/> + + <!-- + Go ahead and clean up the tmp dir first. If in a prior build, + we timeout while downloading the jboss distro, we will be left + with a corrupt zip file which will cause the build to fail as + expected; however, if we do not clean up, then subsequent + builds fail as well. Alternatively we could try and set the + skipexisting attribute on the get task to false which might + also work and be faster but this way ensures we get the + correct bits. + --> + <delete file="${as5.zipfile}"/> + <delete dir="${java.io.tmpdir}/jboss-eap-${as5.version}" failonerror="false"/> + <delete dir="${jboss5.home}"/> + <get src="${as5.url}" dest="${as5.zipfile}" usetimestamp="true" verbose="true"/> <unzip src="${as5.zipfile}" dest="${java.io.tmpdir}"/> @@ -480,7 +495,7 @@ <move file="${java.io.tmpdir}/jboss-${as5.version}" tofile="${jboss5.home}" failonerror="false" overwrite="false"/> - <!-- This works for EAP versions --> + <!-- This works for EAP versions --> <move file="${java.io.tmpdir}/jboss-eap-${as5.version}/jboss-as" tofile="${jboss5.home}" failonerror="false" overwrite="false"/>
commit 33f65e91a7b5121774d4e6928bb16ec95a87836e Author: John Mazzitelli mazz@redhat.com Date: Fri Jan 25 08:50:06 2013 -0500
point to the proper RHQ wiki docs
diff --git a/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/dashboard/DashboardsView.java b/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/dashboard/DashboardsView.java index b48dd19..c5fa4dc 100644 --- a/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/dashboard/DashboardsView.java +++ b/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/dashboard/DashboardsView.java @@ -326,7 +326,7 @@ public class DashboardsView extends LocatableVLayout implements DashboardContain DashboardPortlet news = new DashboardPortlet(MashupPortlet.NAME, MashupPortlet.KEY, 300); if (isRHQ) { news.getConfiguration() - .put(new PropertySimple("address", "https://docs.jboss.org/author/display/RHQ/Home")); + .put(new PropertySimple("address", "https://docs.jboss.org/author/display/RHQ/User+Documentation")); } else { news.getConfiguration().put( new PropertySimple("address", diff --git a/modules/enterprise/gui/coregui/src/main/resources/org/rhq/enterprise/gui/coregui/client/MessageConstants.properties b/modules/enterprise/gui/coregui/src/main/resources/org/rhq/enterprise/gui/coregui/client/MessageConstants.properties index c3b641e..1e3fbe3 100644 --- a/modules/enterprise/gui/coregui/src/main/resources/org/rhq/enterprise/gui/coregui/client/MessageConstants.properties +++ b/modules/enterprise/gui/coregui/src/main/resources/org/rhq/enterprise/gui/coregui/client/MessageConstants.properties @@ -35,7 +35,7 @@ view_help_section_1_item_count = 3 view_help_section_1_propTitle_1 = Frequently Asked Questions (FAQ) view_help_section_1_propUrl_1 = https://docs.jboss.org/author/display/RHQ/FAQ view_help_section_1_propTitle_2 = Documentation Set -view_help_section_1_propUrl_2 = https://docs.jboss.org/author/display/RHQ/Home +view_help_section_1_propUrl_2 = https://docs.jboss.org/author/display/RHQ/User+Documentation view_help_section_1_propTitle_3 = API Javadoc view_help_section_1_propUrl_3 = https://docs.jboss.org/author/display/RHQ/API+Documentation
@@ -48,7 +48,7 @@ view_help_section_2_propTitle_2 = Demo: Bundle Provisioning view_help_section_2_propUrl_2 = http://management-platform.blogspot.com/2011/01/bundle-provisioning-via-rhq.... view_help_section_2_propTitle_3 = How to build Group Definitions view_help_section_2_propIcon_3 = [SKIN]/../actions/help.png -view_help_section_2_propUrl_3 = http://docs.redhat.com/docs/en-US/JBoss_Operations_Network/2.4/html/Basic_Ad... +view_help_section_2_propUrl_3 = https://docs.jboss.org/author/display/RHQ/Group+Definitions view_help_section_2_propTitle_4 = How to use the Search Bar view_help_section_2_propIcon_4 = [SKIN]/../actions/help.png view_help_section_2_propUrl_4 = https://docs.jboss.org/author/display/RHQ/Search
commit 269da6354ef305638316aae2bdcd7039bde62cf3 Author: Thomas Segismont tsegismo@redhat.com Date: Fri Jan 25 10:06:43 2013 +0100
Fix Eclipse classpath file: CDI and javax.inject
diff --git a/.classpath b/.classpath index 6091ec8..9af3a50 100644 --- a/.classpath +++ b/.classpath @@ -336,7 +336,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/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"/>
commit 3ded44d88b2700c95d3e107d2cfdbe48524a41e8 Author: Thomas SEGISMONT tsegismo@redhat.com Date: Mon Dec 10 21:53:49 2012 +0100
Bug 885664 OpenSSHD and MySQL availability check may report stale data
Refactoring of ProcessInfo The class has now a subtype which groups non static data and operations on this data. The purpose is to make clear for users of the class that it caches data and only takes snaphots via SIGAR calls
OpenSSHDComponent and MySQLComponent have their availability check fixed and using this API
Other classes were updated with new API calls for isRunning method
Add lock and interval mechanism to ProcessInfo refresh This will avoid SIGAR bug when making too close calls to getProcState Add corresponding test
Fix bad log in ApacheExecutionUtil
Modified Eclipse classpath file
diff --git a/.classpath b/.classpath index e7fd638..6091ec8 100644 --- a/.classpath +++ b/.classpath @@ -13,7 +13,6 @@ <classpathentry kind="src" path="modules/cli-tests/src/main/java"/> <classpathentry kind="src" path="modules/helpers/jeeGen/src/main/java"/> <classpathentry kind="src" path="modules/helpers/bundleGen/src/main/java"/> - <classpathentry kind="src" path="modules/integration-tests/jndi-access/jndi-access-test/src/test/java"/> <classpathentry kind="src" path="modules/common/drift/src/main/java"/> <classpathentry kind="src" path="modules/common/drift/src/test/java"/> <classpathentry kind="src" path="modules/common/ant-bundle/src/test/java"/> @@ -25,8 +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/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"/> @@ -119,7 +119,9 @@ <classpathentry kind="src" path="modules/plugins/oracle/src/main/java"/> <classpathentry kind="src" path="modules/plugins/oracle/src/test/java"/> <classpathentry kind="src" path="modules/plugins/apache/src/main/java"/> + <classpathentry kind="src" path="modules/plugins/apache/src/main/resources"/> <classpathentry kind="src" path="modules/plugins/apache/src/test/java"/> + <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/ant-bundle/src/main/java"/> @@ -176,7 +178,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/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"/> @@ -239,7 +245,7 @@ <classpathentry exported="true" kind="var" path="M2_REPO/org/richfaces/ui/richfaces-ui/3.3.3.Final/richfaces-ui-3.3.3.Final.jar" sourcepath="/M2_REPO/org/richfaces/ui/richfaces-ui/3.3.0.GA/richfaces-ui-3.3.0.GA-sources.jar"/> <classpathentry exported="true" kind="var" path="M2_REPO/postgresql/postgresql/9.2-1002.jdbc4/postgresql-9.2-1002.jdbc4.jar"/> <classpathentry exported="true" kind="var" path="M2_REPO/jboss/jboss-cache/1.4.1.SP9/jboss-cache-1.4.1.SP9.jar"/> - <classpathentry exported="true" kind="var" path="M2_REPO/org/hyperic/sigar/1.6.5.132-3/sigar-1.6.5.132-3.jar" sourcepath="/M2_REPO/org/hyperic/sigar/1.6.3.82/sigar-1.6.3.82-sources.jar"/> + <classpathentry exported="true" kind="var" path="M2_REPO/org/hyperic/sigar/1.6.5.132-3/sigar-1.6.5.132-3.jar" sourcepath="/M2_REPO/org/hyperic/sigar/1.6.5.132-3/sigar-1.6.5.132-3-sources.jar"/> <classpathentry exported="true" kind="var" path="M2_REPO/org/jboss/jbossts/jbossjts/4.16.2.Final/jbossjts-4.16.2.Final.jar"/> <classpathentry exported="true" kind="var" path="M2_REPO/org/apache/maven/maven-project/2.0.8/maven-project-2.0.8.jar"/> <classpathentry exported="true" kind="var" path="M2_REPO/org/apache/maven/maven-plugin-api/2.0.8/maven-plugin-api-2.0.8.jar"/> @@ -335,9 +341,12 @@ <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"/> <classpathentry exported="true" kind="var" path="M2_REPO/com/wordnik/swagger-annotations_2.9.1/1.1.1-SNAPSHOT/swagger-annotations_2.9.1-1.1.1-20121031.024335-6.jar"/> - <classpathentry exported="true" kind="var" path="JDK_HOME/lib/tools.jar"/> <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 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="JDK_HOME/lib/tools.jar"/> + <classpathentry kind="output" path="eclipse-classes"/> </classpath> diff --git a/modules/core/native-system/src/main/java/org/rhq/core/system/AggregateProcessInfo.java b/modules/core/native-system/src/main/java/org/rhq/core/system/AggregateProcessInfo.java index 271a869..144c4f4 100644 --- a/modules/core/native-system/src/main/java/org/rhq/core/system/AggregateProcessInfo.java +++ b/modules/core/native-system/src/main/java/org/rhq/core/system/AggregateProcessInfo.java @@ -24,10 +24,10 @@ package org.rhq.core.system;
import java.util.ArrayList; import java.util.HashMap; +import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Set; -import java.util.HashSet;
import org.hyperic.sigar.ProcCpu; import org.hyperic.sigar.ProcFd; @@ -110,23 +110,26 @@ public class AggregateProcessInfo extends ProcessInfo { // There are some instances where SIGAR can't get one or more of these (maybe permission issues?). // Do not bomb if we can't get one or more of these - we'll just handle nulls appropriately.
+ // It is safe to get the prior snapshot as we just called super.refresh + ProcessInfoSnapshot priorSnaphot = priorSnaphot(); + try { - procTimes.add(super.procTime); + procTimes.add(priorSnaphot.getTime()); } catch (Exception e) { }
try { - procMems.add(super.procMem); + procMems.add(priorSnaphot.getMemory()); } catch (Exception e) { }
try { - procCpus.add(super.procCpu); + procCpus.add(priorSnaphot.getCpu()); } catch (Exception e) { }
try { - procFds.add(super.procFd); + procFds.add(priorSnaphot.getFileDescriptor()); } catch (Exception e) { }
diff --git a/modules/core/native-system/src/main/java/org/rhq/core/system/ProcessInfo.java b/modules/core/native-system/src/main/java/org/rhq/core/system/ProcessInfo.java index 39b0f0f..7f994ed 100644 --- a/modules/core/native-system/src/main/java/org/rhq/core/system/ProcessInfo.java +++ b/modules/core/native-system/src/main/java/org/rhq/core/system/ProcessInfo.java @@ -1,6 +1,6 @@ /* * RHQ Management Platform - * Copyright (C) 2005-2012 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 @@ -28,6 +28,8 @@ import java.util.HashMap; import java.util.HashSet; import java.util.Map; import java.util.Set; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.locks.ReentrantLock;
import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; @@ -49,39 +51,229 @@ import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable;
/** + * <p> * Encapsulates information about a known process. + * </p> + * <p> + * A few process properties (i.e. PID, command line) will never change during the lifetime of the process and can be + * read directly with this class accessors. Other process properties (i.e. state, cpu usage) will vary and their values + * are grouped in {@link ProcessInfoSnapshot} instances. + * </p> + * <p> + * Operations on static properties of the process must be implemented in the {@link ProcessInfo} type. Operations on + * non static properties must be implemented in the {@link ProcessInfoSnapshot} type. The {@link ProcessInfoSnapshot} + * subtype has been created to remind users of the class that they are working with cached data. + * </p> + * <p>For example, if you want to be sure a process is still alive, you should use this code:<br> + * <code>processInfo.freshSnapshot().isRunning()</code> + * </p> + * <p>Rather than:<br> + * <code>processInfo.priorSnapshot().isRunning()</code> + * </p> * * @author John Mazzitelli * @author Ian Springer + * @author Thomas Segismont */ public class ProcessInfo { - private final Log log = LogFactory.getLog(ProcessInfo.class.getName()); + + /** + * <p> + * Exposes non static process properties and operations computed on them (like {@link #isRunning()} method). + * Operations on non static process properties should all be implemented here. + * </p> + * <p> + * New snapshots are created when {@link ProcessInfo#refresh()} or {@link ProcessInfo#freshSnapshot()} are + * called. + * </p> + * <p> + * Note the current implementation does not actually encapsulate these properties for backward compatibility + * reasons (we have to keep the write access to {@link ProcessInfo} protected properties). + * </p> + */ + public final class ProcessInfoSnapshot { + + public long getParentPid() throws SystemInfoException { + return (ProcessInfo.this.procState != null) ? ProcessInfo.this.procState.getPpid() : 0L; + } + + public ProcState getState() throws SystemInfoException { + return ProcessInfo.this.procState; + } + + public ProcExe getExecutable() throws SystemInfoException { + return ProcessInfo.this.procExe; + } + + public ProcTime getTime() throws SystemInfoException { + return ProcessInfo.this.procTime; + } + + public ProcMem getMemory() throws SystemInfoException { + return ProcessInfo.this.procMem; + } + + public ProcCpu getCpu() throws SystemInfoException { + return ProcessInfo.this.procCpu; + } + + public ProcFd getFileDescriptor() throws SystemInfoException { + return ProcessInfo.this.procFd; + } + + public ProcCred getCredentials() throws SystemInfoException { + return ProcessInfo.this.procCred; + } + + public ProcCredName getCredentialsName() throws SystemInfoException { + return ProcessInfo.this.procCredName; + } + + /** + * @return null if process executable or cwd is unavailable. Otherwise the Cwd as returned from the + * process executable. + * @throws SystemInfoException + */ + public String getCurrentWorkingDirectory() throws SystemInfoException { + String result = null; + try { + if (null != ProcessInfo.this.procExe) { + result = ProcessInfo.this.procExe.getCwd(); + } + } catch (Exception e) { + ProcessInfo.this.handleSigarCallException(e, "procExe.getCwd()"); + } + return result; + } + + /** + * Checks if the process is alive. + * + * @return true if the process is running, sleeping or idle + * @throws SystemInfoException + */ + public boolean isRunning() throws SystemInfoException { + boolean running = false; + if (ProcessInfo.this.procState != null) { + running = (ProcessInfo.this.procState.getState() == ProcState.RUN + || ProcessInfo.this.procState.getState() == ProcState.SLEEP || ProcessInfo.this.procState + .getState() == ProcState.IDLE); + + } + return running; + } + + } + + private static final Log LOG = LogFactory.getLog(ProcessInfo.class); + + // This interval was introduced because of a SIGAR bug: too close calls to getProcState could + // return different values even if the underlying process state has not changed. + private static final int REFRESH_INTERVAL_MILLIS = 1000 * 2; + + // This timeout should always be greater than the refresh interval as one thread which acquired the lock + // could be waiting for the refresh interval to elapse. This value is deliberately high because multiple + // threads could wait for the lock and each of them will also have to wait for the refresh interval to elapse. + private static final int REFRESH_LOCK_ACQUIRE_TIMEOUT_SECONDS = 30; + + private static final String UNKNOWN_PROCESS_NAME = "?"; + + private static final Set<String> MS_WINDOWS_TERMINATE_SIGNAL_NAMES = new HashSet<String>(); + static { + MS_WINDOWS_TERMINATE_SIGNAL_NAMES.add("INT"); + MS_WINDOWS_TERMINATE_SIGNAL_NAMES.add("KILL"); + MS_WINDOWS_TERMINATE_SIGNAL_NAMES.add("QUIT"); + MS_WINDOWS_TERMINATE_SIGNAL_NAMES.add("TERM"); + }
protected boolean initialized;
+ protected SigarProxy sigar; + // these are static - values remain for the life of this object protected long pid; protected String name; - protected String baseName; protected String[] commandLine; + protected Map<String, String> procEnv; + + // these are computed once with static data (purposely lazy in order to speed up discovery process) protected Map<String, String> environmentVariables; - protected SigarProxy sigar; + protected String baseName; + + // this one is computed once with non static data + protected ProcessInfo parentProcess;
// these are refreshed and may change during the life of the process + + /** + * @deprecated as of 4.6. To read this property call {@link #priorSnaphot()} and then corresponding method + * from the returned {@link ProcessInfoSnapshot}. + */ + @Deprecated protected ProcState procState; + + /** + * @deprecated as of 4.6. To read this property call {@link #priorSnaphot()} and then corresponding method + * from the returned {@link ProcessInfoSnapshot}. + */ + @Deprecated protected ProcExe procExe; + + /** + * @deprecated as of 4.6. To read this property call {@link #priorSnaphot()} and then corresponding method + * from the returned {@link ProcessInfoSnapshot}. + */ + @Deprecated protected ProcTime procTime; + + /** + * @deprecated as of 4.6. To read this property call {@link #priorSnaphot()} and then corresponding method + * from the returned {@link ProcessInfoSnapshot}. + */ + @Deprecated protected ProcMem procMem; + + /** + * @deprecated as of 4.6. To read this property call {@link #priorSnaphot()} and then corresponding method + * from the returned {@link ProcessInfoSnapshot}. + */ + @Deprecated protected ProcCpu procCpu; + + /** + * @deprecated as of 4.6. To read this property call {@link #priorSnaphot()} and then corresponding method + * from the returned {@link ProcessInfoSnapshot}. + */ + @Deprecated protected ProcFd procFd; + + /** + * @deprecated as of 4.6. To read this property call {@link #priorSnaphot()} and then corresponding method + * from the returned {@link ProcessInfoSnapshot}. + */ + @Deprecated protected ProcCred procCred; + + /** + * @deprecated as of 4.6. To read this property call {@link #priorSnaphot()} and then corresponding method + * from the returned {@link ProcessInfoSnapshot}. + */ + @Deprecated protected ProcCredName procCredName; - protected Map<String, String> procEnv; - protected transient ProcessInfo parentProcess; - protected transient boolean processDied;
+ // Set to true in handleSigarCallException + protected boolean processDied; + + // Set to true if a SIGAR permission error has already been logged private boolean loggedPermissionsError = false; - private static final String UNKNOWN = "?"; + + // The last snasphot of non static process properties + // In a future implementation a new snapshot will be created on each call to refresh + private ProcessInfoSnapshot snapshot = new ProcessInfoSnapshot(); + + private long nextRefreshTime = System.currentTimeMillis(); + + private ReentrantLock refreshLock = new ReentrantLock();
// useful for mocking this object, this is purposely not public protected ProcessInfo() { @@ -97,15 +289,58 @@ public class ProcessInfo { update(pid); }
+ /** + * Takes a fresh snapshot of non static properties of the underlying process + * + * @throws SystemInfoException + */ public void refresh() throws SystemInfoException { - update(this.pid); + // SIGAR has a bug: too close calls to getProcState could return different values even if the underlying + // process state has not changed. To be sure to get correct data, a lock and an interval were introduced. + // Calling threads must acquire the lock and then make sure the interval has elapsed before calling update. + boolean acquiredLock = false; + try { + acquiredLock = refreshLock.tryLock(REFRESH_LOCK_ACQUIRE_TIMEOUT_SECONDS, TimeUnit.SECONDS); + } catch (InterruptedException e) { + LOG.error("Thread interrupted while trying to acquire ProcessInfo[" + this.pid + "] refresh lock", e); + } + if (!acquiredLock) { + throw new RuntimeException("Could not acquire ProcessInfo[" + this.pid + "] refresh lock"); + } + try { + waitForNextRefreshTime(); + update(this.pid); + } finally { + nextRefreshTime = System.currentTimeMillis() + REFRESH_INTERVAL_MILLIS; + refreshLock.unlock(); + } + } + + private void waitForNextRefreshTime() { + for (;;) { + long timeToNextRefresh = nextRefreshTime - System.currentTimeMillis(); + if (timeToNextRefresh > 0) { + try { + Thread.sleep(timeToNextRefresh); + break; + } catch (InterruptedException ignore) { + } + } else { + break; + } + } }
+ // Refresh and update methods cannot be merged because subclasses may override refresh behavior + // and we can't be sure that instances will already be properly initialized. private void update(long pid) throws SystemInfoException { long startTime = System.currentTimeMillis(); try { + this.processDied = false;
+ // Get ProcState and ProcExe before static data as they can help to determine the name field in some cases. + ProcState procState = null; try { procState = sigar.getProcState(pid); @@ -138,7 +373,7 @@ public class ProcessInfo { try { this.procEnv = sigar.getProcEnv(pid); if (this.procEnv == null) { - log.debug("SIGAR returned a null environment for [" + this.baseName + "] process with pid [" + LOG.debug("SIGAR returned a null environment for [" + getBaseName() + "] process with pid [" + this.pid + "]."); } } catch (Exception e) { @@ -190,14 +425,39 @@ public class ProcessInfo { } catch (Exception e) { throw new SystemInfoException(e); } - if (log.isTraceEnabled()) { + if (LOG.isTraceEnabled()) { long elapsedTime = System.currentTimeMillis() - startTime; - log.trace("Retrieval of process info for pid " + pid + " took " + elapsedTime + " ms."); + LOG.trace("Retrieval of process info for pid " + pid + " took " + elapsedTime + " ms."); }
this.processDied = false; }
+ /** + * <p> + * Returns the last snasphot of the non static process properties. + * </p> + * <p> + * Caveat the returned may hold stale data has it was taken with previous SIGAR calls. + * Calling {@link #freshSnapshot()} instead is almost always a better idea. + * </p> + * + * @return a {@link ProcessInfoSnapshot} possibly holding stale data + */ + public ProcessInfoSnapshot priorSnaphot() { + return snapshot; + } + + /** + * Takes a fresh snapshot of the non static process properties. + * + * @return a fresh {@link ProcessInfoSnapshot} + */ + public ProcessInfoSnapshot freshSnapshot() { + refresh(); + return snapshot; + } + public void destroy() throws SystemInfoException { if (this.sigar instanceof Sigar) { try { @@ -215,7 +475,7 @@ public class ProcessInfo { return; }
- if (isWindows() && (this.pid == 0 || this.pid == 4)) { + if (OperatingSystem.IS_WIN32 && (this.pid == 0 || this.pid == 4)) { // On Windows, Pid 0 and Pid 4 are special Kernel processes (Pid 0 is the "System Idle Process" and Pid 4 is // the "System" process). For these processes, it's normal for many of the Sigar.getProc calls to fail, so // there's no need to log anything. @@ -227,29 +487,28 @@ public class ProcessInfo { if (!this.loggedPermissionsError) { // Only log permissions errors once per process. String currentUserName = System.getProperty("user.name"); - log - .trace("Unable to obtain all info for [" - + procName - + "] process with pid [" - + this.pid - + "] - call to " - + methodName - + "failed. " - + "The process is most likely owned by a user other than the user that owns the RHQ plugin container's process (" - + currentUserName + ")."); + LOG.trace("Unable to obtain all info for [" + + procName + + "] process with pid [" + + this.pid + + "] - call to " + + methodName + + "failed. " + + "The process is most likely owned by a user other than the user that owns the RHQ plugin container's process (" + + currentUserName + ")."); this.loggedPermissionsError = true; } } else if (e instanceof SigarNotImplementedException) { - log.trace("Unable to obtain all info for [" + procName + "] process with pid [" + this.pid + "] - call to " + LOG.trace("Unable to obtain all info for [" + procName + "] process with pid [" + this.pid + "] - call to " + methodName + "failed. Cause: " + e); } else { if (!exists()) { - log.debug("Attempt to refresh info for process with pid [" + this.pid - + "] failed, because the process is no longer running."); + LOG.debug("Attempt to refresh info for process with pid [" + this.pid + + "] failed, because the process is no longer running."); this.processDied = true; }
- log.debug("Unexpected error occurred while looking up info for [" + procName + "] process with pid [" + LOG.debug("Unexpected error occurred while looking up info for [" + procName + "] process with pid [" + this.pid + "] - call to " + methodName + " failed. Did the process die? Cause: " + e); } } @@ -260,7 +519,7 @@ public class ProcessInfo { pids = sigar.getProcList(); } catch (SigarException e1) { // TODO (ips, 04/30/12): It probably makes more sense to let this exception bubble up. - log.error("Failed to obtain process list.", e1); + LOG.error("Failed to obtain process list.", e1); return true; }
@@ -274,10 +533,6 @@ public class ProcessInfo { return foundProcess; }
- private static boolean isWindows() { - return File.separatorChar == '\'; - } - private String determineName(String[] procArgs, ProcExe procExe, ProcState procState) { String name; if ((procArgs != null) && (procArgs.length != 0)) { @@ -286,9 +541,10 @@ public class ProcessInfo { name = procExe.getName(); } else if ((procState != null) && (procState.getName() != null)) { String stateName = procState.getName(); - name = ((stateName.indexOf(File.separatorChar) >= 0) && (new File(stateName).exists())) ? stateName : UNKNOWN; + name = ((stateName.indexOf(File.separatorChar) >= 0) && (new File(stateName).exists())) ? stateName + : UNKNOWN_PROCESS_NAME; } else { - name = UNKNOWN; + name = UNKNOWN_PROCESS_NAME; } return name; } @@ -323,7 +579,7 @@ public class ProcessInfo { */ public String getBaseName() { if (baseName == null) { - baseName = (getName() != null) ? new File(getName()).getName() : UNKNOWN; + baseName = (getName() != null) ? new File(getName()).getName() : UNKNOWN_PROCESS_NAME; } return baseName; } @@ -361,82 +617,114 @@ public class ProcessInfo { * @return the environment value */ @Nullable - public String getEnvironmentVariable(@NotNull String name) { + public String getEnvironmentVariable(@NotNull + String name) { if (this.procEnv == null) { return null; } - SystemInfo systemInfo = SystemInfoFactory.createJavaSystemInfo(); boolean isWindows = systemInfo.getOperatingSystemType() == OperatingSystemType.WINDOWS; // Windows env names are case insensitive, so convert the specified name to all-caps before doing the lookup. return getEnvironmentVariables().get((isWindows) ? name.toUpperCase() : name); }
+ /** + * @deprecated as of 4.6. For similar purpose, call {@link #priorSnaphot()} and then corresponding method + * from the returned {@link ProcessInfoSnapshot}. + */ + @Deprecated public long getParentPid() throws SystemInfoException { - return (this.procState != null) ? this.procState.getPpid() : 0L; + return priorSnaphot().getParentPid(); }
+ /** + * @deprecated as of 4.6. For similar purpose, call {@link #priorSnaphot()} and then corresponding method + * from the returned {@link ProcessInfoSnapshot}. + */ + @Deprecated public ProcState getState() throws SystemInfoException { - return this.procState; + return priorSnaphot().getState(); }
+ /** + * @deprecated as of 4.6. For similar purpose, call {@link #priorSnaphot()} and then corresponding method + * from the returned {@link ProcessInfoSnapshot}. + */ + @Deprecated public ProcExe getExecutable() throws SystemInfoException { - return this.procExe; + return priorSnaphot().getExecutable(); }
+ /** + * @deprecated as of 4.6. For similar purpose, call {@link #priorSnaphot()} and then corresponding method + * from the returned {@link ProcessInfoSnapshot}. + */ + @Deprecated public ProcTime getTime() throws SystemInfoException { - return this.procTime; + return priorSnaphot().getTime(); }
+ /** + * @deprecated as of 4.6. For similar purpose, call {@link #priorSnaphot()} and then corresponding method + * from the returned {@link ProcessInfoSnapshot}. + */ + @Deprecated public ProcMem getMemory() throws SystemInfoException { - return this.procMem; + return priorSnaphot().getMemory(); }
+ /** + * @deprecated as of 4.6. For similar purpose, call {@link #priorSnaphot()} and then corresponding method + * from the returned {@link ProcessInfoSnapshot}. + */ + @Deprecated public ProcCpu getCpu() throws SystemInfoException { - return this.procCpu; + return priorSnaphot().getCpu(); }
+ /** + * @deprecated as of 4.6. For similar purpose, call {@link #priorSnaphot()} and then corresponding method + * from the returned {@link ProcessInfoSnapshot}. + */ + @Deprecated public ProcFd getFileDescriptor() throws SystemInfoException { - return this.procFd; + return priorSnaphot().getFileDescriptor(); }
+ /** + * @deprecated as of 4.6. For similar purpose, call {@link #priorSnaphot()} and then corresponding method + * from the returned {@link ProcessInfoSnapshot}. + */ + @Deprecated public ProcCred getCredentials() throws SystemInfoException { - return this.procCred; + return priorSnaphot().getCredentials(); }
+ /** + * @deprecated as of 4.6. For similar purpose, call {@link #priorSnaphot()} and then corresponding method + * from the returned {@link ProcessInfoSnapshot}. + */ + @Deprecated public ProcCredName getCredentialsName() throws SystemInfoException { - return this.procCredName; + return priorSnaphot().getCredentialsName(); }
/** - * @return null if process executable or cwd is unavailable. Otherwise the Cwd as returned from the - * process executable. - * @throws SystemInfoException + * @deprecated as of 4.6. For similar purpose, call {@link #priorSnaphot()} and then corresponding method + * from the returned {@link ProcessInfoSnapshot}. */ + @Deprecated public String getCurrentWorkingDirectory() throws SystemInfoException { - String result = null; - - try { - if (null != this.procExe) { - result = this.procExe.getCwd(); - } - } catch (Exception e) { - handleSigarCallException(e, "procExe.getCwd()"); - } - - return result; + return priorSnaphot().getCurrentWorkingDirectory(); }
+ /** + * @deprecated as of 4.6. For similar purpose, call {@link #priorSnaphot()} and then corresponding method + * from the returned {@link ProcessInfoSnapshot}. + */ + @Deprecated public boolean isRunning() throws SystemInfoException { - boolean running = false; - - if (this.procState != null) { - running = (this.procState.getState() == ProcState.RUN || this.procState.getState() == ProcState.SLEEP || this.procState - .getState() == ProcState.IDLE); - - } - - return running; + return priorSnaphot().isRunning(); }
/** @@ -450,13 +738,18 @@ public class ProcessInfo { }
/** - * Returns the parent process of this process. + * Returns a {@link ProcessInfo} instance for the parent of this process. + * + * This method uses the parent process id which is not static (it can change if the parent process dies before its + * child). So in theory it should be moved to the {@link ProcessInfoSnapshot} type. + * + * In practice, it stays here because the parent {@link ProcessInfo} instance is cached after creation. * * @since 4.4 */ public ProcessInfo getParentProcess() throws SystemInfoException { if (this.parentProcess == null) { - this.parentProcess = new ProcessInfo(getParentPid(), sigar); + this.parentProcess = new ProcessInfo(priorSnaphot().getParentPid(), sigar); } else { this.parentProcess.refresh(); } @@ -515,44 +808,32 @@ public class ProcessInfo { @Override public String toString() { StringBuilder s = new StringBuilder("process: "); - s.append("pid=["); s.append(getPid()); s.append("], name=["); - s.append((!getName().equals(UNKNOWN)) ? getName() : getBaseName()); + s.append((!getName().equals(UNKNOWN_PROCESS_NAME)) ? getName() : getBaseName()); s.append("], ppid=["); try { - s.append(getParentPid()); + s.append(priorSnaphot().getParentPid()); } catch (Exception e) { s.append(e); } - s.append("]"); - return s.toString(); }
- private static final Set<String> TERMINATE_SIGNAL_NAMES = new HashSet<String>(); - static { - TERMINATE_SIGNAL_NAMES.add("INT"); - TERMINATE_SIGNAL_NAMES.add("KILL"); - TERMINATE_SIGNAL_NAMES.add("QUIT"); - TERMINATE_SIGNAL_NAMES.add("TERM"); - } - private static int getSignalNumber(String signalName) { if (signalName == null) { throw new IllegalArgumentException("Signal name is null."); } - int signalNumber; if (OperatingSystem.IS_WIN32) { - if (TERMINATE_SIGNAL_NAMES.contains(signalName)) { + if (MS_WINDOWS_TERMINATE_SIGNAL_NAMES.contains(signalName)) { signalNumber = 1; } else { throw new IllegalArgumentException("Unsupported signal name: " + signalName - + " - on Windows, the only supported signal names are " + TERMINATE_SIGNAL_NAMES - + ", all of which return 1."); + + " - on Windows, the only supported signal names are " + MS_WINDOWS_TERMINATE_SIGNAL_NAMES + + ", all of which return 1."); } } else { signalNumber = Sigar.getSigNum(signalName); diff --git a/modules/core/native-system/src/test/java/org/rhq/core/system/ProcessInfoRefreshIntervalTest.java b/modules/core/native-system/src/test/java/org/rhq/core/system/ProcessInfoRefreshIntervalTest.java new file mode 100644 index 0000000..84944ef --- /dev/null +++ b/modules/core/native-system/src/test/java/org/rhq/core/system/ProcessInfoRefreshIntervalTest.java @@ -0,0 +1,175 @@ +/* + * 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.core.system; + +import static org.testng.Assert.assertFalse; +import static org.testng.Assert.assertTrue; + +import java.io.File; +import java.io.FileOutputStream; +import java.io.InputStream; +import java.io.OutputStream; +import java.util.LinkedList; +import java.util.List; +import java.util.concurrent.Callable; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; +import java.util.concurrent.Future; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.hyperic.sigar.OperatingSystem; +import org.testng.annotations.AfterTest; +import org.testng.annotations.BeforeTest; +import org.testng.annotations.Test; + +import org.rhq.core.util.stream.StreamUtil; + +/** + * @author Thomas Segismont + */ +public class ProcessInfoRefreshIntervalTest { + + private static final Log LOG = LogFactory.getLog(ProcessInfoRefreshIntervalTest.class); + + private static final String KNOWN_ARG = "hellosigar"; + + private Process testProcess; + + private ProcessInfo testProcessInfo; + + private ExecutorService executorService; + + @BeforeTest(alwaysRun = true) + public void setup() throws Exception { + testProcess = createTestProcess(); + if (!isAlive(testProcess)) { + throw new RuntimeException("Test process is not alive"); + } + NativeSystemInfo systemInfo = new NativeSystemInfo(); + List<ProcessInfo> foundProcesses = systemInfo.getProcesses("arg|" + KNOWN_ARG + "|match=.*"); + if (foundProcesses.size() != 1) { + throw new RuntimeException("Found " + foundProcesses.size() + " with arg [" + KNOWN_ARG + "]"); + } + testProcessInfo = foundProcesses.iterator().next(); + int threadCount = Runtime.getRuntime().availableProcessors(); + executorService = Executors.newFixedThreadPool(threadCount); + if (LOG.isDebugEnabled()) { + LOG.debug("Created an executor service with " + threadCount + " threads"); + } + } + + private Process createTestProcess() throws Exception { + if (OperatingSystem.IS_WIN32) { + // On Windows run a simple bat file which behaves like 'watch echo' + File batFile = File.createTempFile("win-watch-echo", ".bat"); + batFile.deleteOnExit(); + InputStream is = getClass().getClassLoader().getResourceAsStream("org/rhq/core/system/win-watch-echo.bat"); + OutputStream os = new FileOutputStream(batFile); + StreamUtil.copy(is, os, true); + ProcessBuilder processBuilder = new ProcessBuilder("cmd", batFile.getAbsolutePath(), KNOWN_ARG); + return processBuilder.start(); + } else { + // On other systems run a simple bash file which behaves like 'watch echo' + File bashFile = File.createTempFile("bash-watch-echo", ".sh"); + bashFile.deleteOnExit(); + InputStream is = getClass().getClassLoader().getResourceAsStream("org/rhq/core/system/bash-watch-echo.sh"); + OutputStream os = new FileOutputStream(bashFile); + StreamUtil.copy(is, os, true); + ProcessBuilder processBuilder = new ProcessBuilder("bash", bashFile.getAbsolutePath(), KNOWN_ARG); + return processBuilder.start(); + } + } + + @AfterTest(alwaysRun = true) + public void tearDown() { + if (testProcess != null) { + testProcess.destroy(); + testProcess = null; + } + testProcessInfo = null; + if (executorService != null) { + executorService.shutdownNow(); + } + } + + /** + * We want to be sure that conccurent calls to refresh method will result in correct process state + * detection - see comments in {@link ProcessInfo#refresh()}. + * @throws Exception + */ + @Test(timeOut = 1000 * 60) + public void testRefreshInterval() throws Exception { + // Create and execute tasks which will ask a freshSnapshot of the processInfo and check if it is running + List<Future<Boolean>> futures = submitStateTestingTasks(); + for (Future<Boolean> future : futures) { + // All tasks should see the process running + assertTrue(future.get()); + } + // Send kill + testProcess.destroy(); + // Wait for death + while (isAlive(testProcess)) { + Thread.sleep(100); + } + // Create and execute tasks again + futures = submitStateTestingTasks(); + for (Future<Boolean> future : futures) { + // All tasks should now see the process down + assertFalse(future.get()); + } + } + + private List<Future<Boolean>> submitStateTestingTasks() { + List<Future<Boolean>> futures = new LinkedList<Future<Boolean>>(); + for (int i = 0; i < 5; i++) { + final int index = i; + futures.add(executorService.submit(new Callable<Boolean>() { + + @Override + public Boolean call() throws Exception { + if (LOG.isDebugEnabled()) { + LOG.debug("Execute state testing task[" + index + "]"); + } + boolean isRunning = testProcessInfo.freshSnapshot().isRunning(); + if (LOG.isDebugEnabled()) { + LOG.debug("State testing task[" + index + "] result: " + isRunning); + } + return isRunning; + } + })); + } + return futures; + } + + private boolean isAlive(Process process) { + if (process == null) { + return false; + } + try { + process.exitValue(); + return false; + } catch (IllegalThreadStateException e) { + return true; + } + } + +} diff --git a/modules/core/native-system/src/test/resources/org/rhq/core/system/bash-watch-echo.sh b/modules/core/native-system/src/test/resources/org/rhq/core/system/bash-watch-echo.sh new file mode 100644 index 0000000..7d0f4c0 --- /dev/null +++ b/modules/core/native-system/src/test/resources/org/rhq/core/system/bash-watch-echo.sh @@ -0,0 +1,7 @@ +#!/bin/bash + +while : +do + echo $1 + sleep 1 +done diff --git a/modules/core/native-system/src/test/resources/org/rhq/core/system/win-watch-echo.bat b/modules/core/native-system/src/test/resources/org/rhq/core/system/win-watch-echo.bat new file mode 100644 index 0000000..4404159 --- /dev/null +++ b/modules/core/native-system/src/test/resources/org/rhq/core/system/win-watch-echo.bat @@ -0,0 +1,5 @@ +@ECHO OFF +:loop + echo %1 + timeout /t 2 +goto loop diff --git a/modules/core/plugin-api/src/main/java/org/rhq/core/pluginapi/inventory/ResourceContext.java b/modules/core/plugin-api/src/main/java/org/rhq/core/pluginapi/inventory/ResourceContext.java index 76ccf39..16d7bbc 100644 --- a/modules/core/plugin-api/src/main/java/org/rhq/core/pluginapi/inventory/ResourceContext.java +++ b/modules/core/plugin-api/src/main/java/org/rhq/core/pluginapi/inventory/ResourceContext.java @@ -310,6 +310,9 @@ public class ResourceContext<T extends ResourceComponent<?>> { * Returns the information on the native operating system process in which the managed resource is running. If * native support is not available or the process for some reason can no longer be found, this may return <code> * null</code>. + * + * The returned {@link ProcessInfo} always has a fresh snapshot of non static data: it's whether newly created + * or got refreshed in order to determine if the process was still running. * * @return information on the resource's process */ @@ -350,9 +353,9 @@ public class ResourceContext<T extends ResourceComponent<?>> {
details = this.resourceDiscoveryComponent.discoverResources(context); } - + trackedProcesses.update(details); - processInfo = trackedProcesses.getProcessInfo(resourceKey); + processInfo = trackedProcesses.getProcessInfo(resourceKey); } catch (Exception e) { LOG.warn("Cannot get native process for resource [" + this.resourceKey + "] - discovery failed", e); } @@ -366,22 +369,8 @@ public class ResourceContext<T extends ResourceComponent<?>> { return processInfo; }
- /** - * @param processInfo - * @return - */ private boolean isRediscoveryRequired(ProcessInfo processInfo) { - boolean rediscover = processInfo == null; - - if (!rediscover) { - //if the process info thinks the process is running, - //refresh it to check its facts again - if (processInfo.isRunning()) { - processInfo.refresh(); - } - rediscover = !processInfo.isRunning(); - } - return rediscover; + return processInfo == null || !processInfo.freshSnapshot().isRunning(); }
/** @@ -519,6 +508,7 @@ public class ResourceContext<T extends ResourceComponent<?>> { /** * @deprecated Use {@link AvailabilityContext#createAvailabilityCollectorRunnable(AvailabilityFacet, long)} */ + @Deprecated public AvailabilityCollectorRunnable createAvailabilityCollectorRunnable(AvailabilityFacet availChecker, long interval) {
diff --git a/modules/integration-tests/apache-plugin-test/src/test/java/org/rhq/plugins/apache/util/ApacheExecutionUtil.java b/modules/integration-tests/apache-plugin-test/src/test/java/org/rhq/plugins/apache/util/ApacheExecutionUtil.java index 64ab1c0..53f7f0c 100644 --- a/modules/integration-tests/apache-plugin-test/src/test/java/org/rhq/plugins/apache/util/ApacheExecutionUtil.java +++ b/modules/integration-tests/apache-plugin-test/src/test/java/org/rhq/plugins/apache/util/ApacheExecutionUtil.java @@ -185,8 +185,7 @@ public class ApacheExecutionUtil { OperationResult res = serverComponent.invokeOperation(operation, new Configuration());
LOG.debug("Invoked operation '" + operation + "' on " + resourceContext.getResourceKey() + " (waiting for " - + desiredState + "), attempt " + i + ": " - + res.getComplexResults().getMap().toString()); + + desiredState + "), attempt " + i + ": " + res.getComplexResults().getMap().toString());
//wait for max 30s for the operation to "express" itself int w = 0; @@ -212,7 +211,11 @@ public class ApacheExecutionUtil {
++i;
- LOG.warn("Could not detect the httpd process after invoking the start operation but the operation didn't throw any exception. I will retry at most ten times and then fail loudly. This has been attempt no. " + LOG.warn("httpd process is in an unexpected state after invoking the '" + + operation + + "' operation on " + + resourceContext.getResourceKey() + + " but the operation didn't throw any exception. I will retry at most ten times and then fail loudly. This has been attempt no. " + i); }
diff --git a/modules/plugins/cassandra/src/main/java/org/rhq/plugins/cassandra/CassandraNodeComponent.java b/modules/plugins/cassandra/src/main/java/org/rhq/plugins/cassandra/CassandraNodeComponent.java index 5f22f83..efecc27 100644 --- a/modules/plugins/cassandra/src/main/java/org/rhq/plugins/cassandra/CassandraNodeComponent.java +++ b/modules/plugins/cassandra/src/main/java/org/rhq/plugins/cassandra/CassandraNodeComponent.java @@ -54,6 +54,7 @@ import org.rhq.core.pluginapi.util.ProcessExecutionUtility; import org.rhq.core.system.ProcessExecution; import org.rhq.core.system.ProcessExecutionResults; import org.rhq.core.system.ProcessInfo; +import org.rhq.core.system.ProcessInfo.ProcessInfoSnapshot; import org.rhq.core.system.SystemInfo; import org.rhq.core.util.exception.ThrowableUtil; import org.rhq.plugins.jmx.JMXServerComponent; @@ -73,10 +74,14 @@ public class CassandraNodeComponent extends JMXServerComponent<ResourceComponent
if (processInfo == null) { return UNKNOWN; - } else if (processInfo.isRunning()) { - return UP; } else { - return DOWN; + // It is safe to read prior snapshot as getNativeProcess always return a fresh instance + ProcessInfoSnapshot processInfoSnaphot = processInfo.priorSnaphot(); + if (processInfoSnaphot.isRunning()) { + return UP; + } else { + return DOWN; + } } }
diff --git a/modules/plugins/hadoop/src/main/java/org/rhq/plugins/hadoop/HadoopServerComponent.java b/modules/plugins/hadoop/src/main/java/org/rhq/plugins/hadoop/HadoopServerComponent.java index c3a590c..ef1c8c5 100644 --- a/modules/plugins/hadoop/src/main/java/org/rhq/plugins/hadoop/HadoopServerComponent.java +++ b/modules/plugins/hadoop/src/main/java/org/rhq/plugins/hadoop/HadoopServerComponent.java @@ -33,7 +33,6 @@ import org.mc4j.ems.connection.bean.attribute.EmsAttribute; import org.rhq.core.domain.configuration.Configuration; import org.rhq.core.domain.configuration.ConfigurationUpdateStatus; import org.rhq.core.domain.measurement.AvailabilityType; -import org.rhq.core.domain.measurement.DataType; import org.rhq.core.domain.measurement.MeasurementDataNumeric; import org.rhq.core.domain.measurement.MeasurementDataTrait; import org.rhq.core.domain.measurement.MeasurementDefinition; @@ -52,8 +51,6 @@ 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.system.ProcessInfo; -import org.rhq.plugins.hadoop.calltime.HadoopEventAndCalltimeDelegate; -import org.rhq.plugins.hadoop.calltime.JobSummary; import org.rhq.plugins.jmx.JMXComponent; import org.rhq.plugins.jmx.JMXServerComponent;
@@ -61,18 +58,18 @@ public class HadoopServerComponent extends JMXServerComponent<ResourceComponent< JMXComponent<ResourceComponent<?>>, MeasurementFacet, OperationFacet, ConfigurationFacet {
private static final Log LOG = LogFactory.getLog(HadoopServerComponent.class); - + public static final String LOG_EVENT_TYPE = "logEntry"; public static final String LOG_POLLING_INTERVAL_PROPERTY = "logPollingInterval"; - + private Map<String, Boolean> percentageMeasurements; - + private HadoopServerConfigurationDelegate configurationDelegate; - + private HadoopOperationsDelegate operationsDelegate;
private boolean eventsRegistered; - + @Override @SuppressWarnings({ "rawtypes", "unchecked" }) public void start(ResourceContext context) throws Exception { @@ -84,10 +81,11 @@ public class HadoopServerComponent extends JMXServerComponent<ResourceComponent< Set<MeasurementDefinition> measDefinitions = context.getResourceType().getMetricDefinitions(); percentageMeasurements = new HashMap<String, Boolean>(measDefinitions.size()); for (MeasurementDefinition measDefinition : measDefinitions) { - percentageMeasurements.put(measDefinition.getName(), MeasurementUnits.PERCENTAGE.equals(measDefinition.getUnits())); + percentageMeasurements.put(measDefinition.getName(), + MeasurementUnits.PERCENTAGE.equals(measDefinition.getUnits())); } } - + @Override public void stop() { EventContext events = getResourceContext().getEventContext(); @@ -98,7 +96,7 @@ public class HadoopServerComponent extends JMXServerComponent<ResourceComponent< } super.stop(); } - + /** * Return availability of this resource * @see org.rhq.core.pluginapi.inventory.ResourceComponent#getAvailability() @@ -106,15 +104,18 @@ public class HadoopServerComponent extends JMXServerComponent<ResourceComponent< @Override public AvailabilityType getAvailability() { ProcessInfo process = getResourceContext().getNativeProcess(); - - AvailabilityType ret = process == null ? AvailabilityType.DOWN : (process.isRunning() ? AvailabilityType.UP : AvailabilityType.DOWN); - + + // It is safe to read prior snapshot as getNativeProcess always return a fresh instance + AvailabilityType ret = process == null ? AvailabilityType.DOWN + : (process.priorSnaphot().isRunning() ? AvailabilityType.UP : AvailabilityType.DOWN); + EventContext events = getResourceContext().getEventContext(); if (events != null) { if (ret == AvailabilityType.UP) { if (!eventsRegistered) { File logFile = determineLogFile(); - int interval = Integer.parseInt(getResourceContext().getPluginConfiguration().getSimpleValue(LOG_POLLING_INTERVAL_PROPERTY, "60")); + int interval = Integer.parseInt(getResourceContext().getPluginConfiguration().getSimpleValue( + LOG_POLLING_INTERVAL_PROPERTY, "60")); events.registerEventPoller(createNewEventPoller(events, logFile), interval); eventsRegistered = true; } @@ -124,7 +125,7 @@ public class HadoopServerComponent extends JMXServerComponent<ResourceComponent< discardPoller(); } } - + return ret; }
@@ -148,7 +149,7 @@ public class HadoopServerComponent extends JMXServerComponent<ResourceComponent< handleMetric(report, request); } } - + protected void handleMetric(MeasurementReport report, MeasurementScheduleRequest request) throws Exception { String name = request.getName(); int delimIndex = name.lastIndexOf(':'); @@ -169,7 +170,7 @@ public class HadoopServerComponent extends JMXServerComponent<ResourceComponent< } else { report.addData(new MeasurementDataNumeric(request, value.doubleValue())); } - + } else { report.addData(new MeasurementDataTrait(request, valueObject.toString())); } @@ -183,14 +184,14 @@ public class HadoopServerComponent extends JMXServerComponent<ResourceComponent< LOG.error("Failed to obtain measurement [" + name + "]", e); } } - + @Override public Configuration loadResourceConfiguration() throws Exception { return configurationDelegate.loadConfiguration(); }
@Override - public void updateResourceConfiguration(ConfigurationUpdateReport report) { + public void updateResourceConfiguration(ConfigurationUpdateReport report) { try { Configuration updatedConfiguration = report.getConfiguration(); configurationDelegate.updateConfiguration(updatedConfiguration); @@ -218,37 +219,38 @@ public class HadoopServerComponent extends JMXServerComponent<ResourceComponent< } return result; } - + protected EventPoller createNewEventPoller(EventContext eventContext, File logFile) { - return new LogFileEventPoller(eventContext, LOG_EVENT_TYPE, logFile, new Log4JLogEntryProcessor(LOG_EVENT_TYPE, logFile)); + return new LogFileEventPoller(eventContext, LOG_EVENT_TYPE, logFile, new Log4JLogEntryProcessor(LOG_EVENT_TYPE, + logFile)); } - + protected void discardPoller() { - + } - + private File determineLogFile() { String username = getResourceContext().getNativeProcess().getCredentialsName().getUser(); String hostname = getResourceContext().getSystemInformation().getHostname(); - + String serverType = getServerType(); - + String name = "hadoop-" + username + "-" + serverType + "-" + hostname + ".log"; - + return new File(new File(getHomeDir(), "logs"), name); } - + private String getServerType() { String mainClass = getResourceContext().getPluginConfiguration().getSimpleValue("_mainClass"); int dot = mainClass.lastIndexOf('.'); String className = mainClass.substring(dot + 1); - + return className.toLowerCase(); } - + protected File getHomeDir() { - File homeDir = - new File(getResourceContext().getPluginConfiguration().getSimpleValue(HadoopServerDiscovery.HOME_DIR_PROPERTY)); + File homeDir = new File(getResourceContext().getPluginConfiguration().getSimpleValue( + HadoopServerDiscovery.HOME_DIR_PROPERTY));
if (!homeDir.exists()) { throw new IllegalArgumentException("The configured home directory of this Hadoop instance (" @@ -266,5 +268,5 @@ public class HadoopServerComponent extends JMXServerComponent<ResourceComponent< }
return homeDir; - } + } } diff --git a/modules/plugins/mysql/src/main/java/org/rhq/plugins/mysql/MySqlComponent.java b/modules/plugins/mysql/src/main/java/org/rhq/plugins/mysql/MySqlComponent.java index f1a16e4..9d7169e 100644 --- a/modules/plugins/mysql/src/main/java/org/rhq/plugins/mysql/MySqlComponent.java +++ b/modules/plugins/mysql/src/main/java/org/rhq/plugins/mysql/MySqlComponent.java @@ -178,7 +178,7 @@ public class MySqlComponent implements DatabaseComponent<ResourceComponent<?>>, private AggregateProcessInfo findProcessInfo() { AggregateProcessInfo result = null; // is still running reuse - if (aggregateProcessInfo != null && aggregateProcessInfo.isRunning()) { + if (aggregateProcessInfo != null && aggregateProcessInfo.freshSnapshot().isRunning()) { result = aggregateProcessInfo; } else { long pid = findPID(); diff --git a/modules/plugins/platform/src/main/java/org/rhq/plugins/platform/ProcessComponent.java b/modules/plugins/platform/src/main/java/org/rhq/plugins/platform/ProcessComponent.java index c85ec42..a53b678 100644 --- a/modules/plugins/platform/src/main/java/org/rhq/plugins/platform/ProcessComponent.java +++ b/modules/plugins/platform/src/main/java/org/rhq/plugins/platform/ProcessComponent.java @@ -1,6 +1,6 @@ /* * RHQ Management Platform - * Copyright (C) 2005-2008 Red Hat, Inc. + * Copyright (C) 2005-2012 Red Hat, Inc. * All rights reserved. * * This program is free software; you can redistribute it and/or modify @@ -42,6 +42,7 @@ import org.rhq.core.pluginapi.inventory.ResourceContext; import org.rhq.core.pluginapi.measurement.MeasurementFacet; import org.rhq.core.system.AggregateProcessInfo; import org.rhq.core.system.ProcessInfo; +import org.rhq.core.system.ProcessInfo.ProcessInfoSnapshot; import org.rhq.core.system.SystemInfo; import org.rhq.core.util.exception.ThrowableUtil;
@@ -97,7 +98,14 @@ public class ProcessComponent implements ResourceComponent, MeasurementFacet { @Override public AvailabilityType getAvailability() { try { - return getProcess().isRunning() ? AvailabilityType.UP : AvailabilityType.DOWN; + // Get a fresh snapshot of the process + ProcessInfoSnapshot processInfoSnapshot = (this.process == null) ? null : this.process.freshSnapshot(); + if (processInfoSnapshot == null || !processInfoSnapshot.isRunning()) { + this.process = getProcessForConfiguration(); + // Safe to get prior snapshot here, we've just recreated the process info instance + processInfoSnapshot = (this.process == null) ? null : this.process.priorSnaphot(); + } + return processInfoSnapshot.isRunning() ? AvailabilityType.UP : AvailabilityType.DOWN; } catch (Exception e) { if (log.isDebugEnabled()) { log.debug("failed to get process info: " + ThrowableUtil.getAllMessages(e)); @@ -106,21 +114,6 @@ public class ProcessComponent implements ResourceComponent, MeasurementFacet { } }
- private ProcessInfo getProcess() throws Exception { - if (this.process != null && this.process.isRunning()) { - // Refresh existing ProcessInfo when underlying process is apparently running. - // ProcessInfo may hold stale data. - // SIGAR objects do not get updated when a process goes down. - this.process.refresh(); - } - if (this.process == null || !this.process.isRunning()) { - // Create ProcessInfo for the first time or when the underlying process is no longer running. - // When a process is no longer running we need to make a new PIQL or pid file discovery. - this.process = getProcessForConfiguration(); - } - return this.process; - } - private ProcessInfo getProcessForConfiguration() throws Exception { SystemInfo sysInfo = this.resourceContext.getSystemInformation(); return getProcessForConfiguration(this.type, this.pidFile, this.piql, this.fullProcessTree, sysInfo); diff --git a/modules/plugins/sshd/src/main/java/org/rhq/plugins/sshd/OpenSSHDComponent.java b/modules/plugins/sshd/src/main/java/org/rhq/plugins/sshd/OpenSSHDComponent.java index 3cbe5b2..ec518aa 100644 --- a/modules/plugins/sshd/src/main/java/org/rhq/plugins/sshd/OpenSSHDComponent.java +++ b/modules/plugins/sshd/src/main/java/org/rhq/plugins/sshd/OpenSSHDComponent.java @@ -1,6 +1,6 @@ /* * RHQ Management Platform - * Copyright (C) 2005-2008 Red Hat, Inc. + * Copyright (C) 2005-2012 Red Hat, Inc. * All rights reserved. * * This program is free software; you can redistribute it and/or modify @@ -28,6 +28,9 @@ import java.util.Set;
import net.augeas.Augeas;
+import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; + import org.rhq.core.domain.configuration.Configuration; import org.rhq.core.domain.configuration.PropertyList; import org.rhq.core.domain.configuration.PropertyMap; @@ -52,37 +55,62 @@ import org.rhq.core.pluginapi.util.ObjectUtil; import org.rhq.core.system.AggregateProcessInfo; import org.rhq.core.system.NetworkStats; import org.rhq.core.system.ProcessInfo; +import org.rhq.core.system.ProcessInfo.ProcessInfoSnapshot; +import org.rhq.core.util.exception.ThrowableUtil;
/** * @author Greg Hinkle */ public class OpenSSHDComponent implements ResourceComponent, ConfigurationFacet, MeasurementFacet {
+ private static final Log log = LogFactory.getLog(OpenSSHDComponent.class); + private ResourceContext resourceContext; private AggregateProcessInfo processInfo;
+ @Override public void start(ResourceContext resourceContext) throws InvalidPluginConfigurationException, Exception { this.resourceContext = resourceContext; - getSSHDProcess(); + this.processInfo = getSSHDProcess(); }
+ @Override public void stop() { }
+ @Override public AvailabilityType getAvailability() { - return (processInfo != null && processInfo.isRunning()) ? AvailabilityType.UP : AvailabilityType.DOWN; + try { + // Get a fresh snapshot of the process + ProcessInfoSnapshot processInfoSnapshot = (this.processInfo == null) ? null : this.processInfo + .freshSnapshot(); + if (processInfoSnapshot == null || !processInfoSnapshot.isRunning()) { + this.processInfo = getSSHDProcess(); + // Safe to get prior snapshot here, we've just recreated the process info instance + processInfoSnapshot = (this.processInfo == null) ? null : this.processInfo.priorSnaphot(); + } + return (this.processInfo != null && processInfoSnapshot.isRunning()) ? AvailabilityType.UP + : AvailabilityType.DOWN; + } catch (Exception e) { + if (log.isDebugEnabled()) { + log.debug("failed to get availability: " + ThrowableUtil.getAllMessages(e)); + } + return AvailabilityType.DOWN; + } }
- private void getSSHDProcess() { + private AggregateProcessInfo getSSHDProcess() {
List<ProcessInfo> procs = resourceContext.getSystemInformation().getProcesses( "process|basename|match=sshd,process|basename|nomatch|parent=sshd");
if (procs.size() == 1) { - this.processInfo = procs.get(0).getAggregateProcessTree(); + return procs.get(0).getAggregateProcessTree(); } + return null; }
+ @Override public Configuration loadResourceConfiguration() throws Exception { Configuration pluginConfiguration = resourceContext.getPluginConfiguration(); ConfigurationDefinition resourceConfigurationDefinition = resourceContext.getResourceType() @@ -172,8 +200,7 @@ public class OpenSSHDComponent implements ResourceComponent, ConfigurationFacet, // This very hackish bit of code is to suport the list-of-maps standard with a single simple definition in the map PropertyDefinitionList listDef = ((PropertyDefinitionList) p); PropertyDefinitionMap mapDef = ((PropertyDefinitionMap) listDef.getMemberDefinition()); - PropertyDefinitionSimple simpleDef = (PropertyDefinitionSimple) mapDef.getPropertyDefinitions() - .get(0); + PropertyDefinitionSimple simpleDef = (PropertyDefinitionSimple) mapDef.getPropertyDefinitions().get(0); String name = simpleDef.getName();
List<String> allValues = new ArrayList<String>(); @@ -196,9 +223,11 @@ public class OpenSSHDComponent implements ResourceComponent, ConfigurationFacet, return config; }
+ @Override public void updateResourceConfiguration(ConfigurationUpdateReport report) { }
+ @Override public void getValues(MeasurementReport report, Set<MeasurementScheduleRequest> metrics) throws Exception { NetworkStats stats = resourceContext.getSystemInformation().getNetworkStats("localhost", 22); processInfo.refresh();
commit d65b4e4ce17fe7ad97b8634971490395c2521261 Author: Jirka Kremser jkremser@redhat.com Date: Thu Jan 24 16:27:28 2013 +0100
refactoring: renaming class "ResourceResourceAgentView" to "ResourceAgentView"
diff --git a/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/inventory/resource/detail/ResourceDetailView.java b/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/inventory/resource/detail/ResourceDetailView.java index 28ca7ab..e67d697 100644 --- a/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/inventory/resource/detail/ResourceDetailView.java +++ b/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/inventory/resource/detail/ResourceDetailView.java @@ -65,7 +65,7 @@ import org.rhq.enterprise.gui.coregui.client.inventory.resource.detail.configura import org.rhq.enterprise.gui.coregui.client.inventory.resource.detail.configuration.ResourceConfigurationHistoryListView; import org.rhq.enterprise.gui.coregui.client.inventory.resource.detail.inventory.PluginConfigurationEditView; import org.rhq.enterprise.gui.coregui.client.inventory.resource.detail.inventory.PluginConfigurationHistoryListView; -import org.rhq.enterprise.gui.coregui.client.inventory.resource.detail.inventory.ResourceResourceAgentView; +import org.rhq.enterprise.gui.coregui.client.inventory.resource.detail.inventory.ResourceAgentView; import org.rhq.enterprise.gui.coregui.client.inventory.resource.detail.monitoring.CalltimeView; import org.rhq.enterprise.gui.coregui.client.inventory.resource.detail.monitoring.avail.ResourceAvailabilityView; import org.rhq.enterprise.gui.coregui.client.inventory.resource.detail.monitoring.schedules.ResourceSchedulesView; @@ -384,7 +384,7 @@ public class ResourceDetailView extends AbstractTwoLevelTabSetView<ResourceCompo viewFactory = (!enabled) ? null : new ViewFactory() { @Override public Canvas createView() { - return new ResourceResourceAgentView(inventoryTab.extendLocatorId("AgentView"), resourceId); + return new ResourceAgentView(inventoryTab.extendLocatorId("AgentView"), resourceId); } }; updateSubTab(this.inventoryTab, this.inventoryAgent, true, enabled, viewFactory); diff --git a/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/inventory/resource/detail/inventory/ResourceAgentView.java b/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/inventory/resource/detail/inventory/ResourceAgentView.java new file mode 100644 index 0000000..5c91365 --- /dev/null +++ b/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/inventory/resource/detail/inventory/ResourceAgentView.java @@ -0,0 +1,216 @@ +/* + * RHQ Management Platform + * Copyright (C) 2005-2010 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.enterprise.gui.coregui.client.inventory.resource.detail.inventory; + +import java.util.ArrayList; +import java.util.Date; +import java.util.List; + +import com.google.gwt.user.client.rpc.AsyncCallback; +import com.smartgwt.client.widgets.Canvas; +import com.smartgwt.client.widgets.form.fields.FormItem; +import com.smartgwt.client.widgets.form.fields.FormItemIcon; +import com.smartgwt.client.widgets.form.fields.HeaderItem; +import com.smartgwt.client.widgets.form.fields.SpacerItem; +import com.smartgwt.client.widgets.form.fields.StaticTextItem; + +import org.rhq.core.domain.resource.Agent; +import org.rhq.enterprise.gui.coregui.client.CoreGUI; +import org.rhq.enterprise.gui.coregui.client.ImageManager; +import org.rhq.enterprise.gui.coregui.client.RefreshableView; +import org.rhq.enterprise.gui.coregui.client.admin.topology.AgentTableView; +import org.rhq.enterprise.gui.coregui.client.gwt.GWTServiceLookup; +import org.rhq.enterprise.gui.coregui.client.util.StringUtility; +import org.rhq.enterprise.gui.coregui.client.util.selenium.LocatableDynamicForm; +import org.rhq.enterprise.gui.coregui.client.util.selenium.LocatableVLayout; +import org.rhq.enterprise.gui.coregui.client.util.selenium.SeleniumUtility; + +/** + * The content pane for the Resource Inventory>Agent subtab. + * + * @author Simeon Pinder + */ +public class ResourceAgentView extends LocatableVLayout implements RefreshableView { + + private int resourceId; + private LocatableDynamicForm form; + private StaticTextItem nameValue; + private StaticTextItem addressValue; + private StaticTextItem portValue; + private FormItemIcon agentStatusIcon; + private StaticTextItem lastAvailReportValue; + private StaticTextItem lastAvailPingValue; + private StaticTextItem endpointValue; + private StaticTextItem topologyViewItem; + + private boolean loading = false; // will be true if loadData is currently waiting for responses + + public ResourceAgentView(String locatorId, int resourceId) { + super(locatorId); + + this.resourceId = resourceId; + } + + @Override + protected void onDraw() { + super.onDraw(); + + setLeft("10%"); + setWidth("80%"); + + this.form = new LocatableDynamicForm(extendLocatorId("Agent_Info")); + final List<FormItem> formItems = createFormItems(); + this.form.setItems(formItems.toArray(new FormItem[formItems.size()])); + loadData(); + this.addMember(this.form); + } + + @Override + public void refresh() { + loadData(); + } + + private List<FormItem> createFormItems() { + final List<FormItem> formItems = new ArrayList<FormItem>(); + HeaderItem headerItem = new HeaderItem("header", MSG.view_inventory_summary_agent_title()); + headerItem.setValue(MSG.view_inventory_summary_agent_title()); + formItems.add(headerItem); + formItems.add(new SpacerItem()); + + // Name + nameValue = new StaticTextItem("name", MSG.common_title_name()); + formItems.add(nameValue); + + // Address + String address = "address"; + addressValue = new StaticTextItem(address, MSG.common_title_address()); + formItems.add(addressValue); + + // Port + String port = "port"; + portValue = new StaticTextItem(port, MSG.common_title_port()); + formItems.add(portValue); + + // Agent Status + agentStatusIcon = new FormItemIcon(); + agentStatusIcon.setSrc(ImageManager.getAvailabilityLargeIcon(null)); + StaticTextItem agentStatus = new StaticTextItem("agent-comm-status", MSG + .view_inventory_summary_agent_status_title()); + agentStatus.setIcons(agentStatusIcon); + agentStatus.setWrapTitle(false); + formItems.add(agentStatus); + + // Last Received Avail report + String lastAvailReport = "last-avail-report"; + lastAvailReportValue = new StaticTextItem(lastAvailReport, MSG.view_inventory_summary_agent_last_title()); + lastAvailReportValue.setWrapTitle(false); + formItems.add(lastAvailReportValue); + + // Last Received Avail ping + lastAvailPingValue = new StaticTextItem("last-avail-ping", MSG.view_adminTopology_agent_lastAvailabilityPing()); + lastAvailPingValue.setWrapTitle(false); + formItems.add(lastAvailPingValue); + + // Full Endpoint + String fullEndpoint = "full-endpoint"; + endpointValue = new StaticTextItem(fullEndpoint, MSG.view_inventory_summary_agent_fullEnpoint()); + formItems.add(endpointValue); + + // link to agent topology view + String topologyView = "topology-view"; + topologyViewItem = new StaticTextItem("topology-view", MSG.view_admin_topology()); + formItems.add(topologyViewItem); + + return formItems; + } + + private void loadData() { + if (loading) { + return; // we are already loading and waiting for data, no need to re-issue the same queries + } + loading = true; + + GWTServiceLookup.getAgentService().getAgentForResource(this.resourceId, new AsyncCallback<Agent>() { + @Override + public void onFailure(Throwable caught) { + loading = false; + //Permissions failure, generate message to that effect + for (Canvas child : form.getChildren()) { + child.destroy(); + } + + HeaderItem headerItem = new HeaderItem("header", MSG.view_inventory_summary_agent_title()); + headerItem.setValue(MSG.view_inventory_summary_agent_title()); + StaticTextItem permissionsMessage = new StaticTextItem("permissions", "permissionsFailure"); + permissionsMessage.setShowTitle(false); + permissionsMessage.setValue(MSG.view_inventory_summary_agent_error3()); + permissionsMessage.setWrap(false); + form.setFields(headerItem, new SpacerItem(), permissionsMessage); + form.markForRedraw(); + } + + @Override + public void onSuccess(Agent agent) { + GWTServiceLookup.getAgentService().pingAgentForResource(resourceId, new AsyncCallback<Boolean>() { + @Override + public void onFailure(Throwable caught) { + loading = false; + CoreGUI.getErrorHandler().handleError( + MSG.view_inventory_summary_agent_error2() + " " + resourceId + ".", caught); + agentStatusIcon.setSrc(ImageManager.getAvailabilityLargeIcon(null)); + form.markForRedraw(); + } + + @Override + public void onSuccess(Boolean isUp) { + loading = false; + //update icon with correct status + agentStatusIcon.setSrc(ImageManager.getAvailabilityLargeIcon(isUp)); + form.markForRedraw(); + } + }); + nameValue.setValue(agent.getName()); + addressValue.setValue(agent.getAddress()); + portValue.setValue(agent.getPort()); + Long lastAvailReport = agent.getLastAvailabilityReport(); + lastAvailReportValue.setValue((null != lastAvailReport) ? new Date(lastAvailReport) : MSG.common_val_none()); + Long lastAvailPing = agent.getLastAvailabilityPing(); + lastAvailPingValue.setValue((null != lastAvailPing) ? new Date(lastAvailPing) : MSG.common_val_none()); + String remoteEndpoint = agent.getRemoteEndpoint(); + if (remoteEndpoint != null) { + // some browsers (firefox in particular) won't wrap unless you put breaks in the string + // (EDIT: in FF 16 the wrapping works even without a space, so this could be possibly ommited) + remoteEndpoint = remoteEndpoint.replaceAll("&", " &"); + } else { + remoteEndpoint = MSG.view_inventory_summary_agent_fullEnpoint_err1(); + } + endpointValue.setValue(remoteEndpoint); + + // make clickable link for agent topology view + String detailsUrl = "#" + AgentTableView.VIEW_PATH + "/" + agent.getId(); + String formattedValue = StringUtility.escapeHtml(MSG.common_label_link()); + String topologyViewItemText = SeleniumUtility.getLocatableHref(detailsUrl, formattedValue, null); + topologyViewItem.setValue(topologyViewItemText); + + form.markForRedraw(); + } + }); + } + +} \ No newline at end of file diff --git a/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/inventory/resource/detail/inventory/ResourceResourceAgentView.java b/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/inventory/resource/detail/inventory/ResourceResourceAgentView.java deleted file mode 100644 index 478207e..0000000 --- a/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/inventory/resource/detail/inventory/ResourceResourceAgentView.java +++ /dev/null @@ -1,216 +0,0 @@ -/* - * RHQ Management Platform - * Copyright (C) 2005-2010 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.enterprise.gui.coregui.client.inventory.resource.detail.inventory; - -import java.util.ArrayList; -import java.util.Date; -import java.util.List; - -import com.google.gwt.user.client.rpc.AsyncCallback; -import com.smartgwt.client.widgets.Canvas; -import com.smartgwt.client.widgets.form.fields.FormItem; -import com.smartgwt.client.widgets.form.fields.FormItemIcon; -import com.smartgwt.client.widgets.form.fields.HeaderItem; -import com.smartgwt.client.widgets.form.fields.SpacerItem; -import com.smartgwt.client.widgets.form.fields.StaticTextItem; - -import org.rhq.core.domain.resource.Agent; -import org.rhq.enterprise.gui.coregui.client.CoreGUI; -import org.rhq.enterprise.gui.coregui.client.ImageManager; -import org.rhq.enterprise.gui.coregui.client.RefreshableView; -import org.rhq.enterprise.gui.coregui.client.admin.topology.AgentTableView; -import org.rhq.enterprise.gui.coregui.client.gwt.GWTServiceLookup; -import org.rhq.enterprise.gui.coregui.client.util.StringUtility; -import org.rhq.enterprise.gui.coregui.client.util.selenium.LocatableDynamicForm; -import org.rhq.enterprise.gui.coregui.client.util.selenium.LocatableVLayout; -import org.rhq.enterprise.gui.coregui.client.util.selenium.SeleniumUtility; - -/** - * The content pane for the Resource Inventory>Agent subtab. - * - * @author Simeon Pinder - */ -public class ResourceResourceAgentView extends LocatableVLayout implements RefreshableView { - - private int resourceId; - private LocatableDynamicForm form; - private StaticTextItem nameValue; - private StaticTextItem addressValue; - private StaticTextItem portValue; - private FormItemIcon agentStatusIcon; - private StaticTextItem lastAvailReportValue; - private StaticTextItem lastAvailPingValue; - private StaticTextItem endpointValue; - private StaticTextItem topologyViewItem; - - private boolean loading = false; // will be true if loadData is currently waiting for responses - - public ResourceResourceAgentView(String locatorId, int resourceId) { - super(locatorId); - - this.resourceId = resourceId; - } - - @Override - protected void onDraw() { - super.onDraw(); - - setLeft("10%"); - setWidth("80%"); - - this.form = new LocatableDynamicForm(extendLocatorId("Agent_Info")); - final List<FormItem> formItems = createFormItems(); - this.form.setItems(formItems.toArray(new FormItem[formItems.size()])); - loadData(); - this.addMember(this.form); - } - - @Override - public void refresh() { - loadData(); - } - - private List<FormItem> createFormItems() { - final List<FormItem> formItems = new ArrayList<FormItem>(); - HeaderItem headerItem = new HeaderItem("header", MSG.view_inventory_summary_agent_title()); - headerItem.setValue(MSG.view_inventory_summary_agent_title()); - formItems.add(headerItem); - formItems.add(new SpacerItem()); - - // Name - nameValue = new StaticTextItem("name", MSG.common_title_name()); - formItems.add(nameValue); - - // Address - String address = "address"; - addressValue = new StaticTextItem(address, MSG.common_title_address()); - formItems.add(addressValue); - - // Port - String port = "port"; - portValue = new StaticTextItem(port, MSG.common_title_port()); - formItems.add(portValue); - - // Agent Status - agentStatusIcon = new FormItemIcon(); - agentStatusIcon.setSrc(ImageManager.getAvailabilityLargeIcon(null)); - StaticTextItem agentStatus = new StaticTextItem("agent-comm-status", MSG - .view_inventory_summary_agent_status_title()); - agentStatus.setIcons(agentStatusIcon); - agentStatus.setWrapTitle(false); - formItems.add(agentStatus); - - // Last Received Avail report - String lastAvailReport = "last-avail-report"; - lastAvailReportValue = new StaticTextItem(lastAvailReport, MSG.view_inventory_summary_agent_last_title()); - lastAvailReportValue.setWrapTitle(false); - formItems.add(lastAvailReportValue); - - // Last Received Avail ping - lastAvailPingValue = new StaticTextItem("last-avail-ping", MSG.view_adminTopology_agent_lastAvailabilityPing()); - lastAvailPingValue.setWrapTitle(false); - formItems.add(lastAvailPingValue); - - // Full Endpoint - String fullEndpoint = "full-endpoint"; - endpointValue = new StaticTextItem(fullEndpoint, MSG.view_inventory_summary_agent_fullEnpoint()); - formItems.add(endpointValue); - - // link to agent topology view - String topologyView = "topology-view"; - topologyViewItem = new StaticTextItem("topology-view", MSG.view_admin_topology()); - formItems.add(topologyViewItem); - - return formItems; - } - - private void loadData() { - if (loading) { - return; // we are already loading and waiting for data, no need to re-issue the same queries - } - loading = true; - - GWTServiceLookup.getAgentService().getAgentForResource(this.resourceId, new AsyncCallback<Agent>() { - @Override - public void onFailure(Throwable caught) { - loading = false; - //Permissions failure, generate message to that effect - for (Canvas child : form.getChildren()) { - child.destroy(); - } - - HeaderItem headerItem = new HeaderItem("header", MSG.view_inventory_summary_agent_title()); - headerItem.setValue(MSG.view_inventory_summary_agent_title()); - StaticTextItem permissionsMessage = new StaticTextItem("permissions", "permissionsFailure"); - permissionsMessage.setShowTitle(false); - permissionsMessage.setValue(MSG.view_inventory_summary_agent_error3()); - permissionsMessage.setWrap(false); - form.setFields(headerItem, new SpacerItem(), permissionsMessage); - form.markForRedraw(); - } - - @Override - public void onSuccess(Agent agent) { - GWTServiceLookup.getAgentService().pingAgentForResource(resourceId, new AsyncCallback<Boolean>() { - @Override - public void onFailure(Throwable caught) { - loading = false; - CoreGUI.getErrorHandler().handleError( - MSG.view_inventory_summary_agent_error2() + " " + resourceId + ".", caught); - agentStatusIcon.setSrc(ImageManager.getAvailabilityLargeIcon(null)); - form.markForRedraw(); - } - - @Override - public void onSuccess(Boolean isUp) { - loading = false; - //update icon with correct status - agentStatusIcon.setSrc(ImageManager.getAvailabilityLargeIcon(isUp)); - form.markForRedraw(); - } - }); - nameValue.setValue(agent.getName()); - addressValue.setValue(agent.getAddress()); - portValue.setValue(agent.getPort()); - Long lastAvailReport = agent.getLastAvailabilityReport(); - lastAvailReportValue.setValue((null != lastAvailReport) ? new Date(lastAvailReport) : MSG.common_val_none()); - Long lastAvailPing = agent.getLastAvailabilityPing(); - lastAvailPingValue.setValue((null != lastAvailPing) ? new Date(lastAvailPing) : MSG.common_val_none()); - String remoteEndpoint = agent.getRemoteEndpoint(); - if (remoteEndpoint != null) { - // some browsers (firefox in particular) won't wrap unless you put breaks in the string - // (EDIT: in FF 16 the wrapping works even without a space, so this could be possibly ommited) - remoteEndpoint = remoteEndpoint.replaceAll("&", " &"); - } else { - remoteEndpoint = MSG.view_inventory_summary_agent_fullEnpoint_err1(); - } - endpointValue.setValue(remoteEndpoint); - - // make clickable link for agent topology view - String detailsUrl = "#" + AgentTableView.VIEW_PATH + "/" + agent.getId(); - String formattedValue = StringUtility.escapeHtml(MSG.common_label_link()); - String topologyViewItemText = SeleniumUtility.getLocatableHref(detailsUrl, formattedValue, null); - topologyViewItem.setValue(topologyViewItemText); - - form.markForRedraw(); - } - }); - } - -} \ No newline at end of file
commit 875acb2dde6de2de0e5dee792ed437ace1252271 Author: Jirka Kremser jkremser@redhat.com Date: Thu Jan 24 14:47:15 2013 +0100
Adding "Last Availability Ping" to the agent detail page in topology section and to the agent detail page in Inventory->Agent tab
diff --git a/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/admin/topology/AgentDatasource.java b/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/admin/topology/AgentDatasource.java index f8de3a6..0b13a1b 100644 --- a/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/admin/topology/AgentDatasource.java +++ b/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/admin/topology/AgentDatasource.java @@ -23,6 +23,7 @@ import static org.rhq.enterprise.gui.coregui.client.admin.topology.AgentDatasour import static org.rhq.enterprise.gui.coregui.client.admin.topology.AgentDatasourceField.FIELD_AFFINITY_GROUP_ID; import static org.rhq.enterprise.gui.coregui.client.admin.topology.AgentDatasourceField.FIELD_AGENTTOKEN; import static org.rhq.enterprise.gui.coregui.client.admin.topology.AgentDatasourceField.FIELD_ID; +import static org.rhq.enterprise.gui.coregui.client.admin.topology.AgentDatasourceField.FIELD_LAST_AVAILABILITY_PING; import static org.rhq.enterprise.gui.coregui.client.admin.topology.AgentDatasourceField.FIELD_LAST_AVAILABILITY_REPORT; import static org.rhq.enterprise.gui.coregui.client.admin.topology.AgentDatasourceField.FIELD_NAME; import static org.rhq.enterprise.gui.coregui.client.admin.topology.AgentDatasourceField.FIELD_PORT; @@ -101,9 +102,12 @@ public class AgentDatasource extends RPCDataSource<Agent, AgentCriteria> { fields.add(serverIdField);
fields.add(FIELD_PORT.getListGridField("90")); - ListGridField lastAvailabilityReportField = FIELD_LAST_AVAILABILITY_REPORT.getListGridField("120"); + ListGridField lastAvailabilityReportField = FIELD_LAST_AVAILABILITY_REPORT.getListGridField("125"); TimestampCellFormatter.prepareDateField(lastAvailabilityReportField); fields.add(lastAvailabilityReportField); + ListGridField lastAvailabilityPingField = FIELD_LAST_AVAILABILITY_PING.getListGridField("125"); + TimestampCellFormatter.prepareDateField(lastAvailabilityPingField); + fields.add(lastAvailabilityPingField);
if (!isAffinityGroupId) { fields.add(FIELD_AFFINITY_GROUP.getListGridField("100")); @@ -155,6 +159,7 @@ public class AgentDatasource extends RPCDataSource<Agent, AgentCriteria> { record.setAttribute(FIELD_SERVER.propertyName(), from.getServer() == null ? "" : from.getServer().getName()); record.setAttribute(FIELD_SERVER_ID.propertyName(), from.getServer() == null ? "" : from.getServer().getId()); record.setAttribute(FIELD_LAST_AVAILABILITY_REPORT.propertyName(), from.getLastAvailabilityReport()); + record.setAttribute(FIELD_LAST_AVAILABILITY_PING.propertyName(), from.getLastAvailabilityPing()); record.setAttribute(FIELD_AFFINITY_GROUP.propertyName(), from.getAffinityGroup() == null ? "" : from .getAffinityGroup().getName()); record.setAttribute(FIELD_AFFINITY_GROUP_ID.propertyName(), from.getAffinityGroup() == null ? "" : from diff --git a/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/admin/topology/AgentDatasourceField.java b/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/admin/topology/AgentDatasourceField.java index cd736aa..132ee74 100644 --- a/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/admin/topology/AgentDatasourceField.java +++ b/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/admin/topology/AgentDatasourceField.java @@ -46,6 +46,9 @@ public enum AgentDatasourceField {
FIELD_LAST_AVAILABILITY_REPORT("lastAvailabilityReport", CoreGUI.getMessages() .view_adminTopology_agent_lastAvailabilityReport()), + + FIELD_LAST_AVAILABILITY_PING("lastAvailabilityPing", CoreGUI.getMessages() + .view_adminTopology_agent_lastAvailabilityPing()),
FIELD_AGENT_TOKEN("agentToken", CoreGUI.getMessages().view_adminTopology_agentDetail_token()),
diff --git a/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/admin/topology/AgentDetailView.java b/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/admin/topology/AgentDetailView.java index b05a751..50210b5 100644 --- a/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/admin/topology/AgentDetailView.java +++ b/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/admin/topology/AgentDetailView.java @@ -22,6 +22,7 @@ package org.rhq.enterprise.gui.coregui.client.admin.topology; import static org.rhq.enterprise.gui.coregui.client.admin.topology.AgentDatasourceField.FIELD_ADDRESS; import static org.rhq.enterprise.gui.coregui.client.admin.topology.AgentDatasourceField.FIELD_AFFINITY_GROUP; import static org.rhq.enterprise.gui.coregui.client.admin.topology.AgentDatasourceField.FIELD_AGENT_TOKEN; +import static org.rhq.enterprise.gui.coregui.client.admin.topology.AgentDatasourceField.FIELD_LAST_AVAILABILITY_PING; import static org.rhq.enterprise.gui.coregui.client.admin.topology.AgentDatasourceField.FIELD_LAST_AVAILABILITY_REPORT; import static org.rhq.enterprise.gui.coregui.client.admin.topology.AgentDatasourceField.FIELD_NAME; import static org.rhq.enterprise.gui.coregui.client.admin.topology.AgentDatasourceField.FIELD_PORT; @@ -177,11 +178,17 @@ public class AgentDetailView extends LocatableVLayout { final StaticTextItem tokenItem = new StaticTextItem(FIELD_AGENT_TOKEN.propertyName(), FIELD_AGENT_TOKEN.title()); tokenItem.setValue(agent.getAgentToken());
- StaticTextItem lastAvailabilityItem = new StaticTextItem(FIELD_LAST_AVAILABILITY_REPORT.propertyName(), + StaticTextItem lastAvailabilityReportItem = new StaticTextItem(FIELD_LAST_AVAILABILITY_REPORT.propertyName(), FIELD_LAST_AVAILABILITY_REPORT.title()); String lastReport = agent.getLastAvailabilityReport() == null ? "unknown" : TimestampCellFormatter.format( Long.valueOf(agent.getLastAvailabilityReport()), TimestampCellFormatter.DATE_TIME_FORMAT_LONG); - lastAvailabilityItem.setValue(lastReport); + lastAvailabilityReportItem.setValue(lastReport); + + StaticTextItem lastAvailabilityPingItem = new StaticTextItem(FIELD_LAST_AVAILABILITY_PING.propertyName(), + FIELD_LAST_AVAILABILITY_PING.title()); + String lastPing = agent.getLastAvailabilityPing() == null ? "unknown" : TimestampCellFormatter.format( + Long.valueOf(agent.getLastAvailabilityPing()), TimestampCellFormatter.DATE_TIME_FORMAT_LONG); + lastAvailabilityPingItem.setValue(lastPing);
// make clickable link for affinity group StaticTextItem affinityGroupItem = new StaticTextItem(FIELD_AFFINITY_GROUP.propertyName(), @@ -206,8 +213,8 @@ public class AgentDetailView extends LocatableVLayout { } currentServerItem.setValue(serverValue);
- form.setItems(nameItem, addressItem, remoteEndpointItem, portItem, tokenItem, lastAvailabilityItem, - affinityGroupItem, currentServerItem); + form.setItems(nameItem, addressItem, remoteEndpointItem, portItem, tokenItem, lastAvailabilityReportItem, + lastAvailabilityPingItem, affinityGroupItem, currentServerItem);
SectionStackSection section = new SectionStackSection(MSG.common_title_details()); section.setExpanded(true); diff --git a/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/inventory/resource/detail/inventory/ResourceResourceAgentView.java b/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/inventory/resource/detail/inventory/ResourceResourceAgentView.java index ff1addc..478207e 100644 --- a/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/inventory/resource/detail/inventory/ResourceResourceAgentView.java +++ b/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/inventory/resource/detail/inventory/ResourceResourceAgentView.java @@ -34,9 +34,12 @@ import org.rhq.core.domain.resource.Agent; import org.rhq.enterprise.gui.coregui.client.CoreGUI; import org.rhq.enterprise.gui.coregui.client.ImageManager; import org.rhq.enterprise.gui.coregui.client.RefreshableView; +import org.rhq.enterprise.gui.coregui.client.admin.topology.AgentTableView; import org.rhq.enterprise.gui.coregui.client.gwt.GWTServiceLookup; +import org.rhq.enterprise.gui.coregui.client.util.StringUtility; import org.rhq.enterprise.gui.coregui.client.util.selenium.LocatableDynamicForm; import org.rhq.enterprise.gui.coregui.client.util.selenium.LocatableVLayout; +import org.rhq.enterprise.gui.coregui.client.util.selenium.SeleniumUtility;
/** * The content pane for the Resource Inventory>Agent subtab. @@ -52,7 +55,9 @@ public class ResourceResourceAgentView extends LocatableVLayout implements Refre private StaticTextItem portValue; private FormItemIcon agentStatusIcon; private StaticTextItem lastAvailReportValue; + private StaticTextItem lastAvailPingValue; private StaticTextItem endpointValue; + private StaticTextItem topologyViewItem;
private boolean loading = false; // will be true if loadData is currently waiting for responses
@@ -116,11 +121,21 @@ public class ResourceResourceAgentView extends LocatableVLayout implements Refre lastAvailReportValue = new StaticTextItem(lastAvailReport, MSG.view_inventory_summary_agent_last_title()); lastAvailReportValue.setWrapTitle(false); formItems.add(lastAvailReportValue); + + // Last Received Avail ping + lastAvailPingValue = new StaticTextItem("last-avail-ping", MSG.view_adminTopology_agent_lastAvailabilityPing()); + lastAvailPingValue.setWrapTitle(false); + formItems.add(lastAvailPingValue);
// Full Endpoint String fullEndpoint = "full-endpoint"; endpointValue = new StaticTextItem(fullEndpoint, MSG.view_inventory_summary_agent_fullEnpoint()); formItems.add(endpointValue); + + // link to agent topology view + String topologyView = "topology-view"; + topologyViewItem = new StaticTextItem("topology-view", MSG.view_admin_topology()); + formItems.add(topologyViewItem);
return formItems; } @@ -170,20 +185,28 @@ public class ResourceResourceAgentView extends LocatableVLayout implements Refre form.markForRedraw(); } }); - nameValue.setValue(agent.getName()); addressValue.setValue(agent.getAddress()); portValue.setValue(agent.getPort()); - Long lastAvail = agent.getLastAvailabilityReport(); - lastAvailReportValue.setValue((null != lastAvail) ? new Date(lastAvail) : MSG.common_val_none()); + Long lastAvailReport = agent.getLastAvailabilityReport(); + lastAvailReportValue.setValue((null != lastAvailReport) ? new Date(lastAvailReport) : MSG.common_val_none()); + Long lastAvailPing = agent.getLastAvailabilityPing(); + lastAvailPingValue.setValue((null != lastAvailPing) ? new Date(lastAvailPing) : MSG.common_val_none()); String remoteEndpoint = agent.getRemoteEndpoint(); if (remoteEndpoint != null) { // some browsers (firefox in particular) won't wrap unless you put breaks in the string + // (EDIT: in FF 16 the wrapping works even without a space, so this could be possibly ommited) remoteEndpoint = remoteEndpoint.replaceAll("&", " &"); } else { remoteEndpoint = MSG.view_inventory_summary_agent_fullEnpoint_err1(); } endpointValue.setValue(remoteEndpoint); + + // make clickable link for agent topology view + String detailsUrl = "#" + AgentTableView.VIEW_PATH + "/" + agent.getId(); + String formattedValue = StringUtility.escapeHtml(MSG.common_label_link()); + String topologyViewItemText = SeleniumUtility.getLocatableHref(detailsUrl, formattedValue, null); + topologyViewItem.setValue(topologyViewItemText);
form.markForRedraw(); } diff --git a/modules/enterprise/gui/coregui/src/main/resources/org/rhq/enterprise/gui/coregui/client/Messages.properties b/modules/enterprise/gui/coregui/src/main/resources/org/rhq/enterprise/gui/coregui/client/Messages.properties index 2068272..4c29ae3 100644 --- a/modules/enterprise/gui/coregui/src/main/resources/org/rhq/enterprise/gui/coregui/client/Messages.properties +++ b/modules/enterprise/gui/coregui/src/main/resources/org/rhq/enterprise/gui/coregui/client/Messages.properties @@ -551,6 +551,7 @@ view_adminTopology_agent_agentBindAddress = Agent Bind Address view_adminTopology_agent_agentBindPort = Agent Bind Port view_adminTopology_agent_agentName = Agent Name view_adminTopology_agent_connectedServer = Connected Server +view_adminTopology_agent_lastAvailabilityPing = Last Availability Ping view_adminTopology_agent_lastAvailabilityReport = Last Availability Report view_adminTopology_agents = Agents view_adminTopology_message_agentsCount = There are {0} agents registered to this server. This number does not correspond to the number of currently connected agents. diff --git a/modules/enterprise/gui/coregui/src/main/resources/org/rhq/enterprise/gui/coregui/client/Messages_de.properties b/modules/enterprise/gui/coregui/src/main/resources/org/rhq/enterprise/gui/coregui/client/Messages_de.properties index 004a414..9fa7b83 100644 --- a/modules/enterprise/gui/coregui/src/main/resources/org/rhq/enterprise/gui/coregui/client/Messages_de.properties +++ b/modules/enterprise/gui/coregui/src/main/resources/org/rhq/enterprise/gui/coregui/client/Messages_de.properties @@ -517,6 +517,7 @@ view_adminTopology_affinityGroups = Affinitätsgruppen ##view_adminTopology_agent_agentBindPort = Agent Bind Port ##view_adminTopology_agent_agentName = Agent Name ##view_adminTopology_agent_connectedServer = Connected Server +##view_adminTopology_agent_lastAvailabilityPing = Last Availability Ping ##view_adminTopology_agent_lastAvailabilityReport = Last Availability Report view_adminTopology_agents = Agenten ##view_adminTopology_message_agentsCount = There are {0} agents registered to this server. This number doesn't correspond to the number of currently connected agents. diff --git a/modules/enterprise/gui/coregui/src/main/resources/org/rhq/enterprise/gui/coregui/client/Messages_ja.properties b/modules/enterprise/gui/coregui/src/main/resources/org/rhq/enterprise/gui/coregui/client/Messages_ja.properties index 411fb71..404736b 100644 --- a/modules/enterprise/gui/coregui/src/main/resources/org/rhq/enterprise/gui/coregui/client/Messages_ja.properties +++ b/modules/enterprise/gui/coregui/src/main/resources/org/rhq/enterprise/gui/coregui/client/Messages_ja.properties @@ -549,6 +549,7 @@ view_adminTopology_affinityGroups = アフィニティグループ ##view_adminTopology_agent_agentBindPort = Agent Bind Port ##view_adminTopology_agent_agentName = Agent Name ##view_adminTopology_agent_connectedServer = Connected Server +##view_adminTopology_agent_lastAvailabilityPing = Last Availability Ping ##view_adminTopology_agent_lastAvailabilityReport = Last Availability Report view_adminTopology_agents = エージェント ##view_adminTopology_message_agentsCount = There are {0} agents registered to this server. This number doesn't correspond to the number of currently connected agents. diff --git a/modules/enterprise/gui/coregui/src/main/resources/org/rhq/enterprise/gui/coregui/client/Messages_ko.properties b/modules/enterprise/gui/coregui/src/main/resources/org/rhq/enterprise/gui/coregui/client/Messages_ko.properties index 29b0ba7..f358bc7 100644 --- a/modules/enterprise/gui/coregui/src/main/resources/org/rhq/enterprise/gui/coregui/client/Messages_ko.properties +++ b/modules/enterprise/gui/coregui/src/main/resources/org/rhq/enterprise/gui/coregui/client/Messages_ko.properties @@ -455,9 +455,95 @@ view_adminTemplates_prompt_disabledMetricTemplates = 이 자원 유형에 대해 view_adminTemplates_prompt_enabledMetricTemplates = 이 자원 유형에 대해 기본적으로 활성화된 통계 일정 수 view_adminTemplates_servers = 서버 view_adminTopology_affinityGroups = 선호도 그룹 +##view_adminTopology_affinityGroups_agentCount = Agent Count +##view_adminTopology_affinityGroups_agentsInThisGroup = Agents in This Group +##view_adminTopology_affinityGroups_agentsNotPartOfAnAffinityGroup = Agents not Part of an Affinity Group +##view_adminTopology_affinityGroups_agetnMembers = Agent Members +##view_adminTopology_affinityGroups_createNew = Create New +##view_adminTopology_affinityGroups_details = Affinity Group Details +##view_adminTopology_affinityGroups_removeSelected = Remove Selected +##view_adminTopology_affinityGroups_serverCount = Server Count +##view_adminTopology_affinityGroups_serverMembers = Server Members +##view_adminTopology_agentDetail_address = Address +##view_adminTopology_agentDetail_agentFailoverList = Agent Failover List +##view_adminTopology_agentDetail_currentServer = Current Server +##view_adminTopology_agentDetail_token = Token +##view_adminTopology_agent_agentBindAddress = Agent Bind Address +##view_adminTopology_agent_agentBindPort = Agent Bind Port +##view_adminTopology_agent_agentName = Agent Name +##view_adminTopology_agent_connectedServer = Connected Server +##view_adminTopology_agent_lastAvailabilityPing = Last Availability Ping +##view_adminTopology_agent_lastAvailabilityReport = Last Availability Report view_adminTopology_agents = 에이전트 +##view_adminTopology_message_agentsCount = There are {0} agents registered to this server. This number doesn't correspond to the number of currently connected agents. +##view_adminTopology_message_agroupAssingAgentsFail = Unable to assign agents to the affinity group with id {0}. +##view_adminTopology_message_agroupAssingServersFail = Unable to assign servers to the affinity group with id {0}. +##view_adminTopology_message_agroupRemovingAgentsFail = Unable to remove agents from the affinity group with id {0}. +##view_adminTopology_message_agroupRemovingServersFail = Unable to remove servers from the affinity group with id {0}. +##view_adminTopology_message_agroupRenamed = Affinity group with id {0} and name {1} was renamed to {2}. +##view_adminTopology_message_agroupRenamingFail = Unable to rename affinity group with id {0} and name {1}. +##view_adminTopology_message_fetchAgentFail = Unable to fetch agent details for agent with id {0}. +##view_adminTopology_message_fetchAgents2Fail = Unable to fetch agents. +##view_adminTopology_message_fetchAgentsFail = Unable to fetch agent(s) for affinity group with id {0}. +##view_adminTopology_message_fetchAgroupFail = Unable to fetch affinity group details for group with id {0}. +##view_adminTopology_message_fetchAgroupsFail = Unable to fetch affinity group(s). +##view_adminTopology_message_fetchFailOverLists = Unable to fetch fail over list details. +##view_adminTopology_message_fetchPEventDetailsFail = Unable to fetch partition event details for event with id {0}. +##view_adminTopology_message_fetchPEventFail = Unable to fetch partition events. +##view_adminTopology_message_fetchServerFail = Unable to fetch server details for server with id {0}. +##view_adminTopology_message_fetchServers2Fail = Unable to fetch servers. +##view_adminTopology_message_fetchServersFail = Unable to fetch server(s) for affinity group with id {0}. +##view_adminTopology_message_forceRepartition = Do you really want to force a repartition of whole cluster? It will force all the agents to connect to its most preferred server. +##view_adminTopology_message_forceRepartitionFail = Unable to run repartition. +##view_adminTopology_message_order = Order +##view_adminTopology_message_removeAGroupsConfirm = Do you really want to remove following affinity groups {0}? +##view_adminTopology_message_removeAGroupsFail = Unable to remove following affinity groups(s) {0}. +##view_adminTopology_message_removeAllPEventConfirm = Do you really want to purge all partition events? +##view_adminTopology_message_removePEventConfirm = Do you really want to remove following partition events {0}? +##view_adminTopology_message_removePEventFail = Unable to remove {0} partition events(s). +##view_adminTopology_message_removeServerConfirm = Do you really want to remove servers {0}? +##view_adminTopology_message_removeServerFail = Unable to remove {0} server(s). +##view_adminTopology_message_removedAGroups = Removed {0} affinity group(s). +##view_adminTopology_message_removedAllPEvent = All partition events have been purged. +##view_adminTopology_message_removedAllPEventFail = Unable to purge all partition events. +##view_adminTopology_message_removedPEvent = Removed {0} partition events(s). +##view_adminTopology_message_removedServer = Removed {0} server(s). +##view_adminTopology_message_repartitioned = The cluster repartitioning was successfully invoked. +##view_adminTopology_message_serverUpdateFail = Unable to update server {0}. +##view_adminTopology_message_serverUpdated = The server {0} was successfully updated. +##view_adminTopology_message_setMode = Set {0} server(s) to {1} mode. +##view_adminTopology_message_setModeConfirm = Do you really want to set servers {0} to {1} mode? +##view_adminTopology_message_setModeFail = Unable to set {0} server(s) to {1} mode. view_adminTopology_partitionEvents = 이벤트 범주 +##view_adminTopology_partitionEventsDetail_agentAssignments = Agent Assignments +##view_adminTopology_partitionEventsDetail_agentAssignments_nothing = No agents were reassigned as a result of this partition event +##view_adminTopology_partitionEventsDetail_eventDetails = Event Details +##view_adminTopology_partitionEventsDetail_eventExecutionTime = Event Execution Time +##view_adminTopology_partitionEventsDetail_eventType = Event Type +##view_adminTopology_partitionEvents_details = Details +##view_adminTopology_partitionEvents_detailsFilter = Details Filter +##view_adminTopology_partitionEvents_execStatusFilter = Execution Status Filter +##view_adminTopology_partitionEvents_execTime = Execution Time +##view_adminTopology_partitionEvents_executionStatus = Execution Status +##view_adminTopology_partitionEvents_forceRepartition = Force Repartition +##view_adminTopology_partitionEvents_initiatedBy = Initiated By +##view_adminTopology_partitionEvents_purgeAll = Purge All +##view_adminTopology_partitionEvents_type = Type +##view_adminTopology_partitionEvents_typeFilter = Type Filter view_adminTopology_remoteAgentInstall = 원격 에이전트 설치 +##view_adminTopology_serverDetail_connectedAgents = Connected Agents +##view_adminTopology_serverDetail_installationDate = Installation Date +##view_adminTopology_serverDetail_operationMode = Operation Mode +##view_adminTopology_server_affinityGroup = Affinity Group +##view_adminTopology_server_agentCount = Agent Count +##view_adminTopology_server_endpointAddress = Endpoint Address +##view_adminTopology_server_lastUpdateTime = Last Update Time +##view_adminTopology_server_mode = Mode +##view_adminTopology_server_nonSecurePort = Nonsecure Port +##view_adminTopology_server_removeSelected = Remove Selected +##view_adminTopology_server_securePort = Secure Port +##view_adminTopology_server_setMaintenance = Set Maintenance +##view_adminTopology_server_setNormal = Set Normal view_adminTopology_servers = 서버 view_adminUsersDetails_dataTypeName = 사용자 view_adminUsers_failCreateUserWithExistingName = 기존 이름 [{0}]과 사용자를 만들지 못했습니다. 다른 이름을 사용하십시오. diff --git a/modules/enterprise/gui/coregui/src/main/resources/org/rhq/enterprise/gui/coregui/client/Messages_pt.properties b/modules/enterprise/gui/coregui/src/main/resources/org/rhq/enterprise/gui/coregui/client/Messages_pt.properties index 9699756..f5121ae 100644 --- a/modules/enterprise/gui/coregui/src/main/resources/org/rhq/enterprise/gui/coregui/client/Messages_pt.properties +++ b/modules/enterprise/gui/coregui/src/main/resources/org/rhq/enterprise/gui/coregui/client/Messages_pt.properties @@ -554,6 +554,7 @@ view_adminTopology_affinityGroups = Grupos de Afinidade ##view_adminTopology_agent_agentBindPort = Agent Bind Port ##view_adminTopology_agent_agentName = Agent Name ##view_adminTopology_agent_connectedServer = Connected Server +##view_adminTopology_agent_lastAvailabilityPing = Last Availability Ping ##view_adminTopology_agent_lastAvailabilityReport = Last Availability Report view_adminTopology_agents = Agentes ##view_adminTopology_message_agentsCount = There are {0} agents registered to this server. This number doesn't correspond to the number of currently connected agents. diff --git a/modules/enterprise/gui/coregui/src/main/resources/org/rhq/enterprise/gui/coregui/client/Messages_ru.properties b/modules/enterprise/gui/coregui/src/main/resources/org/rhq/enterprise/gui/coregui/client/Messages_ru.properties index 0d56ebc..d4ec501 100644 --- a/modules/enterprise/gui/coregui/src/main/resources/org/rhq/enterprise/gui/coregui/client/Messages_ru.properties +++ b/modules/enterprise/gui/coregui/src/main/resources/org/rhq/enterprise/gui/coregui/client/Messages_ru.properties @@ -516,10 +516,97 @@ #view_adminTemplates_servers = Servers #view_adminTemplates_userTemplates = User Templates #view_adminTopology_affinityGroups = Affinity Groups +##view_adminTopology_affinityGroups_agentCount = Agent Count +##view_adminTopology_affinityGroups_agentsInThisGroup = Agents in This Group +##view_adminTopology_affinityGroups_agentsNotPartOfAnAffinityGroup = Agents not Part of an Affinity Group +##view_adminTopology_affinityGroups_agetnMembers = Agent Members +##view_adminTopology_affinityGroups_createNew = Create New +##view_adminTopology_affinityGroups_details = Affinity Group Details +##view_adminTopology_affinityGroups_removeSelected = Remove Selected +##view_adminTopology_affinityGroups_serverCount = Server Count +##view_adminTopology_affinityGroups_serverMembers = Server Members +##view_adminTopology_agentDetail_address = Address +##view_adminTopology_agentDetail_agentFailoverList = Agent Failover List +##view_adminTopology_agentDetail_currentServer = Current Server +##view_adminTopology_agentDetail_remoteEndpoint = Remote Endpoint +##view_adminTopology_agentDetail_token = Token +##view_adminTopology_agent_agentBindAddress = Agent Bind Address +##view_adminTopology_agent_agentBindPort = Agent Bind Port +##view_adminTopology_agent_agentName = Agent Name +##view_adminTopology_agent_connectedServer = Connected Server +##view_adminTopology_agent_lastAvailabilityPing = Last Availability Ping +##view_adminTopology_agent_lastAvailabilityReport = Last Availability Report #view_adminTopology_agents = Agents +##view_adminTopology_message_agentsCount = There are {0} agents registered to this server. This number doesn't correspond to the number of currently connected agents. +##view_adminTopology_message_agroupAssingAgentsFail = Unable to assign agents to the affinity group with id {0}. +##view_adminTopology_message_agroupAssingServersFail = Unable to assign servers to the affinity group with id {0}. +##view_adminTopology_message_agroupRemovingAgentsFail = Unable to remove agents from the affinity group with id {0}. +##view_adminTopology_message_agroupRemovingServersFail = Unable to remove servers from the affinity group with id {0}. +##view_adminTopology_message_agroupRenamed = Affinity group with id {0} and name {1} was renamed to {2}. +##view_adminTopology_message_agroupRenamingFail = Unable to rename affinity group with id {0} and name {1}. +##view_adminTopology_message_fetchAgentFail = Unable to fetch agent details for agent with id {0}. +##view_adminTopology_message_fetchAgents2Fail = Unable to fetch agents. +##view_adminTopology_message_fetchAgentsFail = Unable to fetch agent(s) for affinity group with id {0}. +##view_adminTopology_message_fetchAgroupFail = Unable to fetch affinity group details for group with id {0}. +##view_adminTopology_message_fetchAgroupsFail = Unable to fetch affinity group(s). +##view_adminTopology_message_fetchFailOverLists = Unable to fetch fail over list details. +##view_adminTopology_message_fetchPEventDetailsFail = Unable to fetch partition event details for event with id {0}. +##view_adminTopology_message_fetchPEventFail = Unable to fetch partition events. +##view_adminTopology_message_fetchServerFail = Unable to fetch server details for server with id {0}. +##view_adminTopology_message_fetchServers2Fail = Unable to fetch servers. +##view_adminTopology_message_fetchServersFail = Unable to fetch server(s) for affinity group with id {0}. +##view_adminTopology_message_forceRepartition = Do you really want to force a repartition of whole cluster? It will force all the agents to connect to its most preferred server. +##view_adminTopology_message_forceRepartitionFail = Unable to run repartition. +##view_adminTopology_message_order = Order +##view_adminTopology_message_removeAGroupsConfirm = Do you really want to remove following affinity groups {0}? +##view_adminTopology_message_removeAGroupsFail = Unable to remove following affinity groups(s) {0}. +##view_adminTopology_message_removeAllPEventConfirm = Do you really want to purge all partition events? +##view_adminTopology_message_removePEventConfirm = Do you really want to remove following partition events {0}? +##view_adminTopology_message_removePEventFail = Unable to remove {0} partition events(s). +##view_adminTopology_message_removeServerConfirm = Do you really want to remove servers {0}? +##view_adminTopology_message_removeServerFail = Unable to remove {0} server(s). +##view_adminTopology_message_removedAGroups = Removed {0} affinity group(s). +##view_adminTopology_message_removedAllPEvent = All partition events have been purged. +##view_adminTopology_message_removedAllPEventFail = Unable to purge all partition events. +##view_adminTopology_message_removedPEvent = Removed {0} partition events(s). +##view_adminTopology_message_removedServer = Removed {0} server(s). +##view_adminTopology_message_repartitioned = The cluster repartitioning was successfully invoked. +##view_adminTopology_message_serverUpdateFail = Unable to update server {0}. +##view_adminTopology_message_serverUpdated = The server {0} was successfully updated. +##view_adminTopology_message_setMode = Set {0} server(s) to {1} mode. +##view_adminTopology_message_setModeConfirm = Do you really want to set servers {0} to {1} mode? +##view_adminTopology_message_setModeFail = Unable to set {0} server(s) to {1} mode. #view_adminTopology_partitionEvents = Partition Events +##view_adminTopology_partitionEventsDetail_agentAssignments = Agent Assignments +##view_adminTopology_partitionEventsDetail_agentAssignments_nothing = No agents were reassigned as a result of this partition event +##view_adminTopology_partitionEventsDetail_eventDetails = Event Details +##view_adminTopology_partitionEventsDetail_eventExecutionTime = Event Execution Time +##view_adminTopology_partitionEventsDetail_eventType = Event Type +##view_adminTopology_partitionEvents_details = Details +##view_adminTopology_partitionEvents_detailsFilter = Details Filter +##view_adminTopology_partitionEvents_execStatusFilter = Execution Status Filter +##view_adminTopology_partitionEvents_execTime = Execution Time +##view_adminTopology_partitionEvents_executionStatus = Execution Status +##view_adminTopology_partitionEvents_forceRepartition = Force Repartition +##view_adminTopology_partitionEvents_initiatedBy = Initiated By +##view_adminTopology_partitionEvents_purgeAll = Purge All +##view_adminTopology_partitionEvents_type = Type +##view_adminTopology_partitionEvents_typeFilter = Type Filter #view_adminTopology_remoteAgentInstall = Remote Agent Install #view_adminTopology_servers = Servers +##view_adminTopology_serverDetail_connectedAgents = Connected Agents +##view_adminTopology_serverDetail_installationDate = Installation Date +##view_adminTopology_serverDetail_operationMode = Operation Mode +##view_adminTopology_server_affinityGroup = Affinity Group +##view_adminTopology_server_agentCount = Agent Count +##view_adminTopology_server_endpointAddress = Endpoint Address +##view_adminTopology_server_lastUpdateTime = Last Update Time +##view_adminTopology_server_mode = Mode +##view_adminTopology_server_nonSecurePort = Nonsecure Port +##view_adminTopology_server_removeSelected = Remove Selected +##view_adminTopology_server_securePort = Secure Port +##view_adminTopology_server_setMaintenance = Set Maintenance +##view_adminTopology_server_setNormal = Set Normal #view_adminUsersDetails_dataTypeName = user #view_admin_administration = Administration #view_admin_configuration = Configuration diff --git a/modules/enterprise/gui/coregui/src/main/resources/org/rhq/enterprise/gui/coregui/client/Messages_zh.properties b/modules/enterprise/gui/coregui/src/main/resources/org/rhq/enterprise/gui/coregui/client/Messages_zh.properties index f6abf6b..40a8517 100644 --- a/modules/enterprise/gui/coregui/src/main/resources/org/rhq/enterprise/gui/coregui/client/Messages_zh.properties +++ b/modules/enterprise/gui/coregui/src/main/resources/org/rhq/enterprise/gui/coregui/client/Messages_zh.properties @@ -541,6 +541,7 @@ view_adminTopology_affinityGroups = \u76f8\u5173\u7ec4 ##view_adminTopology_agent_agentBindPort = Agent Bind Port ##view_adminTopology_agent_agentName = Agent Name ##view_adminTopology_agent_connectedServer = Connected Server +##view_adminTopology_agent_lastAvailabilityPing = Last Availability Ping ##view_adminTopology_agent_lastAvailabilityReport = Last Availability Report view_adminTopology_agents = \u4ee3\u7406 ##view_adminTopology_message_agentsCount = There are {0} agents registered to this server. This number doesn't correspond to the number of currently connected agents.
rhq-commits@lists.fedorahosted.org