2 * ================================================================================
4 * ================================================================================
5 * Copyright (C) 2017 AT&T Intellectual Property
6 * ================================================================================
7 * Licensed under the Apache License, Version 2.0 (the "License");
8 * you may not use this file except in compliance with the License.
9 * You may obtain a copy of the License at
11 * http://www.apache.org/licenses/LICENSE-2.0
13 * Unless required by applicable law or agreed to in writing, software
14 * distributed under the License is distributed on an "AS IS" BASIS,
15 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 * See the License for the specific language governing permissions and
17 * limitations under the License.
18 * ================================================================================
20 package org.openecomp.portalapp.portal.listener;
22 import java.util.List;
24 import javax.annotation.PostConstruct;
25 import javax.annotation.PreDestroy;
27 import org.hibernate.Query;
28 import org.hibernate.Session;
29 import org.hibernate.SessionFactory;
30 import org.openecomp.portalapp.portal.logging.aop.EPMetricsLog;
31 import org.openecomp.portalapp.portal.logging.format.EPAppMessagesEnum;
32 import org.openecomp.portalapp.portal.logging.logic.EPLogUtil;
33 import org.openecomp.portalapp.portal.ueb.EPUebHelper;
34 import org.openecomp.portalapp.portal.utils.EPSystemProperties;
35 import org.openecomp.portalapp.portal.utils.EcompPortalUtils;
36 import org.openecomp.portalsdk.core.logging.logic.EELFLoggerDelegate;
37 import org.openecomp.portalsdk.core.util.SystemProperties;
38 import org.springframework.beans.factory.annotation.Autowired;
39 import org.springframework.context.annotation.EnableAspectJAutoProxy;
40 import org.springframework.transaction.annotation.Transactional;
43 @org.springframework.context.annotation.Configuration
44 @EnableAspectJAutoProxy
46 public class HealthMonitor {
49 private SessionFactory sessionFactory;
52 private EPUebHelper epUebHelper;
54 private static boolean databaseUp;
55 private static boolean uebUp;
56 private static boolean frontEndUp;
57 private static boolean backEndUp;
58 private static boolean dbClusterStatusOk;
59 private static boolean dbPermissionsOk;
60 public static boolean isSuspended = false;
62 Thread healthMonitorThread;
64 EELFLoggerDelegate logger = EELFLoggerDelegate.getLogger(HealthMonitor.class);
66 public HealthMonitor() {
70 public static boolean isDatabaseUp() {
74 public static boolean isClusterStatusOk() {
75 return dbClusterStatusOk;
78 public static boolean isDatabasePermissionsOk() {
79 return dbPermissionsOk;
82 public static boolean isUebUp() {
86 public static boolean isFrontEndUp() {
90 public static boolean isBackEndUp() {
94 private void monitorEPHealth() throws InterruptedException{
96 int numIntervalsDatabaseHasBeenDown = 0;
97 int numIntervalsClusterNotHealthy = 0;
98 int numIntervalsDatabasePermissionsIncorrect = 0;
99 int numIntervalsUebHasBeenDown = 0;
101 logger.debug(EELFLoggerDelegate.debugLogger, "==> Health Monitor thread started");
103 long sleepInterval = (Long.valueOf(SystemProperties.getProperty(EPSystemProperties.HEALTH_POLL_INTERVAL_SECONDS)) * 1000);
104 long numIntervalsBetweenAlerts = Long.valueOf(SystemProperties.getProperty(EPSystemProperties.HEALTHFAIL_ALERT_EVERY_X_INTERVALS));
105 logger.debug(EELFLoggerDelegate.debugLogger, "Polling health every " + sleepInterval + " milliseconds. Alerting every "
106 + (sleepInterval * numIntervalsBetweenAlerts)/1000 + " seconds when component remains down.");
111 // Get DB status. If down, signal alert once every X intervals.
113 databaseUp = this.checkIfDatabaseUp();
114 if (databaseUp == false) {
116 if ((numIntervalsDatabaseHasBeenDown % numIntervalsBetweenAlerts) == 0){
117 // Write a Log entry that will generate an alert
118 EPLogUtil.logEcompError(EPAppMessagesEnum.BeHealthCheckMySqlError);
119 logger.debug(EELFLoggerDelegate.debugLogger, "Database down, logging to error log to trigger alert.");
120 numIntervalsDatabaseHasBeenDown++;
123 numIntervalsDatabaseHasBeenDown = 0;
127 dbClusterStatusOk = this.checkClusterStatus();
128 if (dbClusterStatusOk == false) {
130 if ((numIntervalsClusterNotHealthy % numIntervalsBetweenAlerts) == 0){
131 EPLogUtil.logEcompError(EPAppMessagesEnum.BeHealthCheckMySqlError);
132 logger.debug(EELFLoggerDelegate.debugLogger, "Cluster nodes appear to be down, logging to error log to trigger alert.");
133 numIntervalsClusterNotHealthy++;
136 numIntervalsClusterNotHealthy = 0;
140 dbPermissionsOk = this.checkDatabaseAndPermissions();
141 if (dbPermissionsOk == false) {
143 if ((numIntervalsDatabasePermissionsIncorrect % numIntervalsBetweenAlerts) == 0){
144 EPLogUtil.logEcompError(EPAppMessagesEnum.BeHealthCheckMySqlError);
145 logger.debug(EELFLoggerDelegate.debugLogger, "Database permissions don't seem correct, logging to error log to trigger alert.");
146 numIntervalsDatabasePermissionsIncorrect++;
149 numIntervalsDatabasePermissionsIncorrect = 0;
154 // Get UEB status. Publish a bogus message to EP inbox, if 200 OK returned, status is Up.
155 // If down, signal alert once every X intervals.
156 // EP will ignore this bogus message.
158 uebUp = this.checkIfUebUp();
159 if (uebUp == false) {
161 if ((numIntervalsUebHasBeenDown % numIntervalsBetweenAlerts) == 0){
162 // Write a Log entry that will generate an alert
163 EPLogUtil.logEcompError(EPAppMessagesEnum.BeHealthCheckUebClusterError);
164 logger.debug(EELFLoggerDelegate.debugLogger, "UEB down, logging to error log to trigger alert");
165 numIntervalsUebHasBeenDown++;
168 numIntervalsUebHasBeenDown = 0;
172 //The front end should be up because the API is called through proxy front end server.
176 //If the rest API called, the backend is always up
180 // future nice to have...get Partner status
182 // For all apps exposing a rest url, query one of the rest urls(/roles?) and manage a list
183 // of app name/status. We might not return back a non 200 OK in health check, but we
184 // could return information in the json content of a health check.
188 // Get DB status. If down, signal alert once every X intervals.
190 Thread.sleep(sleepInterval);
195 public void initHealthMonitor() {
197 healthMonitorThread = new Thread("EP HealthMonitor thread") {
201 } catch (InterruptedException e) {
202 logger.debug(EELFLoggerDelegate.debugLogger, "<== Health Monitor thread exiting..." + EcompPortalUtils.getStackTrace(e));
203 } catch(Exception e) {
204 logger.error(EELFLoggerDelegate.errorLogger, "Exception occurred in Healthcheck monitor thread." + EcompPortalUtils.getStackTrace(e));
208 if (healthMonitorThread != null) {
209 healthMonitorThread.start();
214 public void closeHealthMonitor()
216 this.healthMonitorThread.interrupt();
220 private boolean checkIfDatabaseUp() {
222 boolean isUp = false;
224 Session localSession = null;
227 localSession = sessionFactory.openSession();
229 if (localSession != null) {
231 String sql = "select app_name from fn_app where app_id=1";
232 Query query = localSession.createSQLQuery(sql);
233 @SuppressWarnings("unchecked")
234 List <String>queryList = query.list();
235 if (queryList != null) {
238 localSession.close();
241 catch (Exception e) {
242 logger.error(EELFLoggerDelegate.errorLogger, EcompPortalUtils.getStackTrace(e));
250 private boolean checkClusterStatus() {
252 boolean isUp = false;
254 Session localSession = null;
257 localSession = sessionFactory.openSession();
258 if (localSession != null) {
259 /////////////////////////////////////////////////////////////////////////
260 // If all nodes are unhealthy in a cluster, this will throw an exception
261 /////////////////////////////////////////////////////////////////////////
262 String sql = "select * from mysql.user";
263 Query query = localSession.createSQLQuery(sql);
264 @SuppressWarnings("unchecked")
265 List <String>queryList = query.list();
266 if (queryList != null) {
271 catch (Exception e) {
272 logger.error(EELFLoggerDelegate.errorLogger, "checkClusterStatus() exception msg = " + e.getMessage());
273 if ((e.getCause() != null) && (e.getCause().getMessage() != null)) {
274 logger.error(EELFLoggerDelegate.errorLogger, "checkClusterStatus() exception msg = " + e.getCause().getMessage());
276 logger.error(EELFLoggerDelegate.errorLogger, "Exception inside checkClusterStatus() exception = " + EcompPortalUtils.getStackTrace(e));
280 if (localSession != null) {
281 localSession.close();
290 private boolean checkDatabaseAndPermissions() {
292 boolean isUp = false;
294 Session localSession = null;
297 localSession = sessionFactory.openSession();
298 if (localSession != null) {
299 String sql = "SHOW GRANTS FOR CURRENT_USER";
300 Query query = localSession.createSQLQuery(sql);
301 @SuppressWarnings("unchecked")
302 List<String> grantsList = query.list();
303 for (String str : grantsList) {
304 if ((str.toUpperCase().contains("ALL"))
306 (str.toUpperCase().contains("DELETE") &&
307 str.toUpperCase().contains("SELECT") &&
308 str.toUpperCase().contains("UPDATE") &&
309 str.toUpperCase().contains("INSERT"))) {
315 logger.error(EELFLoggerDelegate.errorLogger, "checkDatabaseAndPermissions() returning false. SHOW GRANTS FOR CURRENT_USER being dumped:");
316 for (String str : grantsList) {
317 logger.error(EELFLoggerDelegate.errorLogger, "grants output item = [" + str + "]");
322 catch (Exception e) {
323 logger.error(EELFLoggerDelegate.errorLogger, "checkDatabaseAndPermissions() exception msg = " + e.getMessage());
324 if ((e.getCause() != null) && (e.getCause().getMessage() != null)) {
325 logger.error(EELFLoggerDelegate.errorLogger, "checkDatabaseAndPermissions() exception msg = " + e.getCause().getMessage());
327 logger.error(EELFLoggerDelegate.errorLogger, "Exception inside checkDatabaseAndPermissions() exception = " + EcompPortalUtils.getStackTrace(e));
331 if (localSession != null) {
332 localSession.close();
341 private boolean checkIfUebUp() {
342 boolean uebUp = false;
344 boolean isAvailable = epUebHelper.checkAvailability();
345 boolean messageCanBeSent = epUebHelper.MessageCanBeSentToTopic();
346 uebUp = (isAvailable && messageCanBeSent);
348 catch (Exception e) {
349 logger.error(EELFLoggerDelegate.errorLogger, "Exception inside CheckIfUebUp exception = " + EcompPortalUtils.getStackTrace(e));
358 private boolean checkIfFeUp() {
359 boolean frontenndUp = false;
361 String url = SystemProperties.getProperty(EPSystemProperties.FE_URL);
362 if(StringUtils.isEmpty(url))
364 logger.debug(EELFLoggerDelegate.debugLogger, "The front end URL is empty. Cannot check the status");
368 url = url.replace("index.html", "app/healthCheck.json");
370 URL frontEndURL = new URL(url);
372 HttpURLConnection con = (HttpURLConnection) frontEndURL.openConnection();
374 // optional default is GET
375 con.setRequestMethod("GET");
377 int responseCode = con.getResponseCode();
378 logger.debug(EELFLoggerDelegate.debugLogger, "Fronend response code : " + responseCode);
380 if(responseCode == 200)
387 logger.error(EELFLoggerDelegate.errorLogger, "Exception occurred while trying to access font end" + EcompPortalUtils.getStackTrace(e));