Return-Path: X-Original-To: apmail-brooklyn-commits-archive@minotaur.apache.org Delivered-To: apmail-brooklyn-commits-archive@minotaur.apache.org Received: from mail.apache.org (hermes.apache.org [140.211.11.3]) by minotaur.apache.org (Postfix) with SMTP id BB7BB181E6 for ; Thu, 18 Feb 2016 15:47:30 +0000 (UTC) Received: (qmail 6788 invoked by uid 500); 18 Feb 2016 15:47:21 -0000 Delivered-To: apmail-brooklyn-commits-archive@brooklyn.apache.org Received: (qmail 6723 invoked by uid 500); 18 Feb 2016 15:47:21 -0000 Mailing-List: contact commits-help@brooklyn.apache.org; run by ezmlm Precedence: bulk List-Help: List-Unsubscribe: List-Post: List-Id: Reply-To: dev@brooklyn.apache.org Delivered-To: mailing list commits@brooklyn.apache.org Received: (qmail 5931 invoked by uid 99); 18 Feb 2016 15:47:20 -0000 Received: from git1-us-west.apache.org (HELO git1-us-west.apache.org) (140.211.11.23) by apache.org (qpsmtpd/0.29) with ESMTP; Thu, 18 Feb 2016 15:47:20 +0000 Received: by git1-us-west.apache.org (ASF Mail Server at git1-us-west.apache.org, from userid 33) id 35302E38C8; Thu, 18 Feb 2016 15:47:20 +0000 (UTC) Content-Type: text/plain; charset="us-ascii" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit From: heneveld@apache.org To: commits@brooklyn.apache.org Date: Thu, 18 Feb 2016 15:47:49 -0000 Message-Id: <5dba8d1e7dff4dec9d7c883cd5d50ca6@git.apache.org> In-Reply-To: <185968724a0a448c81570330c9742d65@git.apache.org> References: <185968724a0a448c81570330c9742d65@git.apache.org> X-Mailer: ASF-Git Admin Mailer Subject: [31/34] brooklyn-server git commit: move common ha filter code to shared class move common ha filter code to shared class and ensure classes not in scope aren't referenced Project: http://git-wip-us.apache.org/repos/asf/brooklyn-server/repo Commit: http://git-wip-us.apache.org/repos/asf/brooklyn-server/commit/3ab00406 Tree: http://git-wip-us.apache.org/repos/asf/brooklyn-server/tree/3ab00406 Diff: http://git-wip-us.apache.org/repos/asf/brooklyn-server/diff/3ab00406 Branch: refs/heads/master Commit: 3ab00406bc484ec4d8c667d1a068977a25e2aba6 Parents: 7f047ba Author: Alex Heneveld Authored: Thu Feb 18 12:15:08 2016 +0000 Committer: Alex Heneveld Committed: Thu Feb 18 13:28:54 2016 +0000 ---------------------------------------------------------------------- .../rest/filter/HaHotCheckHelperAbstract.java | 82 ++++++++++++++++++++ .../rest/filter/HaHotCheckResourceFilter.java | 72 +++++------------ .../rest/resources/CatalogResourceTest.java | 2 + .../rest/filter/HaMasterCheckFilter.java | 35 ++++----- .../brooklyn/rest/BrooklynRestApiLauncher.java | 4 - 5 files changed, 118 insertions(+), 77 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/3ab00406/rest/rest-resources/src/main/java/org/apache/brooklyn/rest/filter/HaHotCheckHelperAbstract.java ---------------------------------------------------------------------- diff --git a/rest/rest-resources/src/main/java/org/apache/brooklyn/rest/filter/HaHotCheckHelperAbstract.java b/rest/rest-resources/src/main/java/org/apache/brooklyn/rest/filter/HaHotCheckHelperAbstract.java new file mode 100644 index 0000000..7f183a6 --- /dev/null +++ b/rest/rest-resources/src/main/java/org/apache/brooklyn/rest/filter/HaHotCheckHelperAbstract.java @@ -0,0 +1,82 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.brooklyn.rest.filter; + +import java.util.Set; + +import javax.ws.rs.core.Response; + +import org.apache.brooklyn.api.mgmt.ManagementContext; +import org.apache.brooklyn.api.mgmt.ha.ManagementNodeState; +import org.apache.brooklyn.rest.domain.ApiError; +import org.apache.brooklyn.util.guava.Maybe; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.google.common.annotations.Beta; +import com.google.common.collect.ImmutableSet; + +@Beta +public abstract class HaHotCheckHelperAbstract { + + private static final Logger log = LoggerFactory.getLogger(HaHotCheckHelperAbstract.class); + + public static final String SKIP_CHECK_HEADER = "Brooklyn-Allow-Non-Master-Access"; + + private static final Set HOT_STATES = ImmutableSet.of( + ManagementNodeState.MASTER, ManagementNodeState.HOT_STANDBY, ManagementNodeState.HOT_BACKUP); + + /** Returns a string describing the problem if mgmt is null or not running; returns absent if no problems */ + public static Maybe getProblemMessageIfServerNotRunning(ManagementContext mgmt) { + if (mgmt==null) return Maybe.of("no management context available"); + if (!mgmt.isRunning()) return Maybe.of("server no longer running"); + if (!mgmt.isStartupComplete()) return Maybe.of("server not in required startup-completed state"); + return Maybe.absent(); + } + + public Maybe getProblemMessageIfServerNotRunning() { + return getProblemMessageIfServerNotRunning(mgmt()); + } + + public Response disallowResponse(String problem, Object info) { + log.warn("Disallowing web request as "+problem+": "+info+" (caller should set '"+HaHotCheckHelperAbstract.SKIP_CHECK_HEADER+"' to force)"); + return ApiError.builder() + .message("This request is only permitted against an active master Brooklyn server") + .errorCode(Response.Status.FORBIDDEN).build().asJsonResponse(); + } + + public boolean isSkipCheckHeaderSet(String headerValueString) { + return "true".equalsIgnoreCase(headerValueString); + } + + public boolean isHaHotStatus() { + ManagementNodeState state = mgmt().getHighAvailabilityManager().getNodeState(); + return HOT_STATES.contains(state); + } + + public abstract ManagementContext mgmt(); + + // Maybe there should be a separate state to indicate that we have switched state + // but still haven't finished rebinding. (Previously there was a time delay and an + // isRebinding check, but introducing RebindManager#isAwaitingInitialRebind() seems cleaner.) + public boolean isStateNotYetValid() { + return mgmt().getRebindManager().isAwaitingInitialRebind(); + } + +} http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/3ab00406/rest/rest-resources/src/main/java/org/apache/brooklyn/rest/filter/HaHotCheckResourceFilter.java ---------------------------------------------------------------------- diff --git a/rest/rest-resources/src/main/java/org/apache/brooklyn/rest/filter/HaHotCheckResourceFilter.java b/rest/rest-resources/src/main/java/org/apache/brooklyn/rest/filter/HaHotCheckResourceFilter.java index 13c5cbf..3c9c129 100644 --- a/rest/rest-resources/src/main/java/org/apache/brooklyn/rest/filter/HaHotCheckResourceFilter.java +++ b/rest/rest-resources/src/main/java/org/apache/brooklyn/rest/filter/HaHotCheckResourceFilter.java @@ -21,25 +21,20 @@ package org.apache.brooklyn.rest.filter; import java.io.IOException; import java.lang.annotation.Annotation; import java.lang.reflect.Method; -import java.util.Set; import javax.ws.rs.container.ContainerRequestContext; import javax.ws.rs.container.ContainerRequestFilter; import javax.ws.rs.container.ResourceInfo; import javax.ws.rs.core.Context; -import javax.ws.rs.core.Response; import javax.ws.rs.ext.ContextResolver; import javax.ws.rs.ext.Provider; import org.apache.brooklyn.api.mgmt.ManagementContext; -import org.apache.brooklyn.api.mgmt.ha.ManagementNodeState; -import org.apache.brooklyn.rest.domain.ApiError; +import org.apache.brooklyn.rest.util.BrooklynRestResourceUtils; +import org.apache.brooklyn.util.guava.Maybe; import org.apache.brooklyn.util.text.Strings; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; import com.google.common.annotations.VisibleForTesting; -import com.google.common.collect.ImmutableSet; /** * Checks that if the method or resource class corresponding to a request @@ -52,13 +47,8 @@ import com.google.common.collect.ImmutableSet; */ @Provider public class HaHotCheckResourceFilter implements ContainerRequestFilter { - public static final String SKIP_CHECK_HEADER = "Brooklyn-Allow-Non-Master-Access"; + public static final String SKIP_CHECK_HEADER = HaHotCheckHelperAbstract.SKIP_CHECK_HEADER; - private static final Logger log = LoggerFactory.getLogger(HaHotCheckResourceFilter.class); - - private static final Set HOT_STATES = ImmutableSet.of( - ManagementNodeState.MASTER, ManagementNodeState.HOT_STANDBY, ManagementNodeState.HOT_BACKUP); - // Not quite standards compliant. Should instead be: // @Context Providers providers // .... @@ -70,6 +60,12 @@ public class HaHotCheckResourceFilter implements ContainerRequestFilter { @Context private ResourceInfo resourceInfo; + private HaHotCheckHelperAbstract helper = new HaHotCheckHelperAbstract() { + public ManagementContext mgmt() { + return mgmt.getContext(ManagementContext.class); + } + }; + public HaHotCheckResourceFilter() { } @@ -78,60 +74,44 @@ public class HaHotCheckResourceFilter implements ContainerRequestFilter { this.mgmt = mgmt; } - private ManagementContext mgmt() { - return mgmt.getContext(ManagementContext.class); - } - @Override public void filter(ContainerRequestContext requestContext) throws IOException { String problem = lookForProblem(requestContext); if (Strings.isNonBlank(problem)) { - log.warn("Disallowing web request as "+problem+": "+requestContext.getUriInfo()+"/"+resourceInfo.getResourceMethod()+" (caller should set '"+SKIP_CHECK_HEADER+"' to force)"); - requestContext.abortWith(ApiError.builder() - .message("This request is only permitted against an active hot Brooklyn server") - .errorCode(Response.Status.FORBIDDEN).build().asJsonResponse()); + requestContext.abortWith(helper.disallowResponse(problem, requestContext.getUriInfo()+"/"+resourceInfo.getResourceMethod())); } } private String lookForProblem(ContainerRequestContext requestContext) { - if (isSkipCheckHeaderSet(requestContext)) + if (helper.isSkipCheckHeaderSet(requestContext.getHeaderString(SKIP_CHECK_HEADER))) return null; if (!isHaHotStateRequired()) return null; - String problem = lookForProblemIfServerNotRunning(mgmt()); - if (Strings.isNonBlank(problem)) - return problem; + Maybe problem = helper.getProblemMessageIfServerNotRunning(); + if (problem.isPresent()) + return problem.get(); - if (!isHaHotStatus()) + if (!helper.isHaHotStatus()) return "server not in required HA hot state"; - if (isStateNotYetValid()) + if (helper.isStateNotYetValid()) return "server not yet completed loading data for required HA hot state"; return null; } - + + /** @deprecated since 0.9.0 use {@link BrooklynRestResourceUtils#getProblemMessageIfServerNotRunning(ManagementContext)} */ public static String lookForProblemIfServerNotRunning(ManagementContext mgmt) { - if (mgmt==null) return "no management context available"; - if (!mgmt.isRunning()) return "server no longer running"; - if (!mgmt.isStartupComplete()) return "server not in required startup-completed state"; - return null; + return HaHotCheckHelperAbstract.getProblemMessageIfServerNotRunning(mgmt).orNull(); } - // Maybe there should be a separate state to indicate that we have switched state - // but still haven't finished rebinding. (Previously there was a time delay and an - // isRebinding check, but introducing RebindManager#isAwaitingInitialRebind() seems cleaner.) - private boolean isStateNotYetValid() { - return mgmt().getRebindManager().isAwaitingInitialRebind(); - } - - private boolean isHaHotStateRequired() { + protected boolean isHaHotStateRequired() { // TODO support super annotations Method m = resourceInfo.getResourceMethod(); return getAnnotation(m, HaHotStateRequired.class) != null; } - + private T getAnnotation(Method m, Class annotation) { T am = m.getAnnotation(annotation); if (am != null) { @@ -146,14 +126,4 @@ public class HaHotCheckResourceFilter implements ContainerRequestFilter { return null; } - private boolean isSkipCheckHeaderSet(ContainerRequestContext requestContext) { - return "true".equalsIgnoreCase(requestContext.getHeaderString(SKIP_CHECK_HEADER)); - } - - private boolean isHaHotStatus() { - ManagementNodeState state = mgmt().getHighAvailabilityManager().getNodeState(); - return HOT_STATES.contains(state); - } - - } http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/3ab00406/rest/rest-resources/src/test/java/org/apache/brooklyn/rest/resources/CatalogResourceTest.java ---------------------------------------------------------------------- diff --git a/rest/rest-resources/src/test/java/org/apache/brooklyn/rest/resources/CatalogResourceTest.java b/rest/rest-resources/src/test/java/org/apache/brooklyn/rest/resources/CatalogResourceTest.java index 8d5d017..f3374dc 100644 --- a/rest/rest-resources/src/test/java/org/apache/brooklyn/rest/resources/CatalogResourceTest.java +++ b/rest/rest-resources/src/test/java/org/apache/brooklyn/rest/resources/CatalogResourceTest.java @@ -126,6 +126,7 @@ public class CatalogResourceTest extends BrooklynRestResourceTest { // an InterfacesTag should be created for every catalog item assertEquals(entityItem.getTags().size(), 1); Object tag = entityItem.getTags().iterator().next(); + @SuppressWarnings("unchecked") List actualInterfaces = ((Map>) tag).get("traits"); List> expectedInterfaces = Reflections.getAllInterfaces(TestEntity.class); assertEquals(actualInterfaces.size(), expectedInterfaces.size()); @@ -138,6 +139,7 @@ public class CatalogResourceTest extends BrooklynRestResourceTest { } @Test + // osgi may fail in IDE, typically works on CLI though public void testRegisterOsgiPolicyTopLevelSyntax() { TestResourceUnavailableException.throwIfResourceUnavailable(getClass(), OsgiStandaloneTest.BROOKLYN_TEST_OSGI_ENTITIES_PATH); http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/3ab00406/rest/rest-server/src/main/java/org/apache/brooklyn/rest/filter/HaMasterCheckFilter.java ---------------------------------------------------------------------- diff --git a/rest/rest-server/src/main/java/org/apache/brooklyn/rest/filter/HaMasterCheckFilter.java b/rest/rest-server/src/main/java/org/apache/brooklyn/rest/filter/HaMasterCheckFilter.java index 991d58c..bfb1caf 100644 --- a/rest/rest-server/src/main/java/org/apache/brooklyn/rest/filter/HaMasterCheckFilter.java +++ b/rest/rest-server/src/main/java/org/apache/brooklyn/rest/filter/HaMasterCheckFilter.java @@ -30,18 +30,14 @@ import javax.servlet.ServletRequest; import javax.servlet.ServletResponse; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; -import javax.ws.rs.core.Response; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; import org.apache.brooklyn.api.mgmt.ManagementContext; import org.apache.brooklyn.api.mgmt.ha.ManagementNodeState; -import org.apache.brooklyn.rest.domain.ApiError; +import org.apache.brooklyn.rest.util.OsgiCompat; import org.apache.brooklyn.rest.util.WebResourceUtils; -import org.apache.brooklyn.util.text.Strings; +import org.apache.brooklyn.util.guava.Maybe; import com.google.common.collect.Sets; -import org.apache.brooklyn.rest.util.OsgiCompat; /** * Checks that for requests that want HA master state, the server is up and in that state. @@ -52,13 +48,17 @@ import org.apache.brooklyn.rest.util.OsgiCompat; // TODO Merge with HaHotCheckResourceFilter so the functionality is available in Karaf public class HaMasterCheckFilter implements Filter { - private static final Logger log = LoggerFactory.getLogger(HaMasterCheckFilter.class); - private static final Set SAFE_STANDBY_METHODS = Sets.newHashSet("GET", "HEAD"); protected ServletContext servletContext; protected ManagementContext mgmt; + private HaHotCheckHelperAbstract helper = new HaHotCheckHelperAbstract() { + public ManagementContext mgmt() { + return mgmt; + } + }; + @Override public void init(FilterConfig config) throws ServletException { servletContext = config.getServletContext(); @@ -66,15 +66,15 @@ public class HaMasterCheckFilter implements Filter { } private String lookForProblem(ServletRequest request) { - if (isSkipCheckHeaderSet(request)) + if (helper.isSkipCheckHeaderSet(((HttpServletRequest)request).getHeader(HaHotCheckHelperAbstract.SKIP_CHECK_HEADER))) return null; if (!isMasterRequiredForRequest(request)) return null; - String problem = HaHotCheckResourceFilter.lookForProblemIfServerNotRunning(mgmt); - if (Strings.isNonBlank(problem)) - return problem; + Maybe problem = helper.getProblemMessageIfServerNotRunning(); + if (problem.isPresent()) + return problem.get(); if (!isMaster()) return "server not in required HA master state"; @@ -86,10 +86,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 web request as "+problem+": "+request.getParameterMap()+" (caller should set '"+HaHotCheckResourceFilter.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); + WebResourceUtils.applyJsonResponse(servletContext, helper.disallowResponse(problem, request.getParameterMap()), (HttpServletResponse)response); } else { chain.doFilter(request, response); } @@ -124,10 +121,4 @@ public class HaMasterCheckFilter implements Filter { return true; } - private boolean isSkipCheckHeaderSet(ServletRequest httpRequest) { - if (httpRequest instanceof HttpServletRequest) - return "true".equalsIgnoreCase(((HttpServletRequest)httpRequest).getHeader(HaHotCheckResourceFilter.SKIP_CHECK_HEADER)); - return false; - } - } http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/3ab00406/rest/rest-server/src/test/java/org/apache/brooklyn/rest/BrooklynRestApiLauncher.java ---------------------------------------------------------------------- diff --git a/rest/rest-server/src/test/java/org/apache/brooklyn/rest/BrooklynRestApiLauncher.java b/rest/rest-server/src/test/java/org/apache/brooklyn/rest/BrooklynRestApiLauncher.java index 8d71dcb..d9f0f1a 100644 --- a/rest/rest-server/src/test/java/org/apache/brooklyn/rest/BrooklynRestApiLauncher.java +++ b/rest/rest-server/src/test/java/org/apache/brooklyn/rest/BrooklynRestApiLauncher.java @@ -36,7 +36,6 @@ import org.apache.brooklyn.core.mgmt.internal.LocalManagementContext; import org.apache.brooklyn.core.mgmt.internal.ManagementContextInternal; import org.apache.brooklyn.core.server.BrooklynServerConfig; import org.apache.brooklyn.core.server.BrooklynServiceAttributes; -import org.apache.brooklyn.rest.apidoc.RestApiResourceScanner; import org.apache.brooklyn.rest.filter.BrooklynPropertiesSecurityFilter; import org.apache.brooklyn.rest.filter.HaMasterCheckFilter; import org.apache.brooklyn.rest.filter.LoggingFilter; @@ -44,7 +43,6 @@ import org.apache.brooklyn.rest.filter.RequestTaggingFilter; import org.apache.brooklyn.rest.security.provider.AnyoneSecurityProvider; import org.apache.brooklyn.rest.security.provider.SecurityProvider; import org.apache.brooklyn.rest.util.ManagementContextProvider; -import org.apache.brooklyn.rest.util.OsgiCompat; import org.apache.brooklyn.rest.util.ServerStoppingShutdownHandler; import org.apache.brooklyn.rest.util.ShutdownHandlerProvider; import org.apache.brooklyn.util.core.ResourceUtils; @@ -68,8 +66,6 @@ import com.google.common.collect.ImmutableList; import com.google.common.collect.Lists; import com.google.common.io.Files; -import io.swagger.config.ScannerFactory; - /** Convenience and demo for launching programmatically. Also used for automated tests. *

* BrooklynLauncher has a more full-featured CLI way to start,