modules/core/arquillian-integration/container/src/main/java/org/rhq/test/arquillian/FakeServerInventory.java
| 101 ++--
modules/core/arquillian-integration/container/src/test/java/org/rhq/test/arquillian/CleanUpTest.java
| 8
modules/core/arquillian-integration/container/src/test/java/org/rhq/test/arquillian/InsideAgentSimulationTest.java
| 14
modules/core/arquillian-integration/container/src/test/java/org/rhq/test/arquillian/avail/AvailTest.java
| 14
modules/core/client-api/src/main/java/org/rhq/core/clientapi/server/discovery/DiscoveryServerService.java
| 14
modules/core/domain/src/main/java/org/rhq/core/domain/discovery/MergeInventoryReportResults.java
| 10
modules/core/domain/src/main/java/org/rhq/core/domain/discovery/PlatformSyncInfo.java
| 74 ++
modules/core/domain/src/main/java/org/rhq/core/domain/discovery/ResourceSyncInfo.java
| 87 +--
modules/core/domain/src/main/java/org/rhq/core/domain/discovery/SyncInfo.java
| 98 +++
modules/core/plugin-container-itest/src/test/java/org/rhq/core/pc/avail/AvailTest.java
| 4
modules/core/plugin-container-itest/src/test/java/org/rhq/core/pc/inventory/AbstractIgnoreTypesInventoryManagerBaseTest.java
| 47 +
modules/core/plugin-container-itest/src/test/java/org/rhq/core/pc/inventory/CommitThenIgnoreTypesInventoryManagerTest.java
| 3
modules/core/plugin-container-itest/src/test/java/org/rhq/core/pc/inventory/DiscoveryCallbackAbortTest.java
| 24
modules/core/plugin-container-itest/src/test/java/org/rhq/core/pc/inventory/DiscoveryCallbackTest.java
| 20
modules/core/plugin-container-itest/src/test/java/org/rhq/core/pc/inventory/DiscoveryCallbackVetoTest.java
| 20
modules/core/plugin-container-itest/src/test/java/org/rhq/core/pc/inventory/DiscoveryTest.java
| 4
modules/core/plugin-container-itest/src/test/java/org/rhq/core/pc/inventory/IgnoreTypesInventoryManagerTest.java
| 1
modules/core/plugin-container-itest/src/test/java/org/rhq/core/pc/inventory/InventoryManagerTest.java
| 2
modules/core/plugin-container-itest/src/test/java/org/rhq/core/pc/measurement/LateMeasurementRescheduleTest.java
| 4
modules/core/plugin-container-itest/src/test/java/org/rhq/core/pc/measurement/ReadOnlyScheduleSetTest.java
| 2
modules/core/plugin-container/src/main/java/org/rhq/core/pc/StandaloneContainer.java
| 6
modules/core/plugin-container/src/main/java/org/rhq/core/pc/inventory/InventoryManager.java
| 251 +++++-----
modules/core/plugin-container/src/main/java/org/rhq/core/pc/inventory/RuntimeDiscoveryExecutor.java
| 2
modules/core/plugin-container/src/test/java/org/rhq/core/pc/upgrade/FakeServerInventory.java
| 72 +-
modules/enterprise/server/itests-2/src/test/java/org/rhq/enterprise/server/discovery/DiscoveryBossBeanTest.java
| 50 +
modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/discovery/DiscoveryBossBean.java
| 22
modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/discovery/DiscoveryBossLocal.java
| 17
modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/discovery/DiscoveryServerServiceImpl.java
| 23
modules/integration-tests/apache-plugin-test/src/test/java/org/rhq/plugins/apache/setup/ApacheTestSetup.java
| 10
29 files changed, 668 insertions(+), 336 deletions(-)
New commits:
commit ccdacc890994172b0ef751edbeb0dd4220d18f7e
Author: Jay Shaughnessy <jshaughn(a)redhat.com>
Date: Fri Dec 13 17:21:40 2013 -0500
[1023451] [perf] Large retained heap during inventory report merge (causing OOMs)
Note - this is related work, not necessarily a solution to this problem.
One factor in the memory consumption of mergeInventoryReport is that we
return the entire resource hierarchy for the platform. These hierarchy
is comprised of lightweight (ResourceSyncInfo) objects, but still, for
a large inventory this can be large. Moreover, the agent must receive the
same structure into memory.
This commit aims to reduce memory consumption at the expense of "chunking"
the hierarchy by top-level-server. The general flow is that mergeInventoryReport
now returns the new PlatformSyncInfo, which is just the platform sync info and
the list of top level servers. The agent then performs the sync in pieces, calling
back to the server for each
top level server's ResourceSyncInfo.
notes:
- New abstract SyncInfo pulled down from ResourceSyncInfo and new superclass
PlatformSyncInfo. These are both now used in the sync process.
- ResourceSyncInfo made more lightweight by replacing parentResource with
parentId.
- Had to change test mocks to handle the new strategy
- add mock support for getResourceSyncInfo service
- enhance AbstractIgnoreTypesInventoryManagerBaseTest to actually assign
resource ids to the simulated server inventory
- Fix a few PC itest issues
- increase waitForInventory max time, it wasn't long enough
- add missing waitForInventory in a couple of places
diff --git
a/modules/core/arquillian-integration/container/src/main/java/org/rhq/test/arquillian/FakeServerInventory.java
b/modules/core/arquillian-integration/container/src/main/java/org/rhq/test/arquillian/FakeServerInventory.java
index 94654ee..74a0acc 100644
---
a/modules/core/arquillian-integration/container/src/main/java/org/rhq/test/arquillian/FakeServerInventory.java
+++
b/modules/core/arquillian-integration/container/src/main/java/org/rhq/test/arquillian/FakeServerInventory.java
@@ -41,6 +41,7 @@ import org.rhq.core.clientapi.agent.upgrade.ResourceUpgradeResponse;
import org.rhq.core.clientapi.server.discovery.InventoryReport;
import org.rhq.core.domain.discovery.MergeInventoryReportResults;
import org.rhq.core.domain.discovery.MergeResourceResponse;
+import org.rhq.core.domain.discovery.PlatformSyncInfo;
import org.rhq.core.domain.discovery.ResourceSyncInfo;
import org.rhq.core.domain.measurement.DataType;
import org.rhq.core.domain.measurement.DisplayType;
@@ -63,7 +64,7 @@ import org.rhq.core.domain.resource.ResourceType;
* own. It is only meant as a helper.
* <p>
* This impl uses mockito for defining the answers to various calls.
- *
+ *
* @author Lukas Krejci
*/
public class FakeServerInventory {
@@ -75,7 +76,7 @@ public class FakeServerInventory {
* for the complete discovery to finish in case your
* fake server commits some resources (which starts off
* asynchronous discovery of children).
- *
+ *
*
* @author Lukas Krejci
*/
@@ -235,7 +236,8 @@ public class FakeServerInventory {
platform = persisted;
}
}
- return new MergeInventoryReportResults(getSyncInfo(), null);
+
+ return new MergeInventoryReportResults(getPlatformSyncInfo(),
null);
} finally {
if (discoveryChecker != null &&
!inventoryReport.getAddedRoots().isEmpty()) {
discoveryChecker.setDepth(getResourceTreeDepth());
@@ -246,14 +248,54 @@ public class FakeServerInventory {
};
}
+ public synchronized Answer<ResourceSyncInfo> getResourceSyncInfo() {
+ return new Answer<ResourceSyncInfo>() {
+ @Override
+ public ResourceSyncInfo answer(InvocationOnMock invocation) throws Throwable
{
+ synchronized (FakeServerInventory.this) {
+ Integer resourceId = (Integer) invocation.getArguments()[0];
+
+ try {
+ throwIfFailing();
+
+ for (Resource c : platform.getChildResources()) {
+ if (c.getId() == resourceId) {
+ return getResourceSyncInfo(c);
+ }
+ }
+ return null;
+ } finally {
+ // TODO: We may need to actually do a check here to make sure
we've been invoked once
+ // for every top level server, before setting depth...
+ if (discoveryChecker != null) {
+ discoveryChecker.setDepth(getResourceTreeDepth());
+ }
+ }
+ }
+ }
+ };
+ }
+
public synchronized int getResourceTreeDepth() {
if (platform == null) {
return 0;
}
+ // dumpTree(platform, "");
+
return getTreeDepth(platform);
}
+ /*
+ private static void dumpTree(Resource r, String indent) {
+ System.out.println(indent + r.getName());
+ indent += " ";
+ for (Resource c : r.getChildResources()) {
+ dumpTree(c, indent);
+ }
+ }
+ */
+
private static int getTreeDepth(Resource root) {
int maxDepth = 0;
for (Resource c : root.getChildResources()) {
@@ -266,16 +308,16 @@ public class FakeServerInventory {
return maxDepth + 1;
}
- public synchronized Answer<ResourceSyncInfo> clearPlatform() {
- return new Answer<ResourceSyncInfo>() {
+ public synchronized Answer<PlatformSyncInfo> clearPlatform() {
+ return new Answer<PlatformSyncInfo>() {
@Override
- public ResourceSyncInfo answer(InvocationOnMock invocation) throws Throwable
{
+ public PlatformSyncInfo answer(InvocationOnMock invocation) throws Throwable
{
synchronized (FakeServerInventory.this) {
throwIfFailing();
platform = null;
- return getSyncInfo();
+ return getPlatformSyncInfo();
}
}
};
@@ -576,53 +618,42 @@ public class FakeServerInventory {
return persisted;
}
- private ResourceSyncInfo getSyncInfo() {
- return platform != null ? convert(platform) : null;
+ private PlatformSyncInfo getPlatformSyncInfo() {
+ return platform == null ? null :
PlatformSyncInfo.buildPlatformSyncInfo(platform);
}
- private void throwIfFailing() {
- if (failing) {
- throw new RuntimeException("Fake server inventory is in the failing
mode.");
- }
+ private ResourceSyncInfo getResourceSyncInfo(Resource resource) {
+ return resource == null ? null : convert(resource);
}
private static ResourceSyncInfo convert(Resource root) {
- return convertInternal(root, new HashMap<String, ResourceSyncInfo>());
+ return convertInternal(root, true, new HashMap<String,
ResourceSyncInfo>());
}
- private static ResourceSyncInfo convertInternal(Resource root, Map<String,
ResourceSyncInfo> intermediateResults) {
+ private static ResourceSyncInfo convertInternal(Resource root, boolean
isTopLevelServer,
+ Map<String, ResourceSyncInfo> intermediateResults) {
+
ResourceSyncInfo ret = intermediateResults.get(root.getUuid());
if (ret != null) {
return ret;
}
-
try {
- ret = new ResourceSyncInfo();
-
+ ret = ResourceSyncInfo.buildResourceSyncInfo(root);
intermediateResults.put(root.getUuid(), ret);
- Class<ResourceSyncInfo> clazz = ResourceSyncInfo.class;
-
- getPrivateField(clazz, "id").set(ret, root.getId());
- getPrivateField(clazz, "uuid").set(ret, root.getUuid());
- getPrivateField(clazz, "mtime").set(ret, root.getMtime());
- getPrivateField(clazz, "inventoryStatus").set(ret,
root.getInventoryStatus());
-
- ResourceSyncInfo parent = root.getParentResource() == null ? null :
convertInternal(
- root.getParentResource(), intermediateResults);
-
- getPrivateField(clazz, "parent").set(ret, parent);
+ Integer parentId = root.getParentResource() == null ? null :
root.getParentResource().getId();
+ getPrivateField(ResourceSyncInfo.class, "parentId").set(ret,
parentId);
Set<ResourceSyncInfo> children = new
LinkedHashSet<ResourceSyncInfo>();
for (Resource child : root.getChildResources()) {
- ResourceSyncInfo syncChild = convertInternal(child,
intermediateResults);
+ ResourceSyncInfo syncChild = convertInternal(child, false,
intermediateResults);
children.add(syncChild);
}
- getPrivateField(clazz, "childSyncInfos").set(ret, children);
-
+ getPrivateField(ResourceSyncInfo.class, "childSyncInfos").set(ret,
children);
return ret;
+
} catch (Exception e) {
throw new IllegalStateException("Failed to convert resource " +
root
+ " to a ResourceSyncInfo. This should not happen.", e);
@@ -638,6 +669,12 @@ public class FakeServerInventory {
return field;
}
+ private void throwIfFailing() {
+ if (failing) {
+ throw new RuntimeException("Fake server inventory is in the failing
mode.");
+ }
+ }
+
private static Resource findResource(Resource root, Resource template,
Comparator<Resource> comparator) {
if (root == null)
return null;
diff --git
a/modules/core/arquillian-integration/container/src/test/java/org/rhq/test/arquillian/CleanUpTest.java
b/modules/core/arquillian-integration/container/src/test/java/org/rhq/test/arquillian/CleanUpTest.java
index 4483cba7..60cd53d 100644
---
a/modules/core/arquillian-integration/container/src/test/java/org/rhq/test/arquillian/CleanUpTest.java
+++
b/modules/core/arquillian-integration/container/src/test/java/org/rhq/test/arquillian/CleanUpTest.java
@@ -23,13 +23,13 @@
package org.rhq.test.arquillian;
-import java.util.Arrays;
-import java.util.HashSet;
-
import static org.mockito.Matchers.any;
import static org.mockito.Mockito.when;
import static org.testng.Assert.assertEquals;
+import java.util.Arrays;
+import java.util.HashSet;
+
import org.testng.annotations.Test;
import org.jboss.arquillian.container.test.api.Deployment;
@@ -80,6 +80,8 @@ public class CleanUpTest extends Arquillian {
//autoimport everything
when(serverServices.getDiscoveryServerService().mergeInventoryReport(any(InventoryReport.class))).then(
fakeServerInventory.mergeInventoryReport(InventoryStatus.COMMITTED));
+
when(serverServices.getDiscoveryServerService().getResourceSyncInfo(any(int.class))).then(
+ fakeServerInventory.getResourceSyncInfo());
}
@BeforeDiscovery(testMethods = {"testCleanAll",
"testClearingAfterTest",
"checkDiscoveryCanRunFullBecauseInventoryClear"})
diff --git
a/modules/core/arquillian-integration/container/src/test/java/org/rhq/test/arquillian/InsideAgentSimulationTest.java
b/modules/core/arquillian-integration/container/src/test/java/org/rhq/test/arquillian/InsideAgentSimulationTest.java
index babfe62..2407a9f 100644
---
a/modules/core/arquillian-integration/container/src/test/java/org/rhq/test/arquillian/InsideAgentSimulationTest.java
+++
b/modules/core/arquillian-integration/container/src/test/java/org/rhq/test/arquillian/InsideAgentSimulationTest.java
@@ -66,28 +66,30 @@ public class InsideAgentSimulationTest extends Arquillian {
private FakeServerInventory fakeServerInventory;
private FakeServerInventory.CompleteDiscoveryChecker discoveryCompleteChecker;
-
+
@BeforeDiscovery(order = 1)
public void resetServerServices() {
serverServices.resetMocks();
fakeServerInventory = new FakeServerInventory();
}
-
+
@BeforeDiscovery(testMethods = "testDeepDiscovery", order = 2)
public void setupDiscoveryMocks() throws Exception {
discoveryCompleteChecker =
fakeServerInventory.createAsyncDiscoveryCompletionChecker(3);
//autoimport everything
when(serverServices.getDiscoveryServerService().mergeInventoryReport(any(InventoryReport.class))).then(
fakeServerInventory.mergeInventoryReport(InventoryStatus.COMMITTED));
+
when(serverServices.getDiscoveryServerService().getResourceSyncInfo(any(int.class))).then(
+ fakeServerInventory.getResourceSyncInfo());
}
-
+
@AfterDiscovery
public void waitForAsyncDiscoveries() throws Exception {
if (discoveryCompleteChecker != null) {
discoveryCompleteChecker.waitForDiscoveryComplete();
}
}
-
+
//we need to make sure that the no discovery test is run first, because the plugin
container
//would keep the inventory from the previous test.
//the other two tests get each a new serverside, which, when synced with the PC, will
cause
@@ -98,7 +100,7 @@ public class InsideAgentSimulationTest extends Arquillian {
Assert.assertEquals(discoveredServers.size(), 0, "There should be no server
discovered");
Assert.assertEquals(discoveredServices.size(), 0, "There should be no
service discovered");
}
-
+
//the difference between this test and the deep discovery one is that for this test
//the mocks should not be set up and hence only a top server discovery should occur
@Test(dependsOnMethods = "testNoDiscovery")
@@ -107,7 +109,7 @@ public class InsideAgentSimulationTest extends Arquillian {
Assert.assertEquals(discoveredServers.size(), 1, "There should be 1 server
discovered");
Assert.assertEquals(discoveredServices.size(), 0, "There should be no
service discovered");
}
-
+
@Test(dependsOnMethods = "testNoDiscovery")
@RunDiscovery
public void testDeepDiscovery() throws Exception {
diff --git
a/modules/core/arquillian-integration/container/src/test/java/org/rhq/test/arquillian/avail/AvailTest.java
b/modules/core/arquillian-integration/container/src/test/java/org/rhq/test/arquillian/avail/AvailTest.java
index d2d5efd..f38d021 100644
---
a/modules/core/arquillian-integration/container/src/test/java/org/rhq/test/arquillian/avail/AvailTest.java
+++
b/modules/core/arquillian-integration/container/src/test/java/org/rhq/test/arquillian/avail/AvailTest.java
@@ -5,8 +5,6 @@ import static org.mockito.Mockito.when;
import java.util.Set;
-import org.mockito.invocation.InvocationOnMock;
-import org.mockito.stubbing.Answer;
import org.testng.Assert;
import org.testng.annotations.Test;
@@ -18,7 +16,6 @@ import org.jboss.arquillian.testng.Arquillian;
import org.jboss.shrinkwrap.api.ShrinkWrap;
import org.rhq.core.clientapi.server.discovery.InventoryReport;
-import org.rhq.core.domain.discovery.ResourceSyncInfo;
import org.rhq.core.domain.resource.InventoryStatus;
import org.rhq.core.pc.PluginContainer;
import org.rhq.core.pc.inventory.ResourceContainer;
@@ -55,7 +52,7 @@ public class AvailTest extends Arquillian {
private FakeServerInventory fakeServerInventory;
private FakeServerInventory.CompleteDiscoveryChecker completeDiscoveryChecker;
-
+
@ResourceContainers(plugin = "availPlugin", resourceType =
"AvailParentServer1")
private Set<ResourceContainer> parentContainers1;
@@ -98,16 +95,19 @@ public class AvailTest extends Arquillian {
fakeServerInventory = new FakeServerInventory();
completeDiscoveryChecker =
fakeServerInventory.createAsyncDiscoveryCompletionChecker(4);
-
+
//autoimport everything
-
when(serverServices.getDiscoveryServerService().mergeInventoryReport(any(InventoryReport.class))).then(fakeServerInventory.mergeInventoryReport(InventoryStatus.COMMITTED));
+
when(serverServices.getDiscoveryServerService().mergeInventoryReport(any(InventoryReport.class))).then(
+ fakeServerInventory.mergeInventoryReport(InventoryStatus.COMMITTED));
+
when(serverServices.getDiscoveryServerService().getResourceSyncInfo(any(int.class))).then(
+ fakeServerInventory.getResourceSyncInfo());
}
@AfterDiscovery
public void waitForDiscovery() throws Exception {
completeDiscoveryChecker.waitForDiscoveryComplete();
}
-
+
@Test
@RunDiscovery
public void testConfirmInitialInventory() throws Exception {
diff --git
a/modules/core/client-api/src/main/java/org/rhq/core/clientapi/server/discovery/DiscoveryServerService.java
b/modules/core/client-api/src/main/java/org/rhq/core/clientapi/server/discovery/DiscoveryServerService.java
index 18d4dac..df2a286 100644
---
a/modules/core/client-api/src/main/java/org/rhq/core/clientapi/server/discovery/DiscoveryServerService.java
+++
b/modules/core/client-api/src/main/java/org/rhq/core/clientapi/server/discovery/DiscoveryServerService.java
@@ -34,6 +34,7 @@ import org.rhq.core.communications.command.annotation.Timeout;
import org.rhq.core.domain.discovery.AvailabilityReport;
import org.rhq.core.domain.discovery.MergeInventoryReportResults;
import org.rhq.core.domain.discovery.MergeResourceResponse;
+import org.rhq.core.domain.discovery.ResourceSyncInfo;
import org.rhq.core.domain.measurement.ResourceMeasurementScheduleRequest;
import org.rhq.core.domain.resource.InventoryStatus;
import org.rhq.core.domain.resource.Resource;
@@ -69,6 +70,11 @@ public interface DiscoveryServerService {
MergeInventoryReportResults mergeInventoryReport(InventoryReport inventoryReport)
throws InvalidInventoryReportException, StaleTypeException;
+ @LimitedConcurrency(CONCURRENCY_LIMIT_INVENTORY_REPORT)
+ @Timeout(0L)
+ // should be something like 1000L * 60 * 30 but until we can be assured we never take
longer, disable timeout
+ ResourceSyncInfo getResourceSyncInfo(int resourceId);
+
/**
* Merges a new availability report from the agent into the server. This updates the
availability statuses of known
* resources.
@@ -96,7 +102,7 @@ public interface DiscoveryServerService {
Set<Resource> getResources(Set<Integer> resourceIds, boolean
includeDescendants);
/**
- * Returns the Resources with the given id's. The children are not set.
+ * Returns the Resources with the given id's. The children are not set.
*
* @param resourceIds
* @return a list of resources in the same order as the passed in ids, with the
latest data
@@ -107,7 +113,7 @@ public interface DiscoveryServerService {
/**
* Set the specified resource enabled or disabled. The call has no effect if the
resource is already
* in the desired state.
- *
+ *
* @param resourceId The resource to enable or disable.
* @param setEnabled Enable if true, disable if false.
*/
@@ -165,7 +171,7 @@ public interface DiscoveryServerService {
* Upgrades the data of the resources according to the provided reports.
* The server is free to ignore or modify the requests and will provide the
* true changes made to the resources on the server-side in the result of this
method.
- *
+ *
* @param upgradeRequests contains the information about the upgrade of individual
resources.
* @return details on what resources have been upgraded with what data.
*/
@@ -174,7 +180,7 @@ public interface DiscoveryServerService {
/**
* Gives the server a chance to apply any necessary post-processing that's needed
for newly committed resources
* that have been successfully synchronized on the agent.
- *
+ *
* @param resourceIds a collection of{@link Resource} ids that have been newly
committed and successfully
* synchronized on the agent
*
diff --git
a/modules/core/domain/src/main/java/org/rhq/core/domain/discovery/MergeInventoryReportResults.java
b/modules/core/domain/src/main/java/org/rhq/core/domain/discovery/MergeInventoryReportResults.java
index 95a59cf..615f37e 100644
---
a/modules/core/domain/src/main/java/org/rhq/core/domain/discovery/MergeInventoryReportResults.java
+++
b/modules/core/domain/src/main/java/org/rhq/core/domain/discovery/MergeInventoryReportResults.java
@@ -38,11 +38,11 @@ import org.rhq.core.domain.resource.ResourceType;
public class MergeInventoryReportResults implements Serializable {
private static final long serialVersionUID = 1L;
- private final ResourceSyncInfo resourceSyncInfo;
+ private final PlatformSyncInfo platformSyncInfo;
private final Collection<ResourceTypeFlyweight> ignoredResourceTypes;
- public MergeInventoryReportResults(ResourceSyncInfo rsi,
Collection<ResourceType> ignoredResourceTypes) {
- resourceSyncInfo = rsi;
+ public MergeInventoryReportResults(PlatformSyncInfo psi,
Collection<ResourceType> ignoredResourceTypes) {
+ platformSyncInfo = psi;
if (ignoredResourceTypes == null || ignoredResourceTypes.isEmpty()) {
this.ignoredResourceTypes = null;
@@ -54,8 +54,8 @@ public class MergeInventoryReportResults implements Serializable {
}
}
- public ResourceSyncInfo getResourceSyncInfo() {
- return resourceSyncInfo;
+ public PlatformSyncInfo getPlatformSyncInfo() {
+ return platformSyncInfo;
}
public Collection<ResourceTypeFlyweight> getIgnoredResourceTypes() {
diff --git
a/modules/core/domain/src/main/java/org/rhq/core/domain/discovery/PlatformSyncInfo.java
b/modules/core/domain/src/main/java/org/rhq/core/domain/discovery/PlatformSyncInfo.java
new file mode 100644
index 0000000..951f542
--- /dev/null
+++
b/modules/core/domain/src/main/java/org/rhq/core/domain/discovery/PlatformSyncInfo.java
@@ -0,0 +1,74 @@
+/*
+ * RHQ Management Platform
+ * Copyright (C) 2005-2013 Red Hat, Inc.
+ * All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License, version 2, as
+ * published by the Free Software Foundation, and/or the GNU Lesser
+ * General Public License, version 2.1, also as published by the Free
+ * Software Foundation.
+ *
+ * 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 and the GNU Lesser General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * and the GNU Lesser General Public License along with this program;
+ * if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+package org.rhq.core.domain.discovery;
+
+import java.io.Serializable;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.Set;
+
+import javax.persistence.Entity;
+import javax.persistence.FetchType;
+import javax.persistence.OneToMany;
+import javax.persistence.Table;
+
+import org.rhq.core.domain.resource.InventoryStatus;
+import org.rhq.core.domain.resource.Resource;
+
+/**
+ * @author Ian Springer
+ * @author Jay Shaughnessy
+ */
+@Entity
+@Table(name = "RHQ_RESOURCE")
+public class PlatformSyncInfo extends SyncInfo implements Serializable {
+ private static final long serialVersionUID = 1L;
+
+ @OneToMany(mappedBy = "parentResource", fetch = FetchType.EAGER)
+ private Set<Resource> topLevelServers;
+
+ // JPA requires public or protected no-param constructor; Externalizable requires
public no-param constructor.
+ public PlatformSyncInfo() {
+ }
+
+ public Collection<Resource> getTopLevelServers() {
+ return topLevelServers;
+ }
+
+ // for testing
+ public static PlatformSyncInfo buildPlatformSyncInfo(Resource platform) {
+ Set<Resource> toplevelServers = platform.getChildResources();
+
+ PlatformSyncInfo syncInfo = new PlatformSyncInfo(platform.getId(),
platform.getUuid(), platform.getMtime(),
+ platform.getInventoryStatus(), (null == toplevelServers ?
Collections.EMPTY_SET : toplevelServers));
+
+ return syncInfo;
+ }
+
+ // for testing
+ private PlatformSyncInfo(int id, String uuid, long mtime, InventoryStatus istatus,
Set<Resource> children) {
+ super(id, uuid, mtime, istatus);
+ this.topLevelServers = children;
+ }
+
+}
diff --git
a/modules/core/domain/src/main/java/org/rhq/core/domain/discovery/ResourceSyncInfo.java
b/modules/core/domain/src/main/java/org/rhq/core/domain/discovery/ResourceSyncInfo.java
index b0a5315..e9cb222 100644
---
a/modules/core/domain/src/main/java/org/rhq/core/domain/discovery/ResourceSyncInfo.java
+++
b/modules/core/domain/src/main/java/org/rhq/core/domain/discovery/ResourceSyncInfo.java
@@ -28,14 +28,7 @@ import java.util.HashSet;
import javax.persistence.Column;
import javax.persistence.Entity;
-import javax.persistence.EnumType;
-import javax.persistence.Enumerated;
import javax.persistence.FetchType;
-import javax.persistence.GeneratedValue;
-import javax.persistence.GenerationType;
-import javax.persistence.Id;
-import javax.persistence.JoinColumn;
-import javax.persistence.ManyToOne;
import javax.persistence.OneToMany;
import javax.persistence.Table;
@@ -43,68 +36,31 @@ import org.rhq.core.domain.resource.InventoryStatus;
import org.rhq.core.domain.resource.Resource;
/**
+ * Sync info for any non-platform resource.
+ *
* @author Ian Springer
+ * @author Jay Shaughnessy
*/
@Entity
@Table(name = "RHQ_RESOURCE")
-public class ResourceSyncInfo implements Serializable {
+public class ResourceSyncInfo extends SyncInfo implements Serializable {
private static final long serialVersionUID = 1L;
- /**
- * Server-assigned id
- */
- @Column(name = "ID", nullable = false)
- @Id
- @GeneratedValue(strategy = GenerationType.IDENTITY)
- private int id;
-
- /**
- * Agent-assigned uuid
- */
- @Column(name = "UUID")
- private String uuid;
-
- /**
- * Last modified time
- */
- @Column(name = "MTIME")
- private long mtime;
-
- @Column(name = "INVENTORY_STATUS")
- @Enumerated(EnumType.STRING)
- private InventoryStatus inventoryStatus;
-
- @JoinColumn(name = "PARENT_RESOURCE_ID", nullable = true)
- @ManyToOne(fetch = FetchType.LAZY, optional = true)
- private ResourceSyncInfo parent;
-
- @OneToMany(mappedBy = "parent", fetch = FetchType.EAGER)
+ @Column(name = "PARENT_RESOURCE_ID")
+ private Integer parentId;
+
+ @OneToMany(mappedBy = "parentId", fetch = FetchType.EAGER)
private Collection<ResourceSyncInfo> childSyncInfos;
// JPA requires public or protected no-param constructor; Externalizable requires
public no-param constructor.
public ResourceSyncInfo() {
}
- public int getId() {
- return id;
- }
-
- public String getUuid() {
- return uuid;
- }
-
- public long getMtime() {
- return mtime;
- }
-
- public InventoryStatus getInventoryStatus() {
- return inventoryStatus;
- }
-
public Collection<ResourceSyncInfo> getChildSyncInfos() {
return childSyncInfos;
}
+ // for testing
public static ResourceSyncInfo buildResourceSyncInfo(Resource resource) {
Collection<ResourceSyncInfo> children;
@@ -117,18 +73,35 @@ public class ResourceSyncInfo implements Serializable {
children = new HashSet<ResourceSyncInfo>(0);
}
+ return buildResourceSyncInfo(resource, children);
+ }
+
+ // for testing
+ public static ResourceSyncInfo buildResourceSyncInfo(Resource resource,
Collection<ResourceSyncInfo> children) {
+
ResourceSyncInfo syncInfo = new ResourceSyncInfo(resource.getId(),
resource.getUuid(), resource.getMtime(),
resource.getInventoryStatus(), children);
return syncInfo;
}
+
+ public static ResourceSyncInfo buildResourceSyncInfo(SyncInfo syncInfo) {
+
+ return buildResourceSyncInfo(syncInfo, ((Collection<ResourceSyncInfo>)
null));
+ }
+
+ public static ResourceSyncInfo buildResourceSyncInfo(SyncInfo syncInfo,
Collection<ResourceSyncInfo> children) {
+
+ ResourceSyncInfo resourceSyncInfo = new ResourceSyncInfo(syncInfo.getId(),
syncInfo.getUuid(),
+ syncInfo.getMtime(), syncInfo.getInventoryStatus(), children);
+
+ return resourceSyncInfo;
+ }
+
private ResourceSyncInfo(int id, String uuid, long mtime, InventoryStatus istatus,
Collection<ResourceSyncInfo> children) {
- this.id = id;
- this.uuid = uuid;
- this.mtime = mtime;
- this.inventoryStatus = istatus;
+ super(id, uuid, mtime, istatus);
this.childSyncInfos = children;
}
}
diff --git a/modules/core/domain/src/main/java/org/rhq/core/domain/discovery/SyncInfo.java
b/modules/core/domain/src/main/java/org/rhq/core/domain/discovery/SyncInfo.java
new file mode 100644
index 0000000..370d84f
--- /dev/null
+++ b/modules/core/domain/src/main/java/org/rhq/core/domain/discovery/SyncInfo.java
@@ -0,0 +1,98 @@
+/*
+ * RHQ Management Platform
+ * Copyright (C) 2005-2013 Red Hat, Inc.
+ * All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License, version 2, as
+ * published by the Free Software Foundation, and/or the GNU Lesser
+ * General Public License, version 2.1, also as published by the Free
+ * Software Foundation.
+ *
+ * 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 and the GNU Lesser General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * and the GNU Lesser General Public License along with this program;
+ * if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+package org.rhq.core.domain.discovery;
+
+import java.io.Serializable;
+
+import javax.persistence.Column;
+import javax.persistence.EnumType;
+import javax.persistence.Enumerated;
+import javax.persistence.GeneratedValue;
+import javax.persistence.GenerationType;
+import javax.persistence.Id;
+import javax.persistence.MappedSuperclass;
+
+import org.rhq.core.domain.resource.InventoryStatus;
+
+/**
+ * This is the abstract base class for SyncInfo, which may be for a platform or a [top
level server] resource.
+ *
+ * @author Ian Springer
+ * @author Jay Shaughnessy
+ */
+@MappedSuperclass
+public abstract class SyncInfo implements Serializable {
+ private static final long serialVersionUID = 1L;
+
+ /**
+ * Server-assigned id
+ */
+ @Column(name = "ID", nullable = false)
+ @Id
+ @GeneratedValue(strategy = GenerationType.IDENTITY)
+ private int id;
+
+ /**
+ * Agent-assigned uuid
+ */
+ @Column(name = "UUID")
+ private String uuid;
+
+ /**
+ * Last modified time
+ */
+ @Column(name = "MTIME")
+ private long mtime;
+
+ @Column(name = "INVENTORY_STATUS")
+ @Enumerated(EnumType.STRING)
+ private InventoryStatus inventoryStatus;
+
+ // JPA requires public or protected no-param constructor; Externalizable requires
public no-param constructor.
+ public SyncInfo() {
+ }
+
+ public int getId() {
+ return id;
+ }
+
+ public String getUuid() {
+ return uuid;
+ }
+
+ public long getMtime() {
+ return mtime;
+ }
+
+ public InventoryStatus getInventoryStatus() {
+ return inventoryStatus;
+ }
+
+ protected SyncInfo(int id, String uuid, long mtime, InventoryStatus istatus) {
+ this.id = id;
+ this.uuid = uuid;
+ this.mtime = mtime;
+ this.inventoryStatus = istatus;
+ }
+
+}
diff --git
a/modules/core/plugin-container-itest/src/test/java/org/rhq/core/pc/avail/AvailTest.java
b/modules/core/plugin-container-itest/src/test/java/org/rhq/core/pc/avail/AvailTest.java
index 86cf746..80130ac 100644
---
a/modules/core/plugin-container-itest/src/test/java/org/rhq/core/pc/avail/AvailTest.java
+++
b/modules/core/plugin-container-itest/src/test/java/org/rhq/core/pc/avail/AvailTest.java
@@ -108,6 +108,8 @@ public class AvailTest extends Arquillian {
// autoimport everything
when(serverServices.getDiscoveryServerService().mergeInventoryReport(any(InventoryReport.class))).then(
fakeServerInventory.mergeInventoryReport(InventoryStatus.COMMITTED));
+
when(serverServices.getDiscoveryServerService().getResourceSyncInfo(any(Integer.class))).then(
+ fakeServerInventory.getResourceSyncInfo());
}
@AfterDiscovery
@@ -118,7 +120,7 @@ public class AvailTest extends Arquillian {
}
@BeforeMethod
- public void beforeMethod() throws Exception {
+ protected void beforeMethod() throws Exception {
System.out.println("\n!!!!!!!!!!!!!!!!!!!!!!!!!! BEFORE METHOD (" +
Thread.currentThread().getName() + ")");
scrub();
}
diff --git
a/modules/core/plugin-container-itest/src/test/java/org/rhq/core/pc/inventory/AbstractIgnoreTypesInventoryManagerBaseTest.java
b/modules/core/plugin-container-itest/src/test/java/org/rhq/core/pc/inventory/AbstractIgnoreTypesInventoryManagerBaseTest.java
index 6533b21..4591dfc 100644
---
a/modules/core/plugin-container-itest/src/test/java/org/rhq/core/pc/inventory/AbstractIgnoreTypesInventoryManagerBaseTest.java
+++
b/modules/core/plugin-container-itest/src/test/java/org/rhq/core/pc/inventory/AbstractIgnoreTypesInventoryManagerBaseTest.java
@@ -40,6 +40,7 @@ import org.jboss.shrinkwrap.api.ShrinkWrap;
import org.rhq.core.clientapi.server.discovery.InventoryReport;
import org.rhq.core.domain.discovery.MergeInventoryReportResults;
+import org.rhq.core.domain.discovery.PlatformSyncInfo;
import org.rhq.core.domain.discovery.ResourceSyncInfo;
import org.rhq.core.domain.resource.InventoryStatus;
import org.rhq.core.domain.resource.Resource;
@@ -82,7 +83,7 @@ public abstract class AbstractIgnoreTypesInventoryManagerBaseTest
extends Arquil
protected Resource platform;
- protected HashMap<String, Resource> simulatedInventory; // key == UUID
+ protected HashMap<Integer, Resource> simulatedInventory; // key == resourceId
== UUID.hashcode()
protected HashSet<ResourceType> ignoredTypes;
@@ -101,7 +102,7 @@ public abstract class AbstractIgnoreTypesInventoryManagerBaseTest
extends Arquil
@BeforeDiscovery
public void resetServerServices() throws Exception {
platform = null;
- simulatedInventory = new HashMap<String, Resource>();
+ simulatedInventory = new HashMap<Integer, Resource>();
gotIgnoredTypeFromAgent = new CountDownLatch(1); // will be open once we know
agent discovered types we want ignored
initializeIgnoredTypes();
@@ -110,6 +111,8 @@ public abstract class AbstractIgnoreTypesInventoryManagerBaseTest
extends Arquil
when(serverServices.getDiscoveryServerService().mergeInventoryReport(any(InventoryReport.class))).then(
mergeInventoryReport());
+
when(serverServices.getDiscoveryServerService().getResourceSyncInfo(any(Integer.class))).then(
+ getResourceSyncInfo());
}
@AfterDiscovery
@@ -131,23 +134,26 @@ public abstract class AbstractIgnoreTypesInventoryManagerBaseTest
extends Arquil
if (platform != null) {
platform.getChildResources().clear();
if (simulatedInventory != null) {
- simulatedInventory.put(platform.getUuid(), platform);
+ simulatedInventory.put(platform.getId(), platform);
}
}
}
protected void waitForInventory(int depth) throws Exception {
long start = System.currentTimeMillis();
- while (getInventoryDepth(platform) < depth) {
- Thread.sleep(1000);
- if (System.currentTimeMillis() - start > 30000L) {
- break; // this should never take longer than 30s
+ int inventoryDepth = getInventoryDepth(platform);
+ while (inventoryDepth < depth) {
+ if (System.currentTimeMillis() - start > 60000L) {
+ assert false : "Failed to get proper depth, depth is currently
at=" + inventoryDepth;
}
+ Thread.sleep(1000);
+ inventoryDepth = getInventoryDepth(platform);
}
return;
}
protected int getInventoryDepth(Resource root) {
+ System.out.println("Inventory depth chart: " + root);
if (root == null) {
return 0;
}
@@ -172,27 +178,31 @@ public abstract class AbstractIgnoreTypesInventoryManagerBaseTest
extends Arquil
}
protected MergeInventoryReportResults
simulateInventoryReportServerProcessing(InventoryReport inventoryReport) {
- ResourceSyncInfo syncInfo = null;
+ PlatformSyncInfo syncInfo = null;
if (inventoryReport.getAddedRoots() != null &&
!inventoryReport.getAddedRoots().isEmpty()) {
for (Resource res : inventoryReport.getAddedRoots()) {
persistInSimulatedInventory(res);
}
- syncInfo = ResourceSyncInfo.buildResourceSyncInfo(platform);
+ syncInfo = PlatformSyncInfo.buildPlatformSyncInfo(platform);
}
- return new MergeInventoryReportResults(syncInfo, ignoredTypes);
+
+ MergeInventoryReportResults result = new MergeInventoryReportResults(syncInfo,
ignoredTypes);
+ return result;
}
protected void persistInSimulatedInventory(Resource res) {
if (!ignoredTypes.contains(res.getResourceType())) {
- if (!simulatedInventory.containsKey(res.getUuid())) {
+ if (!simulatedInventory.containsKey(res.getUuid().hashCode())) {
Resource persisted = new Resource(res.getResourceKey(), res.getName(),
res.getResourceType());
+ persisted.setId(res.getUuid().hashCode());
persisted.setUuid(res.getUuid());
persisted.setInventoryStatus(InventoryStatus.COMMITTED);
- simulatedInventory.put(persisted.getUuid(), persisted);
+ // System.out.println("***** PERSISTED:\n" +
persisted.getUuid() + ", " + persisted.getName() + "\n****");
+ simulatedInventory.put(persisted.getUuid().hashCode(), persisted);
if (res.getParentResource() == Resource.ROOT) {
platform = persisted;
} else {
- Resource parent =
simulatedInventory.get(res.getParentResource().getUuid());
+ Resource parent =
simulatedInventory.get(res.getParentResource().getUuid().hashCode());
if (parent != null) {
parent.addChildResource(persisted);
}
@@ -207,6 +217,17 @@ public abstract class AbstractIgnoreTypesInventoryManagerBaseTest
extends Arquil
return;
}
+ protected Answer<ResourceSyncInfo> getResourceSyncInfo() {
+ return new Answer<ResourceSyncInfo>() {
+ @Override
+ public ResourceSyncInfo answer(InvocationOnMock invocation) throws Throwable
{
+ Integer resourceId = (Integer) invocation.getArguments()[0];
+ ResourceSyncInfo result =
ResourceSyncInfo.buildResourceSyncInfo(simulatedInventory.get(resourceId));
+ return result;
+ }
+ };
+ }
+
protected void validateFullInventory() {
System.out.println("Validating full inventory...");
diff --git
a/modules/core/plugin-container-itest/src/test/java/org/rhq/core/pc/inventory/CommitThenIgnoreTypesInventoryManagerTest.java
b/modules/core/plugin-container-itest/src/test/java/org/rhq/core/pc/inventory/CommitThenIgnoreTypesInventoryManagerTest.java
index 65c9ab7..8965ea1 100644
---
a/modules/core/plugin-container-itest/src/test/java/org/rhq/core/pc/inventory/CommitThenIgnoreTypesInventoryManagerTest.java
+++
b/modules/core/plugin-container-itest/src/test/java/org/rhq/core/pc/inventory/CommitThenIgnoreTypesInventoryManagerTest.java
@@ -44,6 +44,7 @@ public class CommitThenIgnoreTypesInventoryManagerTest extends
AbstractIgnoreTyp
@RunDiscovery
public void testIgnoreTypesAfterFullCommit() throws Exception {
// make sure the agent inventory has a full inventory
+ waitForInventory(5);
validateFullInventory();
// simulate the ignoring of types
@@ -59,8 +60,6 @@ public class CommitThenIgnoreTypesInventoryManagerTest extends
AbstractIgnoreTyp
System.out.println("Executing full discovery...");
InventoryReport report = inventoryManager.executeServerScanImmediately();
inventoryManager.handleReport(report);
- report = inventoryManager.executeServiceScanImmediately();
- inventoryManager.handleReport(report);
waitForInventory(3);
validatePartiallyIgnoredInventory();
}
diff --git
a/modules/core/plugin-container-itest/src/test/java/org/rhq/core/pc/inventory/DiscoveryCallbackAbortTest.java
b/modules/core/plugin-container-itest/src/test/java/org/rhq/core/pc/inventory/DiscoveryCallbackAbortTest.java
index 648971e..867e1fa 100644
---
a/modules/core/plugin-container-itest/src/test/java/org/rhq/core/pc/inventory/DiscoveryCallbackAbortTest.java
+++
b/modules/core/plugin-container-itest/src/test/java/org/rhq/core/pc/inventory/DiscoveryCallbackAbortTest.java
@@ -18,11 +18,20 @@
*/
package org.rhq.core.pc.inventory;
+import static org.mockito.Matchers.any;
+import static org.mockito.Mockito.when;
+
+import java.util.Set;
+
+import org.testng.Assert;
+import org.testng.annotations.Test;
+
import org.jboss.arquillian.container.test.api.Deployment;
import org.jboss.arquillian.container.test.api.TargetsContainer;
import org.jboss.arquillian.test.api.ArquillianResource;
import org.jboss.arquillian.testng.Arquillian;
import org.jboss.shrinkwrap.api.ShrinkWrap;
+
import org.rhq.core.clientapi.server.discovery.InventoryReport;
import org.rhq.core.domain.resource.InventoryStatus;
import org.rhq.core.domain.resource.Resource;
@@ -31,24 +40,13 @@ import org.rhq.core.pc.PluginContainerConfiguration;
import org.rhq.core.pc.inventory.discoverycallback.DiscoveryCallbackAbortCallback1;
import org.rhq.core.pc.inventory.discoverycallback.DiscoveryCallbackAbortCallback2;
import
org.rhq.core.pc.inventory.discoverycallback.DiscoveryCallbackAbortDiscoveryComponent;
-import org.rhq.core.pc.inventory.discoverycallback.PluginOneCallback;
-import org.rhq.core.pc.inventory.discoverycallback.PluginTwoCallback1;
-import org.rhq.core.pc.inventory.discoverycallback.PluginTwoCallback2;
import org.rhq.core.pc.inventory.testplugin.TestResourceComponent;
-import org.rhq.core.pc.inventory.testplugin.TestResourceDiscoveryComponent;
import org.rhq.test.arquillian.AfterDiscovery;
import org.rhq.test.arquillian.BeforeDiscovery;
import org.rhq.test.arquillian.FakeServerInventory;
import org.rhq.test.arquillian.MockingServerServices;
import org.rhq.test.arquillian.RunDiscovery;
import org.rhq.test.shrinkwrap.RhqAgentPluginArchive;
-import org.testng.Assert;
-import org.testng.annotations.Test;
-
-import java.util.Set;
-
-import static org.mockito.Matchers.any;
-import static org.mockito.Mockito.when;
/**
* A unit test for testing discovery callbacks.
@@ -86,6 +84,8 @@ public class DiscoveryCallbackAbortTest extends Arquillian {
discoveryCompleteChecker =
fakeServerInventory.createAsyncDiscoveryCompletionChecker(2);
when(serverServices.getDiscoveryServerService().mergeInventoryReport(any(InventoryReport.class))).then(
fakeServerInventory.mergeInventoryReport(InventoryStatus.COMMITTED));
+
when(serverServices.getDiscoveryServerService().getResourceSyncInfo(any(Integer.class))).then(
+ fakeServerInventory.getResourceSyncInfo());
}
@AfterDiscovery
@@ -101,7 +101,7 @@ public class DiscoveryCallbackAbortTest extends Arquillian {
// make sure our inventory is as we expect it to be
validatePluginContainerInventory();
}
-
+
private void validatePluginContainerInventory() throws Exception {
System.out.println("Validating PC inventory...");
diff --git
a/modules/core/plugin-container-itest/src/test/java/org/rhq/core/pc/inventory/DiscoveryCallbackTest.java
b/modules/core/plugin-container-itest/src/test/java/org/rhq/core/pc/inventory/DiscoveryCallbackTest.java
index 4b4b985..0c2cb9c 100644
---
a/modules/core/plugin-container-itest/src/test/java/org/rhq/core/pc/inventory/DiscoveryCallbackTest.java
+++
b/modules/core/plugin-container-itest/src/test/java/org/rhq/core/pc/inventory/DiscoveryCallbackTest.java
@@ -18,11 +18,20 @@
*/
package org.rhq.core.pc.inventory;
+import static org.mockito.Matchers.any;
+import static org.mockito.Mockito.when;
+
+import java.util.Set;
+
+import org.testng.Assert;
+import org.testng.annotations.Test;
+
import org.jboss.arquillian.container.test.api.Deployment;
import org.jboss.arquillian.container.test.api.TargetsContainer;
import org.jboss.arquillian.test.api.ArquillianResource;
import org.jboss.arquillian.testng.Arquillian;
import org.jboss.shrinkwrap.api.ShrinkWrap;
+
import org.rhq.core.clientapi.server.discovery.InventoryReport;
import org.rhq.core.domain.resource.InventoryStatus;
import org.rhq.core.domain.resource.Resource;
@@ -39,13 +48,6 @@ import org.rhq.test.arquillian.FakeServerInventory;
import org.rhq.test.arquillian.MockingServerServices;
import org.rhq.test.arquillian.RunDiscovery;
import org.rhq.test.shrinkwrap.RhqAgentPluginArchive;
-import org.testng.Assert;
-import org.testng.annotations.Test;
-
-import java.util.Set;
-
-import static org.mockito.Matchers.any;
-import static org.mockito.Mockito.when;
/**
* A unit test for testing discovery callbacks.
@@ -86,6 +88,8 @@ public class DiscoveryCallbackTest extends Arquillian {
discoveryCompleteChecker =
fakeServerInventory.createAsyncDiscoveryCompletionChecker(2);
when(serverServices.getDiscoveryServerService().mergeInventoryReport(any(InventoryReport.class))).then(
fakeServerInventory.mergeInventoryReport(InventoryStatus.COMMITTED));
+
when(serverServices.getDiscoveryServerService().getResourceSyncInfo(any(Integer.class))).then(
+ fakeServerInventory.getResourceSyncInfo());
}
@AfterDiscovery
@@ -101,7 +105,7 @@ public class DiscoveryCallbackTest extends Arquillian {
// make sure our inventory is as we expect it to be
validatePluginContainerInventory();
}
-
+
private void validatePluginContainerInventory() throws Exception {
System.out.println("Validating PC inventory...");
diff --git
a/modules/core/plugin-container-itest/src/test/java/org/rhq/core/pc/inventory/DiscoveryCallbackVetoTest.java
b/modules/core/plugin-container-itest/src/test/java/org/rhq/core/pc/inventory/DiscoveryCallbackVetoTest.java
index 67ad6f7..845e655 100644
---
a/modules/core/plugin-container-itest/src/test/java/org/rhq/core/pc/inventory/DiscoveryCallbackVetoTest.java
+++
b/modules/core/plugin-container-itest/src/test/java/org/rhq/core/pc/inventory/DiscoveryCallbackVetoTest.java
@@ -18,11 +18,20 @@
*/
package org.rhq.core.pc.inventory;
+import static org.mockito.Matchers.any;
+import static org.mockito.Mockito.when;
+
+import java.util.Set;
+
+import org.testng.Assert;
+import org.testng.annotations.Test;
+
import org.jboss.arquillian.container.test.api.Deployment;
import org.jboss.arquillian.container.test.api.TargetsContainer;
import org.jboss.arquillian.test.api.ArquillianResource;
import org.jboss.arquillian.testng.Arquillian;
import org.jboss.shrinkwrap.api.ShrinkWrap;
+
import org.rhq.core.clientapi.server.discovery.InventoryReport;
import org.rhq.core.domain.resource.InventoryStatus;
import org.rhq.core.domain.resource.Resource;
@@ -38,13 +47,6 @@ import org.rhq.test.arquillian.FakeServerInventory;
import org.rhq.test.arquillian.MockingServerServices;
import org.rhq.test.arquillian.RunDiscovery;
import org.rhq.test.shrinkwrap.RhqAgentPluginArchive;
-import org.testng.Assert;
-import org.testng.annotations.Test;
-
-import java.util.Set;
-
-import static org.mockito.Matchers.any;
-import static org.mockito.Mockito.when;
/**
* A unit test for testing discovery callbacks and their veto feature.
@@ -82,6 +84,8 @@ public class DiscoveryCallbackVetoTest extends Arquillian {
discoveryCompleteChecker =
fakeServerInventory.createAsyncDiscoveryCompletionChecker(2);
when(serverServices.getDiscoveryServerService().mergeInventoryReport(any(InventoryReport.class))).then(
fakeServerInventory.mergeInventoryReport(InventoryStatus.COMMITTED));
+
when(serverServices.getDiscoveryServerService().getResourceSyncInfo(any(Integer.class))).then(
+ fakeServerInventory.getResourceSyncInfo());
}
@AfterDiscovery
@@ -97,7 +101,7 @@ public class DiscoveryCallbackVetoTest extends Arquillian {
// make sure our inventory is as we expect it to be
validatePluginContainerInventory();
}
-
+
private void validatePluginContainerInventory() throws Exception {
System.out.println("Validating PC inventory...");
diff --git
a/modules/core/plugin-container-itest/src/test/java/org/rhq/core/pc/inventory/DiscoveryTest.java
b/modules/core/plugin-container-itest/src/test/java/org/rhq/core/pc/inventory/DiscoveryTest.java
index 8880b92..592c235 100644
---
a/modules/core/plugin-container-itest/src/test/java/org/rhq/core/pc/inventory/DiscoveryTest.java
+++
b/modules/core/plugin-container-itest/src/test/java/org/rhq/core/pc/inventory/DiscoveryTest.java
@@ -97,6 +97,8 @@ public class DiscoveryTest extends Arquillian {
discoveryCompleteChecker =
fakeServerInventory.createAsyncDiscoveryCompletionChecker(4);
when(serverServices.getDiscoveryServerService().mergeInventoryReport(any(InventoryReport.class))).then(
fakeServerInventory.mergeInventoryReport(InventoryStatus.COMMITTED));
+
when(serverServices.getDiscoveryServerService().getResourceSyncInfo(any(Integer.class))).then(
+ fakeServerInventory.getResourceSyncInfo());
}
@AfterDiscovery
@@ -187,7 +189,7 @@ public class DiscoveryTest extends Arquillian {
response.getResourceId(),
"Operation subsystem isn't aware of the correct resource id for
manual add resource");
}
-
+
private void validatePluginContainerInventory() throws Exception {
System.out.println("Validating PC inventory...");
diff --git
a/modules/core/plugin-container-itest/src/test/java/org/rhq/core/pc/inventory/IgnoreTypesInventoryManagerTest.java
b/modules/core/plugin-container-itest/src/test/java/org/rhq/core/pc/inventory/IgnoreTypesInventoryManagerTest.java
index fc9b610..7495075 100644
---
a/modules/core/plugin-container-itest/src/test/java/org/rhq/core/pc/inventory/IgnoreTypesInventoryManagerTest.java
+++
b/modules/core/plugin-container-itest/src/test/java/org/rhq/core/pc/inventory/IgnoreTypesInventoryManagerTest.java
@@ -44,6 +44,7 @@ public class IgnoreTypesInventoryManagerTest extends
AbstractIgnoreTypesInventor
@RunDiscovery
public void testIgnoreTypes() throws Exception {
// make sure the agent inventory does not have any resources of the ignored
types
+ waitForInventory(3);
validatePartiallyIgnoredInventory();
// simulate the unignoring of all types (i.e. don't ignore any types
anymore)
diff --git
a/modules/core/plugin-container-itest/src/test/java/org/rhq/core/pc/inventory/InventoryManagerTest.java
b/modules/core/plugin-container-itest/src/test/java/org/rhq/core/pc/inventory/InventoryManagerTest.java
index dcacd01..236d1ce 100644
---
a/modules/core/plugin-container-itest/src/test/java/org/rhq/core/pc/inventory/InventoryManagerTest.java
+++
b/modules/core/plugin-container-itest/src/test/java/org/rhq/core/pc/inventory/InventoryManagerTest.java
@@ -85,6 +85,8 @@ public class InventoryManagerTest extends Arquillian {
discoveryCompleteChecker =
fakeServerInventory.createAsyncDiscoveryCompletionChecker(2);
when(serverServices.getDiscoveryServerService().mergeInventoryReport(any(InventoryReport.class))).then(
fakeServerInventory.mergeInventoryReport(InventoryStatus.COMMITTED));
+
when(serverServices.getDiscoveryServerService().getResourceSyncInfo(any(Integer.class))).then(
+ fakeServerInventory.getResourceSyncInfo());
}
@AfterDiscovery
diff --git
a/modules/core/plugin-container-itest/src/test/java/org/rhq/core/pc/measurement/LateMeasurementRescheduleTest.java
b/modules/core/plugin-container-itest/src/test/java/org/rhq/core/pc/measurement/LateMeasurementRescheduleTest.java
index 301d613..159112a 100644
---
a/modules/core/plugin-container-itest/src/test/java/org/rhq/core/pc/measurement/LateMeasurementRescheduleTest.java
+++
b/modules/core/plugin-container-itest/src/test/java/org/rhq/core/pc/measurement/LateMeasurementRescheduleTest.java
@@ -76,6 +76,8 @@ public class LateMeasurementRescheduleTest extends Arquillian {
// autoimport everything
when(serverServices.getDiscoveryServerService().mergeInventoryReport(any(InventoryReport.class))).then(
fakeServerInventory.mergeInventoryReport(InventoryStatus.COMMITTED));
+
when(serverServices.getDiscoveryServerService().getResourceSyncInfo(any(Integer.class))).then(
+ fakeServerInventory.getResourceSyncInfo());
// set up the metric schedules using the metric metadata to determine default
intervals and enablement
when(serverServices.getDiscoveryServerService().postProcessNewlyCommittedResources(any(Set.class))).then(
@@ -119,7 +121,7 @@ public class LateMeasurementRescheduleTest extends Arquillian {
// ** metric2 - starting at time 90 (completes at time 91)
// ** metric2 - starting at time 105 (completes at time 105)
// ** metric1 - starting at time [121..150] (completes at time 90 + 30 +
[1..30])
- //
+ //
// Metric 1 is late because it was supposed to start at t60 but instead came up
for eval at t=90. It is then
// rescheduled by our fix for (currentTime=t90 + delay=30s +
randomInterval=[1..30] based on the 30s Interval).
// And you can see above, that is when the next request to collect metric1 is
done.
diff --git
a/modules/core/plugin-container-itest/src/test/java/org/rhq/core/pc/measurement/ReadOnlyScheduleSetTest.java
b/modules/core/plugin-container-itest/src/test/java/org/rhq/core/pc/measurement/ReadOnlyScheduleSetTest.java
index 4747851..081d601 100644
---
a/modules/core/plugin-container-itest/src/test/java/org/rhq/core/pc/measurement/ReadOnlyScheduleSetTest.java
+++
b/modules/core/plugin-container-itest/src/test/java/org/rhq/core/pc/measurement/ReadOnlyScheduleSetTest.java
@@ -75,6 +75,8 @@ public class ReadOnlyScheduleSetTest extends Arquillian {
// autoimport everything
when(serverServices.getDiscoveryServerService().mergeInventoryReport(any(InventoryReport.class))).then(
fakeServerInventory.mergeInventoryReport(InventoryStatus.COMMITTED));
+
when(serverServices.getDiscoveryServerService().getResourceSyncInfo(any(Integer.class))).then(
+ fakeServerInventory.getResourceSyncInfo());
// set up the metric schedules using the metric metadata to determine default
intervals and enablement
when(serverServices.getDiscoveryServerService().postProcessNewlyCommittedResources(any(Set.class))).then(
diff --git
a/modules/core/plugin-container/src/main/java/org/rhq/core/pc/StandaloneContainer.java
b/modules/core/plugin-container/src/main/java/org/rhq/core/pc/StandaloneContainer.java
index 380e91b..33cf21a 100644
---
a/modules/core/plugin-container/src/main/java/org/rhq/core/pc/StandaloneContainer.java
+++
b/modules/core/plugin-container/src/main/java/org/rhq/core/pc/StandaloneContainer.java
@@ -50,6 +50,7 @@ import org.rhq.core.domain.configuration.definition.PropertyDefinition;
import org.rhq.core.domain.discovery.AvailabilityReport;
import org.rhq.core.domain.discovery.MergeInventoryReportResults;
import org.rhq.core.domain.discovery.MergeResourceResponse;
+import org.rhq.core.domain.discovery.ResourceSyncInfo;
import org.rhq.core.domain.measurement.DataType;
import org.rhq.core.domain.measurement.MeasurementData;
import org.rhq.core.domain.measurement.MeasurementDefinition;
@@ -902,6 +903,11 @@ public class StandaloneContainer {
}
@Override
+ public ResourceSyncInfo getResourceSyncInfo(int resourceId) {
+ return null;
+ }
+
+ @Override
public Set<Resource> getResources(Set<Integer> resourceIds, boolean
includeDescendants) {
return null;
}
diff --git
a/modules/core/plugin-container/src/main/java/org/rhq/core/pc/inventory/InventoryManager.java
b/modules/core/plugin-container/src/main/java/org/rhq/core/pc/inventory/InventoryManager.java
index 35ba2af..b809f6f 100644
---
a/modules/core/plugin-container/src/main/java/org/rhq/core/pc/inventory/InventoryManager.java
+++
b/modules/core/plugin-container/src/main/java/org/rhq/core/pc/inventory/InventoryManager.java
@@ -19,6 +19,9 @@
package org.rhq.core.pc.inventory;
+import gnu.trove.map.TIntObjectMap;
+import gnu.trove.map.hash.TIntObjectHashMap;
+
import java.io.File;
import java.net.URL;
import java.util.ArrayList;
@@ -39,20 +42,17 @@ import java.util.concurrent.Callable;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.CopyOnWriteArraySet;
import java.util.concurrent.ExecutionException;
-import java.util.concurrent.Executor;
import java.util.concurrent.Future;
import java.util.concurrent.ScheduledThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.locks.ReentrantReadWriteLock;
-import gnu.trove.map.TIntObjectMap;
-import gnu.trove.map.hash.TIntObjectHashMap;
-
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
+
import org.rhq.core.clientapi.agent.PluginContainerException;
import org.rhq.core.clientapi.agent.configuration.ConfigurationUtility;
import org.rhq.core.clientapi.agent.discovery.DiscoveryAgentService;
@@ -70,6 +70,7 @@ import org.rhq.core.domain.discovery.AvailabilityReport;
import org.rhq.core.domain.discovery.MergeInventoryReportResults;
import org.rhq.core.domain.discovery.MergeInventoryReportResults.ResourceTypeFlyweight;
import org.rhq.core.domain.discovery.MergeResourceResponse;
+import org.rhq.core.domain.discovery.PlatformSyncInfo;
import org.rhq.core.domain.discovery.ResourceSyncInfo;
import org.rhq.core.domain.measurement.Availability;
import org.rhq.core.domain.measurement.AvailabilityType;
@@ -197,12 +198,14 @@ public class InventoryManager extends AgentService implements
ContainerService,
/**
* UUID to ResourceContainer map
*/
- private final Map<String, ResourceContainer> resourceContainersByUUID = new
ConcurrentHashMap<String, ResourceContainer>(500);
+ private final Map<String, ResourceContainer> resourceContainersByUUID = new
ConcurrentHashMap<String, ResourceContainer>(
+ 500);
/**
* ResourceID to ResourceContainer map
*/
- private final TIntObjectMap<ResourceContainer> resourceContainerByResourceId =
new TIntObjectHashMap<ResourceContainer>(500);
+ private final TIntObjectMap<ResourceContainer> resourceContainerByResourceId =
new TIntObjectHashMap<ResourceContainer>(
+ 500);
/**
* Collection of event listeners to inform of changes to the inventory.
@@ -353,7 +356,8 @@ public class InventoryManager extends AgentService implements
ContainerService,
}
// find the discovery callbacks defined, if there are none, just return the
results as-is
- Map<String, List<String>> callbacks =
this.pluginManager.getMetadataManager().getDiscoveryCallbacks(context.getResourceType());
+ Map<String, List<String>> callbacks =
this.pluginManager.getMetadataManager().getDiscoveryCallbacks(
+ context.getResourceType());
if (callbacks == null || callbacks.isEmpty()) {
return results;
}
@@ -364,7 +368,7 @@ public class InventoryManager extends AgentService implements
ContainerService,
PluginComponentFactory pluginComponentFactory =
PluginContainer.getInstance().getPluginComponentFactory();
ClassLoader originalContextClassLoader =
Thread.currentThread().getContextClassLoader();
- for (Iterator<DiscoveredResourceDetails> detailsIterator =
results.iterator(); detailsIterator.hasNext(); ) {
+ for (Iterator<DiscoveredResourceDetails> detailsIterator =
results.iterator(); detailsIterator.hasNext();) {
DiscoveredResourceDetails details = detailsIterator.next();
int callbackCount = 0;
boolean stopProcessing = false; // if true, a callback told us he found a
details that he modified and we should stop
@@ -374,38 +378,39 @@ public class InventoryManager extends AgentService implements
ContainerService,
String pluginName = entry.getKey();
List<String> callbackClassNames = entry.getValue();
for (String className : callbackClassNames) {
- ResourceDiscoveryCallback callback =
pluginComponentFactory.getDiscoveryCallback(pluginName, className);
+ ResourceDiscoveryCallback callback =
pluginComponentFactory.getDiscoveryCallback(pluginName,
+ className);
try {
Thread.currentThread().setContextClassLoader(callback.getClass().getClassLoader());
- callbackResults= callback.discoveredResources(details);// inline
in our calling thread - no time outs or anything; hopefully the plugin plays nice
+ callbackResults = callback.discoveredResources(details);// inline
in our calling thread - no time outs or anything; hopefully the plugin plays nice
callbackCount++;
if (log.isDebugEnabled()) {
log.debug("Discovery callback [{" + pluginName +
"}" + className + "] returned ["
- + callbackResults + "] #invocations=" +
callbackCount);
+ + callbackResults + "] #invocations=" +
callbackCount);
}
switch (callbackResults) {
- case PROCESSED: {
- if (stopProcessing) {
- abortDiscovery = true;
- log.warn("Another discovery callback [{" +
pluginName + "}" + className
- + "] processed details [" +
details
- + "]. This is not allowed. Discovery
will be aborted for that resource");
- } else {
- stopProcessing = true;
- }
- break;
- }
- case VETO: {
- vetoDiscovery = true;
- log.warn("Discovery callback [{" + pluginName +
"}" + className
- + "] vetoed resource [" + details
- + "]. Discovery will be skipped for that
resource and it will not be inventoried.");
- break;
- }
- default: {
- // callback left the details unprocessed, nothing to do.
- break;
+ case PROCESSED: {
+ if (stopProcessing) {
+ abortDiscovery = true;
+ log.warn("Another discovery callback [{" +
pluginName + "}" + className
+ + "] processed details [" + details
+ + "]. This is not allowed. Discovery will be
aborted for that resource");
+ } else {
+ stopProcessing = true;
}
+ break;
+ }
+ case VETO: {
+ vetoDiscovery = true;
+ log.warn("Discovery callback [{" + pluginName +
"}" + className + "] vetoed resource ["
+ + details
+ + "]. Discovery will be skipped for that resource
and it will not be inventoried.");
+ break;
+ }
+ default: {
+ // callback left the details unprocessed, nothing to do.
+ break;
+ }
}
// note that we keep going, even if we set stopProcessing is true
- this is because we
// want to keep calling callbacks and check if they, too, think
they can identify the details. If
@@ -680,8 +685,7 @@ public class InventoryManager extends AgentService implements
ContainerService,
@NotNull
public InventoryReport executeServiceScanImmediately(Resource resource) {
- RuntimeDiscoveryExecutor discoveryExecutor = new RuntimeDiscoveryExecutor(this,
this.configuration,
- resource);
+ RuntimeDiscoveryExecutor discoveryExecutor = new RuntimeDiscoveryExecutor(this,
this.configuration, resource);
return submit(discoveryExecutor);
}
@@ -746,7 +750,7 @@ public class InventoryManager extends AgentService implements
ContainerService,
try {
//make sure we have the full version of the resource
ResourceContainer container = getResourceContainer(resource.getId());
- if (container == null) {
+ if (container == null) {
//don't bother doing anything
return new AvailabilityReport(changesOnly, getAgent().getName());
}
@@ -1125,7 +1129,7 @@ public class InventoryManager extends AgentService implements
ContainerService,
return true;
}
- ResourceSyncInfo syncInfo;
+ PlatformSyncInfo platformSyncInfo;
Collection<ResourceTypeFlyweight> ignoredTypes;
try {
String reportType = (report.isRuntimeReport()) ? "runtime" :
"server";
@@ -1135,10 +1139,10 @@ public class InventoryManager extends AgentService implements
ContainerService,
.getDiscoveryServerService();
MergeInventoryReportResults results =
discoveryServerService.mergeInventoryReport(report);
if (results != null) {
- syncInfo = results.getResourceSyncInfo();
+ platformSyncInfo = results.getPlatformSyncInfo();
ignoredTypes = results.getIgnoredResourceTypes();
} else {
- syncInfo = null;
+ platformSyncInfo = null;
ignoredTypes = null;
}
if (log.isDebugEnabled()) {
@@ -1183,8 +1187,8 @@ public class InventoryManager extends AgentService implements
ContainerService,
//Another (rare) scenario where this would happen would be when the platform
resource type
//would change.
//In either case, let's sync up with the server - if it's got nothing,
neither should the agent.
- if (syncInfo != null) {
- synchInventory(syncInfo);
+ if (platformSyncInfo != null) {
+ syncPlatform(platformSyncInfo);
} else {
purgeObsoleteResources(Collections.<String> emptySet());
@@ -1196,24 +1200,86 @@ public class InventoryManager extends AgentService implements
ContainerService,
}
/**
- * Performs a sync so that resources passed in are reflected in the agent's
inventory.
- * This assumes the resource sync infos passed in represent the full inventory tree.
+ * Performs a full platform sync so that resources passed in are reflected in the
agent's inventory.
*
- * @param syncInfo information on all resources in the entire inventory tree
+ * @param platformSyncInfo sync info on the platform and references to the top level
servers
*/
- private void synchInventory(ResourceSyncInfo syncInfo) {
- synchInventory(syncInfo, false);
+ private void syncPlatform(PlatformSyncInfo platformSyncInfo) {
+ final Set<String> allServerSideUuids = new HashSet<String>();
+ boolean hadSyncedResources = false;
+
+ // always sync the platform because it does not get included in the top level
server sync
+ allServerSideUuids.add(platformSyncInfo.getUuid());
+ ResourceSyncInfo platformResourceSyncInfo =
ResourceSyncInfo.buildResourceSyncInfo(platformSyncInfo);
+ log.info("Sync Starting: Platform [" + platformResourceSyncInfo.getId()
+ "]");
+ hadSyncedResources = syncResource(platformResourceSyncInfo) ||
hadSyncedResources;
+ log.info("Sync Complete: Platform [" + platformResourceSyncInfo.getId()
+ "]. Local inventory changed: ["
+ + hadSyncedResources + "]");
+
+ // then sync the top level servers by calling back to the server for the sync
info for each. We
+ // do this one at a time to avoid forcing the whole inventory into active memory
at one time during the sync.
+ Collection<Resource> topLevelServers =
platformSyncInfo.getTopLevelServers();
+ if (null != topLevelServers) {
+ DiscoveryServerService service =
configuration.getServerServices().getDiscoveryServerService();
+
+ for (Resource topLevelServer : topLevelServers) {
+ ResourceSyncInfo topLevelServerSyncInfo =
service.getResourceSyncInfo(topLevelServer.getId());
+ if (null != topLevelServerSyncInfo) {
+ //topLevelServerSyncInfo =
ResourceSyncInfo.buildResourceSyncInfo(platformSyncInfo,
+ // topLevelServerSyncInfo);
+ getAllUuids(topLevelServerSyncInfo, allServerSideUuids);
+ log.info("Sync Starting: Top Level Server [" +
topLevelServerSyncInfo.getId() + "]");
+ hadSyncedResources = syncResource(topLevelServerSyncInfo) ||
hadSyncedResources;
+ log.info("Sync Complete: Top Level Server [" +
topLevelServerSyncInfo.getId()
+ + "] Local inventory changed: [" + hadSyncedResources +
"]");
+ }
+ }
+ }
+
+ purgeObsoleteResources(allServerSideUuids);
+
+ // If we synced any Resources, one or more Resource components were probably
started, request a
+ // full avail report to make sure their availabilities are determined on the next
avail run (typically
+ // < 30s away). A full avail report will ensure an initial avail check is
performed for a resource.
+ //
+ // Also kick off a service scan to scan those Resources for new child Resources.
Kick both tasks off
+ // asynchronously.
+ //
+ // Do this only if we are finished with resource upgrade because no availability
checks
+ // or discoveries can happen during upgrade. This is to ensure maximum
consistency of the
+ // inventory with the server side as well as to disallow any other server-agent
traffic during
+ // the upgrade phase. Not to mention the fact that no thread pools are
initialized yet by the
+ // time the upgrade kicks in..
+ if (hadSyncedResources && !isResourceUpgradeActive()) {
+
+ // TODO: If someday this is undesirable for scalability reasons, we could
probably instead call
+ // requestAvailabilityCheck on each unknown or modified resource.
+ requestFullAvailabilityReport();
+
+ this.inventoryThreadPoolExecutor.schedule((Callable<? extends Object>)
this.serviceScanExecutor,
+ configuration.getChildResourceDiscoveryDelay(), TimeUnit.SECONDS);
+ }
+ }
+
+ private void getAllUuids(ResourceSyncInfo syncInfo, Set<String>
allServerSideUuids) {
+ allServerSideUuids.add(syncInfo.getUuid());
+
+ if (null != syncInfo.getChildSyncInfos()) {
+ for (ResourceSyncInfo child : syncInfo.getChildSyncInfos()) {
+ getAllUuids(child, allServerSideUuids);
+ }
+ }
}
/**
- * Performs a sync so that resources passed in are reflected in the agent's
inventory.
+ * Performs a synch on only the single resource and its descendants. This is assumed
to be a partial
+ * inventory. To synch on the full inventory call {@link
#syncPlatform(PlatformSyncInfo)}
*
* @param syncInfo the resources' sync data
- * @param partialInventory if true, syncInfo represents only a partial inventory.
- * if false, syncInfo represents the full inventory tree of
all resources
+ * @return true if any resources needed synchronization, false otherwise
*/
- private void synchInventory(ResourceSyncInfo syncInfo, boolean partialInventory) {
- log.info("Syncing local inventory with Server inventory...");
+ private boolean syncResource(ResourceSyncInfo syncInfo) {
+ boolean result = false;
final long startTime = System.currentTimeMillis();
final Set<Resource> syncedResources = new LinkedHashSet<Resource>();
final Set<ResourceSyncInfo> unknownResourceSyncInfos = new
LinkedHashSet<ResourceSyncInfo>();
@@ -1221,20 +1287,14 @@ public class InventoryManager extends AgentService implements
ContainerService,
final Set<Integer> deletedResourceIds = new
LinkedHashSet<Integer>();
final Set<Resource> newlyCommittedResources = new
LinkedHashSet<Resource>();
final Set<Resource> ignoredResources = new
LinkedHashSet<Resource>();
- final Set<String> allServerSideUuids = new HashSet<String>();
// rhq-980 Adding agent-side logging to report any unexpected synch failure.
try {
- // don't bother doing this if we are processing a partial inventory.
- // allServerSideUuids is only ever used to purge obsolete resources, but we
don't
- // do that for partial inventories, so we don't need to prepare that
collection for partials.
- if (!partialInventory) {
- getAllUuids(syncInfo, allServerSideUuids);
- }
-
log.debug("Processing Server sync info...");
+
processSyncInfo(syncInfo, syncedResources, unknownResourceSyncInfos,
modifiedResourceIds,
deletedResourceIds, newlyCommittedResources, ignoredResources);
+
if (log.isDebugEnabled()) {
log.debug(String.format("DONE Processing sync info: [%d] ms: synced
[%d] resources: "
+ "[%d] unknown, [%d] modified, [%d] deleted, [%d] newly
committed",
@@ -1245,9 +1305,7 @@ public class InventoryManager extends AgentService implements
ContainerService,
mergeUnknownResources(unknownResourceSyncInfos);
mergeModifiedResources(modifiedResourceIds);
purgeIgnoredResources(ignoredResources);
- if (!partialInventory) {
- purgeObsoleteResources(allServerSideUuids);
- }
+
postProcessNewlyCommittedResources(newlyCommittedResources);
if (log.isDebugEnabled()) {
if (!deletedResourceIds.isEmpty()) {
@@ -1257,41 +1315,26 @@ public class InventoryManager extends AgentService implements
ContainerService,
(System.currentTimeMillis() - startTime)));
}
- // If we synced any Resources, one or more Resource components were probably
started, request a
- // full avail report to make sure their availabilities are determined on the
next avail run (typically
- // < 30s away). A full avail report will ensure an initial avail check is
performed for a resource.
- //
- // Also kick off a service scan to scan those Resources for new child
Resources. Kick both tasks off
- // asynchronously.
- //
- // Do this only if we are finished with resource upgrade because no
availability checks
- // or discoveries can happen during upgrade. This is to ensure maximum
consistency of the
- // inventory with the server side as well as to disallow any other
server-agent traffic during
- // the upgrade phase. Not to mention the fact that no thread pools are
initialized yet by the
- // time the upgrade kicks in..
- if (!isResourceUpgradeActive()
- && (!syncedResources.isEmpty() ||
!unknownResourceSyncInfos.isEmpty() || !modifiedResourceIds.isEmpty())) {
-
- // TODO: If someday this is undesirable for scalability reasons, we could
probably instead call
- // requestAvailabilityCheck on each unknown or modified resource.
- requestFullAvailabilityReport();
+ result = !(syncedResources.isEmpty() &&
unknownResourceSyncInfos.isEmpty() && modifiedResourceIds.isEmpty());
- this.inventoryThreadPoolExecutor.schedule((Callable<? extends
Object>) this.serviceScanExecutor,
- configuration.getChildResourceDiscoveryDelay(), TimeUnit.SECONDS);
- }
} catch (Throwable t) {
log.warn("Failed to synchronize local inventory with Server inventory
for Resource [" + syncInfo.getId()
+ "] and its descendants: " + t.getMessage());
// convert to runtime exception so as not to change the api
throw new RuntimeException(t);
}
+
+ return result;
}
- private void getAllUuids(ResourceSyncInfo syncInfo, Set<String>
allServerSideUuids) {
- allServerSideUuids.add(syncInfo.getUuid());
- for (ResourceSyncInfo child : syncInfo.getChildSyncInfos()) {
- getAllUuids(child, allServerSideUuids);
- }
+ public void synchronizeInventory(ResourceSyncInfo resourceSyncInfo) {
+ log.info("Synchronizing local inventory with Server inventory for Resource
[" + resourceSyncInfo.getId()
+ + "] and its descendants...");
+
+ // Get the latest resource data rooted at the given id.
+ syncResource(resourceSyncInfo); // this method assumes we only get a single
resource and its children (BZ 887411)
+ performServiceScan(resourceSyncInfo.getId()); // NOTE: This will block (the
initial scan blocks).
+ // TODO: (jshaughn) should we also request a full avail scan?
}
/**
@@ -1420,8 +1463,7 @@ public class InventoryManager extends AgentService implements
ContainerService,
log.debug("Asked to remove an unknown Resource [" +
resource + "] with UUID [" + resource.getUuid()
+ "]");
}
- }
- else {
+ } else {
this.resourceContainerByResourceId.remove(resource.getId());
}
@@ -1965,8 +2007,8 @@ public class InventoryManager extends AgentService implements
ContainerService,
getEventContext(resource), // for event access
getOperationContext(resource), // for operation manager access
getContentContext(resource), // for content manager access
- getAvailabilityContext(resource),
- getInventoryContext(resource),
this.configuration.getPluginContainerDeployment(), // helps components make determinations
of what to do
+ getAvailabilityContext(resource), getInventoryContext(resource),
+ this.configuration.getPluginContainerDeployment(), // helps components make
determinations of what to do
new ComponentInvocationContextImpl());
}
@@ -2162,8 +2204,8 @@ public class InventoryManager extends AgentService implements
ContainerService,
this.resourceContainerByResourceId.put(resource.getId(),
resourceContainer);
}
- log.info("Inventory with size [" +
this.resourceContainersByUUID.size() + "] loaded from data file in ["
- + (System.currentTimeMillis() - start) + "ms]");
+ log.info("Inventory with size [" +
this.resourceContainersByUUID.size()
+ + "] loaded from data file in [" +
(System.currentTimeMillis() - start) + "ms]");
}
} catch (Exception e) {
this.platform = null;
@@ -2346,15 +2388,6 @@ public class InventoryManager extends AgentService implements
ContainerService,
return platform;
}
- public void synchronizeInventory(ResourceSyncInfo syncInfo) {
- log.info("Synchronizing local inventory with Server inventory for Resource
[" + syncInfo.getId()
- + "] and its descendants...");
-
- // Get the latest resource data rooted at the given id.
- synchInventory(syncInfo, true); // this method assumes we only get a single
resource and its children (BZ 887411)
- performServiceScan(syncInfo.getId()); // NOTE: This will block (the initial scan
blocks).
- }
-
/**
* This method is called for a resource tree that exists in the server inventory but
* not in the agent's inventory.
@@ -2944,9 +2977,11 @@ public class InventoryManager extends AgentService implements
ContainerService,
}
// Recurse...
- for (ResourceSyncInfo childSyncInfo : syncInfo.getChildSyncInfos()) {
- processSyncInfo(childSyncInfo, syncedResources,
unknownResourceSyncInfos, modifiedResourceIds,
- deletedResourceIds, newlyCommittedResources, ignoredResources);
+ if (null != syncInfo.getChildSyncInfos()) {
+ for (ResourceSyncInfo childSyncInfo : syncInfo.getChildSyncInfos())
{
+ processSyncInfo(childSyncInfo, syncedResources,
unknownResourceSyncInfos, modifiedResourceIds,
+ deletedResourceIds, newlyCommittedResources,
ignoredResources);
+ }
}
}
}
@@ -3151,8 +3186,10 @@ public class InventoryManager extends AgentService implements
ContainerService,
while (!queue.isEmpty()) {
ResourceSyncInfo node = queue.remove();
result.add(node.getId());
- for (ResourceSyncInfo child : node.getChildSyncInfos()) {
- queue.add(child);
+ if (null != node.getChildSyncInfos()) {
+ for (ResourceSyncInfo child : node.getChildSyncInfos()) {
+ queue.add(child);
+ }
}
}
diff --git
a/modules/core/plugin-container/src/main/java/org/rhq/core/pc/inventory/RuntimeDiscoveryExecutor.java
b/modules/core/plugin-container/src/main/java/org/rhq/core/pc/inventory/RuntimeDiscoveryExecutor.java
index 5265977..d9431d0 100644
---
a/modules/core/plugin-container/src/main/java/org/rhq/core/pc/inventory/RuntimeDiscoveryExecutor.java
+++
b/modules/core/plugin-container/src/main/java/org/rhq/core/pc/inventory/RuntimeDiscoveryExecutor.java
@@ -216,7 +216,7 @@ public class RuntimeDiscoveryExecutor implements Runnable,
Callable<InventoryRep
AvailabilityType currentAvailabilityType = (null == currentAvailability) ?
AvailabilityType.DOWN
: currentAvailability.getAvailabilityType();
- // If there is no current avail, or this is a SERVER, we must perfom the live
check.
+ // If there is no current avail, or this is a SERVER, we must perform the live
check.
if (AvailabilityType.UP != currentAvailabilityType
|| ResourceCategory.SERVER ==
parentContainer.getResource().getResourceType().getCategory()) {
diff --git
a/modules/core/plugin-container/src/test/java/org/rhq/core/pc/upgrade/FakeServerInventory.java
b/modules/core/plugin-container/src/test/java/org/rhq/core/pc/upgrade/FakeServerInventory.java
index 3f2bbb9..5a18d65 100644
---
a/modules/core/plugin-container/src/test/java/org/rhq/core/pc/upgrade/FakeServerInventory.java
+++
b/modules/core/plugin-container/src/test/java/org/rhq/core/pc/upgrade/FakeServerInventory.java
@@ -19,8 +19,6 @@
package org.rhq.core.pc.upgrade;
-import static org.testng.Assert.fail;
-
import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.Arrays;
@@ -41,6 +39,7 @@ import org.rhq.core.clientapi.agent.upgrade.ResourceUpgradeRequest;
import org.rhq.core.clientapi.agent.upgrade.ResourceUpgradeResponse;
import org.rhq.core.clientapi.server.discovery.InventoryReport;
import org.rhq.core.domain.discovery.MergeInventoryReportResults;
+import org.rhq.core.domain.discovery.PlatformSyncInfo;
import org.rhq.core.domain.discovery.ResourceSyncInfo;
import org.rhq.core.domain.resource.InventoryStatus;
import org.rhq.core.domain.resource.Resource;
@@ -120,7 +119,26 @@ public class FakeServerInventory {
platform = persisted;
}
}
- return new MergeInventoryReportResults(getSyncInfo(), null);
+ return new MergeInventoryReportResults(getPlatformSyncInfo(), null);
+ }
+ }
+ };
+ }
+
+ public synchronized CustomAction getResourceSyncInfo() {
+ return new CustomAction("getResourceSyncInfo") {
+ public Object invoke(Invocation invocation) throws Throwable {
+ synchronized (FakeServerInventory.this) {
+ throwIfFailing();
+
+ Integer resourceId = (Integer) invocation.getParameter(0);
+
+ for (Resource c : platform.getChildResources()) {
+ if (c.getId() == resourceId) {
+ return getResourceSyncInfo(c);
+ }
+ }
+ return null;
}
}
};
@@ -134,7 +152,7 @@ public class FakeServerInventory {
platform = null;
- return new MergeInventoryReportResults(getSyncInfo(), null);
+ return new MergeInventoryReportResults(getPlatformSyncInfo(), null);
}
}
};
@@ -394,57 +412,51 @@ public class FakeServerInventory {
return persisted;
}
- private ResourceSyncInfo getSyncInfo() {
- return platform != null ? convert(platform) : null;
- }
-
private void throwIfFailing() {
if (failing) {
throw new RuntimeException("Fake server inventory is in the failing
mode.");
}
}
+ private PlatformSyncInfo getPlatformSyncInfo() {
+ return platform == null ? null :
PlatformSyncInfo.buildPlatformSyncInfo(platform);
+ }
+
+ private ResourceSyncInfo getResourceSyncInfo(Resource resource) {
+ return resource == null ? null : convert(resource);
+ }
+
private static ResourceSyncInfo convert(Resource root) {
- return convertInternal(root, new HashMap<String, ResourceSyncInfo>());
+ return convertInternal(root, true, new HashMap<String,
ResourceSyncInfo>());
}
- private static ResourceSyncInfo convertInternal(Resource root, Map<String,
ResourceSyncInfo> intermediateResults) {
+ private static ResourceSyncInfo convertInternal(Resource root, boolean
isTopLevelServer,
+ Map<String, ResourceSyncInfo> intermediateResults) {
+
ResourceSyncInfo ret = intermediateResults.get(root.getUuid());
if (ret != null) {
return ret;
}
-
try {
- ret = new ResourceSyncInfo();
-
+ ret = ResourceSyncInfo.buildResourceSyncInfo(root);
intermediateResults.put(root.getUuid(), ret);
- Class<ResourceSyncInfo> clazz = ResourceSyncInfo.class;
-
- getPrivateField(clazz, "id").set(ret, root.getId());
- getPrivateField(clazz, "uuid").set(ret, root.getUuid());
- getPrivateField(clazz, "mtime").set(ret, root.getMtime());
- getPrivateField(clazz, "inventoryStatus").set(ret,
root.getInventoryStatus());
-
- ResourceSyncInfo parent = root.getParentResource() == null ? null :
convertInternal(
- root.getParentResource(), intermediateResults);
-
- getPrivateField(clazz, "parent").set(ret, parent);
+ Integer parentId = root.getParentResource() == null ? null :
root.getParentResource().getId();
+ getPrivateField(ResourceSyncInfo.class, "parentId").set(ret,
parentId);
Set<ResourceSyncInfo> children = new
LinkedHashSet<ResourceSyncInfo>();
for (Resource child : root.getChildResources()) {
- ResourceSyncInfo syncChild = convertInternal(child,
intermediateResults);
+ ResourceSyncInfo syncChild = convertInternal(child, false,
intermediateResults);
children.add(syncChild);
}
-
- getPrivateField(clazz, "childSyncInfos").set(ret, children);
-
+ getPrivateField(ResourceSyncInfo.class, "childSyncInfos").set(ret,
children);
return ret;
+
} catch (Exception e) {
- fail("Failed to convert resource " + root + " to a
ResourceSyncInfo. This should not happen.", e);
- return null;
+ throw new IllegalStateException("Failed to convert resource " +
root
+ + " to a ResourceSyncInfo. This should not happen.", e);
}
}
diff --git
a/modules/enterprise/server/itests-2/src/test/java/org/rhq/enterprise/server/discovery/DiscoveryBossBeanTest.java
b/modules/enterprise/server/itests-2/src/test/java/org/rhq/enterprise/server/discovery/DiscoveryBossBeanTest.java
index e09db85..9cf9f98 100644
---
a/modules/enterprise/server/itests-2/src/test/java/org/rhq/enterprise/server/discovery/DiscoveryBossBeanTest.java
+++
b/modules/enterprise/server/itests-2/src/test/java/org/rhq/enterprise/server/discovery/DiscoveryBossBeanTest.java
@@ -67,6 +67,7 @@ import org.rhq.core.domain.criteria.ResourceCriteria;
import org.rhq.core.domain.discovery.MergeInventoryReportResults;
import org.rhq.core.domain.discovery.MergeInventoryReportResults.ResourceTypeFlyweight;
import org.rhq.core.domain.discovery.MergeResourceResponse;
+import org.rhq.core.domain.discovery.PlatformSyncInfo;
import org.rhq.core.domain.discovery.ResourceSyncInfo;
import org.rhq.core.domain.resource.Agent;
import org.rhq.core.domain.resource.CreateResourceHistory;
@@ -190,8 +191,7 @@ public class DiscoveryBossBeanTest extends AbstractEJB3Test {
MergeInventoryReportResults results =
discoveryBoss.mergeInventoryReport(serialize(inventoryReport));
assert results != null;
assert results.getIgnoredResourceTypes() == null : "nothing should have been
ignored in this test";
- ResourceSyncInfo syncInfo = results.getResourceSyncInfo();
- assert syncInfo != null;
+ assertNotNull(results.getPlatformSyncInfo());
}
@Test(groups = "integration.ejb3")
@@ -204,7 +204,8 @@ public class DiscoveryBossBeanTest extends AbstractEJB3Test {
MergeInventoryReportResults results =
discoveryBoss.mergeInventoryReport(serialize(inventoryReport));
assert results != null;
assert results.getIgnoredResourceTypes() == null : "nothing should have been
ignored in this test";
- ResourceSyncInfo syncInfo = results.getResourceSyncInfo();
+ assertNotNull(results.getPlatformSyncInfo());
+ ResourceSyncInfo syncInfo =
discoveryBoss.getResourceSyncInfo(results.getPlatformSyncInfo().getId());
assert syncInfo != null;
platform.setId(syncInfo.getId());
@@ -227,8 +228,7 @@ public class DiscoveryBossBeanTest extends AbstractEJB3Test {
results = discoveryBoss.mergeInventoryReport(serialize(inventoryReport));
assert results != null;
assert results.getIgnoredResourceTypes() == null : "nothing should have been
ignored in this test";
- syncInfo = results.getResourceSyncInfo();
- assert syncInfo != null;
+ assertNotNull(results.getPlatformSyncInfo());
}
@Test(groups = "integration.ejb3")
@@ -250,7 +250,8 @@ public class DiscoveryBossBeanTest extends AbstractEJB3Test {
MergeInventoryReportResults results =
discoveryBoss.mergeInventoryReport(serialize(inventoryReport));
assert results != null;
assert results.getIgnoredResourceTypes() == null : "nothing should have been
ignored in this test";
- ResourceSyncInfo syncInfo = results.getResourceSyncInfo();
+ assertNotNull(results.getPlatformSyncInfo());
+ ResourceSyncInfo syncInfo =
discoveryBoss.getResourceSyncInfo(results.getPlatformSyncInfo().getId());
assert syncInfo != null;
ResourceSyncInfo serverSyncInfo =
syncInfo.getChildSyncInfos().iterator().next();
@@ -290,18 +291,18 @@ public class DiscoveryBossBeanTest extends AbstractEJB3Test {
assert mergeResults != null;
assert mergeResults.getIgnoredResourceTypes() == null : "nothing should have
been ignored: "
+ mergeResults.getIgnoredResourceTypes();
- ResourceSyncInfo platformSyncInfo = mergeResults.getResourceSyncInfo();
+ PlatformSyncInfo platformSyncInfo = mergeResults.getPlatformSyncInfo();
assert platformSyncInfo != null;
// Check merge result
assertEquals(InventoryStatus.NEW, platformSyncInfo.getInventoryStatus());
- assertEquals(platform.getChildResources().size(),
platformSyncInfo.getChildSyncInfos().size());
+ assertEquals(platform.getChildResources().size(),
platformSyncInfo.getTopLevelServers().size());
// Collect the resource ids generated for the platform and the servers
int platformId = platformSyncInfo.getId();
List<Integer> serverIds = new LinkedList<Integer>();
- for (ResourceSyncInfo serverSyncInfo : platformSyncInfo.getChildSyncInfos()) {
+ for (Resource serverSyncInfo : platformSyncInfo.getTopLevelServers()) {
serverIds.add(serverSyncInfo.getId());
}
int[] arrayOfServerIds = ArrayUtils.unwrapCollection(serverIds);
@@ -360,7 +361,7 @@ public class DiscoveryBossBeanTest extends AbstractEJB3Test {
// Merge this inventory report
MergeInventoryReportResults mergeResults =
discoveryBoss.mergeInventoryReport(serialize(inventoryReport));
assert mergeResults != null;
- ResourceSyncInfo platformSyncInfo = mergeResults.getResourceSyncInfo();
+ PlatformSyncInfo platformSyncInfo = mergeResults.getPlatformSyncInfo();
assert platformSyncInfo != null;
assertNotNull(mergeResults.getIgnoredResourceTypes());
assertEquals(mergeResults.getIgnoredResourceTypes().size(), 1);
@@ -368,7 +369,7 @@ public class DiscoveryBossBeanTest extends AbstractEJB3Test {
// Check merge result - make sure we should not see any children under the
platform (it should have been ignored)
assertEquals(InventoryStatus.NEW, platformSyncInfo.getInventoryStatus());
- assertEquals(platformSyncInfo.getChildSyncInfos().size(), 0);
+ assertEquals(platformSyncInfo.getTopLevelServers().size(), 0);
}
@Test(groups = "integration.ejb3")
@@ -392,7 +393,7 @@ public class DiscoveryBossBeanTest extends AbstractEJB3Test {
// Merge this inventory report
MergeInventoryReportResults mergeResults =
discoveryBoss.mergeInventoryReport(serialize(inventoryReport));
assert mergeResults != null;
- ResourceSyncInfo platformSyncInfo = mergeResults.getResourceSyncInfo();
+ PlatformSyncInfo platformSyncInfo = mergeResults.getPlatformSyncInfo();
assert platformSyncInfo != null;
// now see that we were told about the service types being ignored (even though
we had no resources of that type in the report)
@@ -423,13 +424,13 @@ public class DiscoveryBossBeanTest extends AbstractEJB3Test {
assert mergeResults != null;
assert mergeResults.getIgnoredResourceTypes() == null : "nothing should have
been ignored: "
+ mergeResults.getIgnoredResourceTypes();
- ResourceSyncInfo platformSyncInfo = mergeResults.getResourceSyncInfo();
+ PlatformSyncInfo platformSyncInfo = mergeResults.getPlatformSyncInfo();
assert platformSyncInfo != null;
// Collect the resource ids generated for the platform and the servers
int platformId = platformSyncInfo.getId();
List<Integer> serverIds = new LinkedList<Integer>();
- for (ResourceSyncInfo serverSyncInfo : platformSyncInfo.getChildSyncInfos()) {
+ for (Resource serverSyncInfo : platformSyncInfo.getTopLevelServers()) {
serverIds.add(serverSyncInfo.getId());
}
int[] arrayOfServerIds = ArrayUtils.unwrapCollection(serverIds);
@@ -462,14 +463,14 @@ public class DiscoveryBossBeanTest extends AbstractEJB3Test {
// Merge the inventory report again to simulate another discovery - the servers
should be ignored now
mergeResults = discoveryBoss.mergeInventoryReport(serialize(inventoryReport));
assert mergeResults != null;
- platformSyncInfo = mergeResults.getResourceSyncInfo();
+ platformSyncInfo = mergeResults.getPlatformSyncInfo();
assert platformSyncInfo != null;
assertNotNull(mergeResults.getIgnoredResourceTypes());
assertEquals(mergeResults.getIgnoredResourceTypes().size(), 1);
assert mergeResults.getIgnoredResourceTypes().contains(new
ResourceTypeFlyweight(serverType));
assertEquals(InventoryStatus.COMMITTED, platformSyncInfo.getInventoryStatus());
// notice platform is committed now
- assertEquals(platformSyncInfo.getChildSyncInfos().size(), 0); // notice there are
no server children now
+ assertEquals(platformSyncInfo.getTopLevelServers().size(), 0); // notice there
are no server children now
}
@Test(groups = "integration.ejb3")
@@ -496,15 +497,15 @@ public class DiscoveryBossBeanTest extends AbstractEJB3Test {
assert mergeResults != null;
assert mergeResults.getIgnoredResourceTypes() == null : "nothing should have
been ignored: "
+ mergeResults.getIgnoredResourceTypes();
- ResourceSyncInfo platformSyncInfo = mergeResults.getResourceSyncInfo();
+ PlatformSyncInfo platformSyncInfo = mergeResults.getPlatformSyncInfo();
assert platformSyncInfo != null;
// Check merge result
assertEquals(InventoryStatus.COMMITTED, platformSyncInfo.getInventoryStatus());
- assertEquals(storagePlatform.getChildResources().size(),
platformSyncInfo.getChildSyncInfos().size());
+ assertEquals(storagePlatform.getChildResources().size(),
platformSyncInfo.getTopLevelServers().size());
storageNode = resourceManager.getResourceById(subjectManager.getOverlord(),
platformSyncInfo
- .getChildSyncInfos().iterator().next().getId());
+ .getTopLevelServers().iterator().next().getId());
assertNotNull(storageNode);
assertEquals(InventoryStatus.COMMITTED, storageNode.getInventoryStatus());
}
@@ -526,13 +527,13 @@ public class DiscoveryBossBeanTest extends AbstractEJB3Test {
MergeInventoryReportResults results =
discoveryBoss.mergeInventoryReport(serialize(inventoryReport));
assertNotNull(results);
assertNull("nothing should have been ignored in this test",
results.getIgnoredResourceTypes());
- final ResourceSyncInfo firstDiscoverySyncInfo = results.getResourceSyncInfo();
+ final PlatformSyncInfo firstDiscoverySyncInfo = results.getPlatformSyncInfo();
assertNotNull(firstDiscoverySyncInfo);
// Then simulate a create resource request
final String userSuppliedResourceName = prefix("User Supplied Resource
Name");
final String newResourceKey = prefix("Created Resource Key");
- ResourceSyncInfo serverSyncInfo =
firstDiscoverySyncInfo.getChildSyncInfos().iterator().next();
+ Resource serverSyncInfo =
firstDiscoverySyncInfo.getTopLevelServers().iterator().next();
final int serverResourceId = serverSyncInfo.getId();
executeInTransaction(false, new TransactionCallback() {
@@ -562,13 +563,14 @@ public class DiscoveryBossBeanTest extends AbstractEJB3Test {
results = discoveryBoss.mergeInventoryReport(serialize(inventoryReport));
assertNotNull(results);
assertNull("nothing should have been ignored in this test",
results.getIgnoredResourceTypes());
- ResourceSyncInfo secondDiscoverySyncInfo = results.getResourceSyncInfo();
+ PlatformSyncInfo secondDiscoverySyncInfo = results.getPlatformSyncInfo();
assertNotNull(secondDiscoverySyncInfo);
// Check that the resource ends with the user supplied name in inventory
- serverSyncInfo = secondDiscoverySyncInfo.getChildSyncInfos().iterator().next();
- ResourceSyncInfo service1SyncInfo =
serverSyncInfo.getChildSyncInfos().iterator().next();
+ ResourceSyncInfo topLevelServerSyncInfo =
discoveryBoss.getResourceSyncInfo(secondDiscoverySyncInfo
+ .getTopLevelServers().iterator().next().getId());
+ ResourceSyncInfo service1SyncInfo =
topLevelServerSyncInfo.getChildSyncInfos().iterator().next();
Resource service1Resource = getEntityManager().find(Resource.class,
service1SyncInfo.getId());
assertEquals(userSuppliedResourceName, service1Resource.getName());
}
diff --git
a/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/discovery/DiscoveryBossBean.java
b/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/discovery/DiscoveryBossBean.java
index d7e57bd..71e2e3f 100644
---
a/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/discovery/DiscoveryBossBean.java
+++
b/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/discovery/DiscoveryBossBean.java
@@ -72,6 +72,7 @@ import org.rhq.core.domain.criteria.ResourceCriteria;
import org.rhq.core.domain.criteria.ResourceTypeCriteria;
import org.rhq.core.domain.discovery.MergeInventoryReportResults;
import org.rhq.core.domain.discovery.MergeResourceResponse;
+import org.rhq.core.domain.discovery.PlatformSyncInfo;
import org.rhq.core.domain.discovery.ResourceSyncInfo;
import org.rhq.core.domain.measurement.AvailabilityType;
import org.rhq.core.domain.resource.Agent;
@@ -208,7 +209,7 @@ public class DiscoveryBossBean implements DiscoveryBossLocal,
DiscoveryBossRemot
Set<Resource> roots = report.getAddedRoots();
LOG.debug(report);
- final Map<String, ResourceType> allTypes = new HashMap<String,
ResourceType>();
+ Map<String, ResourceType> allTypes = new HashMap<String,
ResourceType>();
for (Resource root : roots) {
// Make sure all platform, server, and service types are valid. Also, make
sure they're fetched - otherwise
@@ -231,7 +232,7 @@ public class DiscoveryBossBean implements DiscoveryBossLocal,
DiscoveryBossRemot
}
}
- allTypes.clear(); // help GC, we don't need this anymore
+ allTypes = null; // maybe help GC? we don't need this anymore
// Prepare the ResourceSyncInfo tree which contains all the info the PC needs to
sync itself up with us.
// The platform can be null in only one scenario.. a brand new agent has
connected to the server
@@ -239,7 +240,7 @@ public class DiscoveryBossBean implements DiscoveryBossLocal,
DiscoveryBossRemot
// the current inventory on the server side. But at this point there isn't
any since that very
// agent just registered and is starting up for the very first time and therefore
hasn't had
// a chance yet to send us its full inventory report.
- ResourceSyncInfo syncInfo = discoveryBoss.getResourceSyncInfo(knownAgent);
+ PlatformSyncInfo syncInfo = discoveryBoss.getPlatformSyncInfo(knownAgent);
// we need to also tell the agent if there were any ignored types - we must
provide the agent with
// ALL types that are ignored, not just for those resources that were in the
report
@@ -264,13 +265,21 @@ public class DiscoveryBossBean implements DiscoveryBossLocal,
DiscoveryBossRemot
}
@Override
- public ResourceSyncInfo getResourceSyncInfo(Agent knownAgent) {
+ public PlatformSyncInfo getPlatformSyncInfo(Agent knownAgent) {
Resource platform = resourceManager.getPlatform(knownAgent);
if (null == platform) {
return null;
}
- ResourceSyncInfo result = entityManager.find(ResourceSyncInfo.class,
platform.getId());
+ PlatformSyncInfo result = entityManager.find(PlatformSyncInfo.class,
platform.getId());
+ return result;
+ }
+
+ @Override
+ public ResourceSyncInfo getResourceSyncInfo(int resourceId) {
+ // [PERF] this is expensive, it let's hibernate grab the whole hierarchy via
eager fetch of children.
+ ResourceSyncInfo result = entityManager.find(ResourceSyncInfo.class,
resourceId);
+
return result;
}
@@ -1235,7 +1244,8 @@ public class DiscoveryBossBean implements DiscoveryBossLocal,
DiscoveryBossRemot
// Add a product version entry for the new resource.
if ((resource.getVersion() != null) && (resource.getVersion().length()
> 0)) {
- ProductVersion productVersion =
productVersionManager.addProductVersion(resourceType, resource.getVersion());
+ ProductVersion productVersion = productVersionManager
+ .addProductVersion(resourceType, resource.getVersion());
resource.setProductVersion(productVersion);
}
diff --git
a/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/discovery/DiscoveryBossLocal.java
b/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/discovery/DiscoveryBossLocal.java
index a05d2b4..7ed9445 100644
---
a/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/discovery/DiscoveryBossLocal.java
+++
b/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/discovery/DiscoveryBossLocal.java
@@ -37,6 +37,7 @@ import org.rhq.core.domain.auth.Subject;
import org.rhq.core.domain.configuration.Configuration;
import org.rhq.core.domain.discovery.MergeInventoryReportResults;
import org.rhq.core.domain.discovery.MergeResourceResponse;
+import org.rhq.core.domain.discovery.PlatformSyncInfo;
import org.rhq.core.domain.discovery.ResourceSyncInfo;
import org.rhq.core.domain.resource.Agent;
import org.rhq.core.domain.resource.InventoryStatus;
@@ -57,9 +58,9 @@ public interface DiscoveryBossLocal extends DiscoveryBossRemote {
*
* @param report the inventory report to be merged
*
- * @return the server's response, which will include the true IDs for new
resources that were found.
- * This can return null in one specific case - if this is a brand new agent
and it is currently initializing
- * for the very first time.
+ * @return the server's response, which will include the information necessary
for the agent to
+ * start synchronizing its inventory with the server's inventory. This
can return null in one specific
+ * case - if this is a brand new agent and it is currently initializing for
the very first time.
* @throws InvalidInventoryReportException if the inventory report is invalid
*/
MergeInventoryReportResults mergeInventoryReport(InventoryReport report) throws
InvalidInventoryReportException;
@@ -77,10 +78,18 @@ public interface DiscoveryBossLocal extends DiscoveryBossRemote {
throws InvalidInventoryReportException;
/**
+ * Just get the top level server info for the agent's platform. Then, each top
level server
+ * can be individually synced
* @param knownAgent the agent for the platform we want to sync with
* @return null if platform not found
*/
- ResourceSyncInfo getResourceSyncInfo(Agent knownAgent);
+ PlatformSyncInfo getPlatformSyncInfo(Agent knownAgent);
+
+ /**
+ * @param resourceid the root resourceId on which we want to sync
+ * @return null if resource not found, otherwise the entire tree rooted at the
specified resource
+ */
+ ResourceSyncInfo getResourceSyncInfo(int resourceId);
/**
* Returns a map of platforms (the keys) and their servers (the values) that are in
the auto-discovery queue but not
diff --git
a/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/discovery/DiscoveryServerServiceImpl.java
b/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/discovery/DiscoveryServerServiceImpl.java
index d7ff2b3..533948b 100644
---
a/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/discovery/DiscoveryServerServiceImpl.java
+++
b/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/discovery/DiscoveryServerServiceImpl.java
@@ -39,6 +39,7 @@ import org.rhq.core.domain.criteria.ResourceCriteria;
import org.rhq.core.domain.discovery.AvailabilityReport;
import org.rhq.core.domain.discovery.MergeInventoryReportResults;
import org.rhq.core.domain.discovery.MergeResourceResponse;
+import org.rhq.core.domain.discovery.ResourceSyncInfo;
import org.rhq.core.domain.measurement.ResourceMeasurementScheduleRequest;
import org.rhq.core.domain.resource.Agent;
import org.rhq.core.domain.resource.InventoryStatus;
@@ -91,7 +92,7 @@ public class DiscoveryServerServiceImpl implements
DiscoveryServerService {
if (log.isDebugEnabled()) {
log.error("Received invalid inventory report from agent ["
+ agent + "]", e);
} else {
- /*
+ /*
* this is expected when the platform is uninventoried, because the
agent often has in-flight reports
* going to the server at the time the platform's agent is being
deleted from the database
*/
@@ -120,6 +121,26 @@ public class DiscoveryServerServiceImpl implements
DiscoveryServerService {
}
@Override
+ public ResourceSyncInfo getResourceSyncInfo(int resourceId) {
+ long start = System.currentTimeMillis();
+ DiscoveryBossLocal discoveryBoss = LookupUtil.getDiscoveryBoss();
+ ResourceSyncInfo results;
+
+ results = discoveryBoss.getResourceSyncInfo(resourceId);
+
+ long elapsed = (System.currentTimeMillis() - start);
+ if (elapsed > 30000L) {
+ log.warn("Performance: get resource sync info (" + elapsed +
")ms");
+ } else {
+ if (log.isDebugEnabled()) {
+ log.debug("Performance: get resource sync info (" + elapsed +
")ms");
+ }
+ }
+
+ return results;
+ }
+
+ @Override
public boolean mergeAvailabilityReport(AvailabilityReport availabilityReport) {
AvailabilityReportSerializer.getSingleton().lock(availabilityReport.getAgentName());
try {
diff --git
a/modules/integration-tests/apache-plugin-test/src/test/java/org/rhq/plugins/apache/setup/ApacheTestSetup.java
b/modules/integration-tests/apache-plugin-test/src/test/java/org/rhq/plugins/apache/setup/ApacheTestSetup.java
index 908f7d7..f317b3f 100644
---
a/modules/integration-tests/apache-plugin-test/src/test/java/org/rhq/plugins/apache/setup/ApacheTestSetup.java
+++
b/modules/integration-tests/apache-plugin-test/src/test/java/org/rhq/plugins/apache/setup/ApacheTestSetup.java
@@ -45,6 +45,7 @@ import org.rhq.core.domain.resource.ResourceType;
import org.rhq.core.pc.ServerServices;
import org.rhq.core.pc.upgrade.FakeServerInventory;
import org.rhq.core.system.SystemInfoFactory;
+import org.rhq.core.util.TokenReplacingReader;
import org.rhq.core.util.file.FileUtil;
import org.rhq.plugins.apache.ApacheServerComponent;
import org.rhq.plugins.apache.ApacheServerDiscoveryComponent;
@@ -60,7 +61,6 @@ import org.rhq.plugins.apache.util.HttpdAddressUtility;
import org.rhq.plugins.apache.util.ResourceTypes;
import org.rhq.plugins.apache.util.VHostSpec;
import org.rhq.test.ObjectCollectionSerializer;
-import org.rhq.core.util.TokenReplacingReader;
import org.rhq.test.pc.PluginContainerTest;
public class ApacheTestSetup {
@@ -247,7 +247,7 @@ public class ApacheTestSetup {
public ApacheTestSetup withDefaultExpectations() throws Exception {
context.checking(new Expectations() {
{
- addDefaultExceptations(this);
+ addDefaultExpectations(this);
}
});
@@ -255,7 +255,7 @@ public class ApacheTestSetup {
}
@SuppressWarnings("unchecked")
- public void addDefaultExceptations(Expectations expectations) throws Exception {
+ public void addDefaultExpectations(Expectations expectations) throws Exception {
ServerServices ss =
PluginContainerTest.getCurrentPluginContainerConfiguration().getServerServices();
//only import the apache servers we actually care about - we can't assume
another apache won't be present
@@ -276,6 +276,10 @@ public class ApacheTestSetup {
}
}));
+ expectations.allowing(ss.getDiscoveryServerService()).getResourceSyncInfo(
+ expectations.with(Expectations.any(Integer.class)));
+ expectations.will(fakeInventory.getResourceSyncInfo());
+
expectations.allowing(ss.getDiscoveryServerService()).upgradeResources(
expectations.with(Expectations.any(Set.class)));
expectations.will(fakeInventory.upgradeResources());