diff --git a/jkube-kit/common/src/main/java/org/eclipse/jkube/kit/common/util/SpringBootConfiguration.java b/jkube-kit/common/src/main/java/org/eclipse/jkube/kit/common/util/SpringBootConfiguration.java index ae8103d508..7349afe7d7 100644 --- a/jkube-kit/common/src/main/java/org/eclipse/jkube/kit/common/util/SpringBootConfiguration.java +++ b/jkube-kit/common/src/main/java/org/eclipse/jkube/kit/common/util/SpringBootConfiguration.java @@ -35,6 +35,7 @@ public class SpringBootConfiguration { private String managementContextPath; private String actuatorBasePath; private String actuatorDefaultBasePath; + private boolean managementHealthProbesEnabled; public static SpringBootConfiguration from(JavaProject project) { final Properties properties = SpringBootUtil.getSpringBootApplicationProperties( @@ -56,6 +57,7 @@ public static SpringBootConfiguration from(JavaProject project) { .managementPort(Optional.ofNullable(properties.getProperty("management.port")).map(Integer::parseInt).orElse(null)) .serverPort(Integer.parseInt(properties.getProperty("server.port", DEFAULT_SERVER_PORT))) .serverKeystore(properties.getProperty("server.ssl.key-store")) + .managementHealthProbesEnabled(Boolean.parseBoolean(properties.getProperty("management.health.probes.enabled"))) .managementKeystore(properties.getProperty("management.ssl.key-store")) .servletPath(properties.getProperty("server.servlet-path")) .serverContextPath(properties.getProperty("server.context-path")) diff --git a/jkube-kit/jkube-kit-spring-boot/src/main/java/org/eclipse/jkube/springboot/enricher/SpringBootHealthCheckEnricher.java b/jkube-kit/jkube-kit-spring-boot/src/main/java/org/eclipse/jkube/springboot/enricher/SpringBootHealthCheckEnricher.java index b592cee955..d9bc10375b 100644 --- a/jkube-kit/jkube-kit-spring-boot/src/main/java/org/eclipse/jkube/springboot/enricher/SpringBootHealthCheckEnricher.java +++ b/jkube-kit/jkube-kit-spring-boot/src/main/java/org/eclipse/jkube/springboot/enricher/SpringBootHealthCheckEnricher.java @@ -39,6 +39,9 @@ public class SpringBootHealthCheckEnricher extends AbstractHealthCheckEnricher { private static final String SCHEME_HTTPS = "HTTPS"; private static final String SCHEME_HTTP = "HTTP"; + private static final String LIVENESS_PROBE_SUFFIX = "/liveness"; + private static final String READINESS_PROBE_SUFFIX = "/readiness"; + @AllArgsConstructor private enum Config implements Configs.Config { READINESS_PROBE_INITIAL_DELAY_SECONDS("readinessProbeInitialDelaySeconds", "10"), @@ -67,7 +70,7 @@ protected Probe getReadinessProbe() { Integer timeout = Configs.asInteger(getConfig(Config.TIMEOUT_SECONDS)); Integer failureThreshold = Configs.asInteger(getConfig(Config.FAILURE_THRESHOLD)); Integer successThreshold = Configs.asInteger(getConfig(Config.SUCCESS_THRESHOLD)); - return discoverSpringBootHealthCheck(initialDelay, period, timeout, failureThreshold, successThreshold); + return discoverSpringBootHealthCheck(initialDelay, period, timeout, failureThreshold, successThreshold, READINESS_PROBE_SUFFIX); } @Override @@ -77,13 +80,13 @@ protected Probe getLivenessProbe() { Integer timeout = Configs.asInteger(getConfig(Config.TIMEOUT_SECONDS)); Integer failureThreshold = Configs.asInteger(getConfig(Config.FAILURE_THRESHOLD)); Integer successThreshold = Configs.asInteger(getConfig(Config.SUCCESS_THRESHOLD)); - return discoverSpringBootHealthCheck(initialDelay, period, timeout, failureThreshold, successThreshold); + return discoverSpringBootHealthCheck(initialDelay, period, timeout, failureThreshold, successThreshold, LIVENESS_PROBE_SUFFIX); } - protected Probe discoverSpringBootHealthCheck(Integer initialDelay, Integer period, Integer timeout, Integer failureTh, Integer successTh) { + protected Probe discoverSpringBootHealthCheck(Integer initialDelay, Integer period, Integer timeout, Integer failureTh, Integer successTh, String suffix) { try { if (getContext().getProjectClassLoaders().isClassInCompileClasspath(true, REQUIRED_CLASSES)) { - return buildProbe(initialDelay, period, timeout, failureTh, successTh); + return buildProbe(initialDelay, period, timeout, failureTh, successTh, suffix); } } catch (Exception ex) { log.error("Error while reading the spring-boot configuration", ex); @@ -91,7 +94,7 @@ protected Probe discoverSpringBootHealthCheck(Integer initialDelay, Integer peri return null; } - protected Probe buildProbe(Integer initialDelay, Integer period, Integer timeout, Integer failureTh, Integer successTh) { + protected Probe buildProbe(Integer initialDelay, Integer period, Integer timeout, Integer failureTh, Integer successTh, String suffix) { final SpringBootConfiguration springBootConfiguration = SpringBootConfiguration.from(getContext().getProject()); Integer managementPort = springBootConfiguration.getManagementPort(); boolean usingManagementPort = managementPort != null; @@ -122,9 +125,16 @@ protected Probe buildProbe(Integer initialDelay, Integer period, Integer timeout actuatorBasePath = springBootConfiguration.getActuatorBasePath(); } + // adds suffix to probe paths when ManagementHealthProbesEnabled is true + String probePath = prefix + actuatorBasePath + Configs.asString(getConfig(Config.PATH)); + if(springBootConfiguration.isManagementHealthProbesEnabled()){ + probePath += suffix; + } + probePath = normalizeMultipleSlashes(probePath); + // lets default to adding a spring boot actuator health check ProbeBuilder probeBuilder = new ProbeBuilder(). - withNewHttpGet().withNewPort(port).withPath(normalizeMultipleSlashes(prefix + actuatorBasePath + Configs.asString(getConfig(Config.PATH)))).withScheme(scheme).endHttpGet(); + withNewHttpGet().withNewPort(port).withPath(probePath).withScheme(scheme).endHttpGet(); if (initialDelay != null) { probeBuilder = probeBuilder.withInitialDelaySeconds(initialDelay); diff --git a/jkube-kit/jkube-kit-spring-boot/src/test/java/org/eclipse/jkube/springboot/enricher/AbstractSpringBootHealthCheckEnricherTestSupport.java b/jkube-kit/jkube-kit-spring-boot/src/test/java/org/eclipse/jkube/springboot/enricher/AbstractSpringBootHealthCheckEnricherTestSupport.java index c14d1940d7..8752bf97a6 100644 --- a/jkube-kit/jkube-kit-spring-boot/src/test/java/org/eclipse/jkube/springboot/enricher/AbstractSpringBootHealthCheckEnricherTestSupport.java +++ b/jkube-kit/jkube-kit-spring-boot/src/test/java/org/eclipse/jkube/springboot/enricher/AbstractSpringBootHealthCheckEnricherTestSupport.java @@ -86,7 +86,7 @@ private boolean isSpringBootOne() { void zeroConfig() { SpringBootHealthCheckEnricher enricher = new SpringBootHealthCheckEnricher(context); - Probe probe = enricher.buildProbe(10, null, null, 3, 1); + Probe probe = enricher.buildProbe(10, null, null, 3, 1,null); assertHTTPGetPathAndPort(probe, getActuatorDefaultBasePath() + "/health", 8080); } @@ -96,7 +96,7 @@ void withServerPort() { writeProps(); Probe probe = new SpringBootHealthCheckEnricher(context) - .buildProbe(10, null, null, 3, 1); + .buildProbe(10, null, null, 3, 1,null); assertHTTPGetPathAndPort(probe, getActuatorDefaultBasePath() + "/health", 8282); } @@ -108,7 +108,7 @@ void withServerPortAndManagementPort() { writeProps(); Probe probe = new SpringBootHealthCheckEnricher(context) - .buildProbe(10, null, null, 3, 1); + .buildProbe(10, null, null, 3, 1,null); assertHTTPGetPathAndPort(probe, getActuatorDefaultBasePath() + "/health", 8383); } @@ -122,7 +122,7 @@ void withServerPortAndManagementPortAndServerContextPath() { writeProps(); Probe probe = new SpringBootHealthCheckEnricher(context) - .buildProbe(10, null, null, 3, 1); + .buildProbe(10, null, null, 3, 1,null); assertHTTPGetPathAndPort(probe, getActuatorDefaultBasePath() + "/health", 8383); } @@ -138,7 +138,7 @@ void withServerPortAndManagementPortAndServerContextPathAndActuatorBasePath() { writeProps(); Probe probe = new SpringBootHealthCheckEnricher(context) - .buildProbe(10, null, null, 3, 1); + .buildProbe(10, null, null, 3, 1,null); assertHTTPGetPathAndPort(probe, "/actuator-base-path/health", 8383); } @@ -153,7 +153,7 @@ void withServerPortAndManagementPortAndServerContextPathAndActuatorDefaultBasePa writeProps(); Probe probe = new SpringBootHealthCheckEnricher(context) - .buildProbe(10, null, null, 3, 1); + .buildProbe(10, null, null, 3, 1, null); assertHTTPGetPathAndPort(probe, "/health", 8383); } @@ -170,7 +170,7 @@ void withServerPortAndManagementPortAndManagementContextPath() { writeProps(); Probe probe = new SpringBootHealthCheckEnricher(context) - .buildProbe(10, null, null, 3, 1); + .buildProbe(10, null, null, 3, 1,null); assertHTTPGetPathAndPort(probe, "/p2" + getActuatorDefaultBasePath() + "/health", 8383); } @@ -189,7 +189,7 @@ void withServerPortAndManagementPortAndManagementContextPathAndActuatorDefaultBa writeProps(); Probe probe = new SpringBootHealthCheckEnricher(context) - .buildProbe(10, null, null, 3, 1); + .buildProbe(10, null, null, 3, 1,null); assertHTTPGetPathAndPort(probe, "/p2/actuator-base-path/health", 8383); } @@ -207,7 +207,7 @@ void withServerPortAndManagementPortAndManagementContextPathAndActuatorDefaultBa writeProps(); Probe probe = new SpringBootHealthCheckEnricher(context) - .buildProbe(10, null, null, 3, 1); + .buildProbe(10, null, null, 3, 1,null); assertHTTPGetPathAndPort(probe, "/health", 8383); } @@ -227,7 +227,7 @@ void withServerPortAndManagementPortAndManagementContextPathAndServletPath() { writeProps(); Probe probe = new SpringBootHealthCheckEnricher(context) - .buildProbe(10, null, null, 3, 1); + .buildProbe(10, null, null, 3, 1,null); assertHTTPGetPathAndPort(probe, "/p2" + getActuatorDefaultBasePath() + "/health", 8383); } @@ -249,7 +249,7 @@ void withServerPortAndManagementPortAndManagementContextPathAndServletPathAndAct writeProps(); Probe probe = new SpringBootHealthCheckEnricher(context) - .buildProbe(10, null, null, 3, 1); + .buildProbe(10, null, null, 3, 1,null); assertHTTPGetPathAndPort(probe, "/p2/actuator-base-path/health", 8383); } @@ -270,7 +270,7 @@ void withServerPortAndManagementPortAndManagementContextPathAndServletPathAndAct writeProps(); Probe probe = new SpringBootHealthCheckEnricher(context) - .buildProbe(10, null, null, 3, 1); + .buildProbe(10, null, null, 3, 1,null); assertHTTPGetPathAndPort(probe, "/health", 8383); } @@ -283,7 +283,7 @@ void withServerPortAndManagementContextPath() { writeProps(); Probe probe = new SpringBootHealthCheckEnricher(context) - .buildProbe(10, null, null, 3, 1); + .buildProbe(10, null, null, 3, 1,null); assertHTTPGetPathAndPort(probe, "/p1" + getActuatorDefaultBasePath() +"/health", 8282); } @@ -298,7 +298,7 @@ void withServerPortAndManagementContextPathAndActuatorBasePath() { writeProps(); Probe probe = new SpringBootHealthCheckEnricher(context) - .buildProbe(10, null, null, 3, 1); + .buildProbe(10, null, null, 3, 1,null); assertHTTPGetPathAndPort(probe, "/p1/actuator-base-path/health", 8282); } @@ -312,7 +312,7 @@ void withServerPortAndManagementContextPathAndActuatorDefaultBasePathSlash() { writeProps(); Probe probe = new SpringBootHealthCheckEnricher(context) - .buildProbe(10, null, null, 3, 1); + .buildProbe(10, null, null, 3, 1,null); assertHTTPGetPathAndPort(probe, "/health", 8282); } @@ -327,7 +327,7 @@ void withServerPortAndServerContextPathAndManagementContextPath() { writeProps(); Probe probe = new SpringBootHealthCheckEnricher(context) - .buildProbe(10, null, null, 3, 1); + .buildProbe(10, null, null, 3, 1,null); assertHTTPGetPathAndPort(probe, "/p2/p1" + getActuatorDefaultBasePath() + "/health", 8282); } @@ -344,7 +344,7 @@ void withServerPortAndServerContextPathAndManagementContextPathAndActuatorBasePa writeProps(); Probe probe = new SpringBootHealthCheckEnricher(context) - .buildProbe(10, null, null, 3, 1); + .buildProbe(10, null, null, 3, 1,null); assertHTTPGetPathAndPort(probe, "/p2/p1/actuator-base-path/health", 8282); } @@ -360,7 +360,7 @@ void withServerPortAndServerContextPathAndManagementContextPathAndActuatorDefaul writeProps(); Probe probe = new SpringBootHealthCheckEnricher(context) - .buildProbe(10, null, null, 3, 1); + .buildProbe(10, null, null, 3, 1,null); assertHTTPGetPathAndPort(probe, "/health", 8282); } @@ -373,7 +373,7 @@ void withServerPortAndServletPath() { writeProps(); Probe probe = new SpringBootHealthCheckEnricher(context) - .buildProbe(10, null, null, 3, 1); + .buildProbe(10, null, null, 3, 1,null); assertHTTPGetPathAndPort(probe, "/servlet" + getActuatorDefaultBasePath() + "/health", 8282); } @@ -388,7 +388,7 @@ void withServerPortAndServletAndActuatorBasePathPath() { writeProps(); Probe probe = new SpringBootHealthCheckEnricher(context) - .buildProbe(10, null, null, 3, 1); + .buildProbe(10, null, null, 3, 1,null); assertHTTPGetPathAndPort(probe, "/servlet/actuator-base-path/health", 8282); } @@ -402,7 +402,7 @@ void withServerPortAndServletPathAndActuatorDefaultBasePathSlash() { writeProps(); Probe probe = new SpringBootHealthCheckEnricher(context) - .buildProbe(10, null, null, 3, 1); + .buildProbe(10, null, null, 3, 1,null); assertHTTPGetPathAndPort(probe, "/health", 8282); } @@ -418,7 +418,7 @@ void withServerPortAndManagementContextPathAndServletPath() { writeProps(); Probe probe = new SpringBootHealthCheckEnricher(context) - .buildProbe(10, null, null, 3, 1); + .buildProbe(10, null, null, 3, 1,null); assertHTTPGetPathAndPort(probe, "/servlet/p1" + getActuatorDefaultBasePath() + "/health", 8282); } @@ -436,7 +436,7 @@ void withServerPortAndManagementContextPathAndServletPathAndActuatorBasePath() { writeProps(); Probe probe = new SpringBootHealthCheckEnricher(context) - .buildProbe(10, null, null, 3, 1); + .buildProbe(10, null, null, 3, 1,null); assertHTTPGetPathAndPort(probe, "/servlet/p1/actuator-base-path/health", 8282); } @@ -453,7 +453,7 @@ void withServerPortAndManagementContextPathAndServletPathAndActuatorDefaultBaseP writeProps(); Probe probe = new SpringBootHealthCheckEnricher(context) - .buildProbe(10, null, null, 3, 1); + .buildProbe(10, null, null, 3, 1,null); assertHTTPGetPathAndPort(probe, "/health", 8282); } @@ -471,7 +471,7 @@ void withServerPortAndServerContextPathAndManagementContextPathAndServletPath() writeProps(); Probe probe = new SpringBootHealthCheckEnricher(context) - .buildProbe(10, null, null, 3, 1); + .buildProbe(10, null, null, 3, 1,null); assertHTTPGetPathAndPort(probe, "/p2/servlet/p1" + getActuatorDefaultBasePath() + "/health", 8282); } @@ -491,7 +491,7 @@ void withServerPortAndServerContextPathAndManagementContextPathAndServletPathAnd writeProps(); Probe probe = new SpringBootHealthCheckEnricher(context) - .buildProbe(10, null, null, 3, 1); + .buildProbe(10, null, null, 3, 1,null); assertHTTPGetPathAndPort(probe, "/p2/servlet/p1/actuator-base-path/health", 8282); } @@ -510,7 +510,7 @@ void withServerPortAndServerContextPathAndManagementContextPathAndServletPathAnd writeProps(); Probe probe = new SpringBootHealthCheckEnricher(context) - .buildProbe(10, null, null, 3, 1); + .buildProbe(10, null, null, 3, 1,null); assertHTTPGetPathAndPort(probe, "/health", 8282); } @@ -520,7 +520,7 @@ void schemeWithServerPort() { writeProps(); Probe probe = new SpringBootHealthCheckEnricher(context) - .buildProbe(10, null, null, 3, 1); + .buildProbe(10, null, null, 3, 1,null); assertHTTPGetSchemeAndPort(probe, "HTTP", 8443); } @@ -532,7 +532,7 @@ void schemeWithServerPortAndManagementKeystore() { writeProps(); Probe probe = new SpringBootHealthCheckEnricher(context) - .buildProbe(10, null, null, 3, 1); + .buildProbe(10, null, null, 3, 1,null); assertHTTPGetSchemeAndPort(probe, "HTTP", 8080); } @@ -543,7 +543,7 @@ void schemeWithServerPortAndServerKeystore() { writeProps(); Probe probe = new SpringBootHealthCheckEnricher(context) - .buildProbe(10, null, null, 3, 1); + .buildProbe(10, null, null, 3, 1,null); assertHTTPGetSchemeAndPort(probe, "HTTPS", 8443); } @@ -556,7 +556,7 @@ void schemeWithServerPortAndManagementPortAndServerKeystore() { writeProps(); Probe probe = new SpringBootHealthCheckEnricher(context) - .buildProbe(10, null, null, 3, 1); + .buildProbe(10, null, null, 3, 1,null); assertHTTPGetSchemeAndPort(probe, "HTTP", 8081); } @@ -570,7 +570,7 @@ void schemeWithServerPortAndManagementPortAndManagementKeystore() { writeProps(); Probe probe = new SpringBootHealthCheckEnricher(context) - .buildProbe(10, null, null, 3, 1); + .buildProbe(10, null, null, 3, 1,null); assertHTTPGetSchemeAndPort(probe, "HTTPS", 8443); } @@ -634,6 +634,73 @@ void testCustomPropertiesForLivenessAndReadiness() { assertHealthCheckDelays(livenessProbe, 460, 50, null); } + @Test + void testBuildProbeExplicitPathCreation_whenManagementHealthProbesEnabledIsTrue(){ + props.put("management.health.probes.enabled","true"); + writeProps(); + + Probe readinessProbe = new SpringBootHealthCheckEnricher(context).buildProbe(10, null, null, 3, 1,"/example"); + assertHTTPGetPathAndPort(readinessProbe,getActuatorDefaultBasePath() + "/health/example", 8080); + } + + @Test + void testBuildProbeDefaultPathCreation_whenManagementHealthProbesEnabledIsFalse(){ + props.put("management.health.probes.enabled","false"); + writeProps(); + + Probe readinessProbe = new SpringBootHealthCheckEnricher(context).buildProbe(10, null, null, 3, 1,"/example"); + assertHTTPGetPathAndPort(readinessProbe,getActuatorDefaultBasePath() + "/health", 8080); + } + + @Test + void testLivenessAndReadinessProbesForExplicitPath_whenManagementHealthProbesEnabledIsTrue(){ + props.put("management.health.probes.enabled","true"); + writeProps(); + + when(context.getProjectClassLoaders().isClassInCompileClasspath(true, REQUIRED_CLASSES)) + .thenReturn(true); + when(context.getProjectClassLoaders().getCompileClassLoader()) + .thenReturn(new URLClassLoader(new URL[0], AbstractSpringBootHealthCheckEnricherTestSupport.class.getClassLoader())); + + SpringBootHealthCheckEnricher enricher = new SpringBootHealthCheckEnricher(context); + + Probe livenessProbe = enricher.getLivenessProbe(); + assertHTTPGetPathAndPort(livenessProbe,getActuatorDefaultBasePath() + "/health/liveness",8080); + + Probe readinessProbe = enricher.getReadinessProbe(); + assertHTTPGetPathAndPort(readinessProbe,getActuatorDefaultBasePath() + "/health/readiness",8080); + + } + + @Test + void testLivenessAndReadinessProbesForDefaultPath_whenDefaultConfigUsed(){ + when(context.getProjectClassLoaders().isClassInCompileClasspath(true, REQUIRED_CLASSES)) + .thenReturn(true); + SpringBootHealthCheckEnricher enricher = new SpringBootHealthCheckEnricher(context); + + Probe livenessProbe = enricher.getLivenessProbe(); + assertHTTPGetPathAndPort(livenessProbe,getActuatorDefaultBasePath() + "/health",8080); + + Probe readinessProbe = enricher.getReadinessProbe(); + assertHTTPGetPathAndPort(readinessProbe,getActuatorDefaultBasePath() + "/health",8080); + } + + @Test + void testLivenessAndReadinessProbesForDefaultPath_whenManagementHealthProbesEnabledIsFalse(){ + props.put("management.health.probes.enabled","false"); + writeProps(); + + when(projectClassLoaders.isClassInCompileClasspath(true, REQUIRED_CLASSES)) + .thenReturn(true); + + SpringBootHealthCheckEnricher enricher = new SpringBootHealthCheckEnricher(context); + + Probe livenessProbe = enricher.getLivenessProbe(); + assertHTTPGetPathAndPort(livenessProbe,getActuatorDefaultBasePath() + "/health",8080); + Probe readinessProbe = enricher.getReadinessProbe(); + assertHTTPGetPathAndPort(readinessProbe,getActuatorDefaultBasePath() + "/health",8080); + } + private void assertHTTPGetPathAndPort(Probe probe, String path, int port) { assertThat(probe).isNotNull() .extracting(Probe::getHttpGet).isNotNull()