From b5cf61b0a4b1335a96a785674ca3d4e844d212ef Mon Sep 17 00:00:00 2001 From: Dominik Mizyn Date: Thu, 5 Mar 2020 14:14:04 +0100 Subject: [PATCH] HealthCheckController up HealthCheckController up and all needed services Issue-ID: PORTAL-710 Change-Id: I54cc4c32ea03b773833bab4296dcc0d67d3f2ea2 Signed-off-by: Dominik Mizyn --- portal-BE/Dockerfile | 4 +- portal-BE/docker-compose.yml | 2 +- portal-BE/pom.xml | 37 +-- .../portal/controller/HealthCheckController.java | 237 ++++++++++++++ .../onap/portal/controller/ManifestController.java | 81 +++++ .../scheduler/healthMonitor/HealthMonitor.java | 359 +++++++++++++++++++++ .../org/onap/portal/service/ManifestService.java | 35 ++ .../src/main/resources/application.properties | 2 +- 8 files changed, 729 insertions(+), 28 deletions(-) create mode 100644 portal-BE/src/main/java/org/onap/portal/controller/HealthCheckController.java create mode 100644 portal-BE/src/main/java/org/onap/portal/controller/ManifestController.java create mode 100644 portal-BE/src/main/java/org/onap/portal/scheduler/healthMonitor/HealthMonitor.java create mode 100644 portal-BE/src/main/java/org/onap/portal/service/ManifestService.java diff --git a/portal-BE/Dockerfile b/portal-BE/Dockerfile index 99275dca..3da3eec2 100644 --- a/portal-BE/Dockerfile +++ b/portal-BE/Dockerfile @@ -1,6 +1,6 @@ FROM openjdk:8-jdk-alpine VOLUME /tmp -EXPOSE 8080 +EXPOSE 8081 ARG DEPENDENCY=target ADD ${DEPENDENCY}/portal-0.0.1-SNAPSHOT.jar portal-0.0.1-SNAPSHOT.jar -ENTRYPOINT ["java","-jar","portal-0.0.1-SNAPSHOT.jar"] \ No newline at end of file +ENTRYPOINT ["java","-jar","portal-0.0.1-SNAPSHOT.jar"] diff --git a/portal-BE/docker-compose.yml b/portal-BE/docker-compose.yml index 9b8f1ed0..096695a4 100644 --- a/portal-BE/docker-compose.yml +++ b/portal-BE/docker-compose.yml @@ -32,7 +32,7 @@ services: container_name: portal_APP restart: always ports: - - 8080:8080 + - 8081:8081 environment: - spring.datasource.username=${spring_datasource_username} - spring.datasource.password=${spring_datasource_password} diff --git a/portal-BE/pom.xml b/portal-BE/pom.xml index f7f9c371..266c05e7 100644 --- a/portal-BE/pom.xml +++ b/portal-BE/pom.xml @@ -152,6 +152,13 @@ 6.0.18.Final compile + + + com.zaxxer + HikariCP + 3.4.5 + + io.swagger swagger-annotations @@ -182,12 +189,13 @@ 2.6.0 compile + + org.onap.portal.sdk + epsdk-music + 2.6.0 + compile + - - portal - ${project.reporting.outputDirectory}/jacoco-ut/jacoco.xml,${project.reporting.outputDirectory}/jacoco-it/jacoco.xml - true - @@ -240,25 +248,6 @@ - - org.jacoco - jacoco-maven-plugin - 0.7.7.201606060606 - - - - prepare-agent - - - - report - prepare-package - - report - - - - diff --git a/portal-BE/src/main/java/org/onap/portal/controller/HealthCheckController.java b/portal-BE/src/main/java/org/onap/portal/controller/HealthCheckController.java new file mode 100644 index 00000000..ec2f9145 --- /dev/null +++ b/portal-BE/src/main/java/org/onap/portal/controller/HealthCheckController.java @@ -0,0 +1,237 @@ +/*- + * ============LICENSE_START========================================== + * ONAP Portal + * =================================================================== + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * =================================================================== + * + * Unless otherwise specified, all software contained herein is licensed + * under the Apache License, Version 2.0 (the "License"); + * you may not use this software 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. + * + * Unless otherwise specified, all documentation contained herein is licensed + * under the Creative Commons License, Attribution 4.0 Intl. (the "License"); + * you may not use this documentation except in compliance with the License. + * You may obtain a copy of the License at + * + * https://creativecommons.org/licenses/by/4.0/ + * + * Unless required by applicable law or agreed to in writing, documentation + * 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.portal.controller; + +import com.google.gson.Gson; +import java.util.ArrayList; +import java.util.List; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import org.onap.music.main.MusicUtil; +import org.onap.portal.logging.format.EPAppMessagesEnum; +import org.onap.portal.logging.logic.EPLogUtil; +import org.onap.portal.scheduler.healthMonitor.HealthMonitor; +import org.onap.portal.utils.EPCommonSystemProperties; +import org.onap.portal.utils.EcompPortalUtils; +import org.onap.portalsdk.core.logging.logic.EELFLoggerDelegate; +import org.slf4j.MDC; +import org.springframework.context.annotation.Configuration; +import org.springframework.context.annotation.EnableAspectJAutoProxy; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestMethod; +import org.springframework.web.bind.annotation.RestController; + +@RestController +@Configuration +@EnableAspectJAutoProxy +public class HealthCheckController { + + private EELFLoggerDelegate logger = EELFLoggerDelegate.getLogger(HealthCheckController.class); + + private class HealthStatus { + + public int statusCode; + @SuppressWarnings("unused") + public String body; + + public HealthStatus(int code, String body) { + this.statusCode = code; + this.body = body; + } + } + + private class HealthStatusInfo { + + HealthStatusInfo(String healthCheckComponent) { + this.healthCheckComponent = healthCheckComponent; + this.healthCheckStatus = statusUp; // Default value + this.version = ""; + this.description = statusOk; // Default value + this.hostName = ""; + this.ipAddress = ""; + this.dbClusterStatus = ""; + this.dbPermissions = ""; + } + + @SuppressWarnings("unused") + public String healthCheckComponent; + @SuppressWarnings("unused") + public String healthCheckStatus; + @SuppressWarnings("unused") + public String version; + @SuppressWarnings("unused") + public String description; + @SuppressWarnings("unused") + public String hostName; + @SuppressWarnings("unused") + public String ipAddress; + @SuppressWarnings("unused") + public String dbClusterStatus; + @SuppressWarnings("unused") + public String dbPermissions; + } + + private final String statusUp = "UP"; + private final String statusDown = "DOWN"; + private final String statusOk = "OK"; + + @RequestMapping(value = {"/portalApi/healthCheck"}, method = RequestMethod.GET, produces = "application/json") + public HealthStatus healthCheck(HttpServletRequest request, HttpServletResponse response) { + HealthStatus healthStatus = new HealthStatus(500, ""); + + // Return the status as 500 if it suspended due to manual fail over + if (HealthMonitor.isSuspended()) { + healthStatus.body = "Suspended"; + response.setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR); + MDC.put(EPCommonSystemProperties.RESPONSE_CODE, + Integer.toString(HttpServletResponse.SC_INTERNAL_SERVER_ERROR)); + return healthStatus; + } + + try { + boolean overallStatus = true; + + List statusCollection = new ArrayList(); + + HealthStatusInfo beInfo = new HealthStatusInfo("BE"); + beInfo.hostName = EcompPortalUtils.getMyHostName(); + beInfo.ipAddress = EcompPortalUtils.getMyIpAdddress(); + if (!HealthMonitor.isBackEndUp()) { + overallStatus = false; + beInfo.healthCheckStatus = statusDown; + beInfo.description = "Check the logs for more details"; + EPLogUtil.logEcompError(logger, EPAppMessagesEnum.BeHealthCheckError); + } + statusCollection.add(beInfo); + + HealthStatusInfo feInfo = new HealthStatusInfo("FE"); + if (!HealthMonitor.isFrontEndUp()) { + overallStatus = false; + feInfo.healthCheckStatus = statusDown; + feInfo.description = "Check the logs for more details"; + EPLogUtil.logEcompError(logger, EPAppMessagesEnum.FeHealthCheckError); + } + statusCollection.add(feInfo); + + HealthStatusInfo dbInfo = new HealthStatusInfo("DB"); + if (!HealthMonitor.isDatabaseUp()) { + overallStatus = false; + dbInfo.healthCheckStatus = statusDown; + dbInfo.description = "Check the logs for more details"; + EPLogUtil.logEcompError(logger, EPAppMessagesEnum.BeDaoSystemError); + } + if (!HealthMonitor.isDbPermissionsOk()) { + dbInfo.dbPermissions = "Problem, check the logs for more details"; + EPLogUtil.logEcompError(logger, EPAppMessagesEnum.BeDaoSystemError); + } else { + dbInfo.dbPermissions = statusOk; + } + statusCollection.add(dbInfo); + + if (org.onap.portalapp.music.util.MusicUtil.isMusicEnable()) { + HealthStatusInfo CassandraStatusInfo = new HealthStatusInfo("Music-Cassandra"); + //CassandraStatusInfo.hostName = EcompPortalUtils.getMyHostName(); + CassandraStatusInfo.ipAddress = MusicUtil.getMyCassaHost(); + + if (!HealthMonitor.isCassandraStatusOk()) { + overallStatus = false; + CassandraStatusInfo.healthCheckStatus = statusDown; + CassandraStatusInfo.description = "Check the logs for more details"; + EPLogUtil.logEcompError(logger, EPAppMessagesEnum.MusicHealthCheckCassandraError); + } + statusCollection.add(CassandraStatusInfo); + } + + String json = ""; + try { + json = new Gson().toJson(statusCollection); + } catch (Exception e) { + EPLogUtil.logEcompError(logger, EPAppMessagesEnum.BeInvalidJsonInput); + } + logger.info(EELFLoggerDelegate.debugLogger, json); + + if (overallStatus) { + healthStatus = new HealthStatus(200, json); + } else { + healthStatus = new HealthStatus(500, json); + response.setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR); + } + MDC.put(EPCommonSystemProperties.RESPONSE_CODE, Integer.toString(healthStatus.statusCode)); + } catch (Exception e) { + logger.error(EELFLoggerDelegate.errorLogger, "healthCheck failed", e); + } + + EcompPortalUtils.logAndSerializeObject(logger, "/portalApi/healthCheck", "GET result =", response.getStatus()); + + return healthStatus; + } + + @RequestMapping(value = { + "/portalApi/healthCheckSuspend"}, method = RequestMethod.GET, produces = "application/json") + public HealthStatus healthCheckSuspend(HttpServletRequest request, HttpServletResponse response) { + HealthStatus healthStatus = new HealthStatus(500, "Suspended for manual failover mechanism"); + + HealthMonitor.setSuspended(true); + healthStatus.statusCode = 200; + + EcompPortalUtils.logAndSerializeObject(logger, "/portalApi/healthCheckSuspend", "GET result =", + response.getStatus()); + + return healthStatus; + } + + @RequestMapping(value = { + "/portalApi/healthCheckResume"}, method = RequestMethod.GET, produces = "application/json") + public HealthStatus healthCheckResume(HttpServletRequest request, HttpServletResponse response) { + HealthStatus healthStatus = new HealthStatus(500, "Resumed from manual failover mechanism"); + + HealthMonitor.setSuspended(false); + healthStatus.statusCode = 200; + EcompPortalUtils.logAndSerializeObject(logger, "/portalApi/healthCheckResume", "GET result =", + response.getStatus()); + return healthStatus; + } + + @RequestMapping(value = {"/portalApi/ping"}, method = RequestMethod.GET, produces = "application/json") + public HealthStatus ping(HttpServletRequest request, HttpServletResponse response) { + HealthStatus healthStatus = new HealthStatus(200, "OK"); + EcompPortalUtils.logAndSerializeObject(logger, "/portalApi/ping", "GET result =", response.getStatus()); + + return healthStatus; + } +} diff --git a/portal-BE/src/main/java/org/onap/portal/controller/ManifestController.java b/portal-BE/src/main/java/org/onap/portal/controller/ManifestController.java new file mode 100644 index 00000000..ccf864cb --- /dev/null +++ b/portal-BE/src/main/java/org/onap/portal/controller/ManifestController.java @@ -0,0 +1,81 @@ +/*- + * ============LICENSE_START========================================== + * ONAP Portal + * =================================================================== + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * =================================================================== + * + * Unless otherwise specified, all software contained herein is licensed + * under the Apache License, Version 2.0 (the "License"); + * you may not use this software 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. + * + * Unless otherwise specified, all documentation contained herein is licensed + * under the Creative Commons License, Attribution 4.0 Intl. (the "License"); + * you may not use this documentation except in compliance with the License. + * You may obtain a copy of the License at + * + * https://creativecommons.org/licenses/by/4.0/ + * + * Unless required by applicable law or agreed to in writing, documentation + * 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.portal.controller; + +import java.util.HashMap; +import java.util.Map; +import java.util.jar.Attributes; +import javax.servlet.http.HttpServletRequest; +import org.onap.portal.service.ManifestService; +import org.onap.portalsdk.core.controller.RestrictedBaseController; +import org.onap.portalsdk.core.logging.logic.EELFLoggerDelegate; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.annotation.EnableAspectJAutoProxy; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestMethod; +import org.springframework.web.bind.annotation.ResponseBody; +import org.springframework.web.bind.annotation.RestController; + +@RestController +@EnableAspectJAutoProxy +public class ManifestController { + //TODO extends RestrictedBaseController + private EELFLoggerDelegate logger = EELFLoggerDelegate.getLogger(ManifestController.class); + + private final ManifestService manifestService; + + @Autowired + public ManifestController(ManifestService manifestService) { + this.manifestService = manifestService; + } + + @RequestMapping(value = {"/portalApi/manifest"}, method = RequestMethod.GET, produces = "application/json") + @ResponseBody + public Map getManifest(HttpServletRequest request) { + Map response = new HashMap(); + try { + Attributes attributes = manifestService.getWebappManifest(); + response.put("manifest", attributes); + } catch (Exception ex) { + logger.error(EELFLoggerDelegate.errorLogger, "getManifest: failed to read manifest", ex); + response.put("error", "failed to get manifest: " + ex.toString()); + } + return response; + } + +} diff --git a/portal-BE/src/main/java/org/onap/portal/scheduler/healthMonitor/HealthMonitor.java b/portal-BE/src/main/java/org/onap/portal/scheduler/healthMonitor/HealthMonitor.java new file mode 100644 index 00000000..3b83e146 --- /dev/null +++ b/portal-BE/src/main/java/org/onap/portal/scheduler/healthMonitor/HealthMonitor.java @@ -0,0 +1,359 @@ +/*- + * ============LICENSE_START========================================== + * ONAP Portal + * =================================================================== + * Copyright (C) 2017-2018 AT&T Intellectual Property. All rights reserved. + * =================================================================== + * + * Unless otherwise specified, all software contained herein is licensed + * under the Apache License, Version 2.0 (the "License"); + * you may not use this software 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. + * + * Unless otherwise specified, all documentation contained herein is licensed + * under the Creative Commons License, Attribution 4.0 Intl. (the "License"); + * you may not use this documentation except in compliance with the License. + * You may obtain a copy of the License at + * + * https://creativecommons.org/licenses/by/4.0/ + * + * Unless required by applicable law or agreed to in writing, documentation + * 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.portal.scheduler.healthMonitor; + +import java.time.Instant; +import java.util.List; +import javax.annotation.PostConstruct; +import javax.annotation.PreDestroy; +import javax.persistence.EntityManagerFactory; +import lombok.NoArgsConstructor; +import org.apache.zookeeper.client.FourLetterWordMain; +import org.hibernate.Query; +import org.hibernate.Session; +import org.hibernate.SessionFactory; +import org.onap.music.datastore.PreparedQueryObject; +import org.onap.music.exceptions.MusicServiceException; +import org.onap.music.main.MusicCore; +import org.onap.music.main.MusicUtil; +import org.onap.portal.logging.format.EPAppMessagesEnum; +import org.onap.portal.logging.logic.EPLogUtil; +import org.onap.portal.utils.EPCommonSystemProperties; +import org.onap.portalapp.music.util.MusicProperties; +import org.onap.portalsdk.core.logging.logic.EELFLoggerDelegate; +import org.onap.portalsdk.core.util.SystemProperties; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.annotation.Configuration; +import org.springframework.context.annotation.EnableAspectJAutoProxy; +import org.springframework.transaction.annotation.Transactional; + + +@Transactional +@Configuration +@EnableAspectJAutoProxy +@NoArgsConstructor +public class HealthMonitor { + private static EELFLoggerDelegate logger = EELFLoggerDelegate.getLogger(HealthMonitor.class); + private Thread healthMonitorThread; + private static EntityManagerFactory entityManagerFactory; + private static boolean databaseUp; + private static boolean uebUp; + private static boolean frontEndUp; + private static boolean backEndUp; + private static boolean dbPermissionsOk; + private static boolean zookeeperStatusOk; + private static boolean cassandraStatusOk; + private static String application = "Portal"; + private static boolean isSuspended = false; + + @Autowired + public HealthMonitor(EntityManagerFactory entityManagerFactory) { + this.entityManagerFactory = entityManagerFactory; + + } + + private static void monitorEPHealth() { + + int numIntervalsDatabaseHasBeenDown = 0; + int numIntervalsDatabasePermissionsIncorrect = 0; + int numIntervalsZookeeperNotHealthy = 0; + int numIntervalsCassandraNotHealthy = 0; + + logger.debug(EELFLoggerDelegate.debugLogger, "monitorEPHealth thread started"); + + + long sleepInterval = (Long + .parseLong(SystemProperties.getProperty(EPCommonSystemProperties.HEALTH_POLL_INTERVAL_SECONDS)) * 1000); + long numIntervalsBetweenAlerts = Long + .parseLong(SystemProperties.getProperty(EPCommonSystemProperties.HEALTHFAIL_ALERT_EVERY_X_INTERVALS)); + logger.debug(EELFLoggerDelegate.debugLogger, + "monitorEPHealth: Polling health every " + sleepInterval + " milliseconds. Alerting every " + + (sleepInterval * numIntervalsBetweenAlerts) / 1000 + " seconds when component remains down."); + + while (true) { + logger.debug(EELFLoggerDelegate.debugLogger, + "monitorEPHealth: Test Connection to all"); + // + // Get DB status. If down, signal alert once every X intervals. + // + databaseUp = checkIfDatabaseUp(); + if (databaseUp) { + if ((numIntervalsDatabaseHasBeenDown % numIntervalsBetweenAlerts) == 0) { + logger.debug(EELFLoggerDelegate.debugLogger, + "monitorEPHealth: database down, logging to error log to trigger alert."); + // Write a Log entry that will generate an alert + EPLogUtil.logEcompError(logger, EPAppMessagesEnum.BeHealthCheckMySqlError); + numIntervalsDatabaseHasBeenDown++; + } else { + numIntervalsDatabaseHasBeenDown = 0; + } + } + + dbPermissionsOk = checkDatabasePermissions(); + if (!dbPermissionsOk) { + if ((numIntervalsDatabasePermissionsIncorrect % numIntervalsBetweenAlerts) == 0) { + logger.debug(EELFLoggerDelegate.debugLogger, + "monitorEPHealth: database permissions incorrect, logging to error log to trigger alert."); + EPLogUtil.logEcompError(logger, EPAppMessagesEnum.BeHealthCheckMySqlError); + numIntervalsDatabasePermissionsIncorrect++; + } else { + numIntervalsDatabasePermissionsIncorrect = 0; + } + } + if(org.onap.portalapp.music.util.MusicUtil.isMusicEnable()){ + cassandraStatusOk = checkCassandraStatus(); + if (!cassandraStatusOk) { + if ((numIntervalsCassandraNotHealthy % numIntervalsBetweenAlerts) == 0) { + logger.debug(EELFLoggerDelegate.debugLogger, + "monitorEPHealth: cluster nodes down, logging to error log to trigger alert."); + EPLogUtil.logEcompError(logger, EPAppMessagesEnum.MusicHealthCheckCassandraError); + numIntervalsCassandraNotHealthy++; + } else { + numIntervalsCassandraNotHealthy = 0; + } + } + } + frontEndUp = true; + backEndUp = true; + + if (Thread.interrupted()) { + logger.info(EELFLoggerDelegate.errorLogger, "monitorEPHealth: thread interrupted"); + break; + } + + try { + Thread.sleep(sleepInterval); + } catch (InterruptedException e) { + logger.error(EELFLoggerDelegate.errorLogger, "monitorEPHealth: sleep interrupted", e); + Thread.currentThread().interrupt(); + } + } + } + + @PostConstruct + public void initHealthMonitor() { + healthMonitorThread = new Thread("EP HealthMonitor thread") { + @Override + public void run() { + try { + monitorEPHealth(); + } + catch (Exception e) { + logger.error(EELFLoggerDelegate.errorLogger, "healthMonitorThread failed", e); + } + } + }; + healthMonitorThread.start(); + + } + + @PreDestroy + public void closeHealthMonitor() { + this.healthMonitorThread.interrupt(); + } + + /** + * This routine checks whether the database can be read. In June 2017 we + * experimented with checking if the database can be WRITTEN. Writes failed + * with some regularity in a MariaDB Galera cluster, and in that + * environment, the resulting alerts in the log triggered a health monitor + * cron job to shut down the Tomcat instance. The root cause of the cluster + * write failures was not determined. + * + * @return true if the database can be read. + */ + private static boolean checkIfDatabaseUp() { + boolean isUp = false; + Session localSession = null; + try { + localSession = entityManagerFactory.unwrap(SessionFactory.class).openSession(); + if (localSession != null) { + String sql = "select app_name from fn_app where app_id=1"; + Query query = localSession.createSQLQuery(sql); + @SuppressWarnings("unchecked") + List queryList = query.list(); + if (queryList != null) { + isUp = true; + } + } + } catch (Exception e) { + logger.debug(EELFLoggerDelegate.debugLogger, "checkIfDatabaseUp failed", e); + isUp = false; + } finally { + if (localSession != null) + localSession.close(); + } + return isUp; + } + + private static boolean checkZookeeperStatus() { + + String[] zookeeperNodes = MusicUtil.getMyZkHost().split(","); + logger.info(EELFLoggerDelegate.applicationLogger, "MusicUtil.getMyZkHost()---- :" + MusicUtil.getMyZkHost()); + for (String zookeeperNode : zookeeperNodes) { + try { + logger.info(EELFLoggerDelegate.applicationLogger, "server ip--zookeeper :" + zookeeperNode.trim()); + String[] iport = zookeeperNode.split(":"); + String zkNodeStatistics = FourLetterWordMain.send4LetterWord(iport[0].trim(), + Integer.parseInt(iport[1].trim()), "stat"); + logger.info(EELFLoggerDelegate.applicationLogger, + "Getting Status for Zookeeper zkNodeStatistics :" + zkNodeStatistics); + if (!zkNodeStatistics.isEmpty()) { + String state = zkNodeStatistics.substring(zkNodeStatistics.indexOf("Mode:"), + zkNodeStatistics.indexOf("Node")); + logger.info(EELFLoggerDelegate.applicationLogger, + + "Getting Status for zookeeper :" + zookeeperNode.trim() + ":------:" + state); + if (state.contains("leader") || state.contains("follower")) { + return true; + } + } + } catch (Exception e) { + logger.error(EELFLoggerDelegate.errorLogger, "ZookeeperStatus Service is not responding", e.getCause()); + } + } + + return false; + } + + + private static boolean checkCassandraStatus() { + logger.info(EELFLoggerDelegate.applicationLogger, "Getting Status for Cassandra"); + if (getAdminKeySpace()) { + return true; + } else { + logger.error(EELFLoggerDelegate.errorLogger, "Cassandra Service is not responding"); + return false; + } + } + + private static Boolean getAdminKeySpace() { + String musicKeySpace = MusicProperties.getProperty(MusicProperties.MUSIC_SESSION_KEYSPACE); + Instant creationTime = Instant.now(); + PreparedQueryObject pQuery = new PreparedQueryObject(); + pQuery.appendQueryString( + "UPDATE " + musicKeySpace + ".health_check SET creation_time = ? WHERE primary_id = ?"); + pQuery.addValue(creationTime.toString()); + pQuery.addValue(application); + try { + MusicCore.nonKeyRelatedPut(pQuery, MusicUtil.CRITICAL); + } catch (MusicServiceException e) { + logger.error(EELFLoggerDelegate.errorLogger, e.getErrorMessage(), e); + return Boolean.FALSE; + } + return Boolean.TRUE; + + } + + + private static boolean checkDatabasePermissions() { + boolean isUp = false; + Session localSession = null; + try { + localSession = entityManagerFactory.unwrap(SessionFactory.class).openSession(); + if (localSession != null) { + String sql = "SHOW GRANTS FOR CURRENT_USER"; + Query query = localSession.createSQLQuery(sql); + @SuppressWarnings("unchecked") + List grantsList = query.list(); + for (String str : grantsList) { + if ((str.toUpperCase().contains("ALL")) + || (str.toUpperCase().contains("DELETE") && str.toUpperCase().contains("SELECT") + && str.toUpperCase().contains("UPDATE") && str.toUpperCase().contains("INSERT"))) { + isUp = true; + break; + } + } + if (!isUp) { + logger.error(EELFLoggerDelegate.errorLogger, + "checkDatabasePermissions returning false. SHOW GRANTS FOR CURRENT_USER being dumped:"); + for (String str : grantsList) { + logger.error(EELFLoggerDelegate.errorLogger, "grants output item = [" + str + "]"); + } + } + } + } catch (Exception e) { + logger.error(EELFLoggerDelegate.errorLogger, "checkDatabasePermissions failed", e); + if ((e.getCause() != null) && (e.getCause().getMessage() != null)) { + logger.error(EELFLoggerDelegate.errorLogger, "checkDatabasePermissions failure cause", e.getCause()); + } + isUp = false; + } finally { + if (localSession != null) { + localSession.close(); + } + } + return isUp; + } + + public static boolean isDatabaseUp() { + return databaseUp; + } + + public static boolean isUebUp() { + return uebUp; + } + + public static boolean isFrontEndUp() { + return frontEndUp; + } + + public static boolean isBackEndUp() { + return backEndUp; + } + + public static boolean isDbPermissionsOk() { + return dbPermissionsOk; + } + + public static boolean isZookeeperStatusOk() { + return zookeeperStatusOk; + } + + public static boolean isCassandraStatusOk() { + return cassandraStatusOk; + } + + public static boolean isSuspended() { + return isSuspended; + } + + public static void setSuspended(boolean isSuspended) { + HealthMonitor.isSuspended = isSuspended; + } +} diff --git a/portal-BE/src/main/java/org/onap/portal/service/ManifestService.java b/portal-BE/src/main/java/org/onap/portal/service/ManifestService.java new file mode 100644 index 00000000..eb823250 --- /dev/null +++ b/portal-BE/src/main/java/org/onap/portal/service/ManifestService.java @@ -0,0 +1,35 @@ +package org.onap.portal.service; + +import java.io.IOException; +import java.io.InputStream; +import java.util.jar.Attributes; +import java.util.jar.Manifest; +import javax.servlet.ServletContext; +import org.onap.portalsdk.core.logging.logic.EELFLoggerDelegate; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.annotation.EnableAspectJAutoProxy; +import org.springframework.stereotype.Service; + +@Service +@EnableAspectJAutoProxy +public class ManifestService { + + @Autowired + ServletContext context; + + public Attributes getWebappManifest() throws IOException { + EELFLoggerDelegate logger = EELFLoggerDelegate.getLogger(ManifestService.class); + // Path to resource on classpath + final String MANIFEST_RESOURCE_PATH = "/META-INF/MANIFEST.MF"; + // Manifest is formatted as Java-style properties + try { + InputStream inputStream = context.getResourceAsStream(MANIFEST_RESOURCE_PATH); + Manifest manifest = new Manifest(inputStream); + inputStream.close(); + return manifest.getMainAttributes(); + } catch (IOException e) { + logger.error(EELFLoggerDelegate.errorLogger, "getWebappManifest: failed to read/find manifest"); + throw e; + } + } +} diff --git a/portal-BE/src/main/resources/application.properties b/portal-BE/src/main/resources/application.properties index b99840d2..c59fa413 100644 --- a/portal-BE/src/main/resources/application.properties +++ b/portal-BE/src/main/resources/application.properties @@ -1,4 +1,4 @@ -server.port=8080 +server.port=8081 spring.datasource.url=jdbc:mysql://portal-db:3306/testdb?createDatabaseIfNotExist=true&useUnicode=true&useJDBCCompliantTimezoneShift=true&useLegacyDatetimeCode=false&serverTimezone=UTC spring.datasource.driverClassName=org.mariadb.jdbc.Driver -- 2.16.6