You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@brooklyn.apache.org by al...@apache.org on 2016/07/20 17:20:10 UTC
[03/11] brooklyn-server git commit: Cleaner for the old dangling
references
Cleaner for the old dangling references
Project: http://git-wip-us.apache.org/repos/asf/brooklyn-server/repo
Commit: http://git-wip-us.apache.org/repos/asf/brooklyn-server/commit/59f8e8b4
Tree: http://git-wip-us.apache.org/repos/asf/brooklyn-server/tree/59f8e8b4
Diff: http://git-wip-us.apache.org/repos/asf/brooklyn-server/diff/59f8e8b4
Branch: refs/heads/master
Commit: 59f8e8b44c0399ef270da8b53d4b3e6851069cf4
Parents: c7c8db5
Author: Ivana Yovcheva <iv...@gmail.com>
Authored: Wed Jun 15 19:22:43 2016 +0300
Committer: Ivana Yovcheva <iv...@gmail.com>
Committed: Tue Jul 19 18:30:15 2016 +0300
----------------------------------------------------------------------
.../DeleteOrphanedLocationsTransformer.java | 147 ++++++++++-
.../brooklyn/launcher/common/BasicLauncher.java | 7 +-
.../CleanOrphanedLocationsLiveTest.java | 257 +++++++++++++++++++
.../main/java/org/apache/brooklyn/cli/Main.java | 77 ++++++
4 files changed, 475 insertions(+), 13 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/59f8e8b4/core/src/main/java/org/apache/brooklyn/core/mgmt/rebind/transformer/impl/DeleteOrphanedLocationsTransformer.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/core/mgmt/rebind/transformer/impl/DeleteOrphanedLocationsTransformer.java b/core/src/main/java/org/apache/brooklyn/core/mgmt/rebind/transformer/impl/DeleteOrphanedLocationsTransformer.java
index 985ce37..1c9cd9e 100644
--- a/core/src/main/java/org/apache/brooklyn/core/mgmt/rebind/transformer/impl/DeleteOrphanedLocationsTransformer.java
+++ b/core/src/main/java/org/apache/brooklyn/core/mgmt/rebind/transformer/impl/DeleteOrphanedLocationsTransformer.java
@@ -20,13 +20,17 @@ package org.apache.brooklyn.core.mgmt.rebind.transformer.impl;
import java.util.Collection;
import java.util.List;
+import java.util.Map;
import java.util.Set;
+import com.sun.org.apache.xml.internal.dtm.ref.DTMNodeList;
import org.apache.brooklyn.api.mgmt.rebind.mementos.BrooklynMemento;
+import org.apache.brooklyn.api.mgmt.rebind.mementos.BrooklynMementoRawData;
import org.apache.brooklyn.api.mgmt.rebind.mementos.EntityMemento;
import org.apache.brooklyn.api.mgmt.rebind.mementos.LocationMemento;
import org.apache.brooklyn.core.mgmt.rebind.dto.BrooklynMementoImpl;
import org.apache.brooklyn.core.mgmt.rebind.transformer.BrooklynMementoTransformer;
+import org.apache.brooklyn.core.mgmt.rebind.transformer.CompoundTransformer;
import org.apache.brooklyn.util.collections.MutableList;
import org.apache.brooklyn.util.collections.MutableMap;
import org.apache.brooklyn.util.collections.MutableSet;
@@ -34,17 +38,49 @@ import org.apache.brooklyn.util.collections.MutableSet;
import com.google.common.annotations.Beta;
import com.google.common.collect.Lists;
import com.google.common.collect.Sets;
+import org.apache.brooklyn.util.core.xstream.XmlUtil;
+import org.w3c.dom.Node;
+
+import javax.xml.xpath.XPathConstants;
@Beta
-public class DeleteOrphanedLocationsTransformer implements BrooklynMementoTransformer {
+public class DeleteOrphanedLocationsTransformer extends CompoundTransformer implements BrooklynMementoTransformer {
+
+ protected DeleteOrphanedLocationsTransformer(DeleteOrphanedLocationsTransformer.Builder builder) {
+ super(builder);
+ }
+
+ public static Builder builder() {
+ return new DeleteOrphanedLocationsTransformer.Builder();
+ }
+
+ public static class Builder extends CompoundTransformer.Builder {
+
+ public DeleteOrphanedLocationsTransformer build() {
+ return new DeleteOrphanedLocationsTransformer(this);
+ }
+ }
+
+ public BrooklynMementoRawData transform(BrooklynMementoRawData input) {
+ Map<String, String> locationsToKeep = findLocationsToKeep(input);
+
+ return BrooklynMementoRawData.builder()
+ .catalogItems(input.getCatalogItems())
+ .enrichers(input.getEnrichers())
+ .entities(input.getEntities())
+ .feeds(input.getFeeds())
+ .locations(locationsToKeep)
+ .policies(input.getPolicies())
+ .build();
+ }
// TODO Work in progress; untested code!
-
+
public BrooklynMemento transform(BrooklynMemento input) throws Exception {
Set<String> referencedLocationIds = findReferencedLocationIds(input);
Set<String> unreferencedLocationIds = Sets.newLinkedHashSet();
List<String> toCheck = Lists.newLinkedList(input.getLocationIds());
-
+
while (!toCheck.isEmpty()) {
String locationId = toCheck.remove(0);
List<String> locationsInHierarchy = MutableList.<String>builder()
@@ -52,7 +88,7 @@ public class DeleteOrphanedLocationsTransformer implements BrooklynMementoTransf
.addAll(findLocationAncestors(input, locationId))
.addAll(findLocationDescendents(input, locationId))
.build();
-
+
if (containsAny(referencedLocationIds, locationsInHierarchy)) {
// keep them all
} else {
@@ -60,7 +96,7 @@ public class DeleteOrphanedLocationsTransformer implements BrooklynMementoTransf
}
toCheck.removeAll(locationsInHierarchy);
}
-
+
// TODO What about brooklyn version?
return BrooklynMementoImpl.builder()
.applicationIds(input.getApplicationIds())
@@ -78,26 +114,113 @@ public class DeleteOrphanedLocationsTransformer implements BrooklynMementoTransf
.catalogItems(input.getCatalogItemMementos())
.build();
}
-
+
public boolean containsAny(Collection<?> container, Iterable<?> contenders) {
for (Object contender : contenders) {
if (container.contains(contender)) return true;
}
return false;
}
-
+
public Set<String> findReferencedLocationIds(BrooklynMemento input) {
Set<String> result = Sets.newLinkedHashSet();
-
+
for (EntityMemento entity : input.getEntityMementos().values()) {
result.addAll(entity.getLocations());
}
return result;
}
-
+
+ public Map<String, String> findLocationsToKeep(BrooklynMementoRawData input) {
+ Map<String, String> locationsToKeep = MutableMap.of();
+ Set<String> allReferencedLocations = findAllReferencedLocations(input);
+
+ for (Map.Entry location: input.getLocations().entrySet()) {
+ if (allReferencedLocations.contains(location.getKey())) {
+ locationsToKeep.put((String) location.getKey(), (String) location.getValue());
+ }
+ }
+ return locationsToKeep;
+ }
+
+ public Set<String> findAllReferencedLocations(BrooklynMementoRawData input) {
+ Set<String> allReferencedLocations = MutableSet.of();
+
+ allReferencedLocations.addAll(searchLocationsToKeepInEntities(input.getEntities()));
+ allReferencedLocations.addAll(searchLocationsToKeepInPolicies(input.getPolicies()));
+ allReferencedLocations.addAll(searchLocationsToKeepInEnrichers(input.getEnrichers()));
+ allReferencedLocations.addAll(searchLocationsToKeepInLocations(input.getLocations(), allReferencedLocations));
+
+ return allReferencedLocations;
+ }
+
+ private Set<String> searchLocationsToKeepInEntities(Map<String, String> entities) {
+ Set<String> result = MutableSet.of();
+
+ for(Map.Entry entity: entities.entrySet()) {
+
+ String prefix = "/entity";
+ String location = "/locations/string";
+ String locationProxy = "/attributes/softwareservice.provisioningLocation/locationProxy";
+
+ result.addAll(getAllNodesFromXpath((DTMNodeList) XmlUtil.xpath((String) entity.getValue(), prefix+location, XPathConstants.NODESET)));
+ result.addAll(getAllNodesFromXpath((DTMNodeList) XmlUtil.xpath((String) entity.getValue(), prefix+locationProxy, XPathConstants.NODESET)));
+ }
+
+ return result;
+ }
+
+ private Set<String> searchLocationsToKeepInLocations(Map<String, String> locations, Set<String> alreadyReferencedLocations) {
+ Set<String> result = MutableSet.of();
+
+ String prefix = "/location";
+ String locationId = "/id";
+ String locationChildren = "/children/string";
+ String locationParentDirectTag = "/parent";
+ String locationParent = "/locationConfig/jcloudsParent/locationProxy";
+ String locationProxy = "/locationConfig/vmInstanceIds/map/entry/locationProxy";
+
+ for (Map.Entry location: locations.entrySet()) {
+ if (alreadyReferencedLocations.contains(location)) {
+ result.addAll(getAllNodesFromXpath((DTMNodeList) XmlUtil.xpath((String) location.getValue(), prefix+locationId, XPathConstants.NODESET)));
+ result.addAll(getAllNodesFromXpath((DTMNodeList) XmlUtil.xpath((String) location.getValue(), prefix+locationChildren, XPathConstants.NODESET)));
+ result.addAll(getAllNodesFromXpath((DTMNodeList) XmlUtil.xpath((String) location.getValue(), prefix+locationParent, XPathConstants.NODESET)));
+ result.addAll(getAllNodesFromXpath((DTMNodeList) XmlUtil.xpath((String) location.getValue(), prefix+locationParentDirectTag, XPathConstants.NODESET)));
+ result.addAll(getAllNodesFromXpath((DTMNodeList) XmlUtil.xpath((String) location.getValue(), prefix+locationProxy, XPathConstants.NODESET)));
+ }
+ }
+
+ return result;
+ }
+
+ private Set<String> searchLocationsToKeepInPolicies(Map<String, String> policies) {
+ Set<String> result = MutableSet.of();
+
+ return result;
+ }
+
+ private Set<String> searchLocationsToKeepInEnrichers(Map<String, String> enrichers) {
+ Set<String> result = MutableSet.of();
+
+ return result;
+ }
+
+ private Set<String> getAllNodesFromXpath(DTMNodeList nodeList) {
+ Set<String> result = MutableSet.of();
+
+ int i = 0;
+ Node nextNode = nodeList.item(i);
+ while (nextNode != null) {
+ result.add(nextNode.getTextContent());
+ nextNode = nodeList.item(++i);
+ }
+
+ return result;
+ }
+
public Set<String> findLocationAncestors(BrooklynMemento input, String locationId) {
Set<String> result = Sets.newLinkedHashSet();
-
+
String parentId = null;
do {
LocationMemento memento = input.getLocationMemento(locationId);
@@ -107,11 +230,11 @@ public class DeleteOrphanedLocationsTransformer implements BrooklynMementoTransf
return result;
}
-
+
public Set<String> findLocationDescendents(BrooklynMemento input, String locationId) {
Set<String> result = Sets.newLinkedHashSet();
List<String> tovisit = Lists.newLinkedList();
-
+
tovisit.add(locationId);
while (!tovisit.isEmpty()) {
LocationMemento memento = input.getLocationMemento(tovisit.remove(0));
http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/59f8e8b4/launcher-common/src/main/java/org/apache/brooklyn/launcher/common/BasicLauncher.java
----------------------------------------------------------------------
diff --git a/launcher-common/src/main/java/org/apache/brooklyn/launcher/common/BasicLauncher.java b/launcher-common/src/main/java/org/apache/brooklyn/launcher/common/BasicLauncher.java
index b550a5b..3c74549 100644
--- a/launcher-common/src/main/java/org/apache/brooklyn/launcher/common/BasicLauncher.java
+++ b/launcher-common/src/main/java/org/apache/brooklyn/launcher/common/BasicLauncher.java
@@ -45,6 +45,7 @@ import org.apache.brooklyn.config.ConfigKey;
import org.apache.brooklyn.core.catalog.internal.CatalogInitialization;
import org.apache.brooklyn.core.entity.Entities;
import org.apache.brooklyn.core.entity.StartableApplication;
+import org.apache.brooklyn.core.entity.factory.ApplicationBuilder;
import org.apache.brooklyn.core.entity.trait.Startable;
import org.apache.brooklyn.core.internal.BrooklynProperties;
import org.apache.brooklyn.core.mgmt.EntityManagementUtils;
@@ -60,6 +61,7 @@ import org.apache.brooklyn.core.mgmt.persist.PersistenceObjectStore;
import org.apache.brooklyn.core.mgmt.rebind.PersistenceExceptionHandlerImpl;
import org.apache.brooklyn.core.mgmt.rebind.RebindManagerImpl;
import org.apache.brooklyn.core.mgmt.rebind.transformer.CompoundTransformer;
+import org.apache.brooklyn.core.mgmt.rebind.transformer.impl.DeleteOrphanedLocationsTransformer;
import org.apache.brooklyn.core.server.BrooklynServerConfig;
import org.apache.brooklyn.core.server.BrooklynServerPaths;
import org.apache.brooklyn.entity.brooklynnode.BrooklynNode;
@@ -373,7 +375,6 @@ public class BasicLauncher<T extends BasicLauncher<T>> {
managementContext, destinationLocationSpec, destinationDir);
BrooklynPersistenceUtils.writeMemento(managementContext, memento, destinationObjectStore);
BrooklynPersistenceUtils.writeManagerMemento(managementContext, planeState, destinationObjectStore);
-
} catch (Exception e) {
Exceptions.propagateIfFatal(e);
LOG.debug("Error copying persisted state (rethrowing): " + e, e);
@@ -382,6 +383,10 @@ public class BasicLauncher<T extends BasicLauncher<T>> {
}
}
+ public void cleanOrphanedLocations(String destinationDir, @Nullable String destinationLocationSpec) {
+ copyPersistedState(destinationDir, destinationLocationSpec, DeleteOrphanedLocationsTransformer.builder().build());
+ }
+
/** @deprecated since 0.7.0 use {@link #copyPersistedState} instead */
// Make private after deprecation
@Deprecated
http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/59f8e8b4/launcher/src/test/java/org/apache/brooklyn/launcher/CleanOrphanedLocationsLiveTest.java
----------------------------------------------------------------------
diff --git a/launcher/src/test/java/org/apache/brooklyn/launcher/CleanOrphanedLocationsLiveTest.java b/launcher/src/test/java/org/apache/brooklyn/launcher/CleanOrphanedLocationsLiveTest.java
new file mode 100644
index 0000000..cda7cc0
--- /dev/null
+++ b/launcher/src/test/java/org/apache/brooklyn/launcher/CleanOrphanedLocationsLiveTest.java
@@ -0,0 +1,257 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.brooklyn.launcher;
+
+import org.apache.brooklyn.api.mgmt.ManagementContext;
+import org.apache.brooklyn.api.mgmt.ha.HighAvailabilityMode;
+import org.apache.brooklyn.api.mgmt.rebind.PersistenceExceptionHandler;
+import org.apache.brooklyn.api.mgmt.rebind.RebindManager;
+import org.apache.brooklyn.api.mgmt.rebind.mementos.BrooklynMementoRawData;
+import org.apache.brooklyn.core.mgmt.ha.OsgiManager;
+import org.apache.brooklyn.core.mgmt.internal.LocalManagementContext;
+import org.apache.brooklyn.core.mgmt.internal.ManagementContextInternal;
+import org.apache.brooklyn.core.mgmt.persist.BrooklynMementoPersisterToObjectStore;
+import org.apache.brooklyn.core.mgmt.persist.BrooklynPersistenceUtils;
+import org.apache.brooklyn.core.mgmt.persist.PersistMode;
+import org.apache.brooklyn.core.mgmt.persist.PersistenceObjectStore;
+import org.apache.brooklyn.core.mgmt.rebind.PersistenceExceptionHandlerImpl;
+import org.apache.brooklyn.core.mgmt.rebind.RebindManagerImpl;
+import org.apache.brooklyn.core.mgmt.rebind.transformer.impl.DeleteOrphanedLocationsTransformer;
+import org.apache.brooklyn.core.server.BrooklynServerConfig;
+import org.apache.brooklyn.core.server.BrooklynServerPaths;
+import org.apache.brooklyn.test.Asserts;
+import org.apache.brooklyn.util.collections.MutableMap;
+import org.apache.brooklyn.util.collections.MutableSet;
+import org.apache.brooklyn.util.time.Duration;
+import org.apache.commons.lang.builder.EqualsBuilder;
+import org.testng.annotations.AfterMethod;
+import org.testng.annotations.BeforeMethod;
+import org.testng.annotations.Test;
+
+import org.apache.brooklyn.core.internal.BrooklynProperties;
+
+import java.util.Map;
+import java.util.Set;
+
+public class CleanOrphanedLocationsLiveTest {
+
+ private String PERSISTED_STATE_PATH_WITH_ORPHANED_LOCATIONS = "/orphaned-locations-test-data/data-with-orphaned-locations";
+ private String PERSISTED_STATE_PATH_WITH_MULTIPLE_LOCATIONS_OCCURRENCE = "/orphaned-locations-test-data/fake-multiple-location-for-multiple-search-tests";
+ private String PERSISTED_STATE_PATH_WITHOUT_ORPHANED_LOCATIONS = "/orphaned-locations-test-data/data-without-orphaned-locations";
+ private String PERSISTED_STATE_DESTINATION_PATH = "/orphaned-locations-test-data/copy-persisted-state-destination";
+
+
+ private String persistenceDirWithOrphanedLocations;
+ private String persistenceDirWithoutOrphanedLocations;
+ private String persistenceDirWithMultipleLocationsOccurrence;
+ private String destinationDir;
+ private String destinationLocation;
+ private String localBrooklynProperties;
+ private String persistenceLocation;
+ private String highAvailabilityMode;
+
+ private DeleteOrphanedLocationsTransformer transformer;
+
+ private ManagementContext managementContext;
+
+ @BeforeMethod(alwaysRun = true)
+ public void initialize() throws Exception {
+ persistenceDirWithOrphanedLocations = getClass().getResource(PERSISTED_STATE_PATH_WITH_ORPHANED_LOCATIONS).getFile();
+ persistenceDirWithoutOrphanedLocations = getClass().getResource(PERSISTED_STATE_PATH_WITHOUT_ORPHANED_LOCATIONS).getFile();
+ persistenceDirWithMultipleLocationsOccurrence = getClass().getResource(PERSISTED_STATE_PATH_WITH_MULTIPLE_LOCATIONS_OCCURRENCE).getFile();
+
+ destinationDir = getClass().getResource(PERSISTED_STATE_DESTINATION_PATH).getFile();
+
+ transformer = DeleteOrphanedLocationsTransformer.builder().build();
+ }
+
+ private void initManagementContextAndPersistence(String persistenceDir) {
+
+ BrooklynProperties brooklynProperties = BrooklynProperties.Factory.builderDefault().build();
+ brooklynProperties.put(BrooklynServerConfig.MGMT_BASE_DIR.getName(), "");
+
+ managementContext = new LocalManagementContext(brooklynProperties);
+
+ if (persistenceLocation == null) {
+ persistenceLocation = brooklynProperties.getConfig(BrooklynServerConfig.PERSISTENCE_LOCATION_SPEC);
+ }
+
+ persistenceDir = BrooklynServerPaths.newMainPersistencePathResolver(brooklynProperties).location(persistenceLocation).dir(persistenceDir).resolve();
+ PersistenceObjectStore objectStore = BrooklynPersistenceUtils.newPersistenceObjectStore(managementContext, persistenceLocation, persistenceDir,
+ PersistMode.AUTO, HighAvailabilityMode.HOT_STANDBY);
+
+ BrooklynMementoPersisterToObjectStore persister = new BrooklynMementoPersisterToObjectStore(
+ objectStore,
+ ((ManagementContextInternal)managementContext).getBrooklynProperties(),
+ managementContext.getCatalogClassLoader());
+
+ RebindManager rebindManager = managementContext.getRebindManager();
+
+ PersistenceExceptionHandler persistenceExceptionHandler = PersistenceExceptionHandlerImpl.builder().build();
+ ((RebindManagerImpl) rebindManager).setPeriodicPersistPeriod(Duration.ONE_SECOND);
+ rebindManager.setPersister(persister, persistenceExceptionHandler);
+ }
+
+ @Test
+ public void testSelectionWithOrphanedLocationsInData() {
+
+ Set<String> locationsToKeep = MutableSet.of(
+ "tjdywoxbji",
+ "pudtixbw89"
+ );
+
+ Set<String> orphanedLocations = MutableSet.of(
+ "banby1jx4j",
+ "msyp655po0",
+ "ppamsemxgo"
+ );
+
+ initManagementContextAndPersistence(persistenceDirWithOrphanedLocations);
+ BrooklynMementoRawData mementoRawData = managementContext.getRebindManager().retrieveMementoRawData();
+
+ Set<String> allReferencedLocationsFoundByTransformer = transformer.findAllReferencedLocations(mementoRawData);
+ Map<String, String> locationsToKeepFoundByTransformer = transformer.findLocationsToKeep(mementoRawData);
+
+ Asserts.assertEquals(allReferencedLocationsFoundByTransformer, locationsToKeep);
+ Asserts.assertEquals(locationsToKeepFoundByTransformer.keySet(), locationsToKeep);
+
+ Map<String, String> locationsNotToKeepDueToTransormer = MutableMap.of();
+ locationsNotToKeepDueToTransormer.putAll(mementoRawData.getLocations());
+ for (Map.Entry location: locationsToKeepFoundByTransformer.entrySet()) {
+ locationsNotToKeepDueToTransormer.remove(location.getKey());
+ }
+ Set<String> notReferencedLocationsDueToTransormer = MutableSet.of();
+ notReferencedLocationsDueToTransormer.addAll(mementoRawData.getLocations().keySet());
+ for (String location: allReferencedLocationsFoundByTransformer) {
+ notReferencedLocationsDueToTransormer.remove(location);
+ }
+
+ Asserts.assertEquals(notReferencedLocationsDueToTransormer, orphanedLocations);
+ Asserts.assertEquals(locationsNotToKeepDueToTransormer.keySet(), orphanedLocations);
+
+
+ BrooklynMementoRawData transformedMemento = transformer.transform(mementoRawData);
+ Asserts.assertFalse(EqualsBuilder.reflectionEquals(mementoRawData, transformedMemento));
+ Asserts.assertTrue(EqualsBuilder.reflectionEquals(mementoRawData.getEntities(), transformedMemento.getEntities()));
+ Asserts.assertTrue(EqualsBuilder.reflectionEquals(mementoRawData.getEnrichers(), transformedMemento.getEnrichers()));
+ Asserts.assertTrue(EqualsBuilder.reflectionEquals(mementoRawData.getPolicies(), transformedMemento.getPolicies()));
+ Asserts.assertFalse(EqualsBuilder.reflectionEquals(mementoRawData.getLocations(), transformedMemento.getLocations()));
+ }
+
+ @Test
+ public void testSelectionWithoutOrphanedLocationsInData() {
+
+ Set<String> locationsToKeep = MutableSet.of(
+ "tjdywoxbji",
+ "pudtixbw89"
+ );
+
+ initManagementContextAndPersistence(persistenceDirWithoutOrphanedLocations);
+ BrooklynMementoRawData mementoRawData = managementContext.getRebindManager().retrieveMementoRawData();
+
+ Set<String> allReferencedLocationsFoundByTransformer = transformer.findAllReferencedLocations(mementoRawData);
+ Map<String, String> locationsToKeepFoundByTransformer = transformer.findLocationsToKeep(mementoRawData);
+
+ Asserts.assertEquals(allReferencedLocationsFoundByTransformer, locationsToKeep);
+ Asserts.assertEquals(locationsToKeepFoundByTransformer.keySet(), locationsToKeep);
+
+ Map<String, String> locationsNotToKeepDueToTransormer = MutableMap.of();
+ locationsNotToKeepDueToTransormer.putAll(mementoRawData.getLocations());
+ for (Map.Entry location: locationsToKeepFoundByTransformer.entrySet()) {
+ locationsNotToKeepDueToTransormer.remove(location.getKey());
+ }
+ Set<String> notReferencedLocationsDueToTransormer = MutableSet.of();
+ notReferencedLocationsDueToTransormer.addAll(mementoRawData.getLocations().keySet());
+ for (String location: allReferencedLocationsFoundByTransformer) {
+ notReferencedLocationsDueToTransormer.remove(location);
+ }
+
+ Asserts.assertSize(locationsNotToKeepDueToTransormer.keySet(), 0);
+ Asserts.assertSize(notReferencedLocationsDueToTransormer, 0);
+
+ BrooklynMementoRawData transformedMemento = transformer.transform(mementoRawData);
+ Asserts.assertTrue(EqualsBuilder.reflectionEquals(mementoRawData, transformedMemento));
+ }
+
+ @Test
+ public void testCleanedCopiedPersistedState() throws Exception {
+
+ BrooklynLauncher launcher = BrooklynLauncher.newInstance()
+ .localBrooklynPropertiesFile(localBrooklynProperties)
+ .brooklynProperties(OsgiManager.USE_OSGI, false)
+ .persistMode(PersistMode.AUTO)
+ .persistenceDir(persistenceDirWithOrphanedLocations)
+ .persistenceLocation(persistenceLocation)
+ .highAvailabilityMode(HighAvailabilityMode.DISABLED);
+
+ try {
+ launcher.cleanOrphanedLocations(destinationDir, destinationLocation);
+
+ } catch (Exception e) {
+ throw new Exception(e);
+ } finally {
+ launcher.terminate();
+ }
+
+ initManagementContextAndPersistence(destinationDir);
+ BrooklynMementoRawData mementoRawDataFromCleanedState = managementContext.getRebindManager().retrieveMementoRawData();
+ Asserts.assertTrue(mementoRawDataFromCleanedState.getEntities().size() != 0);
+ Asserts.assertTrue(mementoRawDataFromCleanedState.getLocations().size() != 0);
+
+
+ initManagementContextAndPersistence(persistenceDirWithoutOrphanedLocations);
+ BrooklynMementoRawData mementoRawData = managementContext.getRebindManager().retrieveMementoRawData();
+
+ Asserts.assertTrue(EqualsBuilder.reflectionEquals(mementoRawData, mementoRawDataFromCleanedState));
+ }
+
+ @Test
+ public void testMultipleLocationOccurrenceInEntity() {
+ Set<String> allReferencedLocations = MutableSet.of(
+ "m72nvkl799",
+ "m72nTYl799",
+ "m72LKVN799",
+ "jf4rwubqyb",
+ "jf4rwuTTTb",
+ "jf4rwuHHHb",
+ "m72nvkl799",
+ "m72nPTUF99",
+ "m72nhtDr99"
+ );
+
+ Set<String> locationsToKeep = MutableSet.of(
+ "m72nvkl799",
+ "jf4rwubqyb"
+ );
+
+ initManagementContextAndPersistence(persistenceDirWithMultipleLocationsOccurrence);
+
+ BrooklynMementoRawData mementoRawData = managementContext.getRebindManager().retrieveMementoRawData();
+ Set<String> allReferencedLocationsFoundByTransformer = transformer.findAllReferencedLocations(mementoRawData);
+ Map<String, String> locationsToKeepFoundByTransformer = transformer.findLocationsToKeep(mementoRawData);
+
+ Asserts.assertEquals(allReferencedLocationsFoundByTransformer, allReferencedLocations);
+ Asserts.assertEquals(locationsToKeepFoundByTransformer.keySet(), locationsToKeep);
+ }
+
+ @AfterMethod
+ public void cleanCopiedPersistedState() {
+
+ }
+}
http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/59f8e8b4/server-cli/src/main/java/org/apache/brooklyn/cli/Main.java
----------------------------------------------------------------------
diff --git a/server-cli/src/main/java/org/apache/brooklyn/cli/Main.java b/server-cli/src/main/java/org/apache/brooklyn/cli/Main.java
index 2d65ad0..53a7829 100644
--- a/server-cli/src/main/java/org/apache/brooklyn/cli/Main.java
+++ b/server-cli/src/main/java/org/apache/brooklyn/cli/Main.java
@@ -827,6 +827,82 @@ public class Main extends AbstractMain {
}
}
+ @Command(name = "clean-orphaned-locations", description = "Removes existing orphaned locations")
+ public static class CleanOrphanedLocationsCommand extends BrooklynCommandCollectingArgs {
+
+ @Option(name = { "--localBrooklynProperties" }, title = "local brooklyn.properties file",
+ description = "local brooklyn.properties file, specific to this launch (appending to and overriding global properties)")
+ public String localBrooklynProperties;
+
+ @Option(name = { "--persistenceDir" }, title = "persistence dir",
+ description = "The directory to read persisted state (or container name if using an object store)")
+ public String persistenceDir;
+
+ @Option(name = { "--persistenceLocation" }, title = "persistence location",
+ description = "The location spec for an object store to read persisted state")
+ public String persistenceLocation;
+
+ @Option(name = { "--destinationDir" }, required = true, title = "destination dir",
+ description = "The directory to copy persistence data to without orphaned locations")
+ public String destinationDir;
+
+ @Option(name = { "--destinationLocation" }, title = "persistence location",
+ description = "The location spec for an object store to copy data to")
+ public String destinationLocation;
+
+ @Option(name = { "--transformations" }, title = "transformations",
+ description = "local transformations file, to be applied to the copy of the data before uploading it")
+ public String transformations;
+
+ @Override
+ public Void call() throws Exception {
+ checkNotNull(destinationDir, "orphanedReferencesTmpDir");
+
+ BrooklynLauncher launcher;
+ failIfArguments();
+
+ try {
+ log.info("Retrieving and copying persisted state to " + destinationDir + " without orphaned locations");
+
+
+ PersistMode persistMode = PersistMode.AUTO;
+ HighAvailabilityMode highAvailabilityMode = HighAvailabilityMode.DISABLED;
+
+ launcher = BrooklynLauncher.newInstance()
+ .localBrooklynPropertiesFile(localBrooklynProperties)
+ .brooklynProperties(OsgiManager.USE_OSGI, false)
+ .persistMode(persistMode)
+ .persistenceDir(persistenceDir)
+ .persistenceLocation(persistenceLocation)
+ .highAvailabilityMode(highAvailabilityMode);
+
+ } catch (FatalConfigurationRuntimeException e) {
+ throw e;
+ } catch (Exception e) {
+ throw new FatalConfigurationRuntimeException("Fatal error configuring Brooklyn launch: "+e.getMessage(), e);
+ }
+
+ try {
+ launcher.cleanOrphanedLocations(destinationDir, destinationLocation);
+ } catch (FatalRuntimeException e) {
+ throw e;
+ } catch (Exception e) {
+ Exceptions.propagateIfFatal(e);
+ log.error("Error retrieving persisted state: "+Exceptions.collapseText(e), e);
+ Exceptions.propagate(e);
+ } finally {
+ try {
+ launcher.terminate();
+ } catch (Exception e2) {
+ log.warn("Subsequent error during termination: "+e2);
+ log.debug("Details of subsequent error during termination: "+e2, e2);
+ }
+ }
+
+ return null;
+ }
+ }
+
@Command(name = "copy-state", description = "Retrieves persisted state")
public static class CopyStateCommand extends BrooklynCommandCollectingArgs {
@@ -931,6 +1007,7 @@ public class Main extends AbstractMain {
HelpCommand.class,
cliInfoCommand(),
GeneratePasswordCommand.class,
+ CleanOrphanedLocationsCommand.class,
CopyStateCommand.class,
ListAllCommand.class,
cliLaunchCommand()