HealthCheckController up 42/103742/3
authorDominik Mizyn <d.mizyn@samsung.com>
Thu, 5 Mar 2020 13:14:04 +0000 (14:14 +0100)
committerDominik Mizyn <d.mizyn@partner.samsung.com>
Mon, 5 Oct 2020 08:34:48 +0000 (10:34 +0200)
HealthCheckController up and all needed services

Issue-ID: PORTAL-710
Change-Id: I54cc4c32ea03b773833bab4296dcc0d67d3f2ea2
Signed-off-by: Dominik Mizyn <d.mizyn@samsung.com>
portal-BE/Dockerfile
portal-BE/docker-compose.yml
portal-BE/pom.xml
portal-BE/src/main/java/org/onap/portal/controller/HealthCheckController.java [new file with mode: 0644]
portal-BE/src/main/java/org/onap/portal/controller/ManifestController.java [new file with mode: 0644]
portal-BE/src/main/java/org/onap/portal/scheduler/healthMonitor/HealthMonitor.java [new file with mode: 0644]
portal-BE/src/main/java/org/onap/portal/service/ManifestService.java [new file with mode: 0644]
portal-BE/src/main/resources/application.properties

index 99275dc..3da3eec 100644 (file)
@@ -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"]
index 9b8f1ed..096695a 100644 (file)
@@ -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}
index f7f9c37..266c05e 100644 (file)
               <version>6.0.18.Final</version>
               <scope>compile</scope>
           </dependency>
+            <!-- https://mvnrepository.com/artifact/com.zaxxer/HikariCP -->
+            <dependency>
+                  <groupId>com.zaxxer</groupId>
+                  <artifactId>HikariCP</artifactId>
+                  <version>3.4.5</version>
+            </dependency>
+
             <dependency>
                   <groupId>io.swagger</groupId>
                   <artifactId>swagger-annotations</artifactId>
           <version>2.6.0</version>
           <scope>compile</scope>
         </dependency>
+        <dependency>
+          <groupId>org.onap.portal.sdk</groupId>
+          <artifactId>epsdk-music</artifactId>
+          <version>2.6.0</version>
+          <scope>compile</scope>
+        </dependency>
       </dependencies>
-      <properties>
-            <docker.image.prefix>portal</docker.image.prefix>
-            <sonar.coverage.jacoco.xmlReportPaths>${project.reporting.outputDirectory}/jacoco-ut/jacoco.xml,${project.reporting.outputDirectory}/jacoco-it/jacoco.xml</sonar.coverage.jacoco.xmlReportPaths>
-                       <sonar.skip>true</sonar.skip>
-      </properties>
       <build>
             <plugins>
                   <plugin>
                               </execution>
                         </executions>
                   </plugin>
-                  <plugin>
-                        <groupId>org.jacoco</groupId>
-                        <artifactId>jacoco-maven-plugin</artifactId>
-                        <version>0.7.7.201606060606</version>
-                        <executions>
-                              <execution>
-                                    <goals>
-                                          <goal>prepare-agent</goal>
-                                    </goals>
-                              </execution>
-                              <execution>
-                                    <id>report</id>
-                                    <phase>prepare-package</phase>
-                                    <goals>
-                                          <goal>report</goal>
-                                    </goals>
-                              </execution>
-                        </executions>
-                  </plugin>
             </plugins>
             <resources>
                   <resource>
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 (file)
index 0000000..ec2f914
--- /dev/null
@@ -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<HealthStatusInfo> statusCollection = new ArrayList<HealthStatusInfo>();
+
+            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 (file)
index 0000000..ccf864c
--- /dev/null
@@ -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<String, Object> getManifest(HttpServletRequest request) {
+        Map<String, Object> response = new HashMap<String, Object>();
+        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 (file)
index 0000000..3b83e14
--- /dev/null
@@ -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<String> 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<String> 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 (file)
index 0000000..eb82325
--- /dev/null
@@ -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;
+        }
+    }
+}
index b99840d..c59fa41 100644 (file)
@@ -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