From ee78651fb78635afdb7bcf37e903f3d0043741dc Mon Sep 17 00:00:00 2001 From: Shantaram Sawant Date: Wed, 2 Oct 2024 20:00:28 +0530 Subject: echo liveness probe available under /actuator/health - Include database connectivity check in the /echo API of AAI modules. Issue-ID: AAI-3999 Change-Id: Ib34e76a0520624a8383faa56a84c727bdc09ab29 Signed-off-by: Shantaram Sawant --- .../onap/aai/rest/util/EchoHealthIndicator.java | 49 +++++++++++++++ .../java/org/onap/aai/rest/util/EchoResponse.java | 39 +++++------- .../src/main/resources/application.properties | 7 +++ .../java/org/onap/aai/WebClientConfiguration.java | 16 +++++ .../aai/rest/util/EchoHealthIndicatorTest.java | 71 ++++++++++++++++++++++ .../org/onap/aai/rest/util/EchoResponseTest.java | 11 ++-- 6 files changed, 162 insertions(+), 31 deletions(-) create mode 100644 aai-traversal/src/main/java/org/onap/aai/rest/util/EchoHealthIndicator.java create mode 100644 aai-traversal/src/test/java/org/onap/aai/rest/util/EchoHealthIndicatorTest.java diff --git a/aai-traversal/src/main/java/org/onap/aai/rest/util/EchoHealthIndicator.java b/aai-traversal/src/main/java/org/onap/aai/rest/util/EchoHealthIndicator.java new file mode 100644 index 0000000..d44b415 --- /dev/null +++ b/aai-traversal/src/main/java/org/onap/aai/rest/util/EchoHealthIndicator.java @@ -0,0 +1,49 @@ +/** + * ============LICENSE_START======================================================= + * org.onap.aai + * ================================================================================ + * Copyright © 2024 Deutsche Telekom. All rights reserved. + * ================================================================================ + * Licensed 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. + * ============LICENSE_END========================================================= + */ + +package org.onap.aai.rest.util; + + +import org.springframework.boot.actuate.health.Health; +import org.springframework.boot.actuate.health.HealthIndicator; +import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; +import org.springframework.stereotype.Component; + +import lombok.RequiredArgsConstructor; + +@Component +@RequiredArgsConstructor +@ConditionalOnProperty(name = "aai.actuator.echo.enabled", havingValue = "true") +public class EchoHealthIndicator implements HealthIndicator { + + private final AaiGraphChecker aaiGraphChecker; + + @Override + public Health health() { + return healthy() + ? Health.up().build() + : Health.down().build(); + } + + private boolean healthy() { + return aaiGraphChecker.isAaiGraphDbAvailable(); + } + +} diff --git a/aai-traversal/src/main/java/org/onap/aai/rest/util/EchoResponse.java b/aai-traversal/src/main/java/org/onap/aai/rest/util/EchoResponse.java index df677d5..028ebca 100644 --- a/aai-traversal/src/main/java/org/onap/aai/rest/util/EchoResponse.java +++ b/aai-traversal/src/main/java/org/onap/aai/rest/util/EchoResponse.java @@ -54,6 +54,8 @@ public class EchoResponse extends RESTAPI { public EchoResponse(AaiGraphChecker aaiGraphChecker) { this.aaiGraphChecker = aaiGraphChecker; } + + private static final String UP_RESPONSE="{\"status\":\"UP\",\"groups\":[\"liveness\",\"readiness\"]}"; /** * Simple health-check API that echos back the X-FromAppId and X-TransactionId @@ -92,7 +94,7 @@ public class EchoResponse extends RESTAPI { if (!aaiGraphChecker.isAaiGraphDbAvailable()) { throw new AAIException("AAI_5105", "Error establishing a database connection"); } - return generateSuccessResponse(headers, templateVars); + return generateSuccessResponse(); } catch (AAIException aaiException) { ErrorLogHelper.logException(aaiException); return generateFailureResponse(headers, templateVars, aaiException); @@ -102,30 +104,19 @@ public class EchoResponse extends RESTAPI { return generateFailureResponse(headers, templateVars, aaiException); } } - return generateSuccessResponse(headers, templateVars); + return generateSuccessResponse(); } - private Response generateSuccessResponse(HttpHeaders headers, ArrayList templateVariables) { - HashMap> exceptionList = new HashMap<>(); - exceptionList.put(new AAIException("AAI_0002", "OK"), templateVariables); - try { - return Response.status(Status.OK) - .entity( - ErrorLogHelper.getRESTAPIInfoResponse(new ArrayList<>(headers.getAcceptableMediaTypes()), exceptionList)) - .build(); - } catch (Exception e) { - AAIException aaiException = new AAIException("AAI_4000", e); - ErrorLogHelper.logException(aaiException); - return generateFailureResponse(headers, templateVariables, aaiException); - } - } + private Response generateSuccessResponse() { + return Response.status(Status.OK) + .entity(UP_RESPONSE) + .build(); + } - private Response generateFailureResponse(HttpHeaders headers, ArrayList templateVariables, - AAIException aaiException) { - return Response.status(aaiException.getErrorObject().getHTTPResponseCode()) - .entity( - ErrorLogHelper.getRESTAPIErrorResponseWithLogging( - headers.getAcceptableMediaTypes(), aaiException, templateVariables)) - .build(); - } + private Response generateFailureResponse(HttpHeaders headers, ArrayList templateVariables, + AAIException aaiException) { + return Response.status(aaiException.getErrorObject().getHTTPResponseCode()).entity(ErrorLogHelper + .getRESTAPIErrorResponseWithLogging(headers.getAcceptableMediaTypes(), aaiException, templateVariables)) + .build(); + } } diff --git a/aai-traversal/src/main/resources/application.properties b/aai-traversal/src/main/resources/application.properties index 29243ae..de08b4e 100644 --- a/aai-traversal/src/main/resources/application.properties +++ b/aai-traversal/src/main/resources/application.properties @@ -140,3 +140,10 @@ management.metrics.tags.group_id=aai # management.metrics.tags.app_id=${info.build.artifact} #Enable this option only for debug purposes. For more information: https://github.com/micrometer-metrics/micrometer/issues/1584 scrape.uri.metrics=true + + +# If true, the actuator health check will be overriden +# to use the AaiGraphChecker check instead +# this does the same as the /echo endpoint, +# but doesn't show up in micrometer metrics +aai.actuator.echo.enabled=false diff --git a/aai-traversal/src/test/java/org/onap/aai/WebClientConfiguration.java b/aai-traversal/src/test/java/org/onap/aai/WebClientConfiguration.java index 73239c6..4bedf3f 100644 --- a/aai-traversal/src/test/java/org/onap/aai/WebClientConfiguration.java +++ b/aai-traversal/src/test/java/org/onap/aai/WebClientConfiguration.java @@ -22,10 +22,13 @@ package org.onap.aai; import java.time.Duration; import java.util.Collections; + +import org.springframework.beans.factory.annotation.Value; import org.springframework.boot.test.context.TestConfiguration; import org.springframework.boot.web.server.LocalServerPort; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Lazy; +import org.springframework.context.annotation.Primary; import org.springframework.http.MediaType; import org.springframework.test.web.reactive.server.WebTestClient; @@ -34,6 +37,7 @@ public class WebClientConfiguration { @Lazy @Bean + @Primary WebTestClient webTestClient(@LocalServerPort int port) { return WebTestClient.bindToServer() .baseUrl("http://localhost:" + port) @@ -47,4 +51,16 @@ public class WebClientConfiguration { }) .build(); } + + @Lazy + @Bean + WebTestClient mgmtClient(@Value("${local.management.port}") int port) { + return WebTestClient.bindToServer() + .baseUrl("http://localhost:" + port) + .responseTimeout(Duration.ofSeconds(300)) + .defaultHeaders(headers -> { + headers.setAccept(Collections.singletonList(MediaType.APPLICATION_JSON)); + }) + .build(); + } } diff --git a/aai-traversal/src/test/java/org/onap/aai/rest/util/EchoHealthIndicatorTest.java b/aai-traversal/src/test/java/org/onap/aai/rest/util/EchoHealthIndicatorTest.java new file mode 100644 index 0000000..b129e7e --- /dev/null +++ b/aai-traversal/src/test/java/org/onap/aai/rest/util/EchoHealthIndicatorTest.java @@ -0,0 +1,71 @@ +/** + * ============LICENSE_START======================================================= + * org.onap.aai + * ================================================================================ + * Copyright © 2024 Deutsche Telekom. All rights reserved. + * ================================================================================ + * Licensed 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. + * ============LICENSE_END========================================================= + */ + +package org.onap.aai.rest.util; + +import static org.mockito.Mockito.when; + +import org.junit.jupiter.api.Test; +import org.onap.aai.WebClientConfiguration; +import org.onap.aai.rest.AbstractSpringRestTest; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Qualifier; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.boot.test.context.SpringBootTest.WebEnvironment; +import org.springframework.boot.test.mock.mockito.MockBean; +import org.springframework.context.annotation.Import; +import org.springframework.test.context.TestPropertySource; +import org.springframework.test.web.reactive.server.WebTestClient; + + +@Import(WebClientConfiguration.class) +@SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT) +@TestPropertySource(properties = {"aai.actuator.echo.enabled=true", + "server.ssl.enabled=false"}) +public class EchoHealthIndicatorTest extends AbstractSpringRestTest { + + @Autowired + @Qualifier("mgmtClient") + WebTestClient webClient; + + @MockBean private AaiGraphChecker aaiGraphChecker; + + @Test + public void thatActuatorCheckIsHealthy() { + when(aaiGraphChecker.isAaiGraphDbAvailable()).thenReturn(true); + + webClient.get() + .uri("/actuator/health") + .exchange() + .expectStatus() + .isOk(); + } + + @Test + public void thatActuatorCheckIsUnhealthy() { + when(aaiGraphChecker.isAaiGraphDbAvailable()).thenReturn(false); + + webClient.get() + .uri("/actuator/health") + .exchange() + .expectStatus() + .is5xxServerError(); + } +} diff --git a/aai-traversal/src/test/java/org/onap/aai/rest/util/EchoResponseTest.java b/aai-traversal/src/test/java/org/onap/aai/rest/util/EchoResponseTest.java index eb67799..fb71599 100644 --- a/aai-traversal/src/test/java/org/onap/aai/rest/util/EchoResponseTest.java +++ b/aai-traversal/src/test/java/org/onap/aai/rest/util/EchoResponseTest.java @@ -152,13 +152,10 @@ public class EchoResponseTest { } @Test - public void testEchoResultWhenValidHeadersButMediaTypeWrong() throws Exception { - - when(httpHeaders.getAcceptableMediaTypes()).thenThrow(new IllegalStateException()) - .thenReturn(outputMediaTypes); - - Response response = echoResponse.echoResult(httpHeaders, null, null); - + public void testCheckDbNowAction_Unknown() { + when(aaiGraphCheckerMock.isAaiGraphDbAvailable()).thenReturn(null); + Response response = echoResponse.echoResult(httpHeaders, null, "myAction"); + // Verify assertNotNull(response); assertEquals(Response.Status.INTERNAL_SERVER_ERROR.getStatusCode(), response.getStatus()); } -- cgit 1.2.3-korg