Repository: incubator-brooklyn Updated Branches: refs/heads/master d0cbcf36c -> d64808206
adjust cli start sequence so web/rest is avail always, with isUp check on rest api first step towards being able to interactively track the startup sequence and notify on errors Project: http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/repo Commit: http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/commit/20810ac9 Tree: http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/tree/20810ac9 Diff: http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/diff/20810ac9 Branch: refs/heads/master Commit: 20810ac9e275eadbf5c00c8b2ba07534841e56f5 Parents: 7b97cee Author: Alex Heneveld <[email protected]> Authored: Thu Apr 23 07:46:32 2015 +0100 Committer: Alex Heneveld <[email protected]> Committed: Mon Apr 27 08:34:36 2015 +0100 ---------------------------------------------------------------------- .../brooklyn/management/ManagementContext.java | 17 ++++++++- .../internal/AbstractManagementContext.java | 6 +++ .../internal/LocalManagementContext.java | 4 ++ .../NonDeploymentManagementContext.java | 8 ++++ usage/cli/src/main/java/brooklyn/cli/Main.java | 19 +++++----- .../brooklyn/launcher/BrooklynLauncher.java | 39 ++++++++++++++------ .../main/java/brooklyn/rest/api/ServerApi.java | 10 +++++ .../resources/AbstractBrooklynRestResource.java | 13 +++++-- .../brooklyn/rest/resources/ServerResource.java | 31 +++++++++++++++- .../testing/mocks/ManagementContextMock.java | 5 +++ 10 files changed, 125 insertions(+), 27 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/20810ac9/api/src/main/java/brooklyn/management/ManagementContext.java ---------------------------------------------------------------------- diff --git a/api/src/main/java/brooklyn/management/ManagementContext.java b/api/src/main/java/brooklyn/management/ManagementContext.java index b45ecef..12ead70 100644 --- a/api/src/main/java/brooklyn/management/ManagementContext.java +++ b/api/src/main/java/brooklyn/management/ManagementContext.java @@ -172,9 +172,24 @@ public interface ManagementContext { StringConfigMap getConfig(); /** - * Whether this management context is still running, or has been terminated. + * Whether the management context has been initialized and not yet terminated. + * This does not mean startup is entirely completed. See also {@link #isStartupComplete()}. */ + // TODO should we replace this with isNotYetTerminated() ?? + // and perhaps introduce isFullyRunning() which does (isStartupComplete() && isRunning()), + // and/or move to a MgmtContextStatus subclass where errors can also be stored? public boolean isRunning(); + + /** + * Whether all startup tasks have completed. Previous to this point the management context is still usable + * (and hence {@link #isRunning()} returns true immediately after construction) + * but some subsystems (e.g. persistence, OSGi, webapps, entities started at startup) + * may not be available until this returns true. + * <p> + * Also see {@link #isStartupComplete()}. + */ + @Beta // see comment on isRunning() as items might move to a status handler + public boolean isStartupComplete(); /** Record of configured locations and location resolvers */ LocationRegistry getLocationRegistry(); http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/20810ac9/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 14fe100..501f4e4 100644 --- a/core/src/main/java/brooklyn/management/internal/AbstractManagementContext.java +++ b/core/src/main/java/brooklyn/management/internal/AbstractManagementContext.java @@ -163,6 +163,7 @@ public abstract class AbstractManagementContext implements ManagementContextInte private final BrooklynStorage storage; private volatile boolean running = true; + protected boolean startupComplete = false; protected Maybe<URI> uri = Maybe.absent(); @@ -201,6 +202,11 @@ public abstract class AbstractManagementContext implements ManagementContextInte public boolean isRunning() { return running; } + + @Override + public boolean isStartupComplete() { + return startupComplete; + } @Override public BrooklynStorage getStorage() { http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/20810ac9/core/src/main/java/brooklyn/management/internal/LocalManagementContext.java ---------------------------------------------------------------------- diff --git a/core/src/main/java/brooklyn/management/internal/LocalManagementContext.java b/core/src/main/java/brooklyn/management/internal/LocalManagementContext.java index 202e4a6..39e4dc5 100644 --- a/core/src/main/java/brooklyn/management/internal/LocalManagementContext.java +++ b/core/src/main/java/brooklyn/management/internal/LocalManagementContext.java @@ -412,4 +412,8 @@ public class LocalManagementContext extends AbstractManagementContext { public void removePropertiesReloadListener(PropertiesReloadListener listener) { reloadListeners.remove(listener); } + + public void noteStartupComplete() { + startupComplete = true; + } } http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/20810ac9/core/src/main/java/brooklyn/management/internal/NonDeploymentManagementContext.java ---------------------------------------------------------------------- diff --git a/core/src/main/java/brooklyn/management/internal/NonDeploymentManagementContext.java b/core/src/main/java/brooklyn/management/internal/NonDeploymentManagementContext.java index 0972871..72d83bd 100644 --- a/core/src/main/java/brooklyn/management/internal/NonDeploymentManagementContext.java +++ b/core/src/main/java/brooklyn/management/internal/NonDeploymentManagementContext.java @@ -164,6 +164,14 @@ public class NonDeploymentManagementContext implements ManagementContextInternal // Assume that the real management context has not been terminated, so always true return true; } + + @Override + public boolean isStartupComplete() { + // This mgmt context is only used by items who are not yet fully started. + // It's slightly misleading as this does not refer to the main mgmt context. + // OTOH it probably won't be used. TBC. -Alex, Apr 2015 + return false; + } @Override public InternalEntityFactory getEntityFactory() { http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/20810ac9/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 e674c1d..b66a6eb 100644 --- a/usage/cli/src/main/java/brooklyn/cli/Main.java +++ b/usage/cli/src/main/java/brooklyn/cli/Main.java @@ -82,6 +82,7 @@ import brooklyn.util.text.Strings; import com.google.common.annotations.Beta; import com.google.common.annotations.VisibleForTesting; +import com.google.common.base.Function; import com.google.common.base.Objects.ToStringHelper; import com.google.common.collect.ImmutableList; @@ -377,7 +378,15 @@ public class Main extends AbstractMain { } launcher = createLauncher(); - + + launcher.customizeInitialCatalog(new Function<BrooklynLauncher,Void>() { + @Override + public Void apply(BrooklynLauncher launcher) { + populateCatalog(launcher.getServerDetails().getManagementContext().getCatalog()); + return null; + } + }); + launcher.persistMode(persistMode); launcher.persistenceDir(persistenceDir); launcher.persistenceLocation(persistenceLocation); @@ -418,14 +427,6 @@ public class Main extends AbstractMain { BrooklynServerDetails server = launcher.getServerDetails(); ManagementContext ctx = server.getManagementContext(); - try { - populateCatalog(launcher.getServerDetails().getManagementContext().getCatalog()); - } catch (Exception e) { - Exceptions.propagateIfFatal(e); - // don't fail to start just because catalog is not available - log.error("Error populating catalog: "+e, e); - } - if (verbose) { Entities.dumpInfo(launcher.getApplications()); } http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/20810ac9/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 9cc8ea2..10c9afb 100644 --- a/usage/launcher/src/main/java/brooklyn/launcher/BrooklynLauncher.java +++ b/usage/launcher/src/main/java/brooklyn/launcher/BrooklynLauncher.java @@ -158,6 +158,7 @@ public class BrooklynLauncher { private StopWhichAppsOnShutdown stopWhichAppsOnShutdown = StopWhichAppsOnShutdown.THESE_IF_NOT_PERSISTED; private Function<ManagementContext,Void> customizeManagement = null; + private Function<BrooklynLauncher,Void> customizeInitialCatalog = null; private PersistMode persistMode = PersistMode.DISABLED; private HighAvailabilityMode highAvailabilityMode = HighAvailabilityMode.DISABLED; @@ -420,6 +421,11 @@ public class BrooklynLauncher { return this; } + public BrooklynLauncher customizeInitialCatalog(Function<BrooklynLauncher, Void> customizeInitialCatalog) { + this.customizeInitialCatalog = customizeInitialCatalog; + return this; + } + public BrooklynLauncher shutdownOnExit(boolean val) { LOG.warn("Call to deprecated `shutdownOnExit`", new Throwable("source of deprecated call")); stopWhichAppsOnShutdown = StopWhichAppsOnShutdown.THESE_IF_NOT_PERSISTED; @@ -555,13 +561,22 @@ public class BrooklynLauncher { // Create the management context initManagementContext(); + // Start webapps as soon as mgmt context available -- can use them to detect progress of other processes + if (startWebApps) { + try { + startWebApps(); + } catch (Exception e) { + handleSubsystemStartupError(ignoreWebErrors, "core web apps", e); + } + } + // Add a CAMP platform campPlatform = new BrooklynCampPlatformLauncherNoServer() .useManagementContext(managementContext) .launch() .getCampPlatform(); // TODO start CAMP rest _server_ in the below (at /camp) ? - + try { initPersistence(); startPersistence(); @@ -569,34 +584,34 @@ public class BrooklynLauncher { handleSubsystemStartupError(ignorePersistenceErrors, "persistence", e); } + try { + if (customizeInitialCatalog!=null) + customizeInitialCatalog.apply(this); + } catch (Exception e) { + handleSubsystemStartupError(true, "initial catalog", e); + } + // Create the locations. Must happen after persistence is started in case the // management context's catalog is loaded from persisted state. (Location // resolution uses the catalog's classpath to scan for resolvers.) locations.addAll(managementContext.getLocationRegistry().resolve(locationSpecs)); - // Start the web-console - if (startWebApps) { - try { - startWebApps(); - } catch (Exception e) { - handleSubsystemStartupError(ignoreWebErrors, "web apps", e); - } - } - try { createApps(); startApps(); } catch (Exception e) { - handleSubsystemStartupError(ignoreAppErrors, "managed apps", e); + handleSubsystemStartupError(ignoreAppErrors, "brooklyn autostart apps", e); } if (startBrooklynNode) { try { startBrooklynNode(); } catch (Exception e) { - handleSubsystemStartupError(ignoreWebErrors, "web apps", e); + handleSubsystemStartupError(true, "brooklyn node / self entity", e); } } + + ((LocalManagementContext)managementContext).noteStartupComplete(); return this; } http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/20810ac9/usage/rest-api/src/main/java/brooklyn/rest/api/ServerApi.java ---------------------------------------------------------------------- diff --git a/usage/rest-api/src/main/java/brooklyn/rest/api/ServerApi.java b/usage/rest-api/src/main/java/brooklyn/rest/api/ServerApi.java index 624c9db..7ee371f 100644 --- a/usage/rest-api/src/main/java/brooklyn/rest/api/ServerApi.java +++ b/usage/rest-api/src/main/java/brooklyn/rest/api/ServerApi.java @@ -82,6 +82,16 @@ public interface ServerApi { @ApiOperation(value = "Return version identifier information for this Brooklyn instance", responseClass = "String", multiValueResponse = false) public VersionSummary getVersion(); + @GET + @Path("/up") + @ApiOperation(value = "Returns whether this server is up - fully started, and not stopping, though it may have errors") + public boolean isUp(); + + @GET + @Path("/healthy") + @ApiOperation(value = "Returns whether this node is healthy - fully started, not stopping, and no errors") + public boolean isHealthy(); + @Deprecated /** @deprecated since 0.7.0 use /ha/node (which returns correct JSON) */ @GET @Path("/status") http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/20810ac9/usage/rest-server/src/main/java/brooklyn/rest/resources/AbstractBrooklynRestResource.java ---------------------------------------------------------------------- diff --git a/usage/rest-server/src/main/java/brooklyn/rest/resources/AbstractBrooklynRestResource.java b/usage/rest-server/src/main/java/brooklyn/rest/resources/AbstractBrooklynRestResource.java index 553e31c..0f49caf 100644 --- a/usage/rest-server/src/main/java/brooklyn/rest/resources/AbstractBrooklynRestResource.java +++ b/usage/rest-server/src/main/java/brooklyn/rest/resources/AbstractBrooklynRestResource.java @@ -32,6 +32,7 @@ import brooklyn.management.ManagementContextInjectable; import brooklyn.rest.util.BrooklynRestResourceUtils; import brooklyn.rest.util.WebResourceUtils; import brooklyn.rest.util.json.BrooklynJacksonJsonProvider; +import brooklyn.util.guava.Maybe; import brooklyn.util.task.Tasks; import brooklyn.util.time.Duration; @@ -52,12 +53,16 @@ public abstract class AbstractBrooklynRestResource implements ManagementContextI private BrooklynRestResourceUtils brooklynRestResourceUtils; private ObjectMapper mapper; - public synchronized ManagementContext mgmt() { - if (managementContext!=null) return managementContext; + public ManagementContext mgmt() { + return mgmtMaybe().get(); + } + + protected synchronized Maybe<ManagementContext> mgmtMaybe() { + if (managementContext!=null) return Maybe.of(managementContext); managementContext = (ManagementContext) servletContext.getAttribute(BrooklynServiceAttributes.BROOKLYN_MANAGEMENT_CONTEXT); - if (managementContext!=null) return managementContext; + if (managementContext!=null) return Maybe.of(managementContext); - throw new IllegalStateException("ManagementContext not supplied for Brooklyn Jersey Resource "+this); + return Maybe.absent("ManagementContext not available for Brooklyn Jersey Resource "+this); } public void injectManagementContext(ManagementContext managementContext) { http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/20810ac9/usage/rest-server/src/main/java/brooklyn/rest/resources/ServerResource.java ---------------------------------------------------------------------- diff --git a/usage/rest-server/src/main/java/brooklyn/rest/resources/ServerResource.java b/usage/rest-server/src/main/java/brooklyn/rest/resources/ServerResource.java index e44437f..422e06d 100644 --- a/usage/rest-server/src/main/java/brooklyn/rest/resources/ServerResource.java +++ b/usage/rest-server/src/main/java/brooklyn/rest/resources/ServerResource.java @@ -35,6 +35,7 @@ import javax.ws.rs.core.Response; import brooklyn.config.ConfigKey; import brooklyn.entity.basic.ConfigKeys; + import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -46,6 +47,7 @@ import brooklyn.entity.basic.StartableApplication; import brooklyn.entity.rebind.persister.BrooklynPersistenceUtils; import brooklyn.entity.rebind.persister.FileBasedObjectStore; import brooklyn.entity.rebind.persister.PersistenceObjectStore; +import brooklyn.management.ManagementContext; import brooklyn.management.Task; import brooklyn.management.entitlement.EntitlementContext; import brooklyn.management.entitlement.Entitlements; @@ -64,6 +66,7 @@ import brooklyn.util.ResourceUtils; import brooklyn.util.exceptions.Exceptions; import brooklyn.util.file.ArchiveBuilder; import brooklyn.util.flags.TypeCoercions; +import brooklyn.util.guava.Maybe; import brooklyn.util.os.Os; import brooklyn.util.text.Identifiers; import brooklyn.util.text.Strings; @@ -229,6 +232,9 @@ public class ServerResource extends AbstractBrooklynRestResource implements Serv @Override public VersionSummary getVersion() { + if (!Entitlements.isEntitled(mgmt().getEntitlementManager(), Entitlements.SERVER_STATUS, null)) + throw WebResourceUtils.unauthorized("User '%s' is not authorized for this operation", Entitlements.getEntitlementContext().user()); + // TODO reconcile this with BrooklynVersion reading from the OSGi manifest // @ahgittin / @sjcorbett to decide, is there need for this in addition to the OSGi manifest? // TODO as part of this call should we have a strategy for reporting downstream builds in this call? @@ -257,6 +263,26 @@ public class ServerResource extends AbstractBrooklynRestResource implements Serv return new VersionSummary(BrooklynVersion.get(), gitSha1, gitBranch); } + @Override + public boolean isUp() { + if (!Entitlements.isEntitled(mgmt().getEntitlementManager(), Entitlements.SERVER_STATUS, null)) + throw WebResourceUtils.unauthorized("User '%s' is not authorized for this operation", Entitlements.getEntitlementContext().user()); + + Maybe<ManagementContext> mm = mgmtMaybe(); + if (mm.isAbsent()) return false; + ManagementContext m = mm.get(); + if (!m.isStartupComplete()) return false; + if (!m.isRunning()) return false; + return true; + } + + @Override + public boolean isHealthy() { + if (!isUp()) return false; + // TODO errors + return true; + } + @Deprecated @Override public String getStatus() { @@ -282,7 +308,10 @@ public class ServerResource extends AbstractBrooklynRestResource implements Serv public ManagementNodeState getHighAvailabilityNodeState() { if (!Entitlements.isEntitled(mgmt().getEntitlementManager(), Entitlements.SERVER_STATUS, null)) throw WebResourceUtils.unauthorized("User '%s' is not authorized for this operation", Entitlements.getEntitlementContext().user()); - return mgmt().getHighAvailabilityManager().getNodeState(); + + Maybe<ManagementContext> mm = mgmtMaybe(); + if (mm.isAbsent()) return ManagementNodeState.INITIALIZING; + return mm.get().getHighAvailabilityManager().getNodeState(); } @Override http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/20810ac9/usage/rest-server/src/test/java/brooklyn/rest/testing/mocks/ManagementContextMock.java ---------------------------------------------------------------------- diff --git a/usage/rest-server/src/test/java/brooklyn/rest/testing/mocks/ManagementContextMock.java b/usage/rest-server/src/test/java/brooklyn/rest/testing/mocks/ManagementContextMock.java index 90edf1e..d7c461e 100644 --- a/usage/rest-server/src/test/java/brooklyn/rest/testing/mocks/ManagementContextMock.java +++ b/usage/rest-server/src/test/java/brooklyn/rest/testing/mocks/ManagementContextMock.java @@ -135,6 +135,11 @@ public class ManagementContextMock implements ManagementContext { } @Override + public boolean isStartupComplete() { + throw fail(); + } + + @Override public LocationRegistry getLocationRegistry() { throw fail(); }
