From 9adde5462ff9fd281eb5057dbb4c58e4676a9d90 Mon Sep 17 00:00:00 2001 From: Fiete Ostkamp Date: Wed, 12 Oct 2022 09:23:14 +0200 Subject: Enhancement of AAI-traversal healthcheck - enhance the EchoResponse endpoint to check for db connectivity when the myAction parameter is provided Issue-ID: AAI-3547 Signed-off-by: Fiete Ostkamp Change-Id: I4d5686b63efd139b942cee0c222305a17d2a2497 --- .../org/onap/aai/rest/util/AaiGraphChecker.java | 103 +++++++++++++ .../java/org/onap/aai/rest/util/EchoResponse.java | 161 +++++++++++---------- 2 files changed, 189 insertions(+), 75 deletions(-) create mode 100644 aai-traversal/src/main/java/org/onap/aai/rest/util/AaiGraphChecker.java (limited to 'aai-traversal/src/main') diff --git a/aai-traversal/src/main/java/org/onap/aai/rest/util/AaiGraphChecker.java b/aai-traversal/src/main/java/org/onap/aai/rest/util/AaiGraphChecker.java new file mode 100644 index 0000000..11b412d --- /dev/null +++ b/aai-traversal/src/main/java/org/onap/aai/rest/util/AaiGraphChecker.java @@ -0,0 +1,103 @@ +/* + * ============LICENSE_START======================================================= + * Copyright (C) 2022 Bell Canada + * Modification Copyright (C) 2022 Deutsche Telekom SA + * ================================================================================ + * 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 java.util.Iterator; + +import org.janusgraph.core.JanusGraphException; +import org.janusgraph.core.JanusGraphTransaction; +import org.onap.aai.dbmap.AAIGraph; +import org.onap.aai.logging.ErrorLogHelper; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.config.ConfigurableBeanFactory; +import org.springframework.context.annotation.Scope; +import org.springframework.stereotype.Component; + +import com.google.common.collect.Iterators; + +/** + * Singleton class responsible to check that AAI service is able to connect to its back-end + * database. + */ +@Component +@Scope(ConfigurableBeanFactory.SCOPE_SINGLETON) +public class AaiGraphChecker { + private static final Logger LOGGER = LoggerFactory.getLogger(AaiGraphChecker.class); + + private AaiGraphChecker() { + } + + /** + * Checks whether a connection to the graph database can be made. + * + * @return + *
  • true, if database is available
  • + *
  • false, if database is NOT available
  • + */ + public Boolean isAaiGraphDbAvailable() { + Boolean dbAvailable; + JanusGraphTransaction transaction = null; + try { + transaction = AAIGraph.getInstance().getGraph().newTransaction(); + final Iterator vertexIterator = transaction.query().limit(1).vertices().iterator(); + if (LOGGER.isDebugEnabled()) { + LOGGER.debug("Number of vertices retrieved while checking db: {}", + Iterators.size(vertexIterator)); + } + vertexIterator.hasNext(); + LOGGER.debug("Database is available"); + dbAvailable = Boolean.TRUE; + } catch (JanusGraphException e) { + String message = "Database is not available (after JanusGraph exception)"; + ErrorLogHelper.logError("500", message + ": " + e.getMessage()); + LOGGER.error(message, e); + dbAvailable = Boolean.FALSE; + } catch (Error e) { + // Following error occurs when aai resources is starting: + // - UnsatisfiedLinkError (for org.onap.aai.dbmap.AAIGraph$Helper instantiation) + // Following errors are raised when aai resources is starting and cassandra is not + // running: + // - ExceptionInInitializerError + // - NoClassDefFoundError (definition for org.onap.aai.dbmap.AAIGraph$Helper is not + // found) + String message = "Database is not available (after error)"; + ErrorLogHelper.logError("500", message + ": " + e.getMessage()); + LOGGER.error(message, e); + dbAvailable = Boolean.FALSE; + } catch (Exception e) { + String message = "Database availability can not be determined"; + ErrorLogHelper.logError("500", message + ": " + e.getMessage()); + LOGGER.error(message, e); + dbAvailable = null; + } finally { + if (transaction != null && !transaction.isClosed()) { + // check if transaction is open then closed instead of flag + try { + transaction.rollback(); + } catch (Exception e) { + String message = "Exception occurred while closing transaction"; + LOGGER.error(message, e); + ErrorLogHelper.logError("500", message + ": " + e.getMessage()); + } + } + } + return dbAvailable; + } +} 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 d0ba708..2e42e4c 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 @@ -8,7 +8,7 @@ * 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 + * 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, @@ -36,85 +36,96 @@ import javax.ws.rs.core.Response.Status; import org.onap.aai.exceptions.AAIException; import org.onap.aai.logging.ErrorLogHelper; import org.onap.aai.restcore.RESTAPI; +import org.springframework.stereotype.Component; /** * The Class EchoResponse. */ @Path("/util") +@Component public class EchoResponse extends RESTAPI { - protected static String authPolicyFunctionName = "util"; - - public static final String ECHO_PATH = "/echo"; - - /** - * Simple health-check API that echos back the X-FromAppId and X-TransactionId to clients. - * If there is a query string, a transaction gets logged into hbase, proving the application is - * connected to the data store. - * If there is no query string, no transacction logging is done to hbase. - * - * @param headers the headers - * @param req the req - * @param myAction if exists will cause transaction to be logged to hbase - * @return the response - */ - @GET - @Produces({MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON}) - @Path(ECHO_PATH) - public Response echoResult(@Context HttpHeaders headers, @Context HttpServletRequest req, - @QueryParam("action") String myAction) { - AAIException ex = null; - Response response; - String fromAppId; - String transId; - - try { - fromAppId = getFromAppId(headers); - transId = getTransId(headers); - } catch (AAIException e) { - ArrayList templateVars = new ArrayList<>(); - templateVars.add("PUT uebProvider"); - templateVars.add("addTopic"); - return Response - .status(e.getErrorObject().getHTTPResponseCode()).entity(ErrorLogHelper - .getRESTAPIErrorResponse(headers.getAcceptableMediaTypes(), e, templateVars)) - .build(); - } - - try { - - HashMap> exceptionList = new HashMap<>(); - - ArrayList templateVars = new ArrayList<>(); - templateVars.add(fromAppId); - templateVars.add(transId); - - exceptionList.put(new AAIException("AAI_0002", "OK"), templateVars); - - response = Response - .status(Status.OK).entity(ErrorLogHelper - .getRESTAPIInfoResponse(headers.getAcceptableMediaTypes(), exceptionList)) - .build(); - - } catch (Exception e) { - ex = new AAIException("AAI_4000", e); - ArrayList templateVars = new ArrayList<>(); - templateVars.add(Action.GET.name()); - templateVars.add(fromAppId + " " + transId); - - response = Response - .status(Status.INTERNAL_SERVER_ERROR).entity(ErrorLogHelper - .getRESTAPIErrorResponse(headers.getAcceptableMediaTypes(), ex, templateVars)) - .build(); - - } finally { - if (ex != null) { - ErrorLogHelper.logException(ex); - } - - } - - return response; - } - + protected static String authPolicyFunctionName = "util"; + + public static final String ECHO_PATH = "/echo"; + + private AaiGraphChecker aaiGraphChecker; + + public EchoResponse(AaiGraphChecker aaiGraphChecker) { + this.aaiGraphChecker = aaiGraphChecker; + } + + /** + * Simple health-check API that echos back the X-FromAppId and X-TransactionId + * to clients. + * If there is a query string, the healthcheck will also check for database connectivity. + * + * @param headers the headers + * @param req the request + * @param myAction if exists will cause database connectivity check + * @return the response + */ + @GET + @Produces({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON }) + @Path(ECHO_PATH) + public Response echoResult(@Context HttpHeaders headers, @Context HttpServletRequest req, + @QueryParam("action") String myAction) { + + String fromAppId; + String transId; + ArrayList templateVars = new ArrayList<>(); + + try { + fromAppId = getFromAppId(headers); + transId = getTransId(headers); + } catch (AAIException aaiException) { + templateVars.add("PUT uebProvider"); + templateVars.add("addTopic"); + ErrorLogHelper.logException(aaiException); + return generateFailureResponse(headers, templateVars, aaiException); + } + + templateVars.add(fromAppId); + templateVars.add(transId); + if (myAction != null) { + try { + if (!aaiGraphChecker.isAaiGraphDbAvailable()) { + throw new AAIException("AAI_5105", "Error establishing a database connection"); + } + return generateSuccessResponse(headers, templateVars); + } catch (AAIException aaiException) { + ErrorLogHelper.logException(aaiException); + return generateFailureResponse(headers, templateVars, aaiException); + } catch (Exception e) { + AAIException aaiException = new AAIException("AAI_4000", e); + ErrorLogHelper.logException(aaiException); + return generateFailureResponse(headers, templateVars, aaiException); + } + } + return generateSuccessResponse(headers, templateVars); + } + + 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(headers.getAcceptableMediaTypes(), exceptionList)) + .build(); + } catch (Exception e) { + AAIException aaiException = new AAIException("AAI_4000", e); + ErrorLogHelper.logException(aaiException); + return generateFailureResponse(headers, templateVariables, aaiException); + } + } + + private Response generateFailureResponse(HttpHeaders headers, ArrayList templateVariables, + AAIException aaiException) { + return Response.status(aaiException.getErrorObject().getHTTPResponseCode()) + .entity( + ErrorLogHelper.getRESTAPIErrorResponseWithLogging( + headers.getAcceptableMediaTypes(), aaiException, templateVariables)) + .build(); + } } -- cgit 1.2.3-korg