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:16 UTC
[09/11] brooklyn-server git commit: deleting orphaned state: many
fixes/tidies
deleting orphaned state: many fixes/tidies
Now supports deleting enrichers/policies/feeds that have become
orphaned.
Project: http://git-wip-us.apache.org/repos/asf/brooklyn-server/repo
Commit: http://git-wip-us.apache.org/repos/asf/brooklyn-server/commit/660956f7
Tree: http://git-wip-us.apache.org/repos/asf/brooklyn-server/tree/660956f7
Diff: http://git-wip-us.apache.org/repos/asf/brooklyn-server/diff/660956f7
Branch: refs/heads/master
Commit: 660956f72a860b38db9c81db4cdffde38b3615b2
Parents: 4d0c4b8
Author: Aled Sage <al...@gmail.com>
Authored: Wed Jul 20 09:16:14 2016 +0100
Committer: Ivana Yovcheva <iv...@gmail.com>
Committed: Wed Jul 20 12:18:49 2016 +0300
----------------------------------------------------------------------
.../rebind/mementos/BrooklynMementoRawData.java | 13 ++
.../DeleteOrphanedLocationsTransformer.java | 192 ------------------
.../impl/DeleteOrphanedStateTransformer.java | 203 +++++++++++++++++++
.../brooklyn/launcher/common/BasicLauncher.java | 4 +-
...stractBrooklynLauncherRebindTestFixture.java | 155 ++++++++++++++
.../AbstractCleanOrphanedStateTest.java | 179 ++++++++++++++++
.../BrooklynLauncherCleanStateTest.java | 112 ++++++++++
.../BrooklynLauncherRebindTestFixture.java | 114 +----------
.../launcher/CleanOrphanedAdjunctsTest.java | 76 +++++++
.../launcher/CleanOrphanedLocationsTest.java | 140 ++++---------
.../copy-persisted-state-destination/dummy.txt | 0
11 files changed, 781 insertions(+), 407 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/660956f7/api/src/main/java/org/apache/brooklyn/api/mgmt/rebind/mementos/BrooklynMementoRawData.java
----------------------------------------------------------------------
diff --git a/api/src/main/java/org/apache/brooklyn/api/mgmt/rebind/mementos/BrooklynMementoRawData.java b/api/src/main/java/org/apache/brooklyn/api/mgmt/rebind/mementos/BrooklynMementoRawData.java
index 804304d..f2ec4a9 100644
--- a/api/src/main/java/org/apache/brooklyn/api/mgmt/rebind/mementos/BrooklynMementoRawData.java
+++ b/api/src/main/java/org/apache/brooklyn/api/mgmt/rebind/mementos/BrooklynMementoRawData.java
@@ -21,6 +21,8 @@ package org.apache.brooklyn.api.mgmt.rebind.mementos;
import java.util.Collections;
import java.util.Map;
+import javax.annotation.Nullable;
+
import org.apache.brooklyn.api.objs.BrooklynObjectType;
import com.google.common.annotations.Beta;
@@ -120,6 +122,7 @@ public class BrooklynMementoRawData {
}
}
+ private final String brooklynVersion;
private final Map<String, String> entities;
private final Map<String, String> locations;
private final Map<String, String> policies;
@@ -128,6 +131,7 @@ public class BrooklynMementoRawData {
private final Map<String, String> catalogItems;
private BrooklynMementoRawData(Builder builder) {
+ brooklynVersion = builder.brooklynVersion;
entities = builder.entities;
locations = builder.locations;
policies = builder.policies;
@@ -136,6 +140,15 @@ public class BrooklynMementoRawData {
catalogItems = builder.catalogItems;
}
+ /**
+ * Setting the brooklyn version explicitly is optional.
+ */
+ @Beta
+ @Nullable
+ public String getBrooklynVersion() {
+ return brooklynVersion;
+ }
+
public Map<String, String> getEntities() {
return Collections.unmodifiableMap(entities);
}
http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/660956f7/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
deleted file mode 100644
index a26d807..0000000
--- a/core/src/main/java/org/apache/brooklyn/core/mgmt/rebind/transformer/impl/DeleteOrphanedLocationsTransformer.java
+++ /dev/null
@@ -1,192 +0,0 @@
-/*
- * 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.core.mgmt.rebind.transformer.impl;
-
-import java.util.List;
-import java.util.Map;
-import java.util.Set;
-
-import javax.xml.xpath.XPathConstants;
-
-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.transformer.BrooklynMementoTransformer;
-import org.apache.brooklyn.core.mgmt.rebind.transformer.CompoundTransformer;
-import org.apache.brooklyn.util.collections.MutableMap;
-import org.apache.brooklyn.util.collections.MutableSet;
-import org.apache.brooklyn.util.core.xstream.XmlUtil;
-import org.w3c.dom.Node;
-
-import com.google.common.annotations.Beta;
-import com.google.common.annotations.VisibleForTesting;
-import com.google.common.collect.Lists;
-import com.google.common.collect.Sets;
-
-@Beta
-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 {
-
- @Override
- public DeleteOrphanedLocationsTransformer build() {
- return new DeleteOrphanedLocationsTransformer(this);
- }
- }
-
- @Override
- 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();
- }
-
- @Override
- public BrooklynMemento transform(BrooklynMemento input) throws Exception {
- throw new UnsupportedOperationException();
- }
-
- protected Set<String> findReferencedLocationIds(BrooklynMemento input) {
- Set<String> result = Sets.newLinkedHashSet();
-
- for (EntityMemento entity : input.getEntityMementos().values()) {
- result.addAll(entity.getLocations());
- }
- return result;
- }
-
- @VisibleForTesting
- public Map<String, String> findLocationsToKeep(BrooklynMementoRawData input) {
- Map<String, String> locationsToKeep = MutableMap.of();
- Set<String> allReferencedLocations = findAllReferencedLocations(input);
-
- for (Map.Entry<String, String> location: input.getLocations().entrySet()) {
- if (allReferencedLocations.contains(location.getKey())) {
- locationsToKeep.put(location.getKey(), location.getValue());
- }
- }
- return locationsToKeep;
- }
-
- @VisibleForTesting
- public Set<String> findAllReferencedLocations(BrooklynMementoRawData input) {
- Set<String> allReferencedLocations = MutableSet.of();
-
- allReferencedLocations.addAll(searchLocationsToKeep(input.getEntities(), "/entity"));
- allReferencedLocations.addAll(searchLocationsToKeep(input.getPolicies(), "/policy"));
- allReferencedLocations.addAll(searchLocationsToKeep(input.getEnrichers(), "/enricher"));
- allReferencedLocations.addAll(searchLocationsToKeep(input.getFeeds(), "/feed"));
- allReferencedLocations.addAll(searchLocationsToKeepInLocations(input.getLocations(), allReferencedLocations));
-
- return allReferencedLocations;
- }
-
- protected Set<String> searchLocationsToKeep(Map<String, String> entities, String searchInTypePrefix) {
- Set<String> result = MutableSet.of();
-
- for(Map.Entry<String, String> entity: entities.entrySet()) {
-
- String location = "/locations/string";
- String locationProxy = "//locationProxy";
-
- result.addAll(getAllNodesFromXpath((org.w3c.dom.NodeList) XmlUtil.xpath(entity.getValue(), searchInTypePrefix+location, XPathConstants.NODESET)));
- result.addAll(getAllNodesFromXpath((org.w3c.dom.NodeList) XmlUtil.xpath(entity.getValue(), searchInTypePrefix+locationProxy, XPathConstants.NODESET)));
- }
-
- return result;
- }
-
- protected 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 locationProxy = "//locationProxy";
-
- for (Map.Entry<String, String> location: locations.entrySet()) {
- if (alreadyReferencedLocations.contains(location.getKey())) {
- result.addAll(getAllNodesFromXpath((org.w3c.dom.NodeList) XmlUtil.xpath(location.getValue(), prefix+locationId, XPathConstants.NODESET)));
- result.addAll(getAllNodesFromXpath((org.w3c.dom.NodeList) XmlUtil.xpath(location.getValue(), prefix+locationChildren, XPathConstants.NODESET)));
- result.addAll(getAllNodesFromXpath((org.w3c.dom.NodeList) XmlUtil.xpath(location.getValue(), prefix+locationParentDirectTag, XPathConstants.NODESET)));
- result.addAll(getAllNodesFromXpath((org.w3c.dom.NodeList) XmlUtil.xpath(location.getValue(), prefix+locationProxy, XPathConstants.NODESET)));
- }
- }
-
- return result;
- }
-
- protected Set<String> getAllNodesFromXpath(org.w3c.dom.NodeList 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;
- }
-
- protected Set<String> findLocationAncestors(BrooklynMemento input, String locationId) {
- Set<String> result = Sets.newLinkedHashSet();
-
- String parentId = null;
- do {
- LocationMemento memento = input.getLocationMemento(locationId);
- parentId = memento.getParent();
- if (parentId != null) result.add(parentId);
- } while (parentId != null);
-
- return result;
- }
-
- protected 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));
- List<String> children = memento.getChildren();
- result.addAll(children);
- tovisit.addAll(children);
- };
-
- return result;
- }
-}
http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/660956f7/core/src/main/java/org/apache/brooklyn/core/mgmt/rebind/transformer/impl/DeleteOrphanedStateTransformer.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/core/mgmt/rebind/transformer/impl/DeleteOrphanedStateTransformer.java b/core/src/main/java/org/apache/brooklyn/core/mgmt/rebind/transformer/impl/DeleteOrphanedStateTransformer.java
new file mode 100644
index 0000000..9b76e28
--- /dev/null
+++ b/core/src/main/java/org/apache/brooklyn/core/mgmt/rebind/transformer/impl/DeleteOrphanedStateTransformer.java
@@ -0,0 +1,203 @@
+/*
+ * 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.core.mgmt.rebind.transformer.impl;
+
+import java.util.Map;
+import java.util.Set;
+
+import javax.xml.xpath.XPathConstants;
+
+import org.apache.brooklyn.api.mgmt.rebind.mementos.BrooklynMementoRawData;
+import org.apache.brooklyn.core.mgmt.rebind.transformer.CompoundTransformer;
+import org.apache.brooklyn.util.collections.MutableMap;
+import org.apache.brooklyn.util.collections.MutableSet;
+import org.apache.brooklyn.util.core.xstream.XmlUtil;
+import org.apache.brooklyn.util.text.Strings;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.w3c.dom.Node;
+
+import com.google.common.annotations.Beta;
+import com.google.common.annotations.VisibleForTesting;
+import com.google.common.collect.Sets;
+
+@Beta
+public class DeleteOrphanedStateTransformer extends CompoundTransformer {
+
+ // TODO this isn't really a "CompoundTransformer" - it doesn't register any transformers
+ // in its builder, but instead overrides {@link #transform(BrooklynMementoRawData)}.
+ // That is a convenient, concise way to get the behaviour we want. But it is a code smell!
+ // We should probably either extract some common super-type, or another interface like
+ // BrooklynMementoRawDataTransformer (but then what would call the latter? Would it be
+ // a CompoundTransformer?!).
+
+ private static final Logger LOG = LoggerFactory.getLogger(DeleteOrphanedStateTransformer.class);
+
+ public static Builder builder() {
+ return new DeleteOrphanedStateTransformer.Builder();
+ }
+
+ public static class Builder extends CompoundTransformer.Builder {
+ @Override
+ public DeleteOrphanedStateTransformer build() {
+ return new DeleteOrphanedStateTransformer(this);
+ }
+ }
+
+ protected DeleteOrphanedStateTransformer(DeleteOrphanedStateTransformer.Builder builder) {
+ super(builder);
+ }
+
+ @Override
+ public BrooklynMementoRawData transform(BrooklynMementoRawData input) {
+ Map<String, String> locationsToKeep = findLocationsToKeep(input);
+ Map<String, String> enrichersToKeep = copyRetainingKeys(input.getEnrichers(), findAllReferencedEnrichers(input));
+ Map<String, String> policiesToKeep = copyRetainingKeys(input.getPolicies(), findAllReferencedPolicies(input));
+ Map<String, String> feedsToKeep = copyRetainingKeys(input.getFeeds(), findAllReferencedFeeds(input));
+
+ Set<String> locsToDelete = Sets.difference(input.getLocations().keySet(), locationsToKeep.keySet());
+ Set<String> enrichersToDelete = Sets.difference(input.getEnrichers().keySet(), enrichersToKeep.keySet());
+ Set<String> policiesToDelete = Sets.difference(input.getPolicies().keySet(), policiesToKeep.keySet());
+ Set<String> feedsToDelete = Sets.difference(input.getFeeds().keySet(), feedsToKeep.keySet());
+ LOG.info("Deleting {} orphaned location{}: {}", new Object[] {locsToDelete.size(), Strings.s(locsToDelete.size()), locsToDelete});
+ LOG.info("Deleting {} orphaned enricher{}: {}", new Object[] {enrichersToDelete.size(), Strings.s(enrichersToDelete.size()), enrichersToDelete});
+ LOG.info("Deleting {} orphaned polic{}: {}", new Object[] {policiesToDelete.size(), (policiesToDelete.size() == 1 ? "y" : "ies"), policiesToDelete});
+ LOG.info("Deleting {} orphaned feed{}: {}", new Object[] {feedsToDelete.size(), Strings.s(feedsToDelete.size()), feedsToDelete});
+
+ return BrooklynMementoRawData.builder()
+ .brooklynVersion(input.getBrooklynVersion())
+ .catalogItems(input.getCatalogItems())
+ .entities(input.getEntities())
+ .locations(locationsToKeep)
+ .enrichers(enrichersToKeep)
+ .policies(policiesToKeep)
+ .feeds(feedsToKeep)
+ .build();
+ }
+
+ protected Set<String> findAllReferencedEnrichers(BrooklynMementoRawData input) {
+ return findAllReferencedAdjuncts(input.getEntities(), "entity" + "/enrichers/string");
+ }
+
+ protected Set<String> findAllReferencedPolicies(BrooklynMementoRawData input) {
+ return findAllReferencedAdjuncts(input.getEntities(), "entity" + "/policies/string");
+ }
+
+ protected Set<String> findAllReferencedFeeds(BrooklynMementoRawData input) {
+ return findAllReferencedAdjuncts(input.getEntities(), "entity" + "/feeds/string");
+ }
+
+ protected Set<String> findAllReferencedAdjuncts(Map<String, String> items, String xpath) {
+ Set<String> result = Sets.newLinkedHashSet();
+
+ for(Map.Entry<String, String> entry : items.entrySet()) {
+ result.addAll(getAllNodesFromXpath((org.w3c.dom.NodeList) XmlUtil.xpath(entry.getValue(), xpath, XPathConstants.NODESET)));
+ }
+
+ return result;
+ }
+
+ @VisibleForTesting
+ public Map<String, String> findLocationsToKeep(BrooklynMementoRawData input) {
+ Set<String> allReferencedLocations = findAllReferencedLocations(input);
+ return copyRetainingKeys(input.getLocations(), allReferencedLocations);
+ }
+
+ @VisibleForTesting
+ public Set<String> findAllReferencedLocations(BrooklynMementoRawData input) {
+ Set<String> result = Sets.newLinkedHashSet();
+
+ result.addAll(searchLocationsToKeep(input.getEntities(), "/entity"));
+ result.addAll(searchLocationsToKeep(input.getPolicies(), "/policy"));
+ result.addAll(searchLocationsToKeep(input.getEnrichers(), "/enricher"));
+ result.addAll(searchLocationsToKeep(input.getFeeds(), "/feed"));
+ result.addAll(searchLocationsToKeepInLocations(input.getLocations(), result));
+
+ return result;
+ }
+
+ protected Set<String> searchLocationsToKeep(Map<String, String> items, String searchInTypePrefix) {
+ String locationsXpath = searchInTypePrefix+"/locations/string";
+ String locationProxyXpath = searchInTypePrefix+"//locationProxy";
+
+ Set<String> result = Sets.newLinkedHashSet();
+
+ for(Map.Entry<String, String> entry : items.entrySet()) {
+ result.addAll(getAllNodesFromXpath((org.w3c.dom.NodeList) XmlUtil.xpath(entry.getValue(), locationsXpath, XPathConstants.NODESET)));
+ result.addAll(getAllNodesFromXpath((org.w3c.dom.NodeList) XmlUtil.xpath(entry.getValue(), locationProxyXpath, XPathConstants.NODESET)));
+ }
+
+ return result;
+ }
+
+ protected Set<String> searchLocationsToKeepInLocations(Map<String, String> locations, Set<String> alreadyReferencedLocations) {
+ Set<String> result = Sets.newLinkedHashSet();
+
+ String prefix = "/location";
+ String locationChildrenXpath = prefix+"/children/string";
+ String locationParentDirectTagXpath = prefix+"/parent";
+ String locationProxyXpath = prefix+"//locationProxy";
+
+ Set<String> locsToInspect = alreadyReferencedLocations;
+
+ while (locsToInspect.size() > 0) {
+ Set<String> referencedLocs = Sets.newLinkedHashSet();
+ for (String id : locsToInspect) {
+ String xmlData = locations.get(id);
+ if (xmlData != null) {
+ referencedLocs.addAll(getAllNodesFromXpath((org.w3c.dom.NodeList) XmlUtil.xpath(xmlData, locationChildrenXpath, XPathConstants.NODESET)));
+ referencedLocs.addAll(getAllNodesFromXpath((org.w3c.dom.NodeList) XmlUtil.xpath(xmlData, locationParentDirectTagXpath, XPathConstants.NODESET)));
+ referencedLocs.addAll(getAllNodesFromXpath((org.w3c.dom.NodeList) XmlUtil.xpath(xmlData, locationProxyXpath, XPathConstants.NODESET)));
+ }
+ }
+ Set<String> newlyDiscoveredLocs = MutableSet.<String>builder()
+ .addAll(referencedLocs)
+ .removeAll(alreadyReferencedLocations)
+ .removeAll(result)
+ .build();
+ result.addAll(newlyDiscoveredLocs);
+ locsToInspect = newlyDiscoveredLocs;
+ }
+
+ return result;
+ }
+
+ protected <K, V> Map<K, V> copyRetainingKeys(Map<K, V> orig, Set<? extends K> keysToKeep) {
+ Map<K, V> result = MutableMap.of();
+ for (Map.Entry<K, V> entry : orig.entrySet()) {
+ if (keysToKeep.contains(entry.getKey())) {
+ result.put(entry.getKey(), entry.getValue());
+ }
+ }
+ return result;
+ }
+
+ protected Set<String> getAllNodesFromXpath(org.w3c.dom.NodeList nodeList) {
+ Set<String> result = Sets.newLinkedHashSet();
+
+ for (int i = 0; i < nodeList.getLength(); i++) {
+ Node nextNode = nodeList.item(i);
+ if (nextNode != null) {
+ result.add(nextNode.getTextContent());
+ }
+ }
+
+ return result;
+ }
+}
http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/660956f7/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 3c74549..e328d61 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
@@ -61,7 +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.mgmt.rebind.transformer.impl.DeleteOrphanedStateTransformer;
import org.apache.brooklyn.core.server.BrooklynServerConfig;
import org.apache.brooklyn.core.server.BrooklynServerPaths;
import org.apache.brooklyn.entity.brooklynnode.BrooklynNode;
@@ -384,7 +384,7 @@ public class BasicLauncher<T extends BasicLauncher<T>> {
}
public void cleanOrphanedLocations(String destinationDir, @Nullable String destinationLocationSpec) {
- copyPersistedState(destinationDir, destinationLocationSpec, DeleteOrphanedLocationsTransformer.builder().build());
+ copyPersistedState(destinationDir, destinationLocationSpec, DeleteOrphanedStateTransformer.builder().build());
}
/** @deprecated since 0.7.0 use {@link #copyPersistedState} instead */
http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/660956f7/launcher/src/test/java/org/apache/brooklyn/launcher/AbstractBrooklynLauncherRebindTestFixture.java
----------------------------------------------------------------------
diff --git a/launcher/src/test/java/org/apache/brooklyn/launcher/AbstractBrooklynLauncherRebindTestFixture.java b/launcher/src/test/java/org/apache/brooklyn/launcher/AbstractBrooklynLauncherRebindTestFixture.java
new file mode 100644
index 0000000..f768d81
--- /dev/null
+++ b/launcher/src/test/java/org/apache/brooklyn/launcher/AbstractBrooklynLauncherRebindTestFixture.java
@@ -0,0 +1,155 @@
+/*
+ * 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 static org.testng.Assert.assertEquals;
+import static org.testng.Assert.assertNotNull;
+
+import java.util.List;
+
+import org.apache.brooklyn.api.entity.Application;
+import org.apache.brooklyn.api.entity.EntitySpec;
+import org.apache.brooklyn.api.mgmt.ManagementContext;
+import org.apache.brooklyn.api.mgmt.ha.HighAvailabilityMode;
+import org.apache.brooklyn.core.entity.StartableApplication;
+import org.apache.brooklyn.core.internal.BrooklynProperties;
+import org.apache.brooklyn.core.mgmt.persist.BrooklynMementoPersisterToObjectStore;
+import org.apache.brooklyn.core.mgmt.persist.PersistMode;
+import org.apache.brooklyn.core.mgmt.persist.PersistenceObjectStore;
+import org.apache.brooklyn.core.test.entity.LocalManagementContextForTests;
+import org.apache.brooklyn.core.test.entity.TestApplication;
+import org.apache.brooklyn.test.Asserts;
+import org.apache.brooklyn.util.collections.MutableList;
+import org.apache.brooklyn.util.exceptions.FatalConfigurationRuntimeException;
+import org.apache.brooklyn.util.time.Duration;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.testng.annotations.AfterMethod;
+import org.testng.annotations.BeforeMethod;
+
+import com.google.common.base.Function;
+import com.google.common.base.Predicates;
+import com.google.common.collect.ImmutableMap;
+import com.google.common.collect.Iterables;
+
+public abstract class AbstractBrooklynLauncherRebindTestFixture {
+
+ @SuppressWarnings("unused")
+ private static final Logger log = LoggerFactory.getLogger(AbstractBrooklynLauncherRebindTestFixture.class);
+
+ protected String persistenceDir;
+ protected String persistenceLocationSpec;
+ protected List<BrooklynLauncher> launchers = MutableList.of();
+
+ protected abstract String newTempPersistenceContainerName();
+
+ @BeforeMethod(alwaysRun=true)
+ public void setUp() throws Exception {
+ persistenceDir = newTempPersistenceContainerName();
+ }
+
+ @AfterMethod(alwaysRun=true)
+ public void tearDown() throws Exception {
+ for (BrooklynLauncher l: launchers) {
+ if (l.isStarted()) {
+ l.terminate();
+ PersistenceObjectStore store = getPersistenceStore(l.getServerDetails().getManagementContext());
+ if (store!=null) store.deleteCompletely();
+ }
+ }
+ }
+
+ protected BrooklynLauncher newLauncherBase() {
+ BrooklynLauncher l = BrooklynLauncher.newInstance()
+ .webconsole(false);
+ launchers.add(l);
+ return l;
+ }
+
+ protected BrooklynLauncher newLauncherDefault(PersistMode mode) {
+ return newLauncherBase()
+ .managementContext(newManagementContextForTests(null))
+ .persistMode(mode)
+ .persistenceDir(persistenceDir)
+ .persistPeriod(Duration.millis(10));
+ }
+
+ protected LocalManagementContextForTests newManagementContextForTests(BrooklynProperties props) {
+ if (props==null)
+ return new LocalManagementContextForTests();
+ else
+ return new LocalManagementContextForTests(props);
+ }
+
+ protected ManagementContext lastMgmt() {
+ return Iterables.getLast(launchers).getServerDetails().getManagementContext();
+ }
+
+ protected void runRebindFails(PersistMode persistMode, String dir, String errmsg) throws Exception {
+ try {
+ newLauncherDefault(persistMode)
+ .persistenceDir(dir)
+ .start();
+ } catch (FatalConfigurationRuntimeException e) {
+ if (!e.toString().contains(errmsg)) {
+ throw e;
+ }
+ }
+ }
+
+ protected void populatePersistenceDir(String dir, EntitySpec<? extends StartableApplication> appSpec) throws Exception {
+ BrooklynLauncher launcher = newLauncherDefault(PersistMode.CLEAN)
+ .highAvailabilityMode(HighAvailabilityMode.MASTER)
+ .persistenceDir(dir)
+ .application(appSpec)
+ .start();
+ launcher.terminate();
+ assertMementoContainerNonEmptyForTypeEventually("entities");
+ }
+
+ protected void populatePersistenceDir(String dir, Function<ManagementContext, Void> populator) throws Exception {
+ BrooklynLauncher launcher = newLauncherDefault(PersistMode.CLEAN)
+ .highAvailabilityMode(HighAvailabilityMode.MASTER)
+ .persistenceDir(dir)
+ .start();
+ populator.apply(launcher.getManagementContext());
+ launcher.terminate();
+ assertMementoContainerNonEmptyForTypeEventually("entities");
+ }
+
+ protected void assertOnlyApp(ManagementContext managementContext, Class<? extends Application> expectedType) {
+ assertEquals(managementContext.getApplications().size(), 1, "apps="+managementContext.getApplications());
+ assertNotNull(Iterables.find(managementContext.getApplications(), Predicates.instanceOf(TestApplication.class), null), "apps="+managementContext.getApplications());
+ }
+
+ protected void assertMementoContainerNonEmptyForTypeEventually(final String type) {
+ Asserts.succeedsEventually(ImmutableMap.of("timeout", Duration.TEN_SECONDS), new Runnable() {
+ @Override public void run() {
+ getPersistenceStore(lastMgmt()).listContentsWithSubPath(type);
+ }});
+ }
+
+ static PersistenceObjectStore getPersistenceStore(ManagementContext managementContext) {
+ if (managementContext==null) return null;
+ BrooklynMementoPersisterToObjectStore persister = (BrooklynMementoPersisterToObjectStore)managementContext.getRebindManager().getPersister();
+ if (persister==null) return null;
+ return persister.getObjectStore();
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/660956f7/launcher/src/test/java/org/apache/brooklyn/launcher/AbstractCleanOrphanedStateTest.java
----------------------------------------------------------------------
diff --git a/launcher/src/test/java/org/apache/brooklyn/launcher/AbstractCleanOrphanedStateTest.java b/launcher/src/test/java/org/apache/brooklyn/launcher/AbstractCleanOrphanedStateTest.java
new file mode 100644
index 0000000..f8d7455
--- /dev/null
+++ b/launcher/src/test/java/org/apache/brooklyn/launcher/AbstractCleanOrphanedStateTest.java
@@ -0,0 +1,179 @@
+/*
+ * 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 static org.testng.Assert.assertEquals;
+import static org.testng.Assert.assertTrue;
+
+import java.util.Arrays;
+import java.util.Set;
+
+import org.apache.brooklyn.api.mgmt.rebind.mementos.BrooklynMementoRawData;
+import org.apache.brooklyn.core.enricher.AbstractEnricher;
+import org.apache.brooklyn.core.feed.AbstractFeed;
+import org.apache.brooklyn.core.mgmt.rebind.RebindTestFixtureWithApp;
+import org.apache.brooklyn.core.mgmt.rebind.RebindTestUtils;
+import org.apache.brooklyn.core.mgmt.rebind.transformer.impl.DeleteOrphanedStateTransformer;
+import org.apache.brooklyn.core.policy.AbstractPolicy;
+import org.apache.brooklyn.core.test.entity.TestEntityImpl;
+import org.apache.brooklyn.util.collections.MutableMap;
+import org.apache.brooklyn.util.core.flags.SetFromFlag;
+import org.apache.commons.lang.builder.EqualsBuilder;
+
+import com.beust.jcommander.internal.Sets;
+import com.google.common.base.Function;
+import com.google.common.base.Functions;
+
+public abstract class AbstractCleanOrphanedStateTest extends RebindTestFixtureWithApp {
+
+ public static class MementoTweaker implements Function<BrooklynMementoRawData, BrooklynMementoRawData> {
+ private Deletions deletions;
+
+ public MementoTweaker(Deletions deletions) {
+ this.deletions = deletions;
+ }
+ @Override
+ public BrooklynMementoRawData apply(BrooklynMementoRawData input) {
+ return BrooklynMementoRawData.builder()
+ .brooklynVersion(input.getBrooklynVersion())
+ .catalogItems(input.getCatalogItems())
+ .entities(MutableMap.<String, String>builder().putAll(input.getEntities()).removeAll(deletions.entities).build())
+ .locations(MutableMap.<String, String>builder().putAll(input.getLocations()).removeAll(deletions.locations).build())
+ .feeds(MutableMap.<String, String>builder().putAll(input.getFeeds()).removeAll(deletions.feeds).build())
+ .enrichers(MutableMap.<String, String>builder().putAll(input.getEnrichers()).removeAll(deletions.enrichers).build())
+ .policies(MutableMap.<String, String>builder().putAll(input.getPolicies()).removeAll(deletions.policies).build())
+ .build();
+
+ }
+ }
+
+ protected void assertTransformIsNoop() throws Exception {
+ assertTransformIsNoop(getRawData());
+ }
+
+ protected void assertTransformIsNoop(BrooklynMementoRawData origData) throws Exception {
+ assertTransformIsNoop(origData, Functions.<BrooklynMementoRawData>identity());
+ }
+
+ protected void assertTransformIsNoop(Function<? super BrooklynMementoRawData, ? extends BrooklynMementoRawData> origDataTweaker) throws Exception {
+ assertTransformIsNoop(getRawData(), origDataTweaker);
+ }
+
+ protected void assertTransformIsNoop(BrooklynMementoRawData origData, Function<? super BrooklynMementoRawData, ? extends BrooklynMementoRawData> origDataTweaker) throws Exception {
+ BrooklynMementoRawData origDataTweaked = origDataTweaker.apply(origData);
+ BrooklynMementoRawData transformedData = transformRawData(origDataTweaked);
+ assertRawData(transformedData, origDataTweaked);
+ }
+
+ protected void assertTransformDeletes(Deletions deletions) throws Exception {
+ assertTransformDeletes(deletions, Functions.<BrooklynMementoRawData>identity());
+ }
+
+ protected void assertTransformDeletes(Deletions deletions, Function<? super BrooklynMementoRawData, ? extends BrooklynMementoRawData> origDataTweaker) throws Exception {
+ BrooklynMementoRawData origData = getRawData();
+ BrooklynMementoRawData origDataTweaked = origDataTweaker.apply(origData);
+ BrooklynMementoRawData transformedData = transformRawData(origDataTweaked);
+ assertRawData(transformedData, origDataTweaked, deletions);
+ }
+
+ protected BrooklynMementoRawData getRawData() throws Exception {
+ RebindTestUtils.waitForPersisted(origApp);
+ return mgmt().getRebindManager().retrieveMementoRawData();
+ }
+
+ protected BrooklynMementoRawData transformRawData(BrooklynMementoRawData rawData) throws Exception {
+ DeleteOrphanedStateTransformer transformer = DeleteOrphanedStateTransformer.builder().build();
+ return transformer.transform(rawData);
+ }
+
+ protected void assertRawData(BrooklynMementoRawData actual, BrooklynMementoRawData expected) {
+ // asserting lots of times, to ensure we get a more specific error message!
+ assertEquals(actual.getCatalogItems().keySet(), expected.getCatalogItems().keySet(), "catalog ids differ");
+ assertEquals(actual.getCatalogItems(), expected.getCatalogItems());
+ assertEquals(actual.getEntities().keySet(), expected.getEntities().keySet(), "entity ids differ");
+ assertEquals(actual.getEntities(), expected.getEntities());
+ assertEquals(actual.getLocations().keySet(), expected.getLocations().keySet(), "location ids differ");
+ assertEquals(actual.getLocations(), expected.getLocations());
+ assertEquals(actual.getEnrichers().keySet(), expected.getEnrichers().keySet(), "enricher ids differ");
+ assertEquals(actual.getEnrichers(), expected.getEnrichers());
+ assertEquals(actual.getPolicies().keySet(), expected.getPolicies().keySet(), "policy ids differ");
+ assertEquals(actual.getPolicies(), expected.getPolicies());
+ assertEquals(actual.getFeeds().keySet(), expected.getFeeds().keySet(), "feed ids differ");
+ assertEquals(actual.getFeeds(), expected.getFeeds());
+ assertTrue(EqualsBuilder.reflectionEquals(actual, expected));
+ }
+
+ protected void assertRawData(BrooklynMementoRawData actual, BrooklynMementoRawData orig, Deletions deletions) {
+ BrooklynMementoRawData expected = new MementoTweaker(deletions).apply(orig);
+ assertRawData(actual, expected);
+
+ // double-check that the orig data contains what we think we are deleting!
+ // otherwise we could get a lot of false positive tests.
+ assertTrue(orig.getEntities().keySet().containsAll(deletions.entities));
+ assertTrue(orig.getLocations().keySet().containsAll(deletions.locations));
+ assertTrue(orig.getEnrichers().keySet().containsAll(deletions.enrichers));
+ assertTrue(orig.getPolicies().keySet().containsAll(deletions.policies));
+ assertTrue(orig.getFeeds().keySet().containsAll(deletions.feeds));
+ }
+
+ protected static class Deletions {
+ final Set<String> entities = Sets.newLinkedHashSet();
+ final Set<String> locations = Sets.newLinkedHashSet();
+ final Set<String> feeds = Sets.newLinkedHashSet();
+ final Set<String> enrichers = Sets.newLinkedHashSet();
+ final Set<String> policies = Sets.newLinkedHashSet();
+
+ protected Deletions entities(String... vals) {
+ if (vals != null) entities.addAll(Arrays.asList(vals));
+ return this;
+ }
+ protected Deletions locations(String... vals) {
+ if (vals != null) locations.addAll(Arrays.asList(vals));
+ return this;
+ }
+ protected Deletions feeds(String... vals) {
+ if (vals != null) feeds.addAll(Arrays.asList(vals));
+ return this;
+ }
+ protected Deletions enrichers(String... vals) {
+ if (vals != null) enrichers.addAll(Arrays.asList(vals));
+ return this;
+ }
+ protected Deletions policies(String... vals) {
+ if (vals != null) policies.addAll(Arrays.asList(vals));
+ return this;
+ }
+ }
+
+ public static class MyEnricher extends AbstractEnricher {
+ @SetFromFlag Object obj;
+ }
+
+ public static class MyPolicy extends AbstractPolicy {
+ }
+
+ public static class MyFeed extends AbstractFeed {
+ }
+
+ public static class MyEntity extends TestEntityImpl {
+ @Override protected void initEnrichers() {
+ // no stock enrichers
+ }
+ }
+}
http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/660956f7/launcher/src/test/java/org/apache/brooklyn/launcher/BrooklynLauncherCleanStateTest.java
----------------------------------------------------------------------
diff --git a/launcher/src/test/java/org/apache/brooklyn/launcher/BrooklynLauncherCleanStateTest.java b/launcher/src/test/java/org/apache/brooklyn/launcher/BrooklynLauncherCleanStateTest.java
new file mode 100644
index 0000000..25d23d5
--- /dev/null
+++ b/launcher/src/test/java/org/apache/brooklyn/launcher/BrooklynLauncherCleanStateTest.java
@@ -0,0 +1,112 @@
+/*
+ * 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 static org.testng.Assert.assertEquals;
+import static org.testng.Assert.assertNotEquals;
+import static org.testng.Assert.assertTrue;
+
+import java.io.File;
+import java.util.concurrent.atomic.AtomicReference;
+
+import org.apache.brooklyn.api.entity.Entity;
+import org.apache.brooklyn.api.entity.EntitySpec;
+import org.apache.brooklyn.api.location.Location;
+import org.apache.brooklyn.api.location.LocationSpec;
+import org.apache.brooklyn.api.mgmt.ManagementContext;
+import org.apache.brooklyn.api.mgmt.ha.HighAvailabilityMode;
+import org.apache.brooklyn.core.mgmt.persist.PersistMode;
+import org.apache.brooklyn.core.test.entity.TestApplication;
+import org.apache.brooklyn.location.ssh.SshMachineLocation;
+import org.apache.brooklyn.util.os.Os;
+import org.testng.annotations.Test;
+
+import com.google.common.base.Function;
+import com.google.common.base.Joiner;
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.Iterables;
+import com.google.common.io.Files;
+
+/**
+ * See {@link CleanOrphanedLocationsTest} for more thorough testing. This test is to ensure that
+ * it works through the launcher.
+ */
+public class BrooklynLauncherCleanStateTest extends AbstractBrooklynLauncherRebindTestFixture {
+
+ @Override
+ protected String newTempPersistenceContainerName() {
+ File persistenceDirF = Files.createTempDir();
+ Os.deleteOnExitRecursively(persistenceDirF);
+ return persistenceDirF.getAbsolutePath();
+ }
+
+ @Test(groups="Integration")
+ public void testCleanStateState() throws Exception {
+ final AtomicReference<Entity> appToKeep = new AtomicReference<>();
+ final AtomicReference<Location> locToKeep = new AtomicReference<>();
+ final AtomicReference<Location> locToDelete = new AtomicReference<>();
+ populatePersistenceDir(persistenceDir, new Function<ManagementContext, Void>() {
+ @Override
+ public Void apply(ManagementContext mgmt) {
+ TestApplication app = mgmt.getEntityManager().createEntity(EntitySpec.create(TestApplication.class));
+ SshMachineLocation loc = mgmt.getLocationManager().createLocation(LocationSpec.create(SshMachineLocation.class));
+ SshMachineLocation loc2 = mgmt.getLocationManager().createLocation(LocationSpec.create(SshMachineLocation.class));
+ app.addLocations(ImmutableList.of(loc));
+ appToKeep.set(app);
+ locToKeep.set(loc);
+ locToDelete.set(loc2);
+ return null;
+ }});
+
+ File destinationDir = Files.createTempDir();
+ String destination = destinationDir.getAbsolutePath();
+ String destinationLocation = null; // i.e. file system, rather than object store
+ try {
+ // Clean the state
+ BrooklynLauncher launcher = newLauncherDefault(PersistMode.AUTO)
+ .highAvailabilityMode(HighAvailabilityMode.MASTER)
+ .webconsole(false);
+ launcher.cleanOrphanedLocations(destination, destinationLocation);
+ launcher.terminate();
+
+ // Sanity checks (copied from BrooklynLauncherRebindTestToFiles#testCopyPersistedState)
+ File entities = new File(Os.mergePaths(destination), "entities");
+ assertTrue(entities.isDirectory(), "entities directory should exist");
+ assertEquals(entities.listFiles().length, 1, "entities directory should contain one file (contained: "+
+ Joiner.on(", ").join(entities.listFiles()) +")");
+
+ File nodes = new File(Os.mergePaths(destination, "nodes"));
+ assertTrue(nodes.isDirectory(), "nodes directory should exist");
+ assertNotEquals(nodes.listFiles().length, 0, "nodes directory should not be empty");
+
+ // Should now have a usable copy in the destinationDir
+ newLauncherDefault(PersistMode.AUTO)
+ .webconsole(false)
+ .persistenceDir(destinationDir)
+ .start();
+
+ Entity restoredApp = Iterables.getOnlyElement(lastMgmt().getEntityManager().getEntities());
+ Location restoredLoc = Iterables.getOnlyElement(lastMgmt().getLocationManager().getLocations());
+ assertEquals(restoredApp.getId(), appToKeep.get().getId());
+ assertEquals(restoredLoc.getId(), locToKeep.get().getId());
+ } finally {
+ Os.deleteRecursively(destinationDir);
+ }
+ }
+}
http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/660956f7/launcher/src/test/java/org/apache/brooklyn/launcher/BrooklynLauncherRebindTestFixture.java
----------------------------------------------------------------------
diff --git a/launcher/src/test/java/org/apache/brooklyn/launcher/BrooklynLauncherRebindTestFixture.java b/launcher/src/test/java/org/apache/brooklyn/launcher/BrooklynLauncherRebindTestFixture.java
index 59372e3..a98bc23 100644
--- a/launcher/src/test/java/org/apache/brooklyn/launcher/BrooklynLauncherRebindTestFixture.java
+++ b/launcher/src/test/java/org/apache/brooklyn/launcher/BrooklynLauncherRebindTestFixture.java
@@ -18,94 +18,32 @@
*/
package org.apache.brooklyn.launcher;
-import org.apache.brooklyn.api.entity.Application;
+import static org.testng.Assert.assertEquals;
+import static org.testng.Assert.assertNotNull;
+import static org.testng.Assert.assertTrue;
+
import org.apache.brooklyn.api.entity.EntitySpec;
import org.apache.brooklyn.api.location.Location;
-import org.apache.brooklyn.api.mgmt.ManagementContext;
-import org.apache.brooklyn.api.mgmt.ha.HighAvailabilityMode;
import org.apache.brooklyn.core.entity.EntityPredicates;
import org.apache.brooklyn.core.entity.StartableApplication;
import org.apache.brooklyn.core.internal.BrooklynProperties;
-import org.apache.brooklyn.core.mgmt.persist.BrooklynMementoPersisterToObjectStore;
import org.apache.brooklyn.core.mgmt.persist.PersistMode;
-import org.apache.brooklyn.core.mgmt.persist.PersistenceObjectStore;
import org.apache.brooklyn.core.server.BrooklynServerConfig;
import org.apache.brooklyn.core.test.entity.LocalManagementContextForTests;
import org.apache.brooklyn.core.test.entity.TestApplication;
-import org.apache.brooklyn.launcher.BrooklynLauncher;
-import org.apache.brooklyn.test.Asserts;
-import org.apache.brooklyn.util.collections.MutableList;
-import org.apache.brooklyn.util.exceptions.FatalConfigurationRuntimeException;
import org.apache.brooklyn.util.time.Duration;
-
-import static org.testng.Assert.assertEquals;
-import static org.testng.Assert.assertNotNull;
-import static org.testng.Assert.assertTrue;
-
-import java.util.List;
-
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
-import org.testng.annotations.AfterMethod;
-import org.testng.annotations.BeforeMethod;
import org.testng.annotations.Test;
-import com.google.common.base.Predicates;
import com.google.common.collect.ImmutableList;
-import com.google.common.collect.ImmutableMap;
import com.google.common.collect.Iterables;
-public abstract class BrooklynLauncherRebindTestFixture {
+public abstract class BrooklynLauncherRebindTestFixture extends AbstractBrooklynLauncherRebindTestFixture {
@SuppressWarnings("unused")
private static final Logger log = LoggerFactory.getLogger(BrooklynLauncherRebindTestFixture.class);
- protected String persistenceDir;
- protected String persistenceLocationSpec;
- protected List<BrooklynLauncher> launchers = MutableList.of();
-
- @BeforeMethod(alwaysRun=true)
- public void setUp() throws Exception {
- persistenceDir = newTempPersistenceContainerName();
- }
-
- protected abstract String newTempPersistenceContainerName();
-
- @AfterMethod(alwaysRun=true)
- public void tearDown() throws Exception {
- for (BrooklynLauncher l: launchers) {
- if (l.isStarted()) {
- l.terminate();
- PersistenceObjectStore store = getPersistenceStore(l.getServerDetails().getManagementContext());
- if (store!=null) store.deleteCompletely();
- }
- }
- }
-
- protected BrooklynLauncher newLauncherBase() {
- BrooklynLauncher l = BrooklynLauncher.newInstance()
- .webconsole(false);
- launchers.add(l);
- return l;
- }
- protected BrooklynLauncher newLauncherDefault(PersistMode mode) {
- return newLauncherBase()
- .managementContext(newManagementContextForTests(null))
- .persistMode(mode)
- .persistenceDir(persistenceDir)
- .persistPeriod(Duration.millis(10));
- }
- protected LocalManagementContextForTests newManagementContextForTests(BrooklynProperties props) {
- if (props==null)
- return new LocalManagementContextForTests();
- else
- return new LocalManagementContextForTests(props);
- }
-
- protected ManagementContext lastMgmt() {
- return Iterables.getLast(launchers).getServerDetails().getManagementContext();
- }
-
@Test
public void testRebindsToExistingApp() throws Exception {
populatePersistenceDir(persistenceDir, EntitySpec.create(TestApplication.class).displayName("myorig"));
@@ -212,46 +150,4 @@ public abstract class BrooklynLauncherRebindTestFixture {
public void testExplicitRebindFailsIfEmpty() throws Exception {
runRebindFails(PersistMode.REBIND, persistenceDir, "directory is empty");
}
-
- protected void runRebindFails(PersistMode persistMode, String dir, String errmsg) throws Exception {
- try {
- newLauncherDefault(persistMode)
- .persistenceDir(dir)
- .start();
- } catch (FatalConfigurationRuntimeException e) {
- if (!e.toString().contains(errmsg)) {
- throw e;
- }
- }
- }
-
- protected void populatePersistenceDir(String dir, EntitySpec<? extends StartableApplication> appSpec) throws Exception {
- BrooklynLauncher launcher = newLauncherDefault(PersistMode.CLEAN)
- .highAvailabilityMode(HighAvailabilityMode.MASTER)
- .persistenceDir(dir)
- .application(appSpec)
- .start();
- launcher.terminate();
- assertMementoContainerNonEmptyForTypeEventually("entities");
- }
-
- protected void assertOnlyApp(ManagementContext managementContext, Class<? extends Application> expectedType) {
- assertEquals(managementContext.getApplications().size(), 1, "apps="+managementContext.getApplications());
- assertNotNull(Iterables.find(managementContext.getApplications(), Predicates.instanceOf(TestApplication.class), null), "apps="+managementContext.getApplications());
- }
-
- protected void assertMementoContainerNonEmptyForTypeEventually(final String type) {
- Asserts.succeedsEventually(ImmutableMap.of("timeout", Duration.TEN_SECONDS), new Runnable() {
- @Override public void run() {
- getPersistenceStore(lastMgmt()).listContentsWithSubPath(type);
- }});
- }
-
- static PersistenceObjectStore getPersistenceStore(ManagementContext managementContext) {
- if (managementContext==null) return null;
- BrooklynMementoPersisterToObjectStore persister = (BrooklynMementoPersisterToObjectStore)managementContext.getRebindManager().getPersister();
- if (persister==null) return null;
- return persister.getObjectStore();
- }
-
}
http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/660956f7/launcher/src/test/java/org/apache/brooklyn/launcher/CleanOrphanedAdjunctsTest.java
----------------------------------------------------------------------
diff --git a/launcher/src/test/java/org/apache/brooklyn/launcher/CleanOrphanedAdjunctsTest.java b/launcher/src/test/java/org/apache/brooklyn/launcher/CleanOrphanedAdjunctsTest.java
new file mode 100644
index 0000000..f9e772a
--- /dev/null
+++ b/launcher/src/test/java/org/apache/brooklyn/launcher/CleanOrphanedAdjunctsTest.java
@@ -0,0 +1,76 @@
+/*
+ * 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 static org.testng.Assert.assertTrue;
+
+import org.apache.brooklyn.api.entity.Entity;
+import org.apache.brooklyn.api.entity.EntitySpec;
+import org.apache.brooklyn.api.mgmt.rebind.mementos.BrooklynMementoRawData;
+import org.apache.brooklyn.api.policy.PolicySpec;
+import org.apache.brooklyn.api.sensor.EnricherSpec;
+import org.apache.brooklyn.api.sensor.Feed;
+import org.apache.brooklyn.core.entity.EntityInternal;
+import org.apache.brooklyn.core.test.entity.TestEntity;
+import org.testng.annotations.Test;
+
+/**
+ * When entity that the adjunct is associated with is deleted, the adjunct can safely be deleted.
+ */
+public class CleanOrphanedAdjunctsTest extends AbstractCleanOrphanedStateTest {
+
+ @Test
+ public void testDeletesOrphanedEnricher() throws Exception {
+ Entity entity = origApp.addChild(EntitySpec.create(TestEntity.class).impl(MyEntity.class));
+ MyEnricher enricher = entity.enrichers().add(EnricherSpec.create(MyEnricher.class));
+ MementoTweaker tweaker = new MementoTweaker(new Deletions().entities(entity.getId()));
+ assertTransformDeletes(new Deletions().enrichers(enricher.getId()), tweaker);
+ }
+
+ @Test
+ public void testDeletesOrphanedPolicies() throws Exception {
+ Entity entity = origApp.addChild(EntitySpec.create(TestEntity.class).impl(MyEntity.class));
+ MyPolicy policy = entity.policies().add(PolicySpec.create(MyPolicy.class));
+ MementoTweaker tweaker = new MementoTweaker(new Deletions().entities(entity.getId()));
+ assertTransformDeletes(new Deletions().policies(policy.getId()), tweaker);
+ }
+
+ @Test
+ public void testDeletesOrphanedFeeds() throws Exception {
+ EntityInternal entity = origApp.addChild(EntitySpec.create(TestEntity.class).impl(MyEntity.class));
+ Feed feed = entity.feeds().add(new MyFeed());
+ MementoTweaker tweaker = new MementoTweaker(new Deletions().entities(entity.getId()));
+ assertTransformDeletes(new Deletions().feeds(feed.getId()), tweaker);
+ }
+
+ @Test
+ public void testKeepsReachableAdjuncts() throws Exception {
+ MyPolicy policy = origApp.policies().add(PolicySpec.create(MyPolicy.class));
+ MyEnricher enricher = origApp.enrichers().add(EnricherSpec.create(MyEnricher.class));
+ Feed feed = origApp.feeds().add(new MyFeed());
+
+ // Double-check we have the state we expected for the assertions that it is unmodified!
+ BrooklynMementoRawData origData = getRawData();
+ assertTrue(origData.getPolicies().containsKey(policy.getId()));
+ assertTrue(origData.getEnrichers().containsKey(enricher.getId()));
+ assertTrue(origData.getFeeds().containsKey(feed.getId()));
+
+ assertTransformIsNoop(origData);
+ }
+}
http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/660956f7/launcher/src/test/java/org/apache/brooklyn/launcher/CleanOrphanedLocationsTest.java
----------------------------------------------------------------------
diff --git a/launcher/src/test/java/org/apache/brooklyn/launcher/CleanOrphanedLocationsTest.java b/launcher/src/test/java/org/apache/brooklyn/launcher/CleanOrphanedLocationsTest.java
index 7be6bd5..258060b 100644
--- a/launcher/src/test/java/org/apache/brooklyn/launcher/CleanOrphanedLocationsTest.java
+++ b/launcher/src/test/java/org/apache/brooklyn/launcher/CleanOrphanedLocationsTest.java
@@ -18,36 +18,23 @@
*/
package org.apache.brooklyn.launcher;
-import static org.testng.Assert.assertEquals;
-import static org.testng.Assert.assertTrue;
-
-import java.util.Arrays;
-import java.util.Set;
+import static org.testng.Assert.assertFalse;
import org.apache.brooklyn.api.location.Location;
import org.apache.brooklyn.api.location.LocationSpec;
-import org.apache.brooklyn.api.mgmt.rebind.mementos.BrooklynMementoRawData;
+import org.apache.brooklyn.api.location.MachineLocation;
import org.apache.brooklyn.api.policy.PolicySpec;
import org.apache.brooklyn.api.sensor.EnricherSpec;
import org.apache.brooklyn.core.config.ConfigKeys;
-import org.apache.brooklyn.core.enricher.AbstractEnricher;
-import org.apache.brooklyn.core.feed.AbstractFeed;
-import org.apache.brooklyn.core.mgmt.rebind.RebindTestFixtureWithApp;
-import org.apache.brooklyn.core.mgmt.rebind.RebindTestUtils;
-import org.apache.brooklyn.core.mgmt.rebind.transformer.impl.DeleteOrphanedLocationsTransformer;
-import org.apache.brooklyn.core.policy.AbstractPolicy;
+import org.apache.brooklyn.core.location.Locations;
import org.apache.brooklyn.core.sensor.Sensors;
import org.apache.brooklyn.location.ssh.SshMachineLocation;
-import org.apache.brooklyn.util.collections.MutableMap;
-import org.apache.brooklyn.util.core.flags.SetFromFlag;
-import org.apache.commons.lang.builder.EqualsBuilder;
import org.testng.annotations.Test;
-import com.beust.jcommander.internal.Sets;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
-public class CleanOrphanedLocationsTest extends RebindTestFixtureWithApp {
+public class CleanOrphanedLocationsTest extends AbstractCleanOrphanedStateTest {
@Test
public void testDeletesOrphanedLocations() throws Exception {
@@ -73,6 +60,37 @@ public class CleanOrphanedLocationsTest extends RebindTestFixtureWithApp {
assertTransformDeletes(new Deletions().locations(loc1.getId(), loc2.getId()));
}
+ // Tests that we don't accidentally abort or throw exceptions.
+ @Test
+ public void testHandlesDanglingReference() throws Exception {
+ SshMachineLocation todelete = mgmt().getLocationManager().createLocation(LocationSpec.create(SshMachineLocation.class));
+ SshMachineLocation loc = mgmt().getLocationManager().createLocation(LocationSpec.create(SshMachineLocation.class));
+ origApp.addLocations(ImmutableList.of(todelete));
+ origApp.sensors().set(Sensors.newSensor(Object.class, "mysensor"), loc);
+ origApp.config().set(ConfigKeys.newConfigKey(Object.class, "myconfig"), loc);
+ origApp.tags().addTag(loc);
+ loc.config().set(ConfigKeys.newConfigKey(Object.class, "myconfig"), todelete);
+
+ Locations.unmanage(todelete);
+ assertFalse(getRawData().getLocations().containsKey(todelete.getId()));
+
+ assertTransformIsNoop();
+ }
+
+ // Previously when iterating over the list, we'd abort on the first null rather than looking
+ // at all the nodes in the list. This test doesn't quite manage to reproduce that. The non-null
+ // dangling references are persisted.
+ @Test
+ public void testHandlesDanglingReferencesInLocationListSurroundingValidReference() throws Exception {
+ SshMachineLocation todelete = mgmt().getLocationManager().createLocation(LocationSpec.create(SshMachineLocation.class));
+ SshMachineLocation loc = mgmt().getLocationManager().createLocation(LocationSpec.create(SshMachineLocation.class));
+ SshMachineLocation todelete2 = mgmt().getLocationManager().createLocation(LocationSpec.create(SshMachineLocation.class));
+ origApp.addLocations(ImmutableList.of(todelete, loc, todelete2));
+ Locations.unmanage(todelete);
+
+ assertTransformIsNoop();
+ }
+
@Test
public void testKeepsLocationsReferencedInEntityLocs() throws Exception {
SshMachineLocation loc = mgmt().getLocationManager().createLocation(LocationSpec.create(SshMachineLocation.class));
@@ -120,7 +138,7 @@ public class CleanOrphanedLocationsTest extends RebindTestFixtureWithApp {
@Test(groups="WIP", enabled=false)
public void testKeepsLocationsReferencedInConfigKeyDefault() throws Exception {
SshMachineLocation loc = mgmt().getLocationManager().createLocation(LocationSpec.create(SshMachineLocation.class));
- origApp.config().set(ConfigKeys.newConfigKey(Object.class, "myconfig", "my description", loc), null);
+ origApp.config().set(ConfigKeys.newConfigKey(MachineLocation.class, "myconfig", "my description", loc), (MachineLocation)null);
assertTransformIsNoop();
}
@@ -198,90 +216,4 @@ public class CleanOrphanedLocationsTest extends RebindTestFixtureWithApp {
origApp.feeds().add(feed);
assertTransformIsNoop();
}
-
- private void assertTransformIsNoop() throws Exception {
- BrooklynMementoRawData origData = getRawData();
- BrooklynMementoRawData transformedData = transformRawData(origData);
- assertRawData(transformedData, origData);
- }
-
- private void assertTransformDeletes(Deletions deletions) throws Exception {
- BrooklynMementoRawData origData = getRawData();
- BrooklynMementoRawData transformedData = transformRawData(origData);
- assertRawData(transformedData, origData, deletions);
- }
-
- protected BrooklynMementoRawData getRawData() throws Exception {
- RebindTestUtils.waitForPersisted(origApp);
- return mgmt().getRebindManager().retrieveMementoRawData();
- }
-
- protected BrooklynMementoRawData transformRawData(BrooklynMementoRawData rawData) throws Exception {
- DeleteOrphanedLocationsTransformer transformer = DeleteOrphanedLocationsTransformer.builder().build();
- return transformer.transform(rawData);
- }
-
- protected void assertRawData(BrooklynMementoRawData actual, BrooklynMementoRawData expected) {
- // asserting lots of times, to ensure we get a more specific error message!
- assertEquals(actual.getCatalogItems().keySet(), expected.getCatalogItems().keySet());
- assertEquals(actual.getCatalogItems(), expected.getCatalogItems());
- assertEquals(actual.getEntities().keySet(), expected.getEntities().keySet());
- assertEquals(actual.getEntities(), expected.getEntities());
- assertEquals(actual.getLocations().keySet(), expected.getLocations().keySet());
- assertEquals(actual.getLocations(), expected.getLocations());
- assertEquals(actual.getEnrichers().keySet(), expected.getEnrichers().keySet());
- assertEquals(actual.getEnrichers(), expected.getEnrichers());
- assertEquals(actual.getPolicies().keySet(), expected.getPolicies().keySet());
- assertEquals(actual.getPolicies(), expected.getPolicies());
- assertEquals(actual.getFeeds().keySet(), expected.getFeeds().keySet());
- assertEquals(actual.getFeeds(), expected.getFeeds());
- assertTrue(EqualsBuilder.reflectionEquals(actual, expected));
- }
-
- protected void assertRawData(BrooklynMementoRawData actual, BrooklynMementoRawData orig, Deletions deletions) {
- BrooklynMementoRawData expected = BrooklynMementoRawData.builder()
- .catalogItems(orig.getCatalogItems())
- .entities(orig.getEntities())
- .locations(MutableMap.<String, String>builder().putAll(orig.getLocations()).removeAll(deletions.locations).build())
- .feeds(MutableMap.<String, String>builder().putAll(orig.getFeeds()).removeAll(deletions.feeds).build())
- .enrichers(MutableMap.<String, String>builder().putAll(orig.getEnrichers()).removeAll(deletions.enrichers).build())
- .policies(MutableMap.<String, String>builder().putAll(orig.getPolicies()).removeAll(deletions.policies).build())
- .build();
- assertRawData(actual, expected);
- }
-
- @SuppressWarnings("unused")
- private static class Deletions {
- final Set<String> locations = Sets.newLinkedHashSet();
- final Set<String> feeds = Sets.newLinkedHashSet();
- final Set<String> enrichers = Sets.newLinkedHashSet();
- final Set<String> policies = Sets.newLinkedHashSet();
-
- Deletions locations(String... vals) {
- if (vals != null) locations.addAll(Arrays.asList(vals));
- return this;
- }
- Deletions feeds(String... vals) {
- if (vals != null) feeds.addAll(Arrays.asList(vals));
- return this;
- }
- Deletions enrichers(String... vals) {
- if (vals != null) enrichers.addAll(Arrays.asList(vals));
- return this;
- }
- Deletions policies(String... vals) {
- if (vals != null) policies.addAll(Arrays.asList(vals));
- return this;
- }
- }
-
- public static class MyEnricher extends AbstractEnricher {
- @SetFromFlag Object obj;
- }
-
- public static class MyPolicy extends AbstractPolicy {
- }
-
- public static class MyFeed extends AbstractFeed {
- }
}
http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/660956f7/launcher/src/test/resources/orphaned-locations-test-data/copy-persisted-state-destination/dummy.txt
----------------------------------------------------------------------
diff --git a/launcher/src/test/resources/orphaned-locations-test-data/copy-persisted-state-destination/dummy.txt b/launcher/src/test/resources/orphaned-locations-test-data/copy-persisted-state-destination/dummy.txt
deleted file mode 100644
index e69de29..0000000