more code review/cleanup for catalog CLI especially around the official/final/unofficial initialization interplay with HA modes, so that after a node has been promoted to master, on subsequent promotions it doesn't re-apply the initializations
Project: http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/repo Commit: http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/commit/df21c711 Tree: http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/tree/df21c711 Diff: http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/diff/df21c711 Branch: refs/heads/master Commit: df21c7116adb94986c4cb2c8e12ec6b86d580048 Parents: 9cc7293 Author: Alex Heneveld <[email protected]> Authored: Mon May 25 11:24:55 2015 +0100 Committer: Alex Heneveld <[email protected]> Committed: Mon May 25 11:44:09 2015 +0100 ---------------------------------------------------------------------- .../catalog/internal/CatalogInitialization.java | 127 ++++++++++++++----- .../internal/CatalogItemDtoAbstract.java | 4 +- .../rebind/PeriodicDeltaChangeListener.java | 38 +++--- .../entity/rebind/RebindContextImpl.java | 6 +- .../brooklyn/entity/rebind/RebindIteration.java | 51 +++++--- .../entity/rebind/RebindManagerImpl.java | 2 +- .../ha/HighAvailabilityManagerImpl.java | 57 +++++---- .../internal/AbstractManagementContext.java | 4 +- usage/cli/src/main/java/brooklyn/cli/Main.java | 4 + .../java/brooklyn/cli/lister/ClassFinder.java | 2 +- .../brooklyn/launcher/BrooklynLauncher.java | 13 +- .../rest/filter/HaHotCheckResourceFilter.java | 2 +- .../rest/filter/HaMasterCheckFilter.java | 2 +- .../util/javalang/AggregateClassLoader.java | 2 +- 14 files changed, 212 insertions(+), 102 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/df21c711/core/src/main/java/brooklyn/catalog/internal/CatalogInitialization.java ---------------------------------------------------------------------- diff --git a/core/src/main/java/brooklyn/catalog/internal/CatalogInitialization.java b/core/src/main/java/brooklyn/catalog/internal/CatalogInitialization.java index 6f0b80e..8f45a8c 100644 --- a/core/src/main/java/brooklyn/catalog/internal/CatalogInitialization.java +++ b/core/src/main/java/brooklyn/catalog/internal/CatalogInitialization.java @@ -29,6 +29,7 @@ import brooklyn.catalog.CatalogItem; import brooklyn.config.BrooklynServerConfig; import brooklyn.management.ManagementContext; import brooklyn.management.ManagementContextInjectable; +import brooklyn.management.ha.ManagementNodeState; import brooklyn.management.internal.ManagementContextInternal; import brooklyn.util.ResourceUtils; import brooklyn.util.collections.MutableList; @@ -37,6 +38,7 @@ import brooklyn.util.exceptions.FatalRuntimeException; import brooklyn.util.exceptions.RuntimeInterruptedException; import brooklyn.util.flags.TypeCoercions; import brooklyn.util.guava.Maybe; +import brooklyn.util.javalang.JavaClassNames; import brooklyn.util.os.Os; import brooklyn.util.text.Strings; @@ -78,7 +80,15 @@ public class CatalogInitialization implements ManagementContextInjectable { private boolean disallowLocal = false; private List<Function<CatalogInitialization, Void>> callbacks = MutableList.of(); - private boolean hasRunBestEffort = false, hasRunOfficial = false, isPopulating = false; + private boolean + /** has run an unofficial initialization (i.e. an early load, triggered by an early read of the catalog) */ + hasRunUnofficialInitialization = false, + /** has run an official initialization, but it is not a permanent one (e.g. during a hot standby mode, or a run failed) */ + hasRunTransientOfficialInitialization = false, + /** has run an official initialization which is permanent (node is master, and the new catalog is now set) */ + hasRunFinalInitialization = false; + /** is running a populate method; used to prevent recursive loops */ + private boolean isPopulating = false; private ManagementContext managementContext; private boolean isStartingUp = false; @@ -97,6 +107,7 @@ public class CatalogInitialization implements ManagementContextInjectable { this(null, false, null, false); } + @Override public void injectManagementContext(ManagementContext managementContext) { Preconditions.checkNotNull(managementContext, "management context"); if (this.managementContext!=null && managementContext!=this.managementContext) @@ -127,56 +138,108 @@ public class CatalogInitialization implements ManagementContextInjectable { return reset; } - public boolean hasRunOfficial() { return hasRunOfficial; } - public boolean hasRunIncludingBestEffort() { return hasRunOfficial || hasRunBestEffort; } - - /** makes or updates the mgmt catalog, based on the settings in this class */ - public void populateCatalog(boolean needsInitial, Collection<CatalogItem<?, ?>> optionalItemsForResettingCatalog) { + /** Returns true if the canonical initialization has completed, + * that is, an initialization which is done when a node is rebinded as master + * (or an initialization done by the startup routines when not running persistence); + * see also {@link #hasRunAnyInitialization()}. */ + public boolean hasRunFinalInitialization() { return hasRunFinalInitialization; } + /** Returns true if an official initialization has run, + * even if it was a transient run, e.g. so that the launch sequence can tell whether rebind has triggered initialization */ + public boolean hasRunOfficialInitialization() { return hasRunFinalInitialization || hasRunTransientOfficialInitialization; } + /** Returns true if the initializer has run at all, + * including transient initializations which might be needed before a canonical becoming-master rebind, + * for instance because the catalog is being accessed before loading rebind information + * (done by {@link #populateUnofficial(BasicBrooklynCatalog)}) */ + public boolean hasRunAnyInitialization() { return hasRunFinalInitialization || hasRunTransientOfficialInitialization || hasRunUnofficialInitialization; } + + /** makes or updates the mgmt catalog, based on the settings in this class + * @param nodeState the management node for which this is being read; if master, then we expect this run to be the last one, + * and so subsequent applications should ignore any initialization data (e.g. on a subsequent promotion to master, + * after a master -> standby -> master cycle) + * @param needsInitialItemsLoaded whether the catalog needs the initial items loaded + * @param needsInitialItemsLoaded whether the catalog needs the additiona items loaded + * @param optionalExcplicitItemsForResettingCatalog + * if supplied, the catalog is reset to contain only these items, before calling any other initialization + * for use primarily when rebinding + */ + public void populateCatalog(ManagementNodeState nodeState, boolean needsInitialItemsLoaded, boolean needsAdditionsLoaded, Collection<CatalogItem<?, ?>> optionalExcplicitItemsForResettingCatalog) { + if (log.isDebugEnabled()) { + String message = "Populating catalog for "+nodeState+", needsInitial="+needsInitialItemsLoaded+", needsAdditional="+needsAdditionsLoaded+", explicitItems="+(optionalExcplicitItemsForResettingCatalog==null ? "null" : optionalExcplicitItemsForResettingCatalog.size())+"; from "+JavaClassNames.callerNiceClassAndMethod(1); + if (!ManagementNodeState.isHotProxy(nodeState)) { + log.debug(message); + } else { + // in hot modes, make this message trace so we don't get too much output then + log.trace(message); + } + } synchronized (populatingCatalogMutex) { try { + if (hasRunFinalInitialization() && (needsInitialItemsLoaded || needsAdditionsLoaded)) { + // if we have already run "final" then we should only ever be used to reset the catalog, + // not to initialize or add; e.g. we are being given a fixed list on a subsequent master rebind after the initial master rebind + log.warn("Catalog initialization called to populate initial, even though it has already run the final official initialization"); + } isPopulating = true; BasicBrooklynCatalog catalog = (BasicBrooklynCatalog) managementContext.getCatalog(); if (!catalog.getCatalog().isLoaded()) { catalog.load(); } else { - if (needsInitial && (hasRunOfficial || hasRunBestEffort)) { + if (needsInitialItemsLoaded && hasRunAnyInitialization()) { // an indication that something caused it to load early; not severe, but unusual - log.warn("Catalog initialization has not properly run but management context has a catalog; re-populating, possibly overwriting items installed during earlier access (it may have been an early web request)"); + if (hasRunTransientOfficialInitialization) { + log.debug("Catalog initialization now populating, but has noted a previous official run which was not final (probalby loaded while in a standby mode, or a previous run failed); overwriting any items installed earlier"); + } else { + log.warn("Catalog initialization now populating, but has noted a previous unofficial run (it may have been an early web request); overwriting any items installed earlier"); + } catalog.reset(ImmutableList.<CatalogItem<?,?>>of()); } } - hasRunOfficial = true; - populateCatalogImpl(catalog, needsInitial, optionalItemsForResettingCatalog); + populateCatalogImpl(catalog, needsInitialItemsLoaded, needsAdditionsLoaded, optionalExcplicitItemsForResettingCatalog); + if (nodeState == ManagementNodeState.MASTER) { + // TODO ideally this would remain false until it has *persisted* the changed catalog; + // if there is a subsequent startup failure the forced additions will not be persisted, + // but nor will they be loaded on a subsequent run. + // callers will have to restart a brooklyn, or reach into this class to change this field, + // or (recommended) manually adjust the catalog. + // TODO also, if a node comes up in standby, the addition might not take effector for a while + // + // however since these options are mainly for use on the very first brooklyn run, it's not such a big deal; + // once up and running the typical way to add items is via the REST API + hasRunFinalInitialization = true; + } } finally { - hasRunOfficial = true; + if (!hasRunFinalInitialization) { + hasRunTransientOfficialInitialization = true; + } isPopulating = false; } } } - private void populateCatalogImpl(BasicBrooklynCatalog catalog, boolean needsInitial, Collection<CatalogItem<?, ?>> optionalItemsForResettingCatalog) { + private void populateCatalogImpl(BasicBrooklynCatalog catalog, boolean needsInitialItemsLoaded, boolean needsAdditionsLoaded, Collection<CatalogItem<?, ?>> optionalItemsForResettingCatalog) { applyCatalogLoadMode(); if (optionalItemsForResettingCatalog!=null) { catalog.reset(optionalItemsForResettingCatalog); } - if (needsInitial) { + if (needsInitialItemsLoaded) { populateInitial(catalog); } - - populateAdditions(catalog); - populateViaCallbacks(catalog); + if (needsAdditionsLoaded) { + populateAdditions(catalog); + populateViaCallbacks(catalog); + } } private enum PopulateMode { YAML, XML, AUTODETECT } protected void populateInitial(BasicBrooklynCatalog catalog) { if (disallowLocal) { - if (!hasRunOfficial()) { - log.debug("CLI initial catalog not being read with disallow-local mode set."); + if (!hasRunFinalInitialization()) { + log.debug("CLI initial catalog not being read when local catalog load mode is disallowed."); } return; } @@ -201,13 +264,13 @@ public class CatalogInitialization implements ManagementContextInjectable { catalogUrl = Os.mergePaths(BrooklynServerConfig.getMgmtBaseDir( managementContext.getConfig() ), "catalog.bom"); if (new File(catalogUrl).exists()) { - populateInitialFromUri(catalog, "file:"+catalogUrl, PopulateMode.YAML); + populateInitialFromUri(catalog, new File(catalogUrl).toURI().toString(), PopulateMode.YAML); return; } catalogUrl = Os.mergePaths(BrooklynServerConfig.getMgmtBaseDir( managementContext.getConfig() ), "catalog.xml"); if (new File(catalogUrl).exists()) { - populateInitialFromUri(catalog, "file:"+catalogUrl, PopulateMode.XML); + populateInitialFromUri(catalog, new File(catalogUrl).toURI().toString(), PopulateMode.XML); return; } @@ -287,7 +350,7 @@ public class CatalogInitialization implements ManagementContextInjectable { if (Strings.isNonBlank(additionsUri)) { if (disallowLocal) { if (!hasRunAdditions) { - log.warn("CLI additions supplied but not supported in disallow-local mode; ignoring."); + log.warn("CLI additions supplied but not supported when catalog load mode disallows local loads; ignoring."); } return; } @@ -340,21 +403,27 @@ public class CatalogInitialization implements ManagementContextInjectable { } } - /** makes the catalog, warning if persistence is on and hasn't run yet - * (as the catalog will be subsequently replaced) */ - public void populateBestEffort(BasicBrooklynCatalog catalog) { + /** Creates the catalog based on parameters set here, if not yet loaded, + * but ignoring persisted state and warning if persistence is on and we are starting up + * (because the official persistence is preferred and the catalog will be subsequently replaced); + * for use when the catalog is accessed before persistence is completed. + * <p> + * This method is primarily used during testing, which in many cases does not enforce the full startup order + * and which wants a local catalog in any case. It may also be invoked if a client requests the catalog + * while the server is starting up. */ + public void populateUnofficial(BasicBrooklynCatalog catalog) { synchronized (populatingCatalogMutex) { - if (hasRunOfficial || hasRunBestEffort || isPopulating) return; - // if a thread calls back in to this, ie calling to it from a getCatalog() call while populating, - // it will own the mutex and observe isRunningBestEffort, returning quickly + // check isPopulating in case this method gets called from inside another populate call + if (hasRunAnyInitialization() || isPopulating) return; + log.debug("Populating catalog unofficially ("+catalog+")"); isPopulating = true; try { if (isStartingUp) { log.warn("Catalog access requested when not yet initialized; populating best effort rather than through recommended pathway. Catalog data may be replaced subsequently."); } - populateCatalogImpl(catalog, true, null); + populateCatalogImpl(catalog, true, true, null); } finally { - hasRunBestEffort = true; + hasRunUnofficialInitialization = true; isPopulating = false; } } http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/df21c711/core/src/main/java/brooklyn/catalog/internal/CatalogItemDtoAbstract.java ---------------------------------------------------------------------- diff --git a/core/src/main/java/brooklyn/catalog/internal/CatalogItemDtoAbstract.java b/core/src/main/java/brooklyn/catalog/internal/CatalogItemDtoAbstract.java index c6ff97e..131c26e 100644 --- a/core/src/main/java/brooklyn/catalog/internal/CatalogItemDtoAbstract.java +++ b/core/src/main/java/brooklyn/catalog/internal/CatalogItemDtoAbstract.java @@ -184,7 +184,9 @@ public abstract class CatalogItemDtoAbstract<T, SpecT> extends AbstractBrooklynO if (!Objects.equal(displayName, other.displayName)) return false; if (!Objects.equal(iconUrl, other.iconUrl)) return false; if (!Objects.equal(tags, other.tags)) return false; - // 'type' not checked, because deprecated, we might want to allow removal in future + // 'type' not checked, because deprecated, + // and in future we might want to allow it to be removed/blanked in some impls without affecting equality + // (in most cases it is the same as symbolicName so doesn't matter) return true; } http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/df21c711/core/src/main/java/brooklyn/entity/rebind/PeriodicDeltaChangeListener.java ---------------------------------------------------------------------- diff --git a/core/src/main/java/brooklyn/entity/rebind/PeriodicDeltaChangeListener.java b/core/src/main/java/brooklyn/entity/rebind/PeriodicDeltaChangeListener.java index f3861bc..4203b4b 100644 --- a/core/src/main/java/brooklyn/entity/rebind/PeriodicDeltaChangeListener.java +++ b/core/src/main/java/brooklyn/entity/rebind/PeriodicDeltaChangeListener.java @@ -166,9 +166,8 @@ public class PeriodicDeltaChangeListener implements ChangeListener { private DeltaCollector deltaCollector = new DeltaCollector(); - private volatile boolean running = false; - - private volatile boolean stopping = false, stopCompleted = false; + private enum ListenerState { INIT, RUNNING, STOPPING, STOPPED } + private volatile ListenerState state = ListenerState.INIT; private volatile ScheduledTask scheduledTask; @@ -197,18 +196,17 @@ public class PeriodicDeltaChangeListener implements ChangeListener { @SuppressWarnings("unchecked") public void start() { synchronized (startStopMutex) { - if (running || (scheduledTask!=null && !scheduledTask.isDone())) { + if (state==ListenerState.RUNNING || (scheduledTask!=null && !scheduledTask.isDone())) { LOG.warn("Request to start "+this+" when already running - "+scheduledTask+"; ignoring"); return; } - stopCompleted = false; - running = true; + state = ListenerState.RUNNING; Callable<Task<?>> taskFactory = new Callable<Task<?>>() { @Override public Task<Void> call() { return Tasks.<Void>builder().dynamic(false).name("periodic-persister").body(new Callable<Void>() { public Void call() { - persistNowSafely(false); + persistNowSafely(); return null; }}).build(); } @@ -224,9 +222,8 @@ public class PeriodicDeltaChangeListener implements ChangeListener { } void stop(Duration timeout, Duration graceTimeoutForSubsequentOperations) { synchronized (startStopMutex) { - running = false; + state = ListenerState.STOPPING; try { - stopping = true; if (scheduledTask != null) { CountdownTimer expiry = timeout.countdownTimer(); @@ -250,8 +247,7 @@ public class PeriodicDeltaChangeListener implements ChangeListener { deltaCollector = new DeltaCollector(); } } finally { - stopCompleted = true; - stopping = false; + state = ListenerState.STOPPED; } } } @@ -259,7 +255,7 @@ public class PeriodicDeltaChangeListener implements ChangeListener { /** Waits for any in-progress writes to be completed then for or any unwritten data to be written. */ @VisibleForTesting public void waitForPendingComplete(Duration timeout, boolean canTrigger) throws InterruptedException, TimeoutException { - if (!isActive() && !stopping) return; + if (!isActive() && state != ListenerState.STOPPING) return; CountdownTimer timer = timeout.isPositive() ? CountdownTimer.newInstanceStarted(timeout) : CountdownTimer.newInstancePaused(Duration.PRACTICALLY_FOREVER); Integer targetWriteCount = null; @@ -299,14 +295,16 @@ public class PeriodicDeltaChangeListener implements ChangeListener { * Even when not active, changes will still be tracked unless {@link #isStopped()}. */ private boolean isActive() { - return running && persister != null && !isStopped(); + return state == ListenerState.RUNNING && persister != null && !isStopped(); } /** - * Whether we have been stopped, in which case will not persist or store anything. + * Whether we have been stopped, ie are stopping are or fully stopped, + * in which case will not persist or store anything + * (except for a final internal persistence called while STOPPING.) */ private boolean isStopped() { - return stopping || stopCompleted || executionContext.isShutdown(); + return state == ListenerState.STOPPING || state == ListenerState.STOPPED || executionContext.isShutdown(); } private void addReferencedObjects(DeltaCollector deltaCollector) { @@ -336,7 +334,11 @@ public class PeriodicDeltaChangeListener implements ChangeListener { } @VisibleForTesting - public boolean persistNowSafely(boolean alreadyHasMutex) { + public boolean persistNowSafely() { + return persistNowSafely(false); + } + + private boolean persistNowSafely(boolean alreadyHasMutex) { Stopwatch timer = Stopwatch.createStarted(); try { persistNowInternal(alreadyHasMutex); @@ -364,12 +366,12 @@ public class PeriodicDeltaChangeListener implements ChangeListener { } protected void persistNowInternal(boolean alreadyHasMutex) { - if (!isActive() && !stopping) { + if (!isActive() && state != ListenerState.STOPPING) { return; } try { if (!alreadyHasMutex) persistingMutex.acquire(); - if (!isActive() && !stopping) return; + if (!isActive() && state != ListenerState.STOPPING) return; // Atomically switch the delta, so subsequent modifications will be done in the // next scheduled persist http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/df21c711/core/src/main/java/brooklyn/entity/rebind/RebindContextImpl.java ---------------------------------------------------------------------- diff --git a/core/src/main/java/brooklyn/entity/rebind/RebindContextImpl.java b/core/src/main/java/brooklyn/entity/rebind/RebindContextImpl.java index b7eba1a..b39fea4 100644 --- a/core/src/main/java/brooklyn/entity/rebind/RebindContextImpl.java +++ b/core/src/main/java/brooklyn/entity/rebind/RebindContextImpl.java @@ -100,6 +100,10 @@ public class RebindContextImpl implements RebindContext { catalogItems.remove(item.getId()); } + public void clearCatalogItems() { + catalogItems.clear(); + } + public Entity getEntity(String id) { return entities.get(id); } @@ -180,5 +184,5 @@ public class RebindContextImpl implements RebindContext { public LookupContext lookup() { return lookupContext; } - + } http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/df21c711/core/src/main/java/brooklyn/entity/rebind/RebindIteration.java ---------------------------------------------------------------------- diff --git a/core/src/main/java/brooklyn/entity/rebind/RebindIteration.java b/core/src/main/java/brooklyn/entity/rebind/RebindIteration.java index 2d1e47f..ad4915a 100644 --- a/core/src/main/java/brooklyn/entity/rebind/RebindIteration.java +++ b/core/src/main/java/brooklyn/entity/rebind/RebindIteration.java @@ -308,7 +308,7 @@ public abstract class RebindIteration { if (rebindManager.persistCatalogItemsEnabled) { logRebindingDebug("RebindManager instantiating catalog items: {}", mementoManifest.getCatalogItemIds()); for (CatalogItemMemento catalogItemMemento : mementoManifest.getCatalogItemMementos().values()) { - if (LOG.isDebugEnabled()) LOG.debug("RebindManager instantiating catalog item {}", catalogItemMemento); + logRebindingDebug("RebindManager instantiating catalog item {}", catalogItemMemento); try { CatalogItem<?, ?> catalogItem = instantiator.newCatalogItem(catalogItemMemento); rebindContext.registerCatalogItem(catalogItemMemento.getId(), catalogItem); @@ -347,9 +347,9 @@ public abstract class RebindIteration { CatalogInitialization catInit = ((ManagementContextInternal)managementContext).getCatalogInitialization(); catInit.applyCatalogLoadMode(); Collection<CatalogItem<?,?>> itemsForResettingCatalog = null; - boolean needsInitialCatalog; + boolean needsInitialItemsLoaded, needsAdditionalItemsLoaded; if (rebindManager.persistCatalogItemsEnabled) { - if (!catInit.hasRunOfficial() && catInit.isInitialResetRequested()) { + if (!catInit.hasRunFinalInitialization() && catInit.isInitialResetRequested()) { String message = "RebindManager resetting catalog on first run (catalog persistence enabled, but reset explicitly specified). "; if (catalogItems.isEmpty()) { message += "Catalog was empty anyway."; @@ -361,6 +361,15 @@ public abstract class RebindIteration { } logRebindingDebug(message); + // we will have unnecessarily tried to load the catalog item manifests earlier in this iteration, + // and problems there could fail a rebind even when we are resetting; + // it might be cleaner to check earlier whether a reset is happening and not load those items at all, + // but that would be a significant new code path (to remove a directory in the persistent store, essentially), + // and as it stands we don't do much with those manifests (e.g. we won't register them or fail on missing types) + // so we think it's only really corrupted XML or CatalogItem schema changes which would cause such problems. + // in extremis someone might need to wipe their store but for most purposes i don't think there will be any issue + // with loading the catalog item manifests before wiping all those files. + itemsForResettingCatalog = MutableList.<CatalogItem<?,?>>of(); PersisterDeltaImpl delta = new PersisterDeltaImpl(); @@ -368,36 +377,42 @@ public abstract class RebindIteration { getPersister().queueDelta(delta); mementoRawData.clearCatalogItems(); - needsInitialCatalog = true; + rebindContext.clearCatalogItems(); + needsInitialItemsLoaded = true; + needsAdditionalItemsLoaded = true; } else { if (!isEmpty) { logRebindingDebug("RebindManager clearing local catalog and loading from persisted state"); itemsForResettingCatalog = rebindContext.getCatalogItems(); - needsInitialCatalog = false; + needsInitialItemsLoaded = false; + // only apply "add" if we haven't yet done so while in MASTER mode + needsAdditionalItemsLoaded = !catInit.hasRunFinalInitialization(); } else { - if (catInit.hasRunOfficial()) { - logRebindingDebug("RebindManager will re-add any new items (persisted state empty)"); - needsInitialCatalog = false; + if (catInit.hasRunFinalInitialization()) { + logRebindingDebug("RebindManager has already done the final official run, not doing anything (even though persisted state empty)"); + needsInitialItemsLoaded = false; + needsAdditionalItemsLoaded = false; } else { - logRebindingDebug("RebindManager loading initial catalog locally because persisted state empty"); - needsInitialCatalog = true; + logRebindingDebug("RebindManager loading initial catalog locally because persisted state empty and the final official run has not yet been performed"); + needsInitialItemsLoaded = true; + needsAdditionalItemsLoaded = true; } } } } else { - if (catInit.hasRunOfficial()) { + if (catInit.hasRunFinalInitialization()) { logRebindingDebug("RebindManager skipping catalog init because it has already run (catalog persistence disabled)"); - needsInitialCatalog = false; + needsInitialItemsLoaded = false; + needsAdditionalItemsLoaded = false; } else { - logRebindingDebug("RebindManager will initialize catalog locally because catalog persistence is disabled"); - needsInitialCatalog = true; + logRebindingDebug("RebindManager will initialize catalog locally because catalog persistence is disabled and the final official run has not yet been performed"); + needsInitialItemsLoaded = true; + needsAdditionalItemsLoaded = true; } } - // TODO in read-only mode, perhaps do this less frequently than entities etc ? - // both in RW and in RO mode, the first run reads the initialization data; - // maybe not desired for RO as it defers problems, although if it's standalone it is desired - catInit.populateCatalog(needsInitialCatalog, itemsForResettingCatalog); + // TODO in read-only mode, perhaps do this less frequently than entities etc, maybe only if things change? + catInit.populateCatalog(mode, needsInitialItemsLoaded, needsAdditionalItemsLoaded, itemsForResettingCatalog); } protected void instantiateLocationsAndEntities() { http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/df21c711/core/src/main/java/brooklyn/entity/rebind/RebindManagerImpl.java ---------------------------------------------------------------------- diff --git a/core/src/main/java/brooklyn/entity/rebind/RebindManagerImpl.java b/core/src/main/java/brooklyn/entity/rebind/RebindManagerImpl.java index ded0049..c94e8fa 100644 --- a/core/src/main/java/brooklyn/entity/rebind/RebindManagerImpl.java +++ b/core/src/main/java/brooklyn/entity/rebind/RebindManagerImpl.java @@ -441,7 +441,7 @@ public class RebindManagerImpl implements RebindManager { } persistenceStoreAccess.checkpoint(memento, exceptionHandler); } else { - if (!persistenceRealChangeListener.persistNowSafely(false)) { + if (!persistenceRealChangeListener.persistNowSafely()) { throw new IllegalStateException("Forced persistence failed; see logs fore more detail"); } } http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/df21c711/core/src/main/java/brooklyn/management/ha/HighAvailabilityManagerImpl.java ---------------------------------------------------------------------- diff --git a/core/src/main/java/brooklyn/management/ha/HighAvailabilityManagerImpl.java b/core/src/main/java/brooklyn/management/ha/HighAvailabilityManagerImpl.java index ab033fd..96e6bea 100644 --- a/core/src/main/java/brooklyn/management/ha/HighAvailabilityManagerImpl.java +++ b/core/src/main/java/brooklyn/management/ha/HighAvailabilityManagerImpl.java @@ -408,33 +408,40 @@ public class HighAvailabilityManagerImpl implements HighAvailabilityManager { throw new IllegalStateException("Unexpected high availability mode "+startMode+" requested for "+this); } - if ((startMode==HighAvailabilityMode.HOT_STANDBY || startMode==HighAvailabilityMode.HOT_BACKUP) && !ManagementNodeState.isHotProxy(oldState)) { - // now transition to hot proxy - nodeStateTransitionComplete = false; - if (startMode==HighAvailabilityMode.HOT_STANDBY) { - // if it should be hot standby, then we may need to promote - // inform the world that we are transitioning (but not eligible for promotion while going in to hot standby) - // (no harm in doing this twice) - publishHealth(); - } - try { - activateHotProxy(ManagementNodeState.of(startMode).get()).get(); - // error above now throws - nodeStateTransitionComplete = true; - publishHealth(); - - if (getNodeState()==ManagementNodeState.HOT_STANDBY || getNodeState()==ManagementNodeState.HOT_BACKUP) { - LOG.info("Management node "+ownNodeId+" now running as HA "+getNodeState()+"; " - + managementContext.getApplications().size()+" application"+Strings.s(managementContext.getApplications().size())+" loaded"); - } else { - // shouldn't come here, we should have gotten an error above - LOG.warn("Management node "+ownNodeId+" unable to promote to "+startMode+" (currently "+getNodeState()+"); " - + "(see log for further details)"); + if ((startMode==HighAvailabilityMode.HOT_STANDBY || startMode==HighAvailabilityMode.HOT_BACKUP)) { + if (!ManagementNodeState.isHotProxy(oldState)) { + // now transition to hot proxy + nodeStateTransitionComplete = false; + if (startMode==HighAvailabilityMode.HOT_STANDBY) { + // if it should be hot standby, then we may need to promote + // inform the world that we are transitioning (but not eligible for promotion while going in to hot standby) + // (no harm in doing this twice) + publishHealth(); } - } catch (Exception e) { - LOG.warn("Management node "+ownNodeId+" unable to promote to "+startMode+" (currently "+getNodeState()+"); rethrowing: "+Exceptions.collapseText(e)); + try { + activateHotProxy(ManagementNodeState.of(startMode).get()).get(); + // error above now throws + nodeStateTransitionComplete = true; + publishHealth(); + + if (getNodeState()==ManagementNodeState.HOT_STANDBY || getNodeState()==ManagementNodeState.HOT_BACKUP) { + LOG.info("Management node "+ownNodeId+" now running as HA "+getNodeState()+"; " + + managementContext.getApplications().size()+" application"+Strings.s(managementContext.getApplications().size())+" loaded"); + } else { + // shouldn't come here, we should have gotten an error above + LOG.warn("Management node "+ownNodeId+" unable to promote to "+startMode+" (currently "+getNodeState()+"); " + + "(see log for further details)"); + } + } catch (Exception e) { + LOG.warn("Management node "+ownNodeId+" unable to promote to "+startMode+" (currently "+getNodeState()+"); rethrowing: "+Exceptions.collapseText(e)); + nodeStateTransitionComplete = true; + throw Exceptions.propagate(e); + } + } else { + // transitioning among hot proxy states - tell the rebind manager + managementContext.getRebindManager().stopReadOnly(); + managementContext.getRebindManager().startReadOnly(ManagementNodeState.of(startMode).get()); nodeStateTransitionComplete = true; - throw Exceptions.propagate(e); } } else { nodeStateTransitionComplete = true; http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/df21c711/core/src/main/java/brooklyn/management/internal/AbstractManagementContext.java ---------------------------------------------------------------------- diff --git a/core/src/main/java/brooklyn/management/internal/AbstractManagementContext.java b/core/src/main/java/brooklyn/management/internal/AbstractManagementContext.java index b1fdc0c..81dd26b 100644 --- a/core/src/main/java/brooklyn/management/internal/AbstractManagementContext.java +++ b/core/src/main/java/brooklyn/management/internal/AbstractManagementContext.java @@ -363,11 +363,11 @@ public abstract class AbstractManagementContext implements ManagementContextInte @Override public BrooklynCatalog getCatalog() { - if (!getCatalogInitialization().hasRunIncludingBestEffort()) { + if (!getCatalogInitialization().hasRunAnyInitialization()) { // catalog init is needed; normally this will be done from start sequence, // but if accessed early -- and in tests -- we will load it here getCatalogInitialization().injectManagementContext(this); - getCatalogInitialization().populateBestEffort(catalog); + getCatalogInitialization().populateUnofficial(catalog); } return catalog; } http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/df21c711/usage/cli/src/main/java/brooklyn/cli/Main.java ---------------------------------------------------------------------- diff --git a/usage/cli/src/main/java/brooklyn/cli/Main.java b/usage/cli/src/main/java/brooklyn/cli/Main.java index d98e0d8..6e48b3f 100644 --- a/usage/cli/src/main/java/brooklyn/cli/Main.java +++ b/usage/cli/src/main/java/brooklyn/cli/Main.java @@ -785,6 +785,10 @@ public class Main extends AbstractMain { .add("startupFailsOnCatalogErrors", startupFailOnCatalogErrors) .add("startupContinueOnWebErrors", startupContinueOnWebErrors) .add("startupFailOnManagedAppsErrors", startupFailOnManagedAppsErrors) + .add("catalogInitial", catalogInitial) + .add("catalogAdd", catalogAdd) + .add("catalogReset", catalogReset) + .add("catalogForce", catalogForce) .add("stopWhichAppsOnShutdown", stopWhichAppsOnShutdown) .add("noShutdownOnExit", noShutdownOnExit) .add("stopOnKeyPress", stopOnKeyPress) http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/df21c711/usage/cli/src/main/java/brooklyn/cli/lister/ClassFinder.java ---------------------------------------------------------------------- diff --git a/usage/cli/src/main/java/brooklyn/cli/lister/ClassFinder.java b/usage/cli/src/main/java/brooklyn/cli/lister/ClassFinder.java index a66fa7d..2fb913b 100644 --- a/usage/cli/src/main/java/brooklyn/cli/lister/ClassFinder.java +++ b/usage/cli/src/main/java/brooklyn/cli/lister/ClassFinder.java @@ -130,7 +130,7 @@ public class ClassFinder { } } } else { - result.add(new URL("file://"+tidiedFile)); + result.add(tidiedFile.toURI().toURL()); } } http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/df21c711/usage/launcher/src/main/java/brooklyn/launcher/BrooklynLauncher.java ---------------------------------------------------------------------- diff --git a/usage/launcher/src/main/java/brooklyn/launcher/BrooklynLauncher.java b/usage/launcher/src/main/java/brooklyn/launcher/BrooklynLauncher.java index 6a201a2..e7d3948 100644 --- a/usage/launcher/src/main/java/brooklyn/launcher/BrooklynLauncher.java +++ b/usage/launcher/src/main/java/brooklyn/launcher/BrooklynLauncher.java @@ -598,9 +598,16 @@ public class BrooklynLauncher { try { // run cat init now if it hasn't yet been run; // will also run if there was an ignored error in catalog above, allowing it to fail startup here if requested - if (catInit!=null && !catInit.hasRunOfficial()) { - LOG.debug("Loading catalog as part of launcher (persistence did not run it)"); - catInit.populateCatalog(true, null); + if (catInit!=null && !catInit.hasRunOfficialInitialization()) { + if (persistMode==PersistMode.DISABLED) { + LOG.debug("Loading catalog as part of launch sequence (it was not loaded as part of any rebind sequence)"); + catInit.populateCatalog(ManagementNodeState.MASTER, true, true, null); + } else { + // should have loaded during rebind + ManagementNodeState state = managementContext.getHighAvailabilityManager().getNodeState(); + LOG.warn("Loading catalog for "+state+" as part of launch sequence (it was not loaded as part of the rebind sequence)"); + catInit.populateCatalog(state, true, true, null); + } } } catch (Exception e) { handleSubsystemStartupError(ignoreCatalogErrors, "initial catalog", e); http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/df21c711/usage/rest-server/src/main/java/brooklyn/rest/filter/HaHotCheckResourceFilter.java ---------------------------------------------------------------------- diff --git a/usage/rest-server/src/main/java/brooklyn/rest/filter/HaHotCheckResourceFilter.java b/usage/rest-server/src/main/java/brooklyn/rest/filter/HaHotCheckResourceFilter.java index dc2e954..bae561a 100644 --- a/usage/rest-server/src/main/java/brooklyn/rest/filter/HaHotCheckResourceFilter.java +++ b/usage/rest-server/src/main/java/brooklyn/rest/filter/HaHotCheckResourceFilter.java @@ -112,7 +112,7 @@ public class HaHotCheckResourceFilter implements ResourceFilterFactory { public ContainerRequest filter(ContainerRequest request) { String problem = lookForProblem(request); if (Strings.isNonBlank(problem)) { - log.warn("Disallowing request as "+problem+": "+request+"/"+am+" (caller should set '"+HaMasterCheckFilter.SKIP_CHECK_HEADER+"' to force)"); + log.warn("Disallowing web request as "+problem+": "+request+"/"+am+" (caller should set '"+HaMasterCheckFilter.SKIP_CHECK_HEADER+"' to force)"); throw new WebApplicationException(ApiError.builder() .message("This request is only permitted against an active hot Brooklyn server") .errorCode(Response.Status.FORBIDDEN).build().asJsonResponse()); http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/df21c711/usage/rest-server/src/main/java/brooklyn/rest/filter/HaMasterCheckFilter.java ---------------------------------------------------------------------- diff --git a/usage/rest-server/src/main/java/brooklyn/rest/filter/HaMasterCheckFilter.java b/usage/rest-server/src/main/java/brooklyn/rest/filter/HaMasterCheckFilter.java index 9cca507..74e7cf1 100644 --- a/usage/rest-server/src/main/java/brooklyn/rest/filter/HaMasterCheckFilter.java +++ b/usage/rest-server/src/main/java/brooklyn/rest/filter/HaMasterCheckFilter.java @@ -94,7 +94,7 @@ public class HaMasterCheckFilter implements Filter { public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { String problem = lookForProblem(request); if (problem!=null) { - log.warn("Disallowing request as "+problem+": "+request.getParameterMap()+" (caller should set '"+SKIP_CHECK_HEADER+"' to force)"); + log.warn("Disallowing web request as "+problem+": "+request.getParameterMap()+" (caller should set '"+SKIP_CHECK_HEADER+"' to force)"); WebResourceUtils.applyJsonResponse(servletContext, ApiError.builder() .message("This request is only permitted against an active master Brooklyn server") .errorCode(Response.Status.FORBIDDEN).build().asJsonResponse(), (HttpServletResponse)response); http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/df21c711/utils/common/src/main/java/brooklyn/util/javalang/AggregateClassLoader.java ---------------------------------------------------------------------- diff --git a/utils/common/src/main/java/brooklyn/util/javalang/AggregateClassLoader.java b/utils/common/src/main/java/brooklyn/util/javalang/AggregateClassLoader.java index a3ca374..db0254b 100644 --- a/utils/common/src/main/java/brooklyn/util/javalang/AggregateClassLoader.java +++ b/utils/common/src/main/java/brooklyn/util/javalang/AggregateClassLoader.java @@ -115,7 +115,7 @@ public class AggregateClassLoader extends ClassLoader { public Iterator<ClassLoader> iterator() { synchronized (classLoaders) { - // provides iterator of snapshot + // CopyOnWriteList iterator is immutable view of snapshot return classLoaders.iterator(); } }
