[rhq] Branch 'bug/1009945' - modules/enterprise
by John Sanda
modules/enterprise/server/server-metrics/src/main/java/org/rhq/server/metrics/Aggregator.java | 22 ++++-
modules/enterprise/server/server-metrics/src/main/java/org/rhq/server/metrics/MetricsDAO.java | 5 +
modules/enterprise/server/server-metrics/src/test/java/org/rhq/server/metrics/AggregatorTest.java | 43 ++++++++--
3 files changed, 60 insertions(+), 10 deletions(-)
New commits:
commit 3ec94341a05c476c8d74cfea99b82e2e1b364f71
Author: John Sanda <jsanda(a)redhat.com>
Date: Thu Oct 3 07:50:23 2013 -0400
delete 1 hr index entries when aggregation of time slice data is finished
diff --git a/modules/enterprise/server/server-metrics/src/main/java/org/rhq/server/metrics/Aggregator.java b/modules/enterprise/server/server-metrics/src/main/java/org/rhq/server/metrics/Aggregator.java
index ef95516..15b3ff8 100644
--- a/modules/enterprise/server/server-metrics/src/main/java/org/rhq/server/metrics/Aggregator.java
+++ b/modules/enterprise/server/server-metrics/src/main/java/org/rhq/server/metrics/Aggregator.java
@@ -386,8 +386,7 @@ public class Aggregator {
if (log.isDebugEnabled()) {
log.debug("Finished aggregating raw data for time slice [" + startTime + "]");
}
- allAggregationFinished.countDown();
- // TODO delete the row from metrics_index
+ deleteIndexEntries(MetricsTable.ONE_HOUR);
}
}
@@ -399,9 +398,24 @@ public class Aggregator {
log.debug("Finished aggregating one hour data for time slice [startTime: " + start +
", endTime: " + end + "]");
}
- allAggregationFinished.countDown();
- // TODO delete the row from metrics_index
+ deleteIndexEntries(MetricsTable.SIX_HOUR);
}
}
+ private void deleteIndexEntries(final MetricsTable table) {
+ StorageResultSetFuture future = dao.deleteMetricsIndexEntriesAsync(table, startTime.getMillis());
+ Futures.addCallback(future, new FutureCallback<ResultSet>() {
+ @Override
+ public void onSuccess(ResultSet result) {
+ allAggregationFinished.countDown();
+ }
+
+ @Override
+ public void onFailure(Throwable t) {
+ log.warn("Failed to delete index entries for table " + table + " at time [" + startTime + "]");
+ allAggregationFinished.countDown();
+ }
+ });
+ }
+
}
diff --git a/modules/enterprise/server/server-metrics/src/main/java/org/rhq/server/metrics/MetricsDAO.java b/modules/enterprise/server/server-metrics/src/main/java/org/rhq/server/metrics/MetricsDAO.java
index 40450b9..c0d7a67 100644
--- a/modules/enterprise/server/server-metrics/src/main/java/org/rhq/server/metrics/MetricsDAO.java
+++ b/modules/enterprise/server/server-metrics/src/main/java/org/rhq/server/metrics/MetricsDAO.java
@@ -298,4 +298,9 @@ public class MetricsDAO {
BoundStatement statement = deleteIndexEntries.bind(table.getTableName(), new Date(timestamp));
storageSession.execute(statement);
}
+
+ public StorageResultSetFuture deleteMetricsIndexEntriesAsync(MetricsTable table, long timestamp) {
+ BoundStatement statement = deleteIndexEntries.bind(table.getTableName(), new Date(timestamp));
+ return storageSession.executeAsync(statement);
+ }
}
diff --git a/modules/enterprise/server/server-metrics/src/test/java/org/rhq/server/metrics/AggregatorTest.java b/modules/enterprise/server/server-metrics/src/test/java/org/rhq/server/metrics/AggregatorTest.java
index 283d6fb..ea6284b 100644
--- a/modules/enterprise/server/server-metrics/src/test/java/org/rhq/server/metrics/AggregatorTest.java
+++ b/modules/enterprise/server/server-metrics/src/test/java/org/rhq/server/metrics/AggregatorTest.java
@@ -2,6 +2,7 @@ package org.rhq.server.metrics;
import static java.util.Arrays.asList;
import static org.rhq.test.AssertUtils.assertCollectionMatchesNoOrder;
+import static org.testng.Assert.assertEquals;
import java.math.BigDecimal;
import java.math.MathContext;
@@ -131,16 +132,15 @@ public class AggregatorTest extends CassandraIntegrationTest {
assertMetricsIndexEquals(MetricsTable.SIX_HOUR, hour9.minusHours(3).getMillis(), expected6HourIndex,
"Failed to update index for " + MetricsTable.SIX_HOUR);
- // The 6 hour data should not get aggregated since the current 6 hour time slice
- // has not passed yet. More specifically, the aggregation job is running at 09:00
- // which means that the current 6 hour slice is from 06:00 to 12:00.
-// assert6HourDataEmpty(scheduleId);
+ // The 6 hour data should not get aggregated since the current 6 hour time slice,
+ // 06:00 - 12:00, has not yet passed.
+ assert6HourDataEmpty(scheduleId);
// verify that the 24 hour index is empty
-// assert24HourMetricsIndexEmpty(scheduleId, hour0.getMillis());
+ assert24HourMetricsIndexEmpty(scheduleId, hour0.getMillis());
// verify that the 1 hour queue has been purged
-// assert1HourMetricsIndexEmpty(scheduleId, hour9.getMillis());
+ assert1HourMetricsIndexEmpty(scheduleId, hour8.getMillis());
}
static double divide(double dividend, int divisor) {
@@ -174,4 +174,35 @@ public class AggregatorTest extends CassandraIntegrationTest {
expected, actual);
}
+ private void assert6HourDataEmpty(int scheduleId) {
+ assertMetricDataEmpty(scheduleId, MetricsTable.SIX_HOUR);
+ }
+
+ private void assert24HourDataEmpty(int scheduleId) {
+ assertMetricDataEmpty(scheduleId, MetricsTable.TWENTY_FOUR_HOUR);
+ }
+
+ private void assertMetricDataEmpty(int scheduleId, MetricsTable columnFamily) {
+ List<AggregateNumericMetric> metrics = Lists.newArrayList(findAggregateMetrics(columnFamily, scheduleId));
+ assertEquals(metrics.size(), 0, "Expected " + columnFamily + " to be empty for schedule id " + scheduleId +
+ " but found " + metrics);
+ }
+
+ private void assert1HourMetricsIndexEmpty(int scheduleId, long timeSlice) {
+ assertMetricsIndexEmpty(scheduleId, MetricsTable.ONE_HOUR, timeSlice);
+ }
+
+ private void assert6HourMetricsIndexEmpty(int scheduleId, long timeSlice) {
+ assertMetricsIndexEmpty(scheduleId, MetricsTable.SIX_HOUR, timeSlice);
+ }
+
+ private void assert24HourMetricsIndexEmpty(int scheduleId, long timeSlice) {
+ assertMetricsIndexEmpty(scheduleId, MetricsTable.TWENTY_FOUR_HOUR, timeSlice);
+ }
+
+ private void assertMetricsIndexEmpty(int scheduleId, MetricsTable table, long timeSlice) {
+ List<MetricsIndexEntry> index = Lists.newArrayList(dao.findMetricsIndexEntries(table, timeSlice));
+ assertEquals(index.size(), 0, "Expected metrics index for " + table + " to be empty but found " + index);
+ }
+
}
10 years, 7 months
[rhq] modules/plugins
by Thomas Segismont
modules/plugins/jboss-as-7/src/main/java/org/rhq/modules/plugins/jbossas7/JBossProductType.java | 8 +-------
1 file changed, 1 insertion(+), 7 deletions(-)
New commits:
commit 02ed9c403f3ee1aa7fb1b5f1e1cee5713997fa56
Author: Thomas Segismont <tsegismo(a)redhat.com>
Date: Thu Oct 3 12:08:12 2013 +0200
Bug 1014501 - InvalidPluginConfigurationException in agent log - product type is JBoss EAP 6 instead of JBoss JPP 6
Removed unused EPP entry which prevented deterministic constant look-up by product-name value
diff --git a/modules/plugins/jboss-as-7/src/main/java/org/rhq/modules/plugins/jbossas7/JBossProductType.java b/modules/plugins/jboss-as-7/src/main/java/org/rhq/modules/plugins/jbossas7/JBossProductType.java
index 9cb9e5a..8fa7907 100644
--- a/modules/plugins/jboss-as-7/src/main/java/org/rhq/modules/plugins/jbossas7/JBossProductType.java
+++ b/modules/plugins/jboss-as-7/src/main/java/org/rhq/modules/plugins/jbossas7/JBossProductType.java
@@ -34,9 +34,7 @@ public enum JBossProductType {
EAP("EAP", "JBoss EAP 6", "JBoss Enterprise Application Platform 6", "EAP"),
ISPN("ISPN", "Infinispan Server", "Infinispan Server", "ISPN"),
JDG("JDG", "JBoss JDG 6", "JBoss Data Grid 6", "Data Grid"),
- EPP("EPP", "JBoss EAP 6", "JBoss Enterprise Portal Platform 6", "Portal Platform"),
JPP("JPP", "JBoss JPP 6", "JBoss Portal Platform 6", "Portal Platform"),
-// EWP("EWP", "JBoss EWP 6", "JBoss Enterprise Web Platform 6", "EWP"),
SOA("SOA-P", "JBoss SOA-P 6", "Red Hat JBoss Fuse Service Works", "SOAP"),
WILDFLY8("WildFly","WildFly 8" ,"WildFly Application Server 8" , "WildFly");
@@ -128,9 +126,7 @@ public enum JBossProductType {
productType = JBossProductType.ISPN;
} else if (slot.equals("jdg")) {
productType = JBossProductType.JDG;
- } else if (slot.equals("epp")) {//old EPP
- productType = JBossProductType.EPP;
- } else if (slot.equals("jpp")) {//new EPP->JPP plugin
+ } else if (slot.equals("jpp")) {
productType = JBossProductType.JPP;
} else if (slot.equals("soa")) {
productType = JBossProductType.SOA;
@@ -157,8 +153,6 @@ public enum JBossProductType {
productType = JBossProductType.ISPN;
} else if (homeDirName.contains("-jdg-")||(homeDirName.contains("datagrid-server"))) {
productType = JBossProductType.JDG;
- } else if (homeDirName.contains("-epp-")) {
- productType = JBossProductType.EPP;
} else if (homeDirName.contains("-jpp-")) {
productType = JBossProductType.JPP;
} else {
10 years, 7 months
[rhq] modules/enterprise
by lkrejci
modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/util/CriteriaQuery.java | 52 +---
modules/enterprise/server/jar/src/test/java/org/rhq/enterprise/server/util/CriteriaQueryTest.java | 106 +++++++++-
2 files changed, 119 insertions(+), 39 deletions(-)
New commits:
commit 74825e60875dc381da9dc452ab3b94b08d290f90
Author: Lukas Krejci <lkrejci(a)redhat.com>
Date: Thu Oct 3 08:56:12 2013 +0200
[BZ 1014524] - Fixing CriteriaQuery.iterator()
The iterator implementation assumed the page list consistent with
the page control, which might not be true, as brought to light by recent
work on PageControl.isConsistentWith() method.
The iterator implementation has been reworked to correctly iterate even
over the inconsistent results by loosening the assumption on the total
number of rows in all the pages.
diff --git a/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/util/CriteriaQuery.java b/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/util/CriteriaQuery.java
index a2bbfee..877c98e 100644
--- a/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/util/CriteriaQuery.java
+++ b/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/util/CriteriaQuery.java
@@ -20,7 +20,6 @@
*/
package org.rhq.enterprise.server.util;
-import java.util.ArrayList;
import java.util.Iterator;
import java.util.NoSuchElementException;
@@ -82,15 +81,11 @@ public class CriteriaQuery<T, C extends BaseCriteria> implements Iterable<T> {
//
//NOTE: Assumes criteria page iteration starts with page 0. Will continue to iterate over N members.
protected class QueryResultsIterator implements Iterator<T> {
- private int count;
-
private PageList<T> currentPage;
private Iterator<T> iterator;
- private T deletable = null;
-
- private ArrayList<T> forDeletion = new ArrayList<T>();
+ private boolean reachedEnd;
/**The first pageList returned by the criteria instance is where iteration begins.
* @param firstPage
@@ -98,31 +93,11 @@ public class CriteriaQuery<T, C extends BaseCriteria> implements Iterable<T> {
public QueryResultsIterator(PageList<T> firstPage) {
currentPage = firstPage;
iterator = currentPage.iterator();
- count = firstPage == null || firstPage.getPageControl() == null ? 0 : firstPage.getPageControl()
- .getStartRow();
}
@Override
public boolean hasNext() {
- return count < currentPage.getTotalSize();
- }
-
- @Override
- public T next() {
- //define logic for the end of a pagelist to move the iterator onto next page
- if (!iterator.hasNext()) {
- if (count == currentPage.getTotalSize()) {
- throw new NoSuchElementException();
- }
-
- deletable = null; // reset deletable.
-
- //remove all flagged instances of T
- if (!forDeletion.isEmpty()) {
- currentPage.removeAll(forDeletion);
- forDeletion.clear();
- }
-
+ if (!iterator.hasNext() && !reachedEnd) {
// advance the page. Although strange to be using a page control override in conjunction with
// CriteriaQuery, nonetheless make sure we advance it if it exists, because the normal setPaging is
// ignored when their is an overrides.
@@ -140,23 +115,24 @@ public class CriteriaQuery<T, C extends BaseCriteria> implements Iterable<T> {
currentPage = queryExecutor.execute(criteria);
iterator = currentPage.iterator();
+ reachedEnd = !iterator.hasNext(); //if we got an empty collection as a result for obtaining the next page
+ //we can be pretty sure we're past the number of available results
}
- T next = iterator.next();
- deletable = next;
- count++;
- return next;
+ return iterator.hasNext();
}
@Override
- public void remove() {
- if (deletable != null) {
- forDeletion.add(deletable);
- deletable = null;
- } else {
- throw new IllegalStateException(
- "Not allowed to call remove() without calling next() just before this call.");
+ public T next() {
+ if (!hasNext()) {
+ throw new NoSuchElementException();
}
+ return iterator.next();
+ }
+
+ @Override
+ public void remove() {
+ iterator.remove();
}
}
}
diff --git a/modules/enterprise/server/jar/src/test/java/org/rhq/enterprise/server/util/CriteriaQueryTest.java b/modules/enterprise/server/jar/src/test/java/org/rhq/enterprise/server/util/CriteriaQueryTest.java
index b1f5272..769f06e 100644
--- a/modules/enterprise/server/jar/src/test/java/org/rhq/enterprise/server/util/CriteriaQueryTest.java
+++ b/modules/enterprise/server/jar/src/test/java/org/rhq/enterprise/server/util/CriteriaQueryTest.java
@@ -22,6 +22,7 @@ import static java.util.Arrays.asList;
import static org.testng.Assert.assertEquals;
import java.util.ArrayList;
+import java.util.Collections;
import java.util.List;
import org.testng.AssertJUnit;
@@ -84,7 +85,8 @@ public class CriteriaQueryTest {
@Override
public PageList<FakeEntity> execute(FakeEntityCriteria criteria) {
- return pages.get(criteria.getPageNumber());
+ int page = criteria.getPageNumber();
+ return pages.size() > page ? pages.get(page) : new PageList<FakeEntity>(new PageControl(page, pc.getPageSize()));
}
}
@@ -191,6 +193,87 @@ public class CriteriaQueryTest {
}
@Test
+ public void testIteratingOverQueryWithInconsistentResults_fewResultsOnLastPage() {
+ PageControl pc = new PageControl(0, 100);
+ int realResults = 490;
+ FakeCriteriaQueryExecutor executor = prepareExecutor(realResults, 500, pc);
+
+ FakeEntityCriteria criteria = new FakeEntityCriteria();
+
+ criteria.setPaging(pc.getPageNumber(), pc.getPageSize());
+
+ CriteriaQuery<FakeEntity, FakeEntityCriteria> query = new CriteriaQuery<FakeEntity, FakeEntityCriteria>(
+ criteria, executor);
+
+ //Now iterate over the list and make sure that iteration happens in order as expected
+ //monotonically increasing.
+ int num = 0;
+ int last = -1;
+ for (FakeEntity entity : query) {
+ //this fails with earlier bug in CriteriaQuery
+ assertEquals(true, (last < entity.getId()));
+ last = entity.getId();
+ ++num;
+ }
+
+ assertEquals(num, realResults, "Unexpected number for results returned");
+ }
+
+ @Test
+ public void testIteratingOVerQueryWithInconsistentResults_emptyLastPage() {
+ PageControl pc = new PageControl(0, 100);
+ int realResults = 400;
+ FakeCriteriaQueryExecutor executor = prepareExecutor(realResults, 500, pc);
+
+ FakeEntityCriteria criteria = new FakeEntityCriteria();
+
+ criteria.setPaging(pc.getPageNumber(), pc.getPageSize());
+
+ CriteriaQuery<FakeEntity, FakeEntityCriteria> query = new CriteriaQuery<FakeEntity, FakeEntityCriteria>(
+ criteria, executor);
+
+ //Now iterate over the list and make sure that iteration happens in order as expected
+ //monotonically increasing.
+ int num = 0;
+ int last = -1;
+ for (FakeEntity entity : query) {
+ //this fails with earlier bug in CriteriaQuery
+ assertEquals(true, (last < entity.getId()));
+ last = entity.getId();
+ ++num;
+ }
+
+ assertEquals(num, realResults, "Unexpected number for results returned");
+ }
+
+ @Test
+ public void testIteratingOverQueryWithInconsistentResults_tooManyResults() {
+ PageControl pc = new PageControl(0, 100);
+ int realResults = 551;
+ FakeCriteriaQueryExecutor executor = prepareExecutor(realResults, 520, pc);
+
+ FakeEntityCriteria criteria = new FakeEntityCriteria();
+
+ criteria.setPaging(pc.getPageNumber(), pc.getPageSize());
+
+ CriteriaQuery<FakeEntity, FakeEntityCriteria> query = new CriteriaQuery<FakeEntity, FakeEntityCriteria>(
+ criteria, executor);
+
+ //Now iterate over the list and make sure that iteration happens in order as expected
+ //monotonically increasing.
+ int num = 0;
+ int last = -1;
+ for (FakeEntity entity : query) {
+ //this fails with earlier bug in CriteriaQuery
+ assertEquals(true, (last < entity.getId()));
+ last = entity.getId();
+ ++num;
+ }
+
+ assertEquals(num, realResults, "Unexpected number for results returned");
+ }
+
+ @Test
public void singleResultTest() {
// This test doesn't really fit here but I;m adding it for convenience
List<FakeEntity> result = null;
@@ -251,4 +334,25 @@ public class CriteriaQueryTest {
assertEquals("name", CriteriaQueryGenerator.getPageControl(c).getOrderingFields().get(0).getField());
assertEquals("id", CriteriaQueryGenerator.getPageControl(c).getOrderingFields().get(1).getField());
}
+
+
+ private FakeCriteriaQueryExecutor prepareExecutor(int realTotalSize, int reportedTotalSize, PageControl pc) {
+ FakeCriteriaQueryExecutor executor = new FakeCriteriaQueryExecutor(reportedTotalSize, pc);
+
+ List<FakeEntity> page = new ArrayList(pc.getPageSize());
+ for(int i = 0; i < realTotalSize; ++i) {
+ if (i != 0 && i % pc.getPageSize() == 0) {
+ executor.addPage(page);
+ page.clear();
+ }
+ page.add(new FakeEntity(i));
+ }
+
+ //add the last page
+ if (realTotalSize != reportedTotalSize) {
+ executor.addPage(page);
+ }
+
+ return executor;
+ }
}
10 years, 7 months
[rhq] Branch 'bug/1009945' - modules/enterprise
by John Sanda
modules/enterprise/server/server-metrics/src/main/java/org/rhq/server/metrics/Aggregator.java | 215 +++++++++-
modules/enterprise/server/server-metrics/src/main/java/org/rhq/server/metrics/MetricsDAO.java | 23 +
modules/enterprise/server/server-metrics/src/test/java/org/rhq/server/metrics/AggregatorTest.java | 15
3 files changed, 227 insertions(+), 26 deletions(-)
New commits:
commit aaa337e9044fa3e81087a748f2590c836eeed183
Author: John Sanda <jsanda(a)redhat.com>
Date: Wed Oct 2 22:53:11 2013 -0400
initial support for generating 6 hr and 24 hr data
diff --git a/modules/enterprise/server/server-metrics/src/main/java/org/rhq/server/metrics/Aggregator.java b/modules/enterprise/server/server-metrics/src/main/java/org/rhq/server/metrics/Aggregator.java
index d362c97..ef95516 100644
--- a/modules/enterprise/server/server-metrics/src/main/java/org/rhq/server/metrics/Aggregator.java
+++ b/modules/enterprise/server/server-metrics/src/main/java/org/rhq/server/metrics/Aggregator.java
@@ -3,6 +3,7 @@ package org.rhq.server.metrics;
import java.util.Comparator;
import java.util.List;
import java.util.Set;
+import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentSkipListSet;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.atomic.AtomicInteger;
@@ -21,6 +22,7 @@ import org.joda.time.DateTimeComparator;
import org.joda.time.Duration;
import org.rhq.server.metrics.domain.AggregateNumericMetric;
+import org.rhq.server.metrics.domain.AggregateNumericMetricMapper;
import org.rhq.server.metrics.domain.AggregateType;
import org.rhq.server.metrics.domain.MetricsIndexEntry;
import org.rhq.server.metrics.domain.MetricsIndexEntryMapper;
@@ -57,9 +59,15 @@ public class Aggregator {
private boolean sixHourDataReady;
private AtomicInteger remainingRawData;
-// private AtomicInteger remainingOneHourData
+ private AtomicInteger remainingOneHourData;
+ private AtomicInteger remainingSixHourData;
- private CountDownLatch countDownLatch;
+ private CountDownLatch allAggregationFinished;
+ private CountDownLatch oneHourIndexEntriesArrival;
+ private CountDownLatch sixHourIndexEntriesArrival;
+
+ private ConcurrentHashMap<Integer, MetricsIndexEntry> oneHourIndexEntries;
+ private ConcurrentHashMap<Integer, MetricsIndexEntry> sixHourIndexEntries;
public Aggregator(ListeningExecutorService workers, MetricsDAO dao, MetricsConfiguration configuration,
DateTimeService dtService, DateTime startTime) {
@@ -69,17 +77,31 @@ public class Aggregator {
this.dtService = dtService;
this.startTime = startTime;
- DateTime oneHourTimeSlice = dtService.getTimeSlice(startTime, configuration.getOneHourTimeSliceDuration());
- DateTime sixHourTimeSlice = dtService.getTimeSlice(startTime, configuration.getSixHourTimeSliceDuration());
+ DateTime oneHourTimeSlice = getOneHourTimeSlice();
+ DateTime sixHourTimeSlice = getSixHourTimeSlice();
oneHourDataReady = hasTimeSliceEnded(oneHourTimeSlice, configuration.getOneHourTimeSliceDuration());
sixHourDataReady = hasTimeSliceEnded(sixHourTimeSlice, configuration.getSixHourTimeSliceDuration());
int count = 1;
-// count += oneHourDataReady ? 1 : 0;
-// count += sixHourDataReady ? 1 : 0;
+ if (oneHourDataReady) {
+ count++;
+ oneHourIndexEntriesArrival = new CountDownLatch(1);
+ }
+ if (sixHourDataReady) {
+ count++;
+ sixHourIndexEntriesArrival = new CountDownLatch(1);
+ }
+
+ allAggregationFinished = new CountDownLatch(count);
+ }
+
+ private DateTime getSixHourTimeSlice() {
+ return dtService.getTimeSlice(startTime, configuration.getSixHourTimeSliceDuration());
+ }
- countDownLatch = new CountDownLatch(count);
+ private DateTime getOneHourTimeSlice() {
+ return dtService.getTimeSlice(startTime, configuration.getOneHourTimeSliceDuration());
}
private boolean hasTimeSliceEnded(DateTime startTime, Duration duration) {
@@ -107,11 +129,38 @@ public class Aggregator {
@Override
public void onFailure(Throwable t) {
- log.warn("Failed to retrieve raw data index entries for time slice " + startTime +
- ". Data aggregation cannot proceed.", t);
+ log.warn("Failed to retrieve raw data index entries for time slice [" + startTime +
+ "]. Data aggregation cannot proceed.", t);
}
}, workers);
- countDownLatch.await();
+
+ if (oneHourDataReady) {
+ StorageResultSetFuture oneHourFuture = dao.findMetricsIndexEntriesAsync(MetricsTable.SIX_HOUR,
+ startTime.getMillis());
+ Futures.addCallback(oneHourFuture, new FutureCallback<ResultSet>() {
+ @Override
+ public void onSuccess(ResultSet result) {
+ List<Row> rows = result.all();
+ oneHourIndexEntries = new ConcurrentHashMap<Integer, MetricsIndexEntry>(rows.size());
+ MetricsIndexEntryMapper mapper = new MetricsIndexEntryMapper(MetricsTable.SIX_HOUR);
+
+ for (Row row : result) {
+ MetricsIndexEntry indexEntry = mapper.map(row);
+ oneHourIndexEntries.put(indexEntry.getScheduleId(), indexEntry);
+ }
+ remainingOneHourData = new AtomicInteger(oneHourIndexEntries.size());
+ oneHourIndexEntriesArrival.countDown();
+ }
+
+ @Override
+ public void onFailure(Throwable t) {
+ log.warn("Failed to retrieve one hour aggregate index entries for time slice [" + startTime +
+ "]. Some six hour aggregates may not get generated.");
+ }
+ });
+ }
+
+ allAggregationFinished.await();
return oneHourAggregates;
}
@@ -157,6 +206,16 @@ public class Aggregator {
@Override
public void onSuccess(ResultSet result) {
updateRemainingRawDataCount();
+ try {
+ if (oneHourDataReady) {
+ oneHourIndexEntriesArrival.await();
+ calculateAggregate(indexEntry.getScheduleId(), MetricsTable.SIX_HOUR);
+ }
+ } catch (InterruptedException e) {
+ log.warn("An interrupt occurred while waiting one hour data index entries. " +
+ "No 6 hour data will be generated for " + oneHourAggregate.getScheduleId() +
+ " for time slice starting at " + getOneHourTimeSlice());
+ }
}
@Override
@@ -166,8 +225,6 @@ public class Aggregator {
updateRemainingRawDataCount();
}
});
-
- // TODO compute six hour aggregate
}
@Override
@@ -185,6 +242,95 @@ public class Aggregator {
}, workers);
}
+ private void calculateAggregate(final int scheduleId, final MetricsTable toTable) {
+ StorageResultSetFuture future;
+ final DateTime startTime;
+ final DateTime endTime;
+
+ if (toTable == MetricsTable.SIX_HOUR) {
+ startTime = getOneHourTimeSlice();
+ endTime = startTime.plus(configuration.getOneHourTimeSliceDuration());
+ future = dao.findOneHourMetricsAsync(scheduleId, startTime.getMillis(), endTime.getMillis());
+ } else { // toTable == 24 hr table
+ startTime = getSixHourTimeSlice();
+ endTime = startTime.plus(configuration.getSixHourTimeSliceDuration());
+ future = dao.findSixHourMetricsAsync(scheduleId, startTime.getMillis(), endTime.getMillis());
+ }
+
+ Futures.addCallback(future, new FutureCallback<ResultSet>() {
+ @Override
+ public void onSuccess(ResultSet result) {
+ AggregateNumericMetricMapper mapper = new AggregateNumericMetricMapper();
+ List<AggregateNumericMetric> metrics = mapper.mapAll(result);
+ final AggregateNumericMetric aggregate = calculateAggregate(metrics, startTime.getMillis());
+
+ if (toTable == MetricsTable.SIX_HOUR) {
+ ListenableFuture<List<ResultSet>> insertFuture = Futures.allAsList(
+ dao.insertSixHourDataAsync(aggregate.getScheduleId(), startTime.getMillis(), AggregateType.MIN,
+ aggregate.getMin()),
+ dao.insertSixHourDataAsync(aggregate.getScheduleId(), startTime.getMillis(), AggregateType.MAX,
+ aggregate.getMax()),
+ dao.insertSixHourDataAsync(aggregate.getScheduleId(), startTime.getMillis(), AggregateType.AVG,
+ aggregate.getAvg())
+ );
+ Futures.addCallback(insertFuture, new FutureCallback<List<ResultSet>>() {
+ @Override
+ public void onSuccess(List<ResultSet> result) {
+ if (result.get(0) == null) {
+ log.warn("Failed to store the minimum of the 6 hour aggregate " + aggregate);
+ }
+ if (result.get(1) == null) {
+ log.warn("Failed to store the maximum of the 6 hour aggregate " + aggregate);
+ }
+ if (result.get(2) == null) {
+ log.warn("Failed to store the average of the 6 hour aggregate " + aggregate);
+ }
+ DateTime twentyFourHourTimeSlice = dtService.getTimeSlice(new DateTime(
+ aggregate.getTimestamp()), configuration.getSixHourTimeSliceDuration());
+ StorageResultSetFuture indexFuture = dao.updateMetricsIndex(MetricsTable.TWENTY_FOUR_HOUR,
+ aggregate.getScheduleId(), twentyFourHourTimeSlice.getDayOfMonth());
+ Futures.addCallback(indexFuture, new FutureCallback<ResultSet>() {
+ @Override
+ public void onSuccess(ResultSet result) {
+ oneHourIndexEntries.remove(aggregate.getScheduleId());
+ updateRemainingOneHourDataCount();
+ // TODO compute 24 hr aggregate if necessary
+ }
+
+ @Override
+ public void onFailure(Throwable t) {
+ log.warn("Failed to update 24 hour data index for 6 hour aggregate " + aggregate);
+ oneHourIndexEntries.remove(aggregate.getScheduleId());
+ updateRemainingOneHourDataCount();
+ }
+ });
+ }
+
+ @Override
+ public void onFailure(Throwable t) {
+ log.warn("Failed to store six hour aggregate " + aggregate);
+ oneHourIndexEntries.remove(aggregate.getScheduleId());
+ updateRemainingOneHourDataCount();
+ }
+ });
+ } else {
+ // TODO handle 6 hr data
+ }
+ }
+
+ @Override
+ public void onFailure(Throwable t) {
+ if (toTable == MetricsTable.SIX_HOUR) {
+ log.warn("Failed to retrieve one hour data for scheduleId " + scheduleId + ". 6 hour aggregates " +
+ "for time slice [startTime: " + startTime + ", endTime: " + endTime + "] will not be generated.");
+ } else {
+ log.warn("Failed to retrieve six hour data for scheduleId " + scheduleId + ". 24 hour aggregates " +
+ "for time slice [startTime: " + startTime + ", endTime: " + endTime + "] will not be generated.");
+ }
+ }
+ });
+ }
+
private AggregateNumericMetric calculateAggregatedRaw(List<RawNumericMetric> rawMetrics, long timestamp) {
double min = Double.NaN;
double max = min;
@@ -207,15 +353,54 @@ public class Aggregator {
++count;
}
- // We let the caller handle setting the schedule id because in some cases we do
- // not care about it.
return new AggregateNumericMetric(rawMetrics.get(0).getScheduleId(), mean.getArithmeticMean(), min, max,
timestamp);
}
+ private AggregateNumericMetric calculateAggregate(List<AggregateNumericMetric> metrics, long timestamp) {
+ double min = Double.NaN;
+ double max = min;
+ int count = 0;
+ ArithmeticMeanCalculator mean = new ArithmeticMeanCalculator();
+
+ for (AggregateNumericMetric metric : metrics) {
+ if (count == 0) {
+ min = metric.getMin();
+ max = metric.getMax();
+ }
+ if (metric.getMin() < min) {
+ min = metric.getMin();
+ } else if (metric.getMax() > max) {
+ max = metric.getMax();
+ }
+ mean.add(metric.getAvg());
+ ++count;
+ }
+
+ return new AggregateNumericMetric(metrics.get(0).getScheduleId(), mean.getArithmeticMean(), min, max,
+ timestamp);
+ }
+
private void updateRemainingRawDataCount() {
if (remainingRawData.decrementAndGet() == 0) {
- countDownLatch.countDown();
+ if (log.isDebugEnabled()) {
+ log.debug("Finished aggregating raw data for time slice [" + startTime + "]");
+ }
+ allAggregationFinished.countDown();
+ // TODO delete the row from metrics_index
+ }
+ }
+
+ private void updateRemainingOneHourDataCount() {
+ if (remainingOneHourData.decrementAndGet() == 0) {
+ if (log.isDebugEnabled()) {
+ DateTime start = getOneHourTimeSlice();
+ DateTime end = start.plus(configuration.getOneHourTimeSliceDuration());
+ log.debug("Finished aggregating one hour data for time slice [startTime: " + start +
+ ", endTime: " + end + "]");
+ }
+ allAggregationFinished.countDown();
+ // TODO delete the row from metrics_index
}
}
diff --git a/modules/enterprise/server/server-metrics/src/main/java/org/rhq/server/metrics/MetricsDAO.java b/modules/enterprise/server/server-metrics/src/main/java/org/rhq/server/metrics/MetricsDAO.java
index 45a949d..40450b9 100644
--- a/modules/enterprise/server/server-metrics/src/main/java/org/rhq/server/metrics/MetricsDAO.java
+++ b/modules/enterprise/server/server-metrics/src/main/java/org/rhq/server/metrics/MetricsDAO.java
@@ -165,12 +165,25 @@ public class MetricsDAO {
return storageSession.execute(statement);
}
+ public StorageResultSetFuture insertSixHourDataAsync(int scheduleId, long timestamp, AggregateType type,
+ double value) {
+ BoundStatement statement = insertSixHourData.bind(scheduleId, new Date(timestamp), type.ordinal(), value);
+ return storageSession.executeAsync(statement);
+ }
+
public ResultSet insertTwentyFourHourData(int scheduleId, long timestamp, AggregateType type, double value) {
BoundStatement statement = insertTwentyFourHourData.bind(scheduleId, new Date(timestamp), type.ordinal(),
value);
return storageSession.execute(statement);
}
+ public StorageResultSetFuture insertTwentyFourHourDataAsync(int scheduleId, long timestamp, AggregateType type,
+ double value) {
+ BoundStatement statement = insertTwentyFourHourData.bind(scheduleId, new Date(timestamp), type.ordinal(),
+ value);
+ return storageSession.executeAsync(statement);
+ }
+
public Iterable<RawNumericMetric> findRawMetrics(int scheduleId, long startTime, long endTime) {
try {
BoundStatement boundStatement = rawMetricsQuery.bind(scheduleId, new Date(startTime), new Date(endTime));
@@ -205,12 +218,22 @@ public class MetricsDAO {
storageSession);
}
+ public StorageResultSetFuture findOneHourMetricsAsync(int scheduleId, long startTime, long endTime) {
+ BoundStatement statement = findOneHourMetricsByDateRange.bind(scheduleId, new Date(startTime), new Date(endTime));
+ return storageSession.executeAsync(statement);
+ }
+
public Iterable<AggregateNumericMetric> findSixHourMetrics(int scheduleId, long startTime, long endTime) {
BoundStatement statement = findSixHourMetricsByDateRange.bind(scheduleId, new Date(startTime), new Date(endTime));
return new SimplePagedResult<AggregateNumericMetric>(statement, new AggregateNumericMetricMapper(),
storageSession);
}
+ public StorageResultSetFuture findSixHourMetricsAsync(int scheduleId, long startTime, long endTime) {
+ BoundStatement statement = findSixHourMetricsByDateRange.bind(scheduleId, new Date(startTime), new Date(endTime));
+ return storageSession.executeAsync(statement);
+ }
+
public Iterable<AggregateNumericMetric> findTwentyFourHourMetrics(int scheduleId, long startTime, long endTime) {
BoundStatement statement = findTwentyFourHourMetricsByDateRange.bind(scheduleId, new Date(startTime), new Date(endTime));
return new SimplePagedResult<AggregateNumericMetric>(statement, new AggregateNumericMetricMapper(),
diff --git a/modules/enterprise/server/server-metrics/src/test/java/org/rhq/server/metrics/AggregatorTest.java b/modules/enterprise/server/server-metrics/src/test/java/org/rhq/server/metrics/AggregatorTest.java
index 4c65728..283d6fb 100644
--- a/modules/enterprise/server/server-metrics/src/test/java/org/rhq/server/metrics/AggregatorTest.java
+++ b/modules/enterprise/server/server-metrics/src/test/java/org/rhq/server/metrics/AggregatorTest.java
@@ -34,28 +34,21 @@ public class AggregatorTest extends CassandraIntegrationTest {
private static final double TEST_PRECISION = Math.pow(10, -9);
- private static class AggregatorTestStub extends Aggregator {
+ private class AggregatorTestStub extends Aggregator {
public AggregatorTestStub(ListeningExecutorService workers, MetricsDAO dao, MetricsConfiguration configuration,
DateTimeService dtService, DateTime startTime) {
super(workers, dao, configuration, dtService, startTime);
}
- private DateTime currentHour;
-
- public void setCurrentHour(DateTime currentHour) {
- this.currentHour = currentHour;
- }
-
@Override
protected DateTime currentHour() {
- if (currentHour == null) {
- return super.currentHour();
- }
return currentHour;
}
}
+ private DateTime currentHour;
+
private ListeningExecutorService workers;
private MetricsDAO dao;
@@ -97,8 +90,8 @@ public class AggregatorTest extends CassandraIntegrationTest {
DateTime hour9 = hour0.plusHours(9);
DateTime hour8 = hour9.minusHours(1);
+ currentHour = hour9;
AggregatorTestStub aggregator = new AggregatorTestStub(workers, dao, configuration, dateTimeService, hour8);
- aggregator.setCurrentHour(hour9);
DateTime firstMetricTime = hour8.plusMinutes(5);
DateTime secondMetricTime = hour8.plusMinutes(10);
10 years, 7 months
[rhq] 2 commits - modules/enterprise
by mike thompson
modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/inventory/resource/detail/monitoring/table/AddToDashboardComponent.java | 4 ++--
modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/inventory/resource/detail/monitoring/table/MetricsResourceView.java | 2 +-
2 files changed, 3 insertions(+), 3 deletions(-)
New commits:
commit 473e9b9b967a277ba5bed383089cc73564c0a758
Author: Mike Thompson <mithomps(a)redhat.com>
Date: Wed Oct 2 17:01:30 2013 -0700
Fix a svg chart refresh issue when navigating monitoring subtabs.
diff --git a/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/inventory/resource/detail/monitoring/table/MetricsResourceView.java b/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/inventory/resource/detail/monitoring/table/MetricsResourceView.java
index c8d56d3..6378a9e 100644
--- a/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/inventory/resource/detail/monitoring/table/MetricsResourceView.java
+++ b/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/inventory/resource/detail/monitoring/table/MetricsResourceView.java
@@ -182,6 +182,6 @@ public class MetricsResourceView extends AbstractD3GraphListView implements
@Override
public void onViewRendered() {
// refresh the graphs on subtab nav because we are a cached view not new
- availabilityGraph.parentResized();
+ refreshData();
}
}
commit 6da584ee7c2eaa55ce14702d1386944e2d33ad08
Author: Mike Thompson <mithomps(a)redhat.com>
Date: Wed Oct 2 09:43:30 2013 -0700
[BZ 1014586] - "Add To Dashboard" button size is too small on certain displays. Gave the button more room to expand by shrinking the dashboards selectItem expanding the button width where it was using default width. We don't have much room to work with in this toolbar so making the button width fixed so i18n won't bump the layout and text label has room to display.
diff --git a/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/inventory/resource/detail/monitoring/table/AddToDashboardComponent.java b/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/inventory/resource/detail/monitoring/table/AddToDashboardComponent.java
index 8823dcf..e47f366 100644
--- a/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/inventory/resource/detail/monitoring/table/AddToDashboardComponent.java
+++ b/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/inventory/resource/detail/monitoring/table/AddToDashboardComponent.java
@@ -75,12 +75,12 @@ public class AddToDashboardComponent extends EnhancedToolStrip implements Enhanc
private void createToolstrip() {
addSpacer(15);
addToDashboardButton = new IButton(MSG.view_metric_addToDashboard());
+ addToDashboardButton.setWidth(120);
addToDashboardButton.disable();
dashboardSelectItem = new SelectItem();
dashboardSelectItem.setTitle(MSG.chart_metrics_add_to_dashboard_label());
- dashboardSelectItem.setWidth(300);
- dashboardSelectItem.setPickListWidth(210);
+ dashboardSelectItem.setWidth(260);
populateDashboardMenu();
addFormItem(dashboardSelectItem);
addMember(addToDashboardButton);
10 years, 7 months
[rhq] Changes to 'bug/1009945'
by John Sanda
New branch 'bug/1009945' available with the following commits:
commit 84bfdc377cd54b091577e8564ea38adaa5e2048e
Author: John Sanda <jsanda(a)redhat.com>
Date: Wed Oct 2 17:58:38 2013 -0400
update 6 hr index after inserting 1 hr data
commit df288fcf26daf798b1d8e828cfa8353314724e6c
Author: John Sanda <jsanda(a)redhat.com>
Date: Wed Oct 2 17:36:21 2013 -0400
Initial commit for new Aggregator class
This is a first pass at computing multiple aggregates concurrently.
commit a795b916cea3d31a3f95b1f125db214588c39318
Author: John Sanda <jsanda(a)redhat.com>
Date: Wed Oct 2 11:13:48 2013 -0400
remove extraneous logging
10 years, 7 months
[rhq] modules/enterprise
by Thomas Segismont
modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/rest/ContentHandlerBean.java | 18 +---------
1 file changed, 2 insertions(+), 16 deletions(-)
New commits:
commit b2348f2305b80df82a4f4005ce015ec80af54619
Author: Thomas Segismont <tsegismo(a)redhat.com>
Date: Wed Oct 2 23:03:46 2013 +0200
Fix ContentHandlerBean.uploadContent throws java.lang.ArrayIndexOutOfBoundsException
Caused by: java.lang.ArrayIndexOutOfBoundsException
at java.lang.System.arraycopy(Native Method) [rt.jar:1.7.0_40]
at java.io.BufferedOutputStream.write(BufferedOutputStream.java:128) [rt.jar:1.7.0_40]
at org.rhq.enterprise.server.rest.ContentHandlerBean.uploadContent(ContentHandlerBean.java:104) [rhq-server.jar:4.10.0-SNAPSHOT]
I did not look why exactly but we can simply use existing method in StreamUtil
diff --git a/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/rest/ContentHandlerBean.java b/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/rest/ContentHandlerBean.java
index 41d7847..41a47be 100644
--- a/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/rest/ContentHandlerBean.java
+++ b/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/rest/ContentHandlerBean.java
@@ -91,23 +91,9 @@ public class ContentHandlerBean extends AbstractRestBean {
File tmpDir = new File(tmpDirName);
File outFile = File.createTempFile(TMP_FILE_PREFIX, TMP_FILE_SUFFIX,tmpDir);
- FileOutputStream fos = new FileOutputStream(outFile);
- BufferedOutputStream bos = new BufferedOutputStream(fos);
+ BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream(outFile));
- BufferedInputStream bis = new BufferedInputStream(contentStream);
-
- byte[] buf = new byte[32768]; // 32k
-
- int data;
- int off=0;
- while ((data=bis.read(buf))!=-1) {
- bos.write(buf,off,data);
- off+=data;
- }
-
- bos.flush();
- bos.close();
- bis.close();
+ StreamUtil.copy(contentStream, bos, true);
String fileHandle = outFile.getName();
StringValue sv = new StringValue(fileHandle);
10 years, 7 months
[rhq] Changes to 'build-er3'
by Simeon Pinder
New branch 'build-er3' available with the following commits:
commit 46f7ba232572716bb26c0e7ca6628978aaf51f6f
Merge: 0431c61 6c4b6c6
Author: Simeon Pinder <spinder(a)redhat.com>
Date: Wed Oct 2 15:15:57 2013 -0400
Merge branch 'master' into nightly/rhq.jon
10 years, 7 months
[rhq] modules/enterprise
by mazz
modules/enterprise/server/appserver/src/main/scripts/rhq-container.build.xml | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)
New commits:
commit 703f72566b589bbf91eb3e000f38b11dea9950c7
Author: John Mazzitelli <mazz(a)redhat.com>
Date: Wed Oct 2 14:30:49 2013 -0400
change the welcome page to remove the mention of "EAP 6" since customer typically isn't even aware (or care) what we are running on.
Also, took out "RHQ" and only used the word "server" to avoid branding issues when this is run as JON
diff --git a/modules/enterprise/server/appserver/src/main/scripts/rhq-container.build.xml b/modules/enterprise/server/appserver/src/main/scripts/rhq-container.build.xml
index 57d2012..2d14487 100644
--- a/modules/enterprise/server/appserver/src/main/scripts/rhq-container.build.xml
+++ b/modules/enterprise/server/appserver/src/main/scripts/rhq-container.build.xml
@@ -488,11 +488,11 @@
<!-- Changing the default content of the welcome page -->
<replaceregexp file="${jboss.home}/welcome-content/index.html" flags="gis" match='<div class="section">(.*?)</div>' replace='
<div class="section">

- <h1>EAP 6 Notification</h1>

- <h3>Your RHQ Server is being started, please wait.</h3>

+ <h1>Server Initialization</h1>

+ <h3>Your server is starting, please wait.</h3>

<p class="WarnBlock" id="error" style="background-color: #DE7272; display: none;"></p>

<p class="WarnBlock" id="progress">Starting ..</p>

- <sub>You will be automatically redirected once the RHQ server is up and running. If this takes more than 10 minutes, please check the server log for possible issues.</sub>

+ <sub>You will be automatically redirected once the server is up and running. If this takes more than 10 minutes, please check the server log for possible issues.</sub>

</div>'/>
</target>
10 years, 7 months
[rhq] modules/enterprise
by mazz
modules/enterprise/agent/src/main/java/org/rhq/enterprise/agent/AgentConfigurationConstants.java | 2
modules/enterprise/agent/src/main/java/org/rhq/enterprise/agent/AgentConfigurationUpgrade.java | 17 ++
modules/enterprise/agent/src/main/java/org/rhq/enterprise/agent/AgentMain.java | 10 +
modules/enterprise/agent/src/main/java/org/rhq/enterprise/agent/SecurityTokenCommandAuthenticator.java | 69 ++++++++++
modules/enterprise/agent/src/main/resources/agent-configuration.xml | 11 +
modules/enterprise/agent/src/test/java/org/rhq/enterprise/agent/SimpleCommandAuthenticator.java | 7 +
modules/enterprise/comm/src/main/java/org/rhq/enterprise/communications/ServiceContainer.java | 53 +++++++
modules/enterprise/comm/src/main/java/org/rhq/enterprise/communications/command/server/CommandAuthenticator.java | 10 +
modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/agentclient/impl/AgentClientImpl.java | 25 ++-
modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/core/comm/SecurityTokenCommandAuthenticator.java | 8 +
10 files changed, 203 insertions(+), 9 deletions(-)
New commits:
commit c160be0f0e33036cb20c553bfb0cd33703628aa3
Author: John Mazzitelli <mazz(a)redhat.com>
Date: Tue Oct 1 17:16:09 2013 -0400
BZ 965886 - provide a security authentictor for the agent and have the server provide the agent's token when sending messages.
diff --git a/modules/enterprise/agent/src/main/java/org/rhq/enterprise/agent/AgentConfigurationConstants.java b/modules/enterprise/agent/src/main/java/org/rhq/enterprise/agent/AgentConfigurationConstants.java
index c5cf4a8..000fdc0 100644
--- a/modules/enterprise/agent/src/main/java/org/rhq/enterprise/agent/AgentConfigurationConstants.java
+++ b/modules/enterprise/agent/src/main/java/org/rhq/enterprise/agent/AgentConfigurationConstants.java
@@ -58,7 +58,7 @@ public interface AgentConfigurationConstants {
/**
* This is the current schema version that our agent configuration knows about.
*/
- int CURRENT_CONFIG_SCHEMA_VERSION = 7;
+ int CURRENT_CONFIG_SCHEMA_VERSION = 8;
/**
* Flag to indicate if the agent's configuration has been setup.
diff --git a/modules/enterprise/agent/src/main/java/org/rhq/enterprise/agent/AgentConfigurationUpgrade.java b/modules/enterprise/agent/src/main/java/org/rhq/enterprise/agent/AgentConfigurationUpgrade.java
index 27e68f9..e185377 100644
--- a/modules/enterprise/agent/src/main/java/org/rhq/enterprise/agent/AgentConfigurationUpgrade.java
+++ b/modules/enterprise/agent/src/main/java/org/rhq/enterprise/agent/AgentConfigurationUpgrade.java
@@ -69,6 +69,7 @@ public class AgentConfigurationUpgrade extends PreferencesUpgrade {
list.add(new Step4to5()); // goes from v4 to v5
list.add(new Step5to6()); // goes from v5 to v6
list.add(new Step6to7()); // goes from v6 to v7
+ list.add(new Step7to8()); // goes from v7 to v8
return list;
}
@@ -200,4 +201,20 @@ public class AgentConfigurationUpgrade extends PreferencesUpgrade {
return;
}
}
+
+ static class Step7to8 extends PreferencesUpgradeStep {
+ public int getSupportedConfigurationSchemaVersion() {
+ return 8;
+ }
+
+ public void upgrade(Preferences preferences) {
+ // This new schema version added support for the new command authenticator so the agent authenticates servers.
+ // Note that to support tests, we only upgrade the pref if it wasn't set (it should not have been set in production
+ // builds - it was only ever set in tests in older versions).
+ if (null == preferences.get(ServiceContainerConfigurationConstants.COMMAND_AUTHENTICATOR, null)) {
+ preferences.put(ServiceContainerConfigurationConstants.COMMAND_AUTHENTICATOR,
+ SecurityTokenCommandAuthenticator.class.getName());
+ }
+ }
+ }
}
\ No newline at end of file
diff --git a/modules/enterprise/agent/src/main/java/org/rhq/enterprise/agent/AgentMain.java b/modules/enterprise/agent/src/main/java/org/rhq/enterprise/agent/AgentMain.java
index a8d8bdf..77c88b1 100644
--- a/modules/enterprise/agent/src/main/java/org/rhq/enterprise/agent/AgentMain.java
+++ b/modules/enterprise/agent/src/main/java/org/rhq/enterprise/agent/AgentMain.java
@@ -1371,6 +1371,8 @@ public class AgentMain {
// delete any old token so request is unauthenticated to get server to accept it
agent_config.setAgentSecurityToken(null);
+ m_commServices.addCustomData(
+ SecurityTokenCommandAuthenticator.CMDCONFIG_PROP_SECURITY_TOKEN, null);
FailoverListComposite failover_list = null;
try {
@@ -1414,6 +1416,9 @@ public class AgentMain {
// Note that we don't retry even if storing the token fails since this kind
// of failure is probably not recoverable even if we try again.
agent_config.setAgentSecurityToken(token);
+ m_commServices.addCustomData(
+ SecurityTokenCommandAuthenticator.CMDCONFIG_PROP_SECURITY_TOKEN, token);
+
LOG.debug(AgentI18NResourceKeys.NEW_SECURITY_TOKEN, token);
}
@@ -2330,6 +2335,11 @@ public class AgentMain {
// add the command listener that was passed to us
m_commServices.addCommandListener(listener);
+ // In case we are already registered from a previous run, store the token in the custom data - this is used
+ // by the security token authenticator in order to authenticate the remote endpoint sending us messages
+ m_commServices.addCustomData(SecurityTokenCommandAuthenticator.CMDCONFIG_PROP_SECURITY_TOKEN,
+ m_configuration.getAgentSecurityToken());
+
// this listener will enable our sender as soon as we receive a message from the server
CommandListenerStateListener commandListenerStateListener = new CommandListenerStateListener();
m_clientSender.addStateListener(commandListenerStateListener, true);
diff --git a/modules/enterprise/agent/src/main/java/org/rhq/enterprise/agent/SecurityTokenCommandAuthenticator.java b/modules/enterprise/agent/src/main/java/org/rhq/enterprise/agent/SecurityTokenCommandAuthenticator.java
new file mode 100644
index 0000000..d992353
--- /dev/null
+++ b/modules/enterprise/agent/src/main/java/org/rhq/enterprise/agent/SecurityTokenCommandAuthenticator.java
@@ -0,0 +1,69 @@
+/*
+ * RHQ Management Platform
+ * Copyright 2011, 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.enterprise.agent;
+
+import org.rhq.enterprise.communications.ServiceContainer;
+import org.rhq.enterprise.communications.command.Command;
+import org.rhq.enterprise.communications.command.server.CommandAuthenticator;
+
+/**
+ * This is the authenticator object that will make sure we are getting a message from a valid server.
+ * It will check to make sure the token the sender sent us matches our own token. The server will know
+ * what token it assigned us, so it should be able to give us our own token back. If the token doesn't match,
+ * we must be getting a message from some server that isn't the one that we are registered with, thus,
+ * then this happens, the command is aborted.
+ *
+ * @author John Mazzitelli
+ */
+public class SecurityTokenCommandAuthenticator implements CommandAuthenticator {
+
+ /**
+ * This is the name of the command configuration property that the server will set to the security token string.
+ */
+ static final String CMDCONFIG_PROP_SECURITY_TOKEN = "rhq.security-token";
+
+ private ServiceContainer serviceContainer;
+
+ @Override
+ public boolean isAuthenticated(Command command) {
+ if (this.serviceContainer == null) {
+ return false; // we can't authenticate yet, we don't have the service container
+ }
+
+ String incomingToken = command.getConfiguration().getProperty(CMDCONFIG_PROP_SECURITY_TOKEN);
+ Object ourToken = this.serviceContainer.getCustomData(CMDCONFIG_PROP_SECURITY_TOKEN); // the agent puts this in here
+
+ if (incomingToken == null) {
+ if (ourToken == null) {
+ return true; // no tokens anywhere - accept this message in case this command is part of the comm setup
+ } else {
+ return false; // we have a token, but the incoming command doesn't - reject this command
+ }
+ }
+
+ return incomingToken.equals(ourToken);
+ }
+
+ @Override
+ public void setServiceContainer(ServiceContainer serviceContainer) {
+ this.serviceContainer = serviceContainer;
+ }
+}
diff --git a/modules/enterprise/agent/src/main/resources/agent-configuration.xml b/modules/enterprise/agent/src/main/resources/agent-configuration.xml
index 151a218..9f46f62 100644
--- a/modules/enterprise/agent/src/main/resources/agent-configuration.xml
+++ b/modules/enterprise/agent/src/main/resources/agent-configuration.xml
@@ -59,7 +59,7 @@ commands named "config", "setconfig" and "setup" and the command line options
file conforms to. This is the schema for the rhq.agent
preferences.
-->
- <entry key="rhq.agent.configuration-schema-version" value="7" />
+ <entry key="rhq.agent.configuration-schema-version" value="8" />
<!--
_______________________________________________________________
@@ -1097,6 +1097,15 @@ commands named "config", "setconfig" and "setup" and the command line options
-->
<entry key="rhq.communications.remote-pojos" value="org.rhq.enterprise.communications.PingImpl:org.rhq.enterprise.communications.Ping" />
+ <!--
+ _______________________________________________________________
+ rhq.communications.command-authenticator
+
+ A command authenticator class that will be used to authenticate
+ incoming commands from the server.
+ -->
+ <entry key="rhq.communications.command-authenticator" value="org.rhq.enterprise.agent.SecurityTokenCommandAuthenticator" />
+
</map>
</node>
</node>
diff --git a/modules/enterprise/agent/src/test/java/org/rhq/enterprise/agent/SimpleCommandAuthenticator.java b/modules/enterprise/agent/src/test/java/org/rhq/enterprise/agent/SimpleCommandAuthenticator.java
index 376f5ae..cb5b1ba 100644
--- a/modules/enterprise/agent/src/test/java/org/rhq/enterprise/agent/SimpleCommandAuthenticator.java
+++ b/modules/enterprise/agent/src/test/java/org/rhq/enterprise/agent/SimpleCommandAuthenticator.java
@@ -18,6 +18,7 @@
*/
package org.rhq.enterprise.agent;
+import org.rhq.enterprise.communications.ServiceContainer;
import org.rhq.enterprise.communications.command.Command;
import org.rhq.enterprise.communications.command.server.CommandAuthenticator;
@@ -41,8 +42,14 @@ public class SimpleCommandAuthenticator implements CommandAuthenticator {
/**
* @see CommandAuthenticator#isAuthenticated(Command)
*/
+ @Override
public boolean isAuthenticated(Command command) {
String prop_value = command.getConfiguration().getProperty(AUTHENTICATION_PROP);
return AUTHENTICATION_PROP_VALUE.equals(prop_value);
}
+
+ @Override
+ public void setServiceContainer(ServiceContainer serviceContainer) {
+ // no-op
+ }
}
\ No newline at end of file
diff --git a/modules/enterprise/comm/src/main/java/org/rhq/enterprise/communications/ServiceContainer.java b/modules/enterprise/comm/src/main/java/org/rhq/enterprise/communications/ServiceContainer.java
index 6d1bf38..483c79e 100644
--- a/modules/enterprise/comm/src/main/java/org/rhq/enterprise/communications/ServiceContainer.java
+++ b/modules/enterprise/comm/src/main/java/org/rhq/enterprise/communications/ServiceContainer.java
@@ -66,6 +66,7 @@ import org.rhq.enterprise.communications.command.impl.stream.RemoteInputStreamCo
import org.rhq.enterprise.communications.command.impl.stream.RemoteOutputStreamCommand;
import org.rhq.enterprise.communications.command.impl.stream.server.RemoteInputStreamCommandService;
import org.rhq.enterprise.communications.command.impl.stream.server.RemoteOutputStreamCommandService;
+import org.rhq.enterprise.communications.command.server.CommandAuthenticator;
import org.rhq.enterprise.communications.command.server.CommandListener;
import org.rhq.enterprise.communications.command.server.CommandProcessor;
import org.rhq.enterprise.communications.command.server.CommandService;
@@ -239,12 +240,57 @@ public class ServiceContainer {
private ConcurrencyManager m_concurrencyManager;
/**
+ * Custom data is a way to share information across disparate components so long as those components
+ * have access to this service container object. This data is never used by the service container - it
+ * can be null, empty, or chock full of data. No validation is performed on this data.
+ */
+ private Map<String, Object> m_customData;
+
+ /**
* Private to prevent external instantiation.
*/
public ServiceContainer() {
m_discoveryListener = new ServiceContainerNetworkNotificationListener();
m_senderCreationListeners = new Vector<ServiceContainerSenderCreationListener>(); // synchronized
m_commandListeners = new ArrayList<CommandListener>();
+ m_customData = new HashMap<String, Object>();
+ }
+
+ /**
+ * Returns custom data identified with the given key. If no data exists that is identified by that key,
+ * null is returned.
+ *
+ * @param key identifies the custom data to return - if null, this method returns null
+ * @return the custom data or null if there is no custom data associated with the given key
+ */
+ public Object getCustomData(String key) {
+ if (key == null) {
+ return null;
+ }
+ synchronized (this.m_customData) {
+ return this.m_customData.get(key);
+ }
+ }
+
+ /**
+ * Stores the given custom data to be identified with the given key. You can retrieve this data
+ * via {@link #getCustomData(String)}.
+ *
+ * @param key identifies the custom data to store - if null, this method does nothing and returns.
+ * @param data custom data to add - it will be associated with the given key.
+ */
+ public void addCustomData(String key, Object data) {
+ if (key == null) {
+ return;
+ }
+ synchronized (this.m_customData) {
+ if (data != null) {
+ this.m_customData.put(key, data);
+ } else {
+ this.m_customData.remove(key);
+ }
+ }
+ return;
}
/**
@@ -671,6 +717,7 @@ public class ServiceContainer {
m_discoveryListener.removeAll();
m_commandListeners.clear();
m_senderCreationListeners.clear();
+ m_customData.clear();
LOG.info(CommI18NResourceKeys.SERVICE_CONTAINER_SHUTDOWN);
@@ -1221,7 +1268,11 @@ public class ServiceContainer {
handler.addCommandListener(listener);
}
- handler.setCommandAuthenticator(m_configuration.getCommandAuthenticator());
+ CommandAuthenticator commandAuthenticator = m_configuration.getCommandAuthenticator();
+ if (commandAuthenticator != null) {
+ commandAuthenticator.setServiceContainer(this);
+ handler.setCommandAuthenticator(commandAuthenticator);
+ }
m_connector.addInvocationHandler(SUBSYSTEM, handler);
m_connector.start();
diff --git a/modules/enterprise/comm/src/main/java/org/rhq/enterprise/communications/command/server/CommandAuthenticator.java b/modules/enterprise/comm/src/main/java/org/rhq/enterprise/communications/command/server/CommandAuthenticator.java
index df2afb0..9a1a053 100644
--- a/modules/enterprise/comm/src/main/java/org/rhq/enterprise/communications/command/server/CommandAuthenticator.java
+++ b/modules/enterprise/comm/src/main/java/org/rhq/enterprise/communications/command/server/CommandAuthenticator.java
@@ -18,6 +18,7 @@
*/
package org.rhq.enterprise.communications.command.server;
+import org.rhq.enterprise.communications.ServiceContainer;
import org.rhq.enterprise.communications.command.Command;
/**
@@ -37,4 +38,13 @@ public interface CommandAuthenticator {
* processing of the command should take place
*/
boolean isAuthenticated(Command command);
+
+ /**
+ * This sets the object that is handling the communications and is what received the command that needs to be authenticated.
+ * This service container contains {@link ServiceContainer#getCustomData(String) custom data} that can be retrieved by the
+ * authenticator if needed. This method is only called once when the authenticator object is created.
+ *
+ * @param serviceContainer
+ */
+ void setServiceContainer(ServiceContainer serviceContainer);
}
\ No newline at end of file
diff --git a/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/agentclient/impl/AgentClientImpl.java b/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/agentclient/impl/AgentClientImpl.java
index c1a3c15..ee550f4 100644
--- a/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/agentclient/impl/AgentClientImpl.java
+++ b/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/agentclient/impl/AgentClientImpl.java
@@ -46,6 +46,12 @@ import org.rhq.enterprise.server.safeinvoker.HibernateDetachUtility;
*/
public class AgentClientImpl implements AgentClient {
/**
+ * This is the name of the command configuration property that will get assigned the security token string.
+ * All commands sent to the agent will get this command property set which contains the agent's token.
+ */
+ private static final String CMDCONFIG_PROP_SECURITY_TOKEN = "rhq.security-token";
+
+ /**
* The agent that this client communicates with.
*/
private final Agent agent;
@@ -87,7 +93,7 @@ public class AgentClientImpl implements AgentClient {
this.agent = agent;
this.sender = sender;
this.clientRemotePojoFactory = sender.getClientRemotePojoFactory();
- this.sender.setSendCallbacks(new SendCallback[] { new ExternalizableStrategySendCallback() });
+ this.sender.setSendCallbacks(new SendCallback[] { new AgentSendCallback(agent) });
// enforce the restriction (instituted in 1.1 due to multi-server HA concerns)
// that no server->agent calls use guaranteedDelivery
this.clientRemotePojoFactory.setDeliveryGuaranteed(ClientRemotePojoFactory.GuaranteedDelivery.DISABLED);
@@ -230,22 +236,29 @@ public class AgentClientImpl implements AgentClient {
*
* @author jshaughnessy
*/
- private static class ExternalizableStrategySendCallback implements SendCallback {
+ private static class AgentSendCallback implements SendCallback {
+
+ private final String token;
- public ExternalizableStrategySendCallback() {
- };
+ public AgentSendCallback(Agent targetAgent) {
+ token = targetAgent.getAgentToken();
+ }
public void sending(Command command) {
- // long start = System.currentTimeMillis();
try {
HibernateDetachUtility.nullOutUninitializedFields(command,
HibernateDetachUtility.SerializationType.SERIALIZATION);
- // System.out.println("HDU: " + (System.currentTimeMillis() - start));
} catch (Exception e) {
e.printStackTrace();
}
ExternalizableStrategy.setStrategy(ExternalizableStrategy.Subsystem.AGENT);
+
+ if (token != null) {
+ command.getConfiguration().setProperty(CMDCONFIG_PROP_SECURITY_TOKEN, token);
+ }
+
+ return;
}
public CommandResponse sent(Command command, CommandResponse response) {
diff --git a/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/core/comm/SecurityTokenCommandAuthenticator.java b/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/core/comm/SecurityTokenCommandAuthenticator.java
index 1719e2b..a6f0c16 100644
--- a/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/core/comm/SecurityTokenCommandAuthenticator.java
+++ b/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/core/comm/SecurityTokenCommandAuthenticator.java
@@ -20,8 +20,10 @@ package org.rhq.enterprise.server.core.comm;
import java.util.Hashtable;
import java.util.Map;
+
import org.rhq.core.clientapi.server.core.CoreServerService;
import org.rhq.core.domain.resource.Agent;
+import org.rhq.enterprise.communications.ServiceContainer;
import org.rhq.enterprise.communications.command.Command;
import org.rhq.enterprise.communications.command.impl.remotepojo.RemotePojoInvocationCommand;
import org.rhq.enterprise.communications.command.server.CommandAuthenticator;
@@ -74,6 +76,7 @@ public class SecurityTokenCommandAuthenticator implements CommandAuthenticator {
/**
* @see CommandAuthenticator#isAuthenticated(Command)
*/
+ @Override
public boolean isAuthenticated(Command command) {
String security_token = command.getConfiguration().getProperty(CMDCONFIG_PROP_SECURITY_TOKEN);
@@ -111,6 +114,11 @@ public class SecurityTokenCommandAuthenticator implements CommandAuthenticator {
return true;
}
+ @Override
+ public void setServiceContainer(ServiceContainer serviceContainer) {
+ // don't need this, no need to store it
+ }
+
/**
* This examines the given command and determines if it is a command asking to register an agent.
*
10 years, 7 months