You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@brooklyn.apache.org by he...@apache.org on 2017/11/21 17:08:19 UTC
[4/8] brooklyn-server git commit: bundle-force-remove: don’t re-install if come across reference
bundle-force-remove: don’t re-install if come across reference
Project: http://git-wip-us.apache.org/repos/asf/brooklyn-server/repo
Commit: http://git-wip-us.apache.org/repos/asf/brooklyn-server/commit/b9710776
Tree: http://git-wip-us.apache.org/repos/asf/brooklyn-server/tree/b9710776
Diff: http://git-wip-us.apache.org/repos/asf/brooklyn-server/diff/b9710776
Branch: refs/heads/master
Commit: b97107768a5f5897e2dd33bdaef0927bf807bad7
Parents: 419f03f
Author: Aled Sage <al...@gmail.com>
Authored: Thu Nov 16 18:48:56 2017 +0000
Committer: Aled Sage <al...@gmail.com>
Committed: Fri Nov 17 15:05:17 2017 +0000
----------------------------------------------------------------------
.../core/mgmt/ha/OsgiArchiveInstaller.java | 45 +++-
.../mgmt/ha/OsgiBundleInstallationResult.java | 10 +
.../core/typereg/BundleUpgradeParser.java | 39 ++++
.../BrooklynLauncherUpgradeCatalogOsgiTest.java | 203 +++++++++++++++++++
4 files changed, 294 insertions(+), 3 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/b9710776/core/src/main/java/org/apache/brooklyn/core/mgmt/ha/OsgiArchiveInstaller.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/core/mgmt/ha/OsgiArchiveInstaller.java b/core/src/main/java/org/apache/brooklyn/core/mgmt/ha/OsgiArchiveInstaller.java
index 15d847e..41164cb 100644
--- a/core/src/main/java/org/apache/brooklyn/core/mgmt/ha/OsgiArchiveInstaller.java
+++ b/core/src/main/java/org/apache/brooklyn/core/mgmt/ha/OsgiArchiveInstaller.java
@@ -43,10 +43,10 @@ import org.apache.brooklyn.core.catalog.internal.BasicBrooklynCatalog;
import org.apache.brooklyn.core.catalog.internal.CatalogInitialization;
import org.apache.brooklyn.core.mgmt.ha.OsgiBundleInstallationResult.ResultCode;
import org.apache.brooklyn.core.mgmt.internal.ManagementContextInternal;
-import org.apache.brooklyn.core.mgmt.rebind.RebindManagerImpl;
import org.apache.brooklyn.core.server.BrooklynServerConfig;
import org.apache.brooklyn.core.typereg.BasicBrooklynTypeRegistry;
import org.apache.brooklyn.core.typereg.BasicManagedBundle;
+import org.apache.brooklyn.core.typereg.BundleUpgradeParser.CatalogUpgrades;
import org.apache.brooklyn.core.typereg.RegisteredTypePredicates;
import org.apache.brooklyn.core.typereg.RegisteredTypes;
import org.apache.brooklyn.util.collections.MutableList;
@@ -72,6 +72,7 @@ import org.slf4j.LoggerFactory;
import com.google.common.annotations.VisibleForTesting;
import com.google.common.base.Function;
import com.google.common.base.Objects;
+import com.google.common.base.Optional;
import com.google.common.base.Preconditions;
import com.google.common.base.Predicate;
import com.google.common.collect.Iterables;
@@ -363,6 +364,16 @@ class OsgiArchiveInstaller {
try {
init();
+
+ // Before even trying to find or download the bundle, check if it is supposed to be forcibly replaced.
+ // If so, return the replacement (if any).
+ if (suppliedKnownBundleMetadata != null && suppliedKnownBundleMetadata.isNameResolved()) {
+ Maybe<VersionedName> forcedReplacementBundle = CatalogUpgrades.tryGetBundleForcedReplaced(mgmt(), suppliedKnownBundleMetadata.getVersionedName());
+ if (forcedReplacementBundle.isPresent()) {
+ return generateForciblyRemovedResult(suppliedKnownBundleMetadata.getVersionedName(), Optional.fromNullable(forcedReplacementBundle.get()));
+ }
+ }
+
makeLocalZipFileFromInputStreamOrUrl();
if (result.code!=null) return ReferenceWithError.newInstanceWithoutError(result);
discoverManifestFromCatalogBom(false);
@@ -437,13 +448,19 @@ class OsgiArchiveInstaller {
}
} else {
// No such Brooklyn-managed bundle.
-
+
// Check if likely-looking bundle already installed to OSGi subsystem, but brooklyn not aware of it.
// This will often happen on a karaf restart where bundle was cached by karaf, so we need to allow it;
// can also happen if brooklyn.libraries references an existing bundle.
//
// If we're not certain that the bundle is identical
+ // First check if this bundle is forcibly removed (and optionally upgraded).
+ // If so, don't install it - return the replacement, if any.
+ Maybe<VersionedName> forcedReplacementBundle = CatalogUpgrades.tryGetBundleForcedReplaced(mgmt(), inferredMetadata.getVersionedName());
+ if (forcedReplacementBundle.isPresent()) {
+ return generateForciblyRemovedResult(inferredMetadata.getVersionedName(), Optional.fromNullable(forcedReplacementBundle.get()));
+ }
result.metadata = inferredMetadata;
@@ -699,7 +716,29 @@ class OsgiArchiveInstaller {
close();
}
}
-
+
+ private ReferenceWithError<OsgiBundleInstallationResult> generateForciblyRemovedResult(VersionedName desiredBundle, Optional<VersionedName> replacementBundle) {
+ if (replacementBundle.isPresent()) {
+ result.metadata = osgiManager.getManagedBundle(replacementBundle.get());
+ if (result.getMetadata() != null) {
+ result.bundle = osgiManager.framework.getBundleContext().getBundle(result.getMetadata().getOsgiUniqueUrl());
+
+ log.debug("Bundle "+inferredMetadata+" forcibly replaced by bundle "+result.getMetadata()
+ +"; install is no-op");
+ result.setIgnoringForciblyRemoved(inferredMetadata.getVersionedName(), replacementBundle);
+ return ReferenceWithError.newInstanceWithoutError(result);
+ } else {
+ throw new IllegalArgumentException("Bundle "+inferredMetadata+" forcibly replaced by bundle "
+ +replacementBundle.get()+", but replacement not found");
+ }
+ } else {
+ log.debug("Bundle "+inferredMetadata+" forcibly removed, but no upgrade bundle supplied"
+ + "; install is no-op");
+ result.setIgnoringForciblyRemoved(inferredMetadata.getVersionedName(), Optional.absent());
+ return ReferenceWithError.newInstanceWithoutError(result);
+ }
+ }
+
@VisibleForTesting
boolean isBlacklistedForPersistence(ManagedBundle managedBundle) {
// We treat as "managed bundles" (to extract their catalog.bom) the contents of:
http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/b9710776/core/src/main/java/org/apache/brooklyn/core/mgmt/ha/OsgiBundleInstallationResult.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/core/mgmt/ha/OsgiBundleInstallationResult.java b/core/src/main/java/org/apache/brooklyn/core/mgmt/ha/OsgiBundleInstallationResult.java
index 68106d4..8c5b6dd 100644
--- a/core/src/main/java/org/apache/brooklyn/core/mgmt/ha/OsgiBundleInstallationResult.java
+++ b/core/src/main/java/org/apache/brooklyn/core/mgmt/ha/OsgiBundleInstallationResult.java
@@ -27,6 +27,7 @@ import org.apache.brooklyn.util.osgi.VersionedName;
import org.osgi.framework.Bundle;
import com.google.common.annotations.Beta;
+import com.google.common.base.Optional;
import com.google.common.collect.ImmutableList;
@Beta
@@ -44,6 +45,9 @@ public class OsgiBundleInstallationResult {
* (safe in that behaviour won't be different or dangerous;
* could potentially be surprising, but ability to idempotently install things is nicer) */
IGNORING_BUNDLE_AREADY_INSTALLED(false),
+ /** Bundle has been forcibly removed; not installing;
+ * bundle metadata for an upgrade may be returned, if there is one */
+ IGNORING_BUNDLE_FORCIBLY_REMOVED(false),
/** bundle could not be made insto a state where it could be installed; bundle is not installed, even if forced */
ERROR_PREPARING_BUNDLE(true),
/** bundle successfully installed to OSGi container but there was an error launching it,
@@ -98,6 +102,12 @@ public class OsgiBundleInstallationResult {
message = "Bundle "+getMetadata().getVersionedName()+" already installed as "+getMetadata().getId();
}
+ void setIgnoringForciblyRemoved(VersionedName requestedBundle, Optional<VersionedName> replacementBundle) {
+ code = OsgiBundleInstallationResult.ResultCode.IGNORING_BUNDLE_FORCIBLY_REMOVED;
+ message = "Bundle "+requestedBundle+" forcibly removed, "
+ +(replacementBundle.isPresent() ? "upgraded to "+replacementBundle.get().getOsgiVersionString() : "no upgrade defined");
+ }
+
@Override
public String toString() {
return OsgiBundleInstallationResult.class.getSimpleName()+"["+code+", "+metadata+", "+message+"]";
http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/b9710776/core/src/main/java/org/apache/brooklyn/core/typereg/BundleUpgradeParser.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/core/typereg/BundleUpgradeParser.java b/core/src/main/java/org/apache/brooklyn/core/typereg/BundleUpgradeParser.java
index d808c24..8b16d69 100644
--- a/core/src/main/java/org/apache/brooklyn/core/typereg/BundleUpgradeParser.java
+++ b/core/src/main/java/org/apache/brooklyn/core/typereg/BundleUpgradeParser.java
@@ -308,9 +308,11 @@ public class BundleUpgradeParser {
public Set<VersionedName> getUpgradesForBundle(VersionedName bundle) {
return findUpgradesIn(bundle, upgradesProvidedByBundles);
}
+
public Set<VersionedName> getUpgradesForType(VersionedName type) {
return findUpgradesIn(type, upgradesProvidedByTypes);
}
+
private static Set<VersionedName> findUpgradesIn(VersionedName item, Multimap<VersionedName,VersionRangedName> upgradesMap) {
Set<VersionedName> result = new TreeSet<>(VersionedNameComparator.INSTANCE);
for (Map.Entry<VersionedName,VersionRangedName> n: upgradesMap.entries()) {
@@ -350,6 +352,42 @@ public class BundleUpgradeParser {
return builder().build();
}
+ /**
+ * If the given bundle (vName) has been forcibly removed, return the bundle that
+ * upgrades it (if any).
+ *
+ * The result will be one of:
+ * <ul>
+ * <li>{@code Maybe.absent} if the bundle has not been forcibly removed
+ * <li>{@code Maybe.of(replacementBundle} if the bundle has been forcibly removed
+ * and there is a bundle for upgrading it.
+ * <li>{@code Maybe.of(null} if the bundle has been forcibly removed, but there is no upgrade available.
+ * </ul>
+ *
+ * See {@link BundleUpgradeParser#MANIFEST_HEADER_FORCE_REMOVE_BUNDLES}
+ */
+ @Beta
+ public static Maybe<VersionedName> tryGetBundleForcedReplaced(ManagementContext mgmt, VersionedName vName) {
+ // mgmt can be null in some edge cases, eg BasicCatalogItemRebindSupport.possiblyUpgradedBundle
+ if (vName==null || mgmt==null) return Maybe.absent();
+ Maybe<OsgiManager> osgi = ((ManagementContextInternal)mgmt).getOsgiManager();
+ if (osgi.isAbsent()) {
+ // ignore upgrades if not osgi
+ return Maybe.absent();
+ }
+
+ CatalogUpgrades cu = getFromManagementContext(mgmt);
+ if (!cu.isBundleRemoved(vName)) {
+ return Maybe.absent();
+ }
+ Set<VersionedName> upgrades = cu.getUpgradesForBundle(vName);
+ if (upgrades.isEmpty()) {
+ return Maybe.of((VersionedName)null);
+ } else {
+ return Maybe.of(upgrades.iterator().next());
+ }
+ }
+
@Beta
public static String getBundleUpgradedIfNecessary(ManagementContext mgmt, String vName) {
// mgmt can be null in some edge cases, eg BasicCatalogItemRebindSupport.possiblyUpgradedBundle
@@ -365,6 +403,7 @@ public class BundleUpgradeParser {
}
return getItemUpgradedIfNecessary(mgmt, vName, (cu,vn) -> cu.getUpgradesForBundle(vn));
}
+
@Beta
public static String getTypeUpgradedIfNecessary(ManagementContext mgmt, String vName) {
if (vName==null || mgmt.getTypeRegistry().get(vName)!=null) {
http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/b9710776/launcher/src/test/java/org/apache/brooklyn/launcher/BrooklynLauncherUpgradeCatalogOsgiTest.java
----------------------------------------------------------------------
diff --git a/launcher/src/test/java/org/apache/brooklyn/launcher/BrooklynLauncherUpgradeCatalogOsgiTest.java b/launcher/src/test/java/org/apache/brooklyn/launcher/BrooklynLauncherUpgradeCatalogOsgiTest.java
index 3bd73dc..01c2b68 100644
--- a/launcher/src/test/java/org/apache/brooklyn/launcher/BrooklynLauncherUpgradeCatalogOsgiTest.java
+++ b/launcher/src/test/java/org/apache/brooklyn/launcher/BrooklynLauncherUpgradeCatalogOsgiTest.java
@@ -21,6 +21,9 @@ package org.apache.brooklyn.launcher;
import static org.apache.brooklyn.core.typereg.BundleUpgradeParser.MANIFEST_HEADER_FORCE_REMOVE_BUNDLES;
import static org.apache.brooklyn.core.typereg.BundleUpgradeParser.MANIFEST_HEADER_FORCE_REMOVE_LEGACY_ITEMS;
import static org.apache.brooklyn.core.typereg.BundleUpgradeParser.MANIFEST_HEADER_UPGRADE_FOR_BUNDLES;
+import static org.testng.Assert.assertEquals;
+import static org.testng.Assert.assertNull;
+import static org.testng.Assert.assertTrue;
import java.io.File;
import java.net.URI;
@@ -29,6 +32,9 @@ import org.apache.brooklyn.api.entity.Application;
import org.apache.brooklyn.api.entity.Entity;
import org.apache.brooklyn.api.entity.Group;
import org.apache.brooklyn.core.catalog.internal.CatalogInitialization;
+import org.apache.brooklyn.core.mgmt.ha.OsgiBundleInstallationResult;
+import org.apache.brooklyn.core.mgmt.ha.OsgiBundleInstallationResult.ResultCode;
+import org.apache.brooklyn.util.exceptions.ReferenceWithError;
import org.apache.brooklyn.util.osgi.VersionedName;
import org.testng.Assert;
import org.testng.annotations.BeforeMethod;
@@ -205,4 +211,201 @@ public class BrooklynLauncherUpgradeCatalogOsgiTest extends AbstractBrooklynLaun
launcher.terminate();
}
+
+ @Test
+ public void testForciblyRemovedBundleNotAdded() throws Exception {
+ runForciblyRemovedBundleNotAdded(true);
+ }
+
+ @Test
+ public void testForciblyRemovedBundleNotAddedWithNoUpgradeTarget() throws Exception {
+ runForciblyRemovedBundleNotAdded(false);
+ }
+
+ protected void runForciblyRemovedBundleNotAdded(boolean hasUpgradeForBundle) throws Exception {
+ VersionedName one_1_0_0 = VersionedName.fromString("one:1.0.0");
+ VersionedName one_2_0_0 = VersionedName.fromString("one:2.0.0");
+
+ BundleFile bundleV1 = bundleBuilder()
+ .name("org.example.bundleBeingUpgraded", "1.0.0")
+ .catalogBom(ImmutableList.<URI>of(), ImmutableSet.<VersionedName>of(one_1_0_0))
+ .build();
+
+ // A bundle that references the forcibly-replaced bundle via url;
+ // (add this to persisted state).
+ BundleFile bundleWithReferenceUrl = bundleBuilder()
+ .name("org.example.bundleWithReferenceUrl", "1.0.0")
+ .catalogBom(Joiner.on("\n").join(
+ "brooklyn.catalog:",
+ " version: 1.0.0",
+ " brooklyn.libraries:",
+ " - "+bundleV1.getFile().toURI()))
+ .build();
+
+ newPersistedStateInitializer()
+ .bundle(bundleV1)
+ .bundle(bundleWithReferenceUrl)
+ .initState();
+
+ BundleFile bundleV2 = bundleBuilder()
+ .name(bundleV1.getVersionedName().getSymbolicName(), "2.0.0")
+ .catalogBom(ImmutableList.<URI>of(), ImmutableSet.<VersionedName>of(one_2_0_0))
+ .manifestLines(ImmutableMap.<String, String>builder()
+ .put(MANIFEST_HEADER_FORCE_REMOVE_BUNDLES, "\"*\"")
+ .put(hasUpgradeForBundle ? MANIFEST_HEADER_UPGRADE_FOR_BUNDLES : "disabled-upgrade", "\"*\"")
+ .build())
+ .build();
+
+ File initialBomFile = newTmpFile(createCatalogYaml(ImmutableList.of(bundleV2.getFile().toURI()), ImmutableList.of()));
+
+ BrooklynLauncher launcher = newLauncherForTests(initialBomFile.getAbsolutePath());
+ launcher.start();
+ assertHealthyMaster(launcher);
+ assertCatalogConsistsOfIds(launcher, ImmutableList.of(one_2_0_0));
+ assertManagedBundle(launcher, bundleV2.getVersionedName(), ImmutableSet.<VersionedName>of(one_2_0_0));
+ assertNotManagedBundle(launcher, bundleV1.getVersionedName());
+
+ // Try installing the removed bundle explicitly (force=false)
+ ReferenceWithError<OsgiBundleInstallationResult> resultWithoutForce = installBundle(launcher, bundleV1.getFile(), false);
+ resultWithoutForce.checkNoError();
+ ResultCode resultWithoutForceCode = resultWithoutForce.get().getCode();
+ String resultWithoutForceMessage = resultWithoutForce.get().getMessage();
+ assertEquals(resultWithoutForceCode, ResultCode.IGNORING_BUNDLE_FORCIBLY_REMOVED);
+ if (hasUpgradeForBundle) {
+ assertEquals(resultWithoutForce.get().getMetadata().getVersionedName(), bundleV2.getVersionedName());
+ assertTrue(resultWithoutForceMessage.contains("Bundle "+bundleV1.getVersionedName()+" forcibly removed, upgraded to 2.0.0"), "msg="+resultWithoutForceMessage);
+ } else {
+ assertNull(resultWithoutForce.get().getMetadata());
+ assertTrue(resultWithoutForceMessage.contains("Bundle "+bundleV1.getVersionedName()+" forcibly removed, no upgrade defined"), "msg="+resultWithoutForceMessage);
+ }
+
+ // Try installing the removed bundle explicitly (force=true)
+ ReferenceWithError<OsgiBundleInstallationResult> resultWithForce = installBundle(launcher, bundleV1.getFile(), true);
+ resultWithForce.checkNoError();
+ ResultCode resultWithForceCode = resultWithForce.get().getCode();
+ String resultWithForceMessage = resultWithForce.get().getMessage();
+ assertEquals(resultWithForceCode, ResultCode.IGNORING_BUNDLE_FORCIBLY_REMOVED);
+ if (hasUpgradeForBundle) {
+ assertEquals(resultWithForce.get().getMetadata().getVersionedName(), bundleV2.getVersionedName());
+ assertTrue(resultWithForceMessage.contains("Bundle "+bundleV1.getVersionedName()+" forcibly removed, upgraded to 2.0.0"), "msg="+resultWithForceMessage);
+ } else {
+ assertNull(resultWithoutForce.get().getMetadata());
+ assertTrue(resultWithForceMessage.contains("Bundle "+bundleV1.getVersionedName()+" forcibly removed, no upgrade defined"), "msg="+resultWithForceMessage);
+ }
+
+ launcher.terminate();
+ }
+
+ @Test
+ public void testForciblyRemovedBundleNotAddedWhenReferencedByName() throws Exception {
+ VersionedName one_1_0_0 = VersionedName.fromString("one:1.0.0");
+ VersionedName one_2_0_0 = VersionedName.fromString("one:2.0.0");
+
+ BundleFile bundleV1 = bundleBuilder()
+ .name("org.example.bundleBeingUpgraded", "1.0.0")
+ .catalogBom(ImmutableList.<URI>of(), ImmutableSet.<VersionedName>of(one_1_0_0))
+ .build();
+
+ // A bundle that references the forcibly-replaced bundle via name:version;
+ // (add this to persisted state).
+ BundleFile bundleWithReferenceByNameVersionName = bundleBuilder()
+ .name("org.example.bundleWithReferenceByName", "1.0.0")
+ .catalogBom(Joiner.on("\n").join(
+ "brooklyn.catalog:",
+ " version: 1.0.0",
+ " brooklyn.libraries:",
+ " - name: "+bundleV1.getVersionedName().getSymbolicName(),
+ " version: 1.0.0"))
+ .build();
+
+ newPersistedStateInitializer()
+ .bundle(bundleV1)
+ .bundle(bundleWithReferenceByNameVersionName)
+ .initState();
+
+ BundleFile bundleV2 = bundleBuilder()
+ .name(bundleV1.getVersionedName().getSymbolicName(), "2.0.0")
+ .catalogBom(ImmutableList.<URI>of(), ImmutableSet.<VersionedName>of(one_2_0_0))
+ .manifestLines(ImmutableMap.<String, String>builder()
+ .put(MANIFEST_HEADER_FORCE_REMOVE_BUNDLES, "\"*\"")
+ .put(MANIFEST_HEADER_UPGRADE_FOR_BUNDLES, "\"*\"")
+ .build())
+ .build();
+
+ File initialBomFile = newTmpFile(createCatalogYaml(ImmutableList.of(bundleV2.getFile().toURI()), ImmutableList.of()));
+
+ BrooklynLauncher launcher = newLauncherForTests(initialBomFile.getAbsolutePath());
+ launcher.start();
+ assertHealthyMaster(launcher);
+ assertCatalogConsistsOfIds(launcher, ImmutableList.of(one_2_0_0));
+ assertManagedBundle(launcher, bundleV2.getVersionedName(), ImmutableSet.<VersionedName>of(one_2_0_0));
+ assertNotManagedBundle(launcher, bundleV1.getVersionedName());
+
+ // Try installing the removed bundle explicitly (force=false)
+ ReferenceWithError<OsgiBundleInstallationResult> resultWithoutForce = installBundle(launcher, bundleV1.getFile(), false);
+ resultWithoutForce.checkNoError();
+ ResultCode resultWithoutForceCode = resultWithoutForce.get().getCode();
+ String resultWithoutForceMessage = resultWithoutForce.get().getMessage();
+ assertEquals(resultWithoutForceCode, ResultCode.IGNORING_BUNDLE_FORCIBLY_REMOVED);
+ assertEquals(resultWithoutForce.get().getMetadata().getVersionedName(), bundleV2.getVersionedName());
+ assertTrue(resultWithoutForceMessage.contains("Bundle "+bundleV1.getVersionedName()+" forcibly removed, upgraded to 2.0.0"), "msg="+resultWithoutForceMessage);
+
+ launcher.terminate();
+ }
+
+ @Test
+ public void testForciblyRemovedBundleNotAddedWhenReferencedByMvnUrl() throws Exception {
+ VersionedName one_1_0_0 = VersionedName.fromString("one:1.0.0");
+ VersionedName one_2_0_0 = VersionedName.fromString("one:2.0.0");
+
+ BundleFile bundleV1 = bundleBuilder()
+ .name("org.example.bundleBeingUpgraded", "1.0.0")
+ .catalogBom(ImmutableList.<URI>of(), ImmutableSet.<VersionedName>of(one_1_0_0))
+ .build();
+
+ // A bundle that references the forcibly-replaced bundle via name:version;
+ // (add this to persisted state).
+ BundleFile bundleWithReferenceByNameVersionName = bundleBuilder()
+ .name("org.example.bundleWithReferenceByName", "1.0.0")
+ .catalogBom(Joiner.on("\n").join(
+ "brooklyn.catalog:",
+ " version: 1.0.0",
+ " brooklyn.libraries:",
+ " - mvn:org.example/bundleWithReferenceByName/1.0.0"))
+ .build();
+
+ newPersistedStateInitializer()
+ .bundle(bundleV1)
+ .bundle(bundleWithReferenceByNameVersionName)
+ .initState();
+
+ BundleFile bundleV2 = bundleBuilder()
+ .name(bundleV1.getVersionedName().getSymbolicName(), "2.0.0")
+ .catalogBom(ImmutableList.<URI>of(), ImmutableSet.<VersionedName>of(one_2_0_0))
+ .manifestLines(ImmutableMap.<String, String>builder()
+ .put(MANIFEST_HEADER_FORCE_REMOVE_BUNDLES, "\"*\"")
+ .put(MANIFEST_HEADER_UPGRADE_FOR_BUNDLES, "\"*\"")
+ .build())
+ .build();
+
+ File initialBomFile = newTmpFile(createCatalogYaml(ImmutableList.of(bundleV2.getFile().toURI()), ImmutableList.of()));
+
+ BrooklynLauncher launcher = newLauncherForTests(initialBomFile.getAbsolutePath());
+ launcher.start();
+ assertHealthyMaster(launcher);
+ assertCatalogConsistsOfIds(launcher, ImmutableList.of(one_2_0_0));
+ assertManagedBundle(launcher, bundleV2.getVersionedName(), ImmutableSet.<VersionedName>of(one_2_0_0));
+ assertNotManagedBundle(launcher, bundleV1.getVersionedName());
+
+ // Try installing the removed bundle explicitly (force=false)
+ ReferenceWithError<OsgiBundleInstallationResult> resultWithoutForce = installBundle(launcher, bundleV1.getFile(), false);
+ resultWithoutForce.checkNoError();
+ ResultCode resultWithoutForceCode = resultWithoutForce.get().getCode();
+ String resultWithoutForceMessage = resultWithoutForce.get().getMessage();
+ assertEquals(resultWithoutForceCode, ResultCode.IGNORING_BUNDLE_FORCIBLY_REMOVED);
+ assertEquals(resultWithoutForce.get().getMetadata().getVersionedName(), bundleV2.getVersionedName());
+ assertTrue(resultWithoutForceMessage.contains("Bundle "+bundleV1.getVersionedName()+" forcibly removed, upgraded to 2.0.0"), "msg="+resultWithoutForceMessage);
+
+ launcher.terminate();
+ }
}