echo liveness probe available under /actuator/health 94/139094/1
authorShantaram Sawant <s.shantaram.sawant@accenture.com>
Wed, 2 Oct 2024 14:30:28 +0000 (20:00 +0530)
committerShantaram Sawant <s.shantaram.sawant@accenture.com>
Wed, 2 Oct 2024 14:30:28 +0000 (20:00 +0530)
- Include database connectivity check in the /echo API of AAI modules.

Issue-ID: AAI-3999
Change-Id: Ib34e76a0520624a8383faa56a84c727bdc09ab29
Signed-off-by: Shantaram Sawant <s.shantaram.sawant@accenture.com>
aai-traversal/src/main/java/org/onap/aai/rest/util/EchoHealthIndicator.java [new file with mode: 0644]
aai-traversal/src/main/java/org/onap/aai/rest/util/EchoResponse.java
aai-traversal/src/main/resources/application.properties
aai-traversal/src/test/java/org/onap/aai/WebClientConfiguration.java
aai-traversal/src/test/java/org/onap/aai/rest/util/EchoHealthIndicatorTest.java [new file with mode: 0644]
aai-traversal/src/test/java/org/onap/aai/rest/util/EchoResponseTest.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 (file)
index 0000000..d44b415
--- /dev/null
@@ -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();
+       }
+
+}
index df677d5..028ebca 100644 (file)
@@ -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<String> templateVariables) {
-               HashMap<AAIException, ArrayList<String>> 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<String> templateVariables,
-                       AAIException aaiException) {
-               return Response.status(aaiException.getErrorObject().getHTTPResponseCode())
-                               .entity(
-                                               ErrorLogHelper.getRESTAPIErrorResponseWithLogging(
-                                                               headers.getAcceptableMediaTypes(), aaiException, templateVariables))
-                               .build();
-       }
+    private Response generateFailureResponse(HttpHeaders headers, ArrayList<String> templateVariables,
+               AAIException aaiException) {
+       return Response.status(aaiException.getErrorObject().getHTTPResponseCode()).entity(ErrorLogHelper
+                       .getRESTAPIErrorResponseWithLogging(headers.getAcceptableMediaTypes(), aaiException, templateVariables))
+                       .build();
+    }
 }
index 29243ae..de08b4e 100644 (file)
@@ -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
index 73239c6..4bedf3f 100644 (file)
@@ -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 (file)
index 0000000..b129e7e
--- /dev/null
@@ -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();
+  }
+}
index eb67799..fb71599 100644 (file)
@@ -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());
     }