added Health-Interface for microservice diag-tool
diff --git a/pom.xml b/pom.xml index 3467b1a..3151c18 100644 --- a/pom.xml +++ b/pom.xml
@@ -6,7 +6,7 @@ <groupId>openk.pta.de</groupId> <artifactId>portal</artifactId> - <version>1.0.1</version> + <version>1.0.2</version> <packaging>war</packaging> <properties>
diff --git a/src/main/java/org/eclipse/openk/portal/auth2/util/JwtHelper.java b/src/main/java/org/eclipse/openk/portal/auth2/util/JwtHelper.java index be182d5..f3a550a 100644 --- a/src/main/java/org/eclipse/openk/portal/auth2/util/JwtHelper.java +++ b/src/main/java/org/eclipse/openk/portal/auth2/util/JwtHelper.java
@@ -45,11 +45,18 @@ public static JwtToken login(String user, String password) throws PortalInternalServerError { String token = sendPost(BackendConfig.getInstance().getAuthServerUrl() + "auth/realms/" + - BackendConfig.getInstance().getKeycloakRealm() + "/protocol/openid-connect/token", - "username=" + user + "&password=" + password + "&client_id=" + BackendConfig.getInstance().getKeycloakClient() + "&grant_type=password"); + BackendConfig.getInstance().getKeycloakRealm() + "/protocol/openid-connect/token", + "username=" + user + "&password=" + password + "&client_id=" + + BackendConfig.getInstance().getKeycloakClient() + "&grant_type=password"); return getJwtTokenFromJson(token); } + public static boolean serviceAvailable() throws PortalInternalServerError { + String jsonRet = sendGet(BackendConfig.getInstance().getAuthServerUrl() + "auth/realms/" + + BackendConfig.getInstance().getKeycloakRealm(), "", null); + return jsonRet.contains("realm") && jsonRet.contains(BackendConfig.getInstance().getKeycloakRealm()); + } + public static List<KeyCloakUser> getUsers(JwtToken jwtToken, int maxUsers) throws PortalInternalServerError { String users = sendGet(BackendConfig.getInstance().getAuthServerUrl() + "auth/admin/realms/" + BackendConfig.getInstance().getKeycloakRealm() + "/users?max="+maxUsers, MediaType.APPLICATION_JSON, jwtToken.getAccessToken());
diff --git a/src/main/java/org/eclipse/openk/portal/health/base/HealthCheck.java b/src/main/java/org/eclipse/openk/portal/health/base/HealthCheck.java new file mode 100644 index 0000000..08fc817 --- /dev/null +++ b/src/main/java/org/eclipse/openk/portal/health/base/HealthCheck.java
@@ -0,0 +1,17 @@ +/* + ****************************************************************************** + * Copyright © 2017-2018 PTA GmbH. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * + * http://www.eclipse.org/legal/epl-v10.html + * + ****************************************************************************** + */ +package org.eclipse.openk.portal.health.base; + +public abstract class HealthCheck { + + protected abstract Result check() throws Exception; +}
diff --git a/src/main/java/org/eclipse/openk/portal/health/base/HealthChecker.java b/src/main/java/org/eclipse/openk/portal/health/base/HealthChecker.java new file mode 100644 index 0000000..33d04f5 --- /dev/null +++ b/src/main/java/org/eclipse/openk/portal/health/base/HealthChecker.java
@@ -0,0 +1,47 @@ +/* + ****************************************************************************** + * Copyright © 2017-2018 PTA GmbH. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * + * http://www.eclipse.org/legal/epl-v10.html + * + ****************************************************************************** +*/ +package org.eclipse.openk.portal.health.base; + +import org.apache.log4j.Logger; + +import java.util.HashMap; +import java.util.LinkedList; +import java.util.List; +import java.util.Map; + +public class HealthChecker { + private static final Logger logger = Logger.getLogger(HealthChecker.class); + + private List<HealthCheck> registeredHealthChecks = new LinkedList<>(); + private Map<HealthCheck, String> namingMap = new HashMap<>(); + + public void register( String title, HealthCheck hc ) { + namingMap.put(hc, title); + registeredHealthChecks.add(hc); + } + + public List<NamedHealthCheckResult> performHealthChecks() { + List<NamedHealthCheckResult> hcList = new LinkedList<>(); + for( HealthCheck hc : registeredHealthChecks) { + try { + hcList.add(new NamedHealthCheckResult(namingMap.get(hc), hc.check())); + + } catch (Throwable t) { + logger.error("Error during healthcheck", t); + hcList.add(new NamedHealthCheckResult(namingMap.get(hc), + Result.unhealthy("Exception during test: "+t+" -> See Log!"))); + } + } + return hcList; + } + +}
diff --git a/src/main/java/org/eclipse/openk/portal/health/base/NamedHealthCheckResult.java b/src/main/java/org/eclipse/openk/portal/health/base/NamedHealthCheckResult.java new file mode 100644 index 0000000..9ee581e --- /dev/null +++ b/src/main/java/org/eclipse/openk/portal/health/base/NamedHealthCheckResult.java
@@ -0,0 +1,53 @@ +/* + ****************************************************************************** + * Copyright © 2017-2018 PTA GmbH. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * + * http://www.eclipse.org/legal/epl-v10.html + * + ****************************************************************************** + */ +package org.eclipse.openk.portal.health.base; + +import com.google.gson.GsonBuilder; + +import java.util.List; + +public class NamedHealthCheckResult { + private String name; + private Result result; + + public NamedHealthCheckResult( String name, Result result ) { + this.name = name; + this.result = result; + } + + public String toJson() { + StringBuffer buffer = new StringBuffer(); + buffer.append("\""+name+"\":"); + buffer.append(new GsonBuilder().disableHtmlEscaping().create().toJson(result)); + return buffer.toString(); + } + + public static String toJson(List<NamedHealthCheckResult> resultArray ) { + StringBuilder builder = new StringBuilder(); + builder.append('{'); + for( int i=0; i < resultArray.size(); i++ ) { + builder.append(resultArray.get(i).toJson()); + if( i+1 < resultArray.size() ) { + builder.append(','); + } + } + return builder.append('}').toString(); + } + + public String getName() { + return name; + } + + public Result getResult() { + return result; + } +}
diff --git a/src/main/java/org/eclipse/openk/portal/health/base/Result.java b/src/main/java/org/eclipse/openk/portal/health/base/Result.java new file mode 100644 index 0000000..6ff7de7 --- /dev/null +++ b/src/main/java/org/eclipse/openk/portal/health/base/Result.java
@@ -0,0 +1,41 @@ +/* + ****************************************************************************** + * Copyright © 2017-2018 PTA GmbH. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * + * http://www.eclipse.org/legal/epl-v10.html + * + ****************************************************************************** + */ +package org.eclipse.openk.portal.health.base; + + +public class Result { + private boolean healthy; + private String message; + + private Result() {} + + public static Result healthy() { + Result res = new Result(); + res.healthy = true; + return res; + } + + public static Result unhealthy(String message) { + Result res = new Result(); + res.healthy = false; + res.message = message; + return res; + } + + public String getMessage() { + return message; + } + + public boolean isHealthy() { + return healthy; + } +}
diff --git a/src/main/java/org/eclipse/openk/portal/health/impl/KeyCloakPresentHealthCheck.java b/src/main/java/org/eclipse/openk/portal/health/impl/KeyCloakPresentHealthCheck.java new file mode 100644 index 0000000..1295f46 --- /dev/null +++ b/src/main/java/org/eclipse/openk/portal/health/impl/KeyCloakPresentHealthCheck.java
@@ -0,0 +1,38 @@ +/* + ****************************************************************************** + * Copyright © 2017-2018 PTA GmbH. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * + * http://www.eclipse.org/legal/epl-v10.html + * + ****************************************************************************** + */ +package org.eclipse.openk.portal.health.impl; + +import org.eclipse.openk.portal.auth2.util.JwtHelper; +import org.eclipse.openk.portal.common.BackendConfig; +import org.eclipse.openk.portal.exceptions.PortalInternalServerError; +import org.eclipse.openk.portal.health.base.HealthCheck; +import org.eclipse.openk.portal.health.base.Result; + +public class KeyCloakPresentHealthCheck extends HealthCheck { + public KeyCloakPresentHealthCheck() {} + + protected boolean checkit() throws PortalInternalServerError { + return JwtHelper.serviceAvailable(); + } + + @Override + protected Result check() throws Exception { + if( checkit() ) { + return Result.healthy(); + } + else { + BackendConfig gc = BackendConfig.getInstance(); + String msg = gc.getAuthServerUrl() + "/" + gc.getKeycloakRealm(); + return Result.unhealthy("KeyCloak-Service not available: "+msg); + } + } +}
diff --git a/src/main/java/org/eclipse/openk/portal/rest/BackendRestService.java b/src/main/java/org/eclipse/openk/portal/rest/BackendRestService.java index 532349d..79ce8e8 100644 --- a/src/main/java/org/eclipse/openk/portal/rest/BackendRestService.java +++ b/src/main/java/org/eclipse/openk/portal/rest/BackendRestService.java
@@ -11,7 +11,8 @@ */ package org.eclipse.openk.portal.rest; -import javax.ws.rs.PathParam; +import javax.ws.rs.*; + import org.apache.log4j.Logger; import org.eclipse.openk.portal.auth2.model.JwtToken; import org.eclipse.openk.portal.common.Globals; @@ -24,14 +25,11 @@ import org.eclipse.openk.portal.exceptions.PortalException; import org.eclipse.openk.portal.exceptions.PortalExceptionMapper; import org.eclipse.openk.portal.exceptions.PortalUnauthorized; +import org.eclipse.openk.portal.health.base.HealthChecker; +import org.eclipse.openk.portal.health.base.NamedHealthCheckResult; +import org.eclipse.openk.portal.health.impl.KeyCloakPresentHealthCheck; import org.eclipse.openk.portal.viewmodel.VersionInfo; -import javax.ws.rs.Consumes; -import javax.ws.rs.GET; -import javax.ws.rs.HeaderParam; -import javax.ws.rs.POST; -import javax.ws.rs.Path; -import javax.ws.rs.Produces; import javax.ws.rs.core.Context; import javax.ws.rs.core.Response; import javax.ws.rs.core.UriInfo; @@ -137,6 +135,23 @@ return invoke(accessToken, false, new ControllerImplementations.GetUsers()); } + @GET + @Path("/healthcheck") + @Produces("application/json") + public Response getHealthCheck(@FormParam(value = "pretty") boolean yn) { + HealthChecker hc = new HealthChecker(); + hc.register("Keycloak present", new KeyCloakPresentHealthCheck()); + + String returnJson = NamedHealthCheckResult.toJson(hc.performHealthChecks()); + + try { + return ResponseBuilderWrapper.INSTANCE.buildOKResponse(returnJson); + } catch (PortalException e) { + logger.error("unexpected error", e); + return Response.status(Response.Status.INTERNAL_SERVER_ERROR).build(); + } + } + private boolean isBackdoor( String sessionId ) { // backdoor is only available when the version(POM) contains "DEVELOP" or "SNAPSHOT" return DEVELOP_MODE && LET_ME_IN.equals(sessionId);
diff --git a/src/test/java/org/eclipse/openk/portal/health/base/HealthCheckerTest.java b/src/test/java/org/eclipse/openk/portal/health/base/HealthCheckerTest.java new file mode 100644 index 0000000..87aed26 --- /dev/null +++ b/src/test/java/org/eclipse/openk/portal/health/base/HealthCheckerTest.java
@@ -0,0 +1,93 @@ +/* + ****************************************************************************** + * Copyright © 2018 PTA GmbH. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * + * http://www.eclipse.org/legal/epl-v10.html + * + ****************************************************************************** +*/ +package org.eclipse.openk.portal.health.base; + +import org.junit.Before; +import org.junit.Test; + +import java.util.List; + +import static junit.framework.TestCase.assertTrue; +import static org.junit.Assert.*; + +public class HealthCheckerTest { + public boolean hc1Called; + public boolean hc2Called; + public boolean hc3Called; + + @Before + public void init() { + hc1Called = false; + hc2Called = false; + hc3Called = false; + } + + @Test + public void test_ok() { + HealthCheck hc1 = new HealthCheck() { + + @Override + protected Result check() throws Exception { + hc1Called = true; + return Result.healthy(); + } + }; + + HealthCheck hc2 = new HealthCheck() { + @Override + protected Result check() throws Exception { + hc2Called = true; + return Result.unhealthy("because of..."); + } + }; + + HealthChecker theChecker = new HealthChecker(); + theChecker.register("firstTest", hc1 ); + theChecker.register( "secondTest", hc2 ); + + List<NamedHealthCheckResult> retList = theChecker.performHealthChecks(); + + assertEquals( 2, retList.size() ); + assertTrue( hc1Called ); + assertTrue( hc2Called ); + assertNull( retList.get(0).getResult().getMessage()); + assertNotNull( retList.get(1).getResult().getMessage()); + assertEquals( "firstTest", retList.get(0).getName()); + assertEquals( "secondTest", retList.get(1).getName()); + assertTrue( retList.get(0).getResult().isHealthy()); + assertFalse( retList.get(1).getResult().isHealthy()); + } + + @Test + public void test_nok() { + HealthCheck hc1 = new HealthCheck() { + + @Override + protected Result check() throws Exception { + hc3Called = true; + throw new Exception("Error in healthCheck"); + } + }; + + + HealthChecker theChecker = new HealthChecker(); + theChecker.register("errorTest", hc1 ); + + List<NamedHealthCheckResult> retList = theChecker.performHealthChecks(); + + assertEquals( 1, retList.size() ); + assertTrue( hc3Called ); + assertNotNull( retList.get(0).getResult().getMessage()); + assertFalse( retList.get(0).getResult().isHealthy()); + + } +}
diff --git a/src/test/java/org/eclipse/openk/portal/health/base/NamedHealthCheckResultTest.java b/src/test/java/org/eclipse/openk/portal/health/base/NamedHealthCheckResultTest.java new file mode 100644 index 0000000..0fdd4e7 --- /dev/null +++ b/src/test/java/org/eclipse/openk/portal/health/base/NamedHealthCheckResultTest.java
@@ -0,0 +1,25 @@ +package org.eclipse.openk.portal.health.base; + +import org.junit.Test; + +import java.util.LinkedList; +import java.util.List; + +import static org.junit.Assert.assertEquals; + +public class NamedHealthCheckResultTest { + @Test + public void testAll() { + NamedHealthCheckResult h1 = new NamedHealthCheckResult("Uno", Result.healthy()); + NamedHealthCheckResult h2 = new NamedHealthCheckResult("Due", Result.unhealthy("Darum")); + + assertEquals("\"Uno\":{\"healthy\":true}", h1.toJson()); + assertEquals("\"Due\":{\"healthy\":false,\"message\":\"Darum\"}", h2.toJson()); + + List<NamedHealthCheckResult> lista = new LinkedList<>(); + lista.add(h1); + lista.add(h2); + assertEquals( "{\"Uno\":{\"healthy\":true},\"Due\":{\"healthy\":false,\"message\":\"Darum\"}}", + NamedHealthCheckResult.toJson(lista)); + } +}
diff --git a/src/test/java/org/eclipse/openk/portal/health/base/ResultTest.java b/src/test/java/org/eclipse/openk/portal/health/base/ResultTest.java new file mode 100644 index 0000000..9379922 --- /dev/null +++ b/src/test/java/org/eclipse/openk/portal/health/base/ResultTest.java
@@ -0,0 +1,20 @@ +package org.eclipse.openk.portal.health.base; + +import org.junit.Test; + +import static org.junit.Assert.*; + +public class ResultTest { + + @Test + public void testAll() { + Result res1 = Result.healthy(); + Result res2 = Result.unhealthy("Msg"); + + assertTrue(res1.isHealthy()); + assertFalse(res2.isHealthy()); + assertNull(res1.getMessage()); + assertNotNull(res2.getMessage()); + + } +}
diff --git a/src/test/java/org/eclipse/openk/portal/health/impl/KeyCloakPresentHealthCheckTest.java b/src/test/java/org/eclipse/openk/portal/health/impl/KeyCloakPresentHealthCheckTest.java new file mode 100644 index 0000000..1727b6a --- /dev/null +++ b/src/test/java/org/eclipse/openk/portal/health/impl/KeyCloakPresentHealthCheckTest.java
@@ -0,0 +1,37 @@ +package org.eclipse.openk.portal.health.impl; + +import org.junit.Before; +import org.junit.Test; +import org.powermock.reflect.Whitebox; + +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; + +public class KeyCloakPresentHealthCheckTest { + private KeyCloakPresentHealthCheck hc; + + @Before + public void init() { + hc = new KeyCloakPresentHealthCheck() { + public boolean checkit; + + @Override + protected boolean checkit() { + return checkit; + } + }; + } + + @Test + public void testOk() throws Exception { + Whitebox.setInternalState(hc, "checkit", true); + assertTrue(hc.check().isHealthy()); + } + + @Test + public void testNok() throws Exception { + Whitebox.setInternalState(hc, "checkit", false); + assertFalse(hc.check().isHealthy()); + } + +}