more tests, warning messages, prep for upgrading bundles and types
Project: http://git-wip-us.apache.org/repos/asf/brooklyn-server/repo Commit: http://git-wip-us.apache.org/repos/asf/brooklyn-server/commit/9173183f Tree: http://git-wip-us.apache.org/repos/asf/brooklyn-server/tree/9173183f Diff: http://git-wip-us.apache.org/repos/asf/brooklyn-server/diff/9173183f Branch: refs/heads/master Commit: 9173183f247add9a99316c6f5276b28a45429d62 Parents: d64ca16 Author: Alex Heneveld <[email protected]> Authored: Mon Oct 30 22:38:03 2017 +0000 Committer: Alex Heneveld <[email protected]> Committed: Tue Oct 31 01:07:44 2017 +0000 ---------------------------------------------------------------------- .../brooklyn/api/mgmt/ManagementContext.java | 3 +- .../CatalogOsgiVersionMoreEntityRebindTest.java | 2 +- .../mgmt/internal/LocalManagementContext.java | 1 + .../mgmt/rebind/RebindExceptionHandlerImpl.java | 2 +- .../core/mgmt/rebind/RebindIteration.java | 44 +++++++--- .../core/typereg/BundleUpgradeParser.java | 87 +++++++++++++++++++- .../AbstractBrooklynLauncherRebindTest.java | 18 +++- .../BrooklynLauncherRebindCatalogOsgiTest.java | 72 +++++++++++++--- .../BrooklynLauncherUpgradeCatalogOsgiTest.java | 48 +++++++++++ 9 files changed, 246 insertions(+), 31 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/9173183f/api/src/main/java/org/apache/brooklyn/api/mgmt/ManagementContext.java ---------------------------------------------------------------------- diff --git a/api/src/main/java/org/apache/brooklyn/api/mgmt/ManagementContext.java b/api/src/main/java/org/apache/brooklyn/api/mgmt/ManagementContext.java index 2c615ed..4ad9718 100644 --- a/api/src/main/java/org/apache/brooklyn/api/mgmt/ManagementContext.java +++ b/api/src/main/java/org/apache/brooklyn/api/mgmt/ManagementContext.java @@ -243,7 +243,8 @@ public interface ManagementContext { @Beta // see comment on isRunning() as items might move to a status handler public boolean isStartupComplete(); - /** Returns node state, always reporting {@link ManagementNodeState#INITIALIZING} if there is any transition. + /** Returns node state, always reporting {@link ManagementNodeState#INITIALIZING} if there is any transition + * and {@link ManagementNodeState#FAILED} if there are any server errors. * If this returns {@link ManagementNodeState#MASTER} we can guarantee the node to be in master state, * unlike {@link HighAvailabilityManager#getNodeState()} which may return {@link ManagementNodeState#MASTER} slightly early. */ http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/9173183f/camp/camp-brooklyn/src/test/java/org/apache/brooklyn/camp/brooklyn/catalog/CatalogOsgiVersionMoreEntityRebindTest.java ---------------------------------------------------------------------- diff --git a/camp/camp-brooklyn/src/test/java/org/apache/brooklyn/camp/brooklyn/catalog/CatalogOsgiVersionMoreEntityRebindTest.java b/camp/camp-brooklyn/src/test/java/org/apache/brooklyn/camp/brooklyn/catalog/CatalogOsgiVersionMoreEntityRebindTest.java index 64cd99e..835609d 100644 --- a/camp/camp-brooklyn/src/test/java/org/apache/brooklyn/camp/brooklyn/catalog/CatalogOsgiVersionMoreEntityRebindTest.java +++ b/camp/camp-brooklyn/src/test/java/org/apache/brooklyn/camp/brooklyn/catalog/CatalogOsgiVersionMoreEntityRebindTest.java @@ -274,7 +274,7 @@ public class CatalogOsgiVersionMoreEntityRebindTest extends AbstractYamlRebindTe Asserts.shouldHaveFailedPreviously("Expected deployment to fail rebind; instead got "+app2); } catch (Exception e) { // should fail to rebind this entity - Asserts.expectedFailureContainsIgnoreCase(e, more.getId(), "unable to load", BROOKLYN_TEST_MORE_ENTITIES_MORE_ENTITY); + Asserts.expectedFailureContainsIgnoreCase(e, more.getId(), "class", BROOKLYN_TEST_MORE_ENTITIES_MORE_ENTITY, "not found"); } } http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/9173183f/core/src/main/java/org/apache/brooklyn/core/mgmt/internal/LocalManagementContext.java ---------------------------------------------------------------------- diff --git a/core/src/main/java/org/apache/brooklyn/core/mgmt/internal/LocalManagementContext.java b/core/src/main/java/org/apache/brooklyn/core/mgmt/internal/LocalManagementContext.java index d6c69d4..e5af9b1 100644 --- a/core/src/main/java/org/apache/brooklyn/core/mgmt/internal/LocalManagementContext.java +++ b/core/src/main/java/org/apache/brooklyn/core/mgmt/internal/LocalManagementContext.java @@ -453,6 +453,7 @@ public class LocalManagementContext extends AbstractManagementContext { public ManagementNodeState getNodeState() { synchronized (startupSynchObject) { if (!startupComplete) return ManagementNodeState.INITIALIZING; + if (!errors().isEmpty()) return ManagementNodeState.FAILED; return getHighAvailabilityManager().getNodeState(); } } http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/9173183f/core/src/main/java/org/apache/brooklyn/core/mgmt/rebind/RebindExceptionHandlerImpl.java ---------------------------------------------------------------------- diff --git a/core/src/main/java/org/apache/brooklyn/core/mgmt/rebind/RebindExceptionHandlerImpl.java b/core/src/main/java/org/apache/brooklyn/core/mgmt/rebind/RebindExceptionHandlerImpl.java index 17d4073..794161b 100644 --- a/core/src/main/java/org/apache/brooklyn/core/mgmt/rebind/RebindExceptionHandlerImpl.java +++ b/core/src/main/java/org/apache/brooklyn/core/mgmt/rebind/RebindExceptionHandlerImpl.java @@ -242,7 +242,7 @@ public class RebindExceptionHandlerImpl implements RebindExceptionHandler { if (danglingRefFailureMode == RebindManager.RebindFailureMode.FAIL_FAST) { throw new IllegalStateException("No catalog item found with id "+id); } else { - warn("No catalog item found with id "+id+"; dangling reference on rebind"); + warn("No catalog item found with id "+id+"; dangling reference on rebind (subsequent log messages will indicate context)"); return null; } } http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/9173183f/core/src/main/java/org/apache/brooklyn/core/mgmt/rebind/RebindIteration.java ---------------------------------------------------------------------- diff --git a/core/src/main/java/org/apache/brooklyn/core/mgmt/rebind/RebindIteration.java b/core/src/main/java/org/apache/brooklyn/core/mgmt/rebind/RebindIteration.java index 8a667eb..4751341 100644 --- a/core/src/main/java/org/apache/brooklyn/core/mgmt/rebind/RebindIteration.java +++ b/core/src/main/java/org/apache/brooklyn/core/mgmt/rebind/RebindIteration.java @@ -970,10 +970,15 @@ public abstract class RebindIteration { } @SuppressWarnings("unchecked") + // TODO should prefer a registered type as the type to load (in lieu of jType), + // but note some callers (enrichers etc) use catalogItemId to be the first entry in search path rather than their actual type, + // so until callers are all updated all we can do here is load the java type with no guarantee the catalogItemId should be the same. + // (yoml should help a lot with this.) protected <T extends BrooklynObject> LoadedClass<? extends T> load(Class<T> bType, String jType, String catalogItemId, List<String> searchPath, String contextSuchAsId) { checkNotNull(jType, "Type of %s (%s) must not be null", contextSuchAsId, bType.getSimpleName()); + List<String> warnings = MutableList.of(); List<String> reboundSearchPath = MutableList.of(); if (searchPath != null && !searchPath.isEmpty()) { for (String searchItemId : searchPath) { @@ -987,8 +992,7 @@ public abstract class RebindIteration { if (fixedSearchItemId != null) { reboundSearchPath.add(fixedSearchItemId); } else { - LOG.warn("Unable to load catalog item "+ searchItemId - + " for search path of "+contextSuchAsId + " (" + bType.getSimpleName()+"); attempting to load "+jType+" nevertheless"); + warnings.add("unable to resolve search path entry "+ searchItemId); } } } @@ -1016,23 +1020,31 @@ public abstract class RebindIteration { return new LoadedClass<T>(loader.loadClass(jType, bType), transformedCatalogItemId, reboundSearchPath); } catch (Exception e) { Exceptions.propagateIfFatal(e); - LOG.warn("Unable to load class "+jType+" needed for "+catalogItemId+" for "+contextSuchAsId+", via "+transformedCatalogItemId+" loader (will try reflections)"); + warnings.add("unable to load class "+jType+" for resovled context type "+transformedCatalogItemId); } } else { - LOG.warn("Unable to load catalog item "+catalogItemId+" ("+bType+") for " + contextSuchAsId + - " ("+bType.getSimpleName()+"); will try reflection"); + // TODO fail, rather than fallback to java? + warnings.add("unable to resolve context type "+catalogItemId); } + } else { + // can happen for enrichers etc added by java, and for BasicApplication when things are deployed; + // no need to warn } try { - return new LoadedClass<T>((Class<T>)loadClass(jType), catalogItemId, reboundSearchPath); + Class<T> jTypeC = (Class<T>)loadClass(jType); + if (!warnings.isEmpty()) { + LOG.warn("Loaded java type "+jType+" for "+bType.getSimpleName().toLowerCase()+" "+contextSuchAsId+" but had errors: "+Strings.join(warnings, ";")); + } + return new LoadedClass<T>(jTypeC, catalogItemId, reboundSearchPath); } catch (Exception e) { Exceptions.propagateIfFatal(e); - LOG.warn("Unable to load class "+jType+" needed for "+catalogItemId+" for "+contextSuchAsId+", via reflections (may try others, will throw if fails)"); } if (catalogItemId != null) { - throw new IllegalStateException("Unable to load "+jType+" for catalog item " + catalogItemId + " for " + contextSuchAsId); + String msg = "Class "+jType+" not found for "+bType.getSimpleName().toLowerCase()+" "+contextSuchAsId+" ("+catalogItemId+"): "+Strings.join(warnings, ";"); + LOG.warn(msg+" (rethrowing)"); + throw new IllegalStateException(msg); } else if (BrooklynFeatureEnablement.isEnabled(FEATURE_BACKWARDS_COMPATIBILITY_INFER_CATALOG_ITEM_ON_REBIND)) { //Try loading from whichever catalog bundle succeeds (legacy CI items only; also disabling this, as no longer needed 2017-09) @@ -1041,15 +1053,21 @@ public abstract class RebindIteration { BrooklynClassLoadingContext catalogLoader = CatalogUtils.newClassLoadingContext(managementContext, item); Maybe<Class<?>> catalogClass = catalogLoader.tryLoadClass(jType); if (catalogClass.isPresent()) { - LOG.warn("Found "+jType+" only by scanning catalog item search paths"); + LOG.warn("Falling back to java type "+jType+" for "+bType.getSimpleName().toLowerCase()+" "+contextSuchAsId+" using catalog search paths, found on "+item+ + (warnings.isEmpty() ? "" : ", after errors: "+Strings.join(warnings, ";"))); return new LoadedClass<T>((Class<? extends T>) catalogClass.get(), catalogItemId, reboundSearchPath); } } - throw new IllegalStateException("No catalogItemId specified for " + contextSuchAsId + - " and can't load class (" + jType + ") from either classpath or catalog items"); + String msg = "Class "+jType+" not found for "+bType.getSimpleName().toLowerCase()+" "+contextSuchAsId+", even after legacy global classpath search"+ + (warnings.isEmpty() ? "" : ": "+Strings.join(warnings, ";")); + LOG.warn(msg+" (rethrowing)"); + throw new IllegalStateException(msg); + } else { - throw new IllegalStateException("No catalogItemId specified for " + contextSuchAsId + - " and can't load class (" + jType + ") from classpath"); + String msg = "Class "+jType+" not found for "+bType.getSimpleName().toLowerCase()+" "+contextSuchAsId+ + (warnings.isEmpty() ? "" : ": "+Strings.join(warnings, ";")); + LOG.warn(msg+" (rethrowing)"); + throw new IllegalStateException(msg); } } http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/9173183f/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 e797137..bfac6c6 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 @@ -23,8 +23,10 @@ import static com.google.common.base.Preconditions.checkNotNull; import java.util.ArrayList; import java.util.Collection; import java.util.Dictionary; +import java.util.LinkedHashMap; import java.util.LinkedHashSet; import java.util.List; +import java.util.Map; import java.util.Set; import org.apache.brooklyn.api.catalog.CatalogItem; @@ -65,8 +67,8 @@ public class BundleUpgradeParser { * version 1.0.0 and its catalog.bom contains items "foo" and "bar", then it is equivalent * to writing {@code "foo:[0,1.0.0)","bar:[0,1.0.0)"}. * As per the comments on {@link #MANIFEST_HEADER_FORCE_REMOVE_BUNDLES}, - * the version of the bundle and items being added here to replace legacy catalog items - * should typically be larger in major/minor/point value + * the version of the bundle and items being added by a bundle to replace legacy catalog items + * should typically be larger in major/minor/point value, * as a qualifier bump can be quite complex due to ordering differences. * </ul> */ @@ -106,7 +108,84 @@ public class BundleUpgradeParser { */ @Beta public static final String MANIFEST_HEADER_FORCE_REMOVE_BUNDLES = "brooklyn-catalog-force-remove-bundles"; - + + /** + * A header in a bundle's manifest, indicating that this bundle recommends a set of upgrades. + * These will be advisory unless the bundle being upgraded is force-removed in which case it will be applied automatically + * wherever the bundle is in use. + * + * The format is a comma separate list of {@code key=value} pairs, where each key and value is a name with a version range + * (as per {@link #MANIFEST_HEADER_FORCE_REMOVE_BUNDLES}). The {@code =value} can be omitted, and usually is, + * to mean this bundle at this version. (The {@code =value} is available if one bundle is defining upgrades for other bundles.) + * + * A wildcard can be given as the key, without a version ({@code *}) or with ({@code *:[0,1)}) to refer to + * all previous versions (OSGi ordering, see below) or the indicated versions, respectively, of the bundle this manifest is defining. + * + * If this header is supplied and {@link #MANIFEST_HEADER_UPGRADE_FOR_TYPES} is omitted, the types to upgrade are inferred as + * being all types defined in the bundle this manifest is defining, and all versions of this bundle upgraded by this bundle + * according to this header. If this header is included but does not declare any versions of this bundle upgraded by this bundle, + * then {@link #MANIFEST_HEADER_UPGRADE_FOR_TYPES} must be explicitly set. + * + * Version ordering may be surprising particularly in regard to qualifiers. + * See {@link #MANIFEST_HEADER_FORCE_REMOVE_BUNDLES} for discussion of this. + * + * <p> + * + * In most use cases, one can provide a single line, e.g. if releasing a v2.0.0: + * + * {@code brooklyn-catalog-upgrade-for-bundles: *:[0,2)} + * + * to indicate that this bundle is able to upgrade all instances of this bundle lower than 2.0.0, + * and all types in this bundle will upgrade earlier types. + * + * This can be used in conjunction with: + * + * {@code brooklyn-catalog-force-remove-bundles: *:[0,2)} + * + * to forcibly remove older bundles at an appropriate point (eg a restart) and cause all earlier instances of the bundle + * and the type instances they contain to be upgraded with the same-named types in the 2.0.0 bundle. + * + * It is not necessary to supply {@link #MANIFEST_HEADER_UPGRADE_FOR_TYPES} unless types are being renamed + * or versions are not in line with previous versions of this bundle. + */ + @Beta + public static final String MANIFEST_HEADER_UPGRADE_FOR_BUNDLES = "brooklyn-catalog-upgrade-for-bundles"; + + /** + * A header in a bundle's manifest, indicating that this bundle recommends a set of upgrades. + * These will be advisory unless the type being upgraded is force-removed in which case it will be applied automatically + * wherever the type is in use. + * + * The format is as per {@link #MANIFEST_HEADER_UPGRADE_FOR_BUNDLES}, with two differences in interpretation. + * + * If {@code =value} is omitted, the ugprade target is assumed to be the same type as the corresonding key but at the + * version of the bundle. + * + * A wildcard can be given as the key, without a version ({@code *}) or with ({@code *:[0,1)}) to refer to + * all types in the present bundle. + * + * If the version/range for a type is omitted in any key, it is inferred as the versions of this bundle + * that this bundle declares it can upgrade in the {@link #MANIFEST_HEADER_UPGRADE_FOR_BUNDLES} header. + * It is an error to omit a version/range if that header is not present or does not declare versions + * of the same bundle being upgraded. + * + * If this key is omitted, then the default is {@code *} if a {@link #MANIFEST_HEADER_UPGRADE_FOR_BUNDLES} header + * is present and empty if that header is not present. + * + * What this is saying in most cases is that if a bundle {@code foo:1} contains {@code foo-node:1}, and + * bundle {@code foo:2} contains {@code foo-node:2}, then: + * if {@code foo:2} declares {@code brooklyn-catalog-upgrade-for-bundles: foo:1} it will also declare that + * {@code foo-node:2} upgrades {@code foo-node:1}; + * if {@code foo:2} declares {@code brooklyn-catalog-upgrade-for-bundles: *} the same thing will occur + * (and it would also upgrade a {@code foo:0} contains {@code foo-node:0}); + * if {@code foo:2} declares no {@code brooklyn-catalog-upgrade} manifest headers, then no advisory + * upgrades will be noted. + * + * As noted in {@link #MANIFEST_HEADER_UPGRADE_FOR_BUNDLES} the primary use case for this header is type renames. + */ + @Beta + public static final String MANIFEST_HEADER_UPGRADE_FOR_TYPES = "brooklyn-catalog-upgrade-for-types"; + /** * The result from parsing bundle(s) to find their upgrade info. */ @@ -116,6 +195,8 @@ public class BundleUpgradeParser { public static class Builder { private Set<VersionRangedName> removedLegacyItems = new LinkedHashSet<>(); private Set<VersionRangedName> removedBundles = new LinkedHashSet<>(); + private Map<VersionedName,VersionRangedName> upgradeBundles = new LinkedHashMap<>(); + private Map<VersionedName,VersionRangedName> upgradeTypes = new LinkedHashMap<>(); public Builder removedLegacyItems(Collection<VersionRangedName> vals) { removedLegacyItems.addAll(vals); http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/9173183f/launcher/src/test/java/org/apache/brooklyn/launcher/AbstractBrooklynLauncherRebindTest.java ---------------------------------------------------------------------- diff --git a/launcher/src/test/java/org/apache/brooklyn/launcher/AbstractBrooklynLauncherRebindTest.java b/launcher/src/test/java/org/apache/brooklyn/launcher/AbstractBrooklynLauncherRebindTest.java index 474c72b..461dce7 100644 --- a/launcher/src/test/java/org/apache/brooklyn/launcher/AbstractBrooklynLauncherRebindTest.java +++ b/launcher/src/test/java/org/apache/brooklyn/launcher/AbstractBrooklynLauncherRebindTest.java @@ -41,15 +41,22 @@ import javax.annotation.Nullable; import org.apache.brooklyn.api.catalog.BrooklynCatalog; import org.apache.brooklyn.api.catalog.CatalogItem; +import org.apache.brooklyn.api.entity.Application; +import org.apache.brooklyn.api.entity.Entity; +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.api.objs.BrooklynObjectType; import org.apache.brooklyn.api.typereg.BrooklynTypeRegistry; import org.apache.brooklyn.api.typereg.ManagedBundle; import org.apache.brooklyn.api.typereg.RegisteredType; +import org.apache.brooklyn.camp.brooklyn.spi.creation.CampTypePlanTransformer; import org.apache.brooklyn.core.catalog.internal.CatalogInitialization; +import org.apache.brooklyn.core.entity.trait.Startable; import org.apache.brooklyn.core.mgmt.internal.ManagementContextInternal; import org.apache.brooklyn.core.mgmt.persist.PersistMode; import org.apache.brooklyn.core.test.entity.LocalManagementContextForTests; +import org.apache.brooklyn.core.typereg.RegisteredTypeLoadingContexts; import org.apache.brooklyn.entity.stock.BasicEntity; import org.apache.brooklyn.util.collections.MutableMap; import org.apache.brooklyn.util.core.ResourceUtils; @@ -214,7 +221,7 @@ public abstract class AbstractBrooklynLauncherRebindTest { } protected void assertManagedBundle(BrooklynLauncher launcher, VersionedName bundleId, Set<VersionedName> expectedCatalogItems) { - assertNotNull(findManagedBundle(launcher, bundleId), bundleId+" not found"); + assertNotNull(findManagedBundle(launcher, bundleId), "Bundle "+bundleId+" not found"); Set<VersionedName> actualCatalogItems = new LinkedHashSet<>(); Iterable<RegisteredType> types = launcher.getManagementContext().getTypeRegistry().getAll(); @@ -402,4 +409,13 @@ public abstract class AbstractBrooklynLauncherRebindTest { launcher.terminate(); } } + + public static Application createAndStartApplication(ManagementContext mgmt, String input) throws Exception { + EntitySpec<?> spec = + mgmt.getTypeRegistry().createSpecFromPlan(CampTypePlanTransformer.FORMAT, input, RegisteredTypeLoadingContexts.spec(Application.class), EntitySpec.class); + final Entity app = mgmt.getEntityManager().createEntity(spec); + app.invoke(Startable.START, MutableMap.of()).get(); + return (Application) app; + } + } http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/9173183f/launcher/src/test/java/org/apache/brooklyn/launcher/BrooklynLauncherRebindCatalogOsgiTest.java ---------------------------------------------------------------------- diff --git a/launcher/src/test/java/org/apache/brooklyn/launcher/BrooklynLauncherRebindCatalogOsgiTest.java b/launcher/src/test/java/org/apache/brooklyn/launcher/BrooklynLauncherRebindCatalogOsgiTest.java index 119f341..b67a29e 100644 --- a/launcher/src/test/java/org/apache/brooklyn/launcher/BrooklynLauncherRebindCatalogOsgiTest.java +++ b/launcher/src/test/java/org/apache/brooklyn/launcher/BrooklynLauncherRebindCatalogOsgiTest.java @@ -30,16 +30,20 @@ import java.util.LinkedHashSet; import java.util.List; import java.util.Set; +import org.apache.brooklyn.api.entity.Application; +import org.apache.brooklyn.api.entity.Entity; import org.apache.brooklyn.api.mgmt.ManagementContext; import org.apache.brooklyn.api.mgmt.ha.HighAvailabilityMode; import org.apache.brooklyn.api.mgmt.ha.ManagementNodeState; import org.apache.brooklyn.api.objs.BrooklynObjectType; +import org.apache.brooklyn.api.typereg.RegisteredType; import org.apache.brooklyn.core.catalog.internal.BasicBrooklynCatalog; import org.apache.brooklyn.core.catalog.internal.CatalogInitialization; import org.apache.brooklyn.core.mgmt.ha.OsgiBundleInstallationResult; import org.apache.brooklyn.core.mgmt.ha.OsgiManager; import org.apache.brooklyn.core.mgmt.internal.ManagementContextInternal; import org.apache.brooklyn.core.mgmt.rebind.RebindTestUtils; +import org.apache.brooklyn.core.typereg.BundleUpgradeParser; import org.apache.brooklyn.test.Asserts; import org.apache.brooklyn.test.support.TestResourceUnavailableException; import org.apache.brooklyn.util.core.osgi.Osgis; @@ -49,6 +53,8 @@ import org.apache.brooklyn.util.os.Os; import org.apache.brooklyn.util.osgi.OsgiTestResources; import org.apache.brooklyn.util.osgi.VersionedName; import org.apache.brooklyn.util.text.Identifiers; +import org.apache.brooklyn.util.time.Duration; +import org.apache.brooklyn.util.time.Time; import org.osgi.framework.Bundle; import org.osgi.framework.launch.Framework; import org.testng.Assert; @@ -140,6 +146,10 @@ public abstract class BrooklynLauncherRebindCatalogOsgiTest extends AbstractBroo } protected void startT2(BrooklynLauncher l) { + startT2(l, true); + } + + protected void startT2(BrooklynLauncher l, boolean assertSuccess) { if (launcherT2!=null) throw new IllegalStateException("Already started T2 launcher"); try { @@ -153,7 +163,6 @@ public abstract class BrooklynLauncherRebindCatalogOsgiTest extends AbstractBroo l.highAvailabilityMode(HighAvailabilityMode.HOT_STANDBY); } l.start(); - Framework f = ((ManagementContextInternal)l.getManagementContext()).getOsgiManager().get().getFramework(); launcherLast = launcherT2 = l; if (isT1KeptRunningWhenT2Starts()) { assertHotStandbyNow(launcherT2); @@ -162,9 +171,14 @@ public abstract class BrooklynLauncherRebindCatalogOsgiTest extends AbstractBroo if (startupAssertions!=null) startupAssertions.run(); } protected void promoteT2IfStandby() { + promoteT2IfStandby(true); + } + protected void promoteT2IfStandby(boolean assertSuccess) { if (isT1KeptRunningWhenT2Starts()) { launcherT1.terminate(); - assertMasterEventually(launcherT2); + if (assertSuccess) { + assertMasterEventually(launcherT2); + } if (startupAssertions!=null) startupAssertions.run(); } @@ -449,8 +463,10 @@ public abstract class BrooklynLauncherRebindCatalogOsgiTest extends AbstractBroo } protected String getBundleSupplyingFirstType(Set<VersionedName> bundleItems) { - return VersionedName.fromString( launcherLast.getManagementContext().getTypeRegistry().get( - bundleItems.iterator().next().toString() ).getContainingBundle() ).getVersionString(); + RegisteredType type = launcherLast.getManagementContext().getTypeRegistry().get( + bundleItems.iterator().next().toString() ); + if (type==null) return null; + return VersionedName.fromString( type.getContainingBundle() ).getVersionString(); } @Test @@ -599,12 +615,34 @@ public abstract class BrooklynLauncherRebindCatalogOsgiTest extends AbstractBroo Assert.assertNotEquals(bundlePersistenceId1, bundlePersistenceId2); } } - - // TODO removed item in deployment fails - rebind and upgrade uses new item - // TODO removed item in deployment upgrades - rebind and upgrade uses new item - // TODO removed item in spec fails - // TODO removed item in spec upgrades - // TODO removed item deployed after rebind + + @Test + // might change this to fail in future, see RebindIteration.load + public void testRebindRemovedItemWorksIfJavaClassFound() throws Exception { + Set<VersionedName> bundleItemsV1 = ImmutableSet.of(VersionedName.fromString("one:1.0.0")); + String bundleBomV1 = createCatalogYaml(ImmutableList.of(), bundleItemsV1); + VersionedName bundleNameV1 = new VersionedName("org.example.testRebindGetsInitialOsgiCatalog", "1.0.0"); + File bundleFileV1 = newTmpBundle(ImmutableMap.of(BasicBrooklynCatalog.CATALOG_BOM, bundleBomV1.getBytes(StandardCharsets.UTF_8)), bundleNameV1); + File initialBomFileV1 = newTmpFile(createCatalogYaml(ImmutableList.of(bundleFileV1.toURI()), ImmutableList.of())); + + Set<VersionedName> bundleItemsV2 = ImmutableSet.of(VersionedName.fromString("one:2.0.0")); + String bundleBomV2 = createCatalogYaml(ImmutableList.of(), bundleItemsV2); + VersionedName bundleNameV2 = new VersionedName("org.example.testRebindGetsInitialOsgiCatalog", "2.0.0"); + File bundleFileV2 = newTmpBundle(ImmutableMap.of(BasicBrooklynCatalog.CATALOG_BOM, bundleBomV2.getBytes(StandardCharsets.UTF_8)), bundleNameV2, + ImmutableMap.of(BundleUpgradeParser.MANIFEST_HEADER_FORCE_REMOVE_BUNDLES, "*")); + File initialBomFileV2 = newTmpFile(createCatalogYaml(ImmutableList.of(bundleFileV2.toURI()), ImmutableList.of())); + + startT1(newLauncherForTests(initialBomFileV1.getAbsolutePath())); + Application app = createAndStartApplication(launcherLast.getManagementContext(), + "services: [ { type: 'one:1.0.0' } ]"); + + // should start and promote fine, but entity's type shouldn't be loadable (and there will be warnings) + startT2(newLauncherForTests(initialBomFileV2.getAbsolutePath())); + promoteT2IfStandby(); + + Entity entity = Iterables.getOnlyElement( Iterables.getOnlyElement(launcherLast.getManagementContext().getApplications()).getChildren() ); + Assert.assertEquals(entity.getCatalogItemId(), bundleItemsV1.iterator().next()); + } protected void assertPersistedBundleListingEqualsEventually(BrooklynLauncher launcher, Set<VersionedName> bundles) { Asserts.succeedsEventually(new Runnable() { @@ -703,5 +741,17 @@ public abstract class BrooklynLauncherRebindCatalogOsgiTest extends AbstractBroo String bundleBom = createCatalogYaml(ImmutableList.of(), ImmutableList.of(), catalogItems, randomNoise); return newTmpBundle(ImmutableMap.of(BasicBrooklynCatalog.CATALOG_BOM, bundleBom.getBytes(StandardCharsets.UTF_8)), bundleName); } - + + public static void main(String[] args) throws Exception { + try { + BrooklynLauncherRebindCatalogOsgiTest fixture = new LauncherRebindSubTests(); + fixture.setUp(); + fixture.testRebindRemovedItemWorksIfJavaClassFound(); + fixture.tearDown(); + } catch (Exception e) { + e.printStackTrace(); + System.exit(1); + } + System.exit(0); + } } http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/9173183f/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 a6f5129..289b96a 100644 --- a/launcher/src/test/java/org/apache/brooklyn/launcher/BrooklynLauncherUpgradeCatalogOsgiTest.java +++ b/launcher/src/test/java/org/apache/brooklyn/launcher/BrooklynLauncherUpgradeCatalogOsgiTest.java @@ -21,21 +21,26 @@ package org.apache.brooklyn.launcher; import static org.apache.brooklyn.core.catalog.internal.BasicBrooklynCatalog.CATALOG_BOM; 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 java.io.File; import java.net.URI; import java.nio.charset.StandardCharsets; import java.util.Map; +import org.apache.brooklyn.api.entity.Application; +import org.apache.brooklyn.api.entity.Entity; import org.apache.brooklyn.core.catalog.internal.BasicBrooklynCatalog; import org.apache.brooklyn.core.catalog.internal.CatalogInitialization; import org.apache.brooklyn.util.osgi.VersionedName; +import org.testng.Assert; import org.testng.annotations.BeforeMethod; import org.testng.annotations.Test; import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableMap; import com.google.common.collect.ImmutableSet; +import com.google.common.collect.Iterables; public class BrooklynLauncherUpgradeCatalogOsgiTest extends AbstractBrooklynLauncherRebindTest { @@ -144,4 +149,47 @@ public class BrooklynLauncherUpgradeCatalogOsgiTest extends AbstractBrooklynLaun assertManagedBundle(launcher, bundleVersionedName, ImmutableSet.<VersionedName>of(one_1_0_0)); launcher.terminate(); } + + // removed item with upgrade deployed after rebind + // TODO WIP + @Test + public void testForceUpgradeItemByRemovingBundle() throws Exception { + VersionedName one_1_0_0 = VersionedName.fromString("one:1.0.0"); + VersionedName one_2_0_0 = VersionedName.fromString("one:2.0.0"); + + String bundleSymbolicName = "org.example.testForceUpgradeBundle"; + VersionedName bundleVersionedName1 = new VersionedName(bundleSymbolicName, "1.0.0"); + String bundleBom1 = createCatalogYaml(ImmutableList.<URI>of(), ImmutableSet.<VersionedName>of(one_1_0_0)); + File bundleFile1 = newTmpBundle(ImmutableMap.of(BasicBrooklynCatalog.CATALOG_BOM, bundleBom1.getBytes(StandardCharsets.UTF_8)), bundleVersionedName1); + + newPersistedStateInitializer() + .bundle(bundleVersionedName1, bundleFile1) + .initState(); + + VersionedName bundleVersionedName2 = new VersionedName(bundleSymbolicName, "2.0.0"); + String bundleBom2 = createCatalogYaml(ImmutableList.<URI>of(), ImmutableSet.<VersionedName>of(one_2_0_0)); + Map<String, String> bundleManifest2 = ImmutableMap.of( + MANIFEST_HEADER_FORCE_REMOVE_BUNDLES, "\""+bundleSymbolicName+":[0.0.0,2.0.0)\"", + MANIFEST_HEADER_UPGRADE_FOR_BUNDLES, "*"); + File bundleFile2 = newTmpBundle(ImmutableMap.of(BasicBrooklynCatalog.CATALOG_BOM, bundleBom2.getBytes(StandardCharsets.UTF_8)), bundleVersionedName2, bundleManifest2); + + File initialBomFile = newTmpFile(createCatalogYaml(ImmutableList.of(bundleFile2.toURI()), ImmutableList.of())); + + BrooklynLauncher launcher = newLauncherForTests(initialBomFile.getAbsolutePath()); + launcher.start(); + + Application app = createAndStartApplication(launcher.getManagementContext(), + "services: [ { type: 'one:1.0.0' } ]"); + Entity one = Iterables.getOnlyElement( app.getChildren() ); + Assert.assertEquals(one.getCatalogItemId(), "one:2.0.0"); + + launcher.terminate(); + } + + // NB other related tests in BrooklynLauncherRebindCatalogOsgiTest: + // * removed item in deployment fails - rebind and upgrade uses new item + // * removed item in deployment upgrades - rebind and upgrade uses new item + // * removed item in spec fails + // * removed item in spec upgrades + }
