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();
     }

Reply via email to