From 0e5e2b4234e96d4201283368e95d923da8892340 Mon Sep 17 00:00:00 2001 From: Oskar Date: Tue, 12 Mar 2024 10:42:01 +0100 Subject: [PATCH] feat(actuator): adding operator health indicator (#132) --- starter-test/pom.xml | 10 +++++ .../starter/test/HealthIndicatorTest.java | 31 +++++++++++++ starter/pom.xml | 6 ++- .../starter/OperatorHealthIndicator.java | 45 +++++++++++++++++++ ...ratorHealthIndicatorAutoConfiguration.java | 20 +++++++++ 5 files changed, 111 insertions(+), 1 deletion(-) create mode 100644 starter-test/src/test/java/io/javaoperatorsdk/operator/springboot/starter/test/HealthIndicatorTest.java create mode 100644 starter/src/main/java/io/javaoperatorsdk/operator/springboot/starter/OperatorHealthIndicator.java create mode 100644 starter/src/main/java/io/javaoperatorsdk/operator/springboot/starter/OperatorHealthIndicatorAutoConfiguration.java diff --git a/starter-test/pom.xml b/starter-test/pom.xml index c40a544..7750bb5 100644 --- a/starter-test/pom.xml +++ b/starter-test/pom.xml @@ -41,6 +41,16 @@ org.springframework.boot spring-boot-starter + + org.springframework.boot + spring-boot-starter-web + test + + + org.springframework.boot + spring-boot-starter-actuator + test + io.javaoperatorsdk operator-framework diff --git a/starter-test/src/test/java/io/javaoperatorsdk/operator/springboot/starter/test/HealthIndicatorTest.java b/starter-test/src/test/java/io/javaoperatorsdk/operator/springboot/starter/test/HealthIndicatorTest.java new file mode 100644 index 0000000..80fa857 --- /dev/null +++ b/starter-test/src/test/java/io/javaoperatorsdk/operator/springboot/starter/test/HealthIndicatorTest.java @@ -0,0 +1,31 @@ +package io.javaoperatorsdk.operator.springboot.starter.test; + +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.boot.test.web.client.TestRestTemplate; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; + +import static org.assertj.core.api.Assertions.assertThat; + +@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT, properties = { + "management.endpoint.health.enabled=true", "management.endpoint.health.show-details=always"}) +@EnableMockOperator(crdPaths = "classpath:crd.yml") +class HealthIndicatorTest { + + @Autowired + private TestRestTemplate restTemplate; + + @Test + void testOperatorHealthIndicator() { + ResponseEntity entity = + this.restTemplate.getForEntity("/actuator/health", String.class); + assertThat(entity.getStatusCode()).isEqualTo(HttpStatus.OK); + assertThat(entity.getBody()).contains("\"status\":\"UP\""); + assertThat(entity.getBody()) + .contains( + "\"operator\":{\"status\":\"UP\",\"details\":{\"customservicereconciler\":\"OK\"}}"); + } + +} diff --git a/starter/pom.xml b/starter/pom.xml index 82534b6..c811a59 100644 --- a/starter/pom.xml +++ b/starter/pom.xml @@ -53,7 +53,11 @@ org.springframework.boot spring-boot-autoconfigure - + + org.springframework.boot + spring-boot-actuator-autoconfigure + true + org.springframework.boot spring-boot-starter-test diff --git a/starter/src/main/java/io/javaoperatorsdk/operator/springboot/starter/OperatorHealthIndicator.java b/starter/src/main/java/io/javaoperatorsdk/operator/springboot/starter/OperatorHealthIndicator.java new file mode 100644 index 0000000..05a04b6 --- /dev/null +++ b/starter/src/main/java/io/javaoperatorsdk/operator/springboot/starter/OperatorHealthIndicator.java @@ -0,0 +1,45 @@ +package io.javaoperatorsdk.operator.springboot.starter; + +import org.springframework.boot.actuate.health.AbstractHealthIndicator; +import org.springframework.boot.actuate.health.Health; +import org.springframework.stereotype.Component; +import org.springframework.util.Assert; + +import io.javaoperatorsdk.operator.Operator; + +@Component +public class OperatorHealthIndicator extends AbstractHealthIndicator { + + private final Operator operator; + + public OperatorHealthIndicator(final Operator operator) { + super("OperatorSDK health check failed"); + Assert.notNull(operator, "OperatorSDK Operator not initialized"); + this.operator = operator; + } + + @Override + protected void doHealthCheck(Health.Builder builder) { + final var runtimeInfo = operator.getRuntimeInfo(); + if (runtimeInfo.isStarted()) { + final boolean[] healthy = {true}; + runtimeInfo.getRegisteredControllers().forEach(rc -> { + final var name = rc.getConfiguration().getName(); + final var unhealthy = rc.getControllerHealthInfo().unhealthyEventSources(); + if (unhealthy.isEmpty()) { + builder.withDetail(name, "OK"); + } else { + healthy[0] = false; + builder.withDetail(name, "unhealthy: " + String.join(", ", unhealthy.keySet())); + } + }); + if (healthy[0]) { + builder.up(); + } else { + builder.down(); + } + } else { + builder.unknown(); + } + } +} diff --git a/starter/src/main/java/io/javaoperatorsdk/operator/springboot/starter/OperatorHealthIndicatorAutoConfiguration.java b/starter/src/main/java/io/javaoperatorsdk/operator/springboot/starter/OperatorHealthIndicatorAutoConfiguration.java new file mode 100644 index 0000000..adbb672 --- /dev/null +++ b/starter/src/main/java/io/javaoperatorsdk/operator/springboot/starter/OperatorHealthIndicatorAutoConfiguration.java @@ -0,0 +1,20 @@ +package io.javaoperatorsdk.operator.springboot.starter; + +import org.springframework.boot.autoconfigure.condition.ConditionalOnBean; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.ComponentScan; +import org.springframework.context.annotation.Configuration; + +import io.javaoperatorsdk.operator.Operator; + +@Configuration(proxyBeanMethods = false) +@ConditionalOnBean(Operator.class) +@ComponentScan("io.javaoperatorsdk.operator.springboot.starter") +public class OperatorHealthIndicatorAutoConfiguration { + + @Bean + public OperatorHealthIndicator createOperatorHealthIndicator(Operator operator) { + return new OperatorHealthIndicator(operator); + } + +}