Merge "Reorder modifiers"
[so.git] / status-control / src / main / java / org / openecomp / mso / HealthCheckUtils.java
1 /*-
2  * ============LICENSE_START=======================================================
3  * ONAP - SO
4  * ================================================================================
5  * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved.
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
10  *
11  *      http://www.apache.org/licenses/LICENSE-2.0
12  *
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  * ============LICENSE_END=========================================================
19  */
20
21 package org.openecomp.mso;
22
23
24 import org.openecomp.mso.db.catalog.CatalogDatabase;
25 import org.openecomp.mso.logger.MessageEnum;
26 import org.openecomp.mso.logger.MsoLogger;
27 import org.openecomp.mso.properties.MsoJavaProperties;
28 import org.openecomp.mso.properties.MsoPropertiesFactory;
29 import org.openecomp.mso.requestsdb.RequestsDatabase;
30 import org.apache.http.HttpResponse;
31 import org.apache.http.HttpStatus;
32 import org.apache.http.client.config.RequestConfig;
33 import org.apache.http.client.methods.HttpGet;
34 import org.apache.http.impl.client.CloseableHttpClient;
35 import org.apache.http.impl.client.HttpClientBuilder;
36
37 import javax.ws.rs.core.Response;
38
39 public class HealthCheckUtils {
40
41     private static final String HEALTH_CHECK = "HealthCheck";
42     private static MsoLogger msoLogger = MsoLogger.getMsoLogger(MsoLogger.Catalog.GENERAL);
43     private static final String MSO_PROP_TOPOLOGY = "MSO_PROP_TOPOLOGY";
44     private static MsoPropertiesFactory msoPropertiesFactory = new MsoPropertiesFactory();
45     private static final String CHECK_HTML = "<!DOCTYPE html><html><head><meta charset=\"ISO-8859-1\"><title>Health Check</title></head><body>Application ready</body></html>";
46     private static final String NOT_FOUND = "<!DOCTYPE html><html><head><meta charset=\"ISO-8859-1\"><title>Application Not Started</title></head><body>Application not started. Properties file missing or invalid or database Connection failed</body></html>";
47     private static final String NOT_HEALTHY = "<!DOCTYPE html><html><head><meta charset=\"ISO-8859-1\"><title>Application Not Started</title></head><body>Application not available or at least one of the sub-modules is not available.</body></html>";
48     public static final Response HEALTH_CHECK_RESPONSE = Response.status (HttpStatus.SC_OK)
49             .entity (CHECK_HTML)
50             .build ();
51     public static final Response HEALTH_CHECK_NOK_RESPONSE = Response.status (HttpStatus.SC_SERVICE_UNAVAILABLE)
52             .entity (NOT_HEALTHY)
53             .  build ();
54     public static final Response NOT_STARTED_RESPONSE = Response.status (HttpStatus.SC_SERVICE_UNAVAILABLE)
55             .entity (NOT_FOUND)
56             .build ();
57
58     public enum NodeType {APIH, RA, BPMN}
59
60     public boolean catalogDBCheck (MsoLogger subMsoLogger, long startTime) {
61         try(CatalogDatabase catalogDB = CatalogDatabase.getInstance()) {
62             catalogDB.healthCheck ();
63         } catch (Exception e) {
64             subMsoLogger.error(MessageEnum.GENERAL_EXCEPTION, "", HEALTH_CHECK, MsoLogger.ErrorCode.DataError, "Failed to check catalog database", e);
65             subMsoLogger.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.DBAccessError, "Exception during healthcheck");
66             return false;
67         }
68         return true;
69     }
70
71     public boolean requestDBCheck (MsoLogger subMsoLogger, long startTime) {
72         try {
73             (RequestsDatabase.getInstance()).healthCheck ();
74         } catch (Exception e) {
75             subMsoLogger.error(MessageEnum.GENERAL_EXCEPTION, "", HEALTH_CHECK, MsoLogger.ErrorCode.DataError, "Failed to check request database", e);
76             subMsoLogger.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.ServiceNotAvailable, "Exception during local healthcheck");
77             return false;
78         }
79         return true;
80     }
81
82     public boolean siteStatusCheck(MsoLogger subMsoLogger) {
83         // Check the Site Status value in DB first, if set to false, return NOK
84         String site = getProperty("site-name");
85
86         MsoStatusUtil statusUtil = new MsoStatusUtil ();
87         if (!statusUtil.getSiteStatus (site)) {
88             subMsoLogger.debug("This site is currently disabled for maintenance.");
89             return false;
90         }
91         return true;
92     }
93
94     public boolean configFileCheck (MsoLogger subMsoLogger, long startTime, String propertiesFile) {
95         if (null != propertiesFile) {
96             MsoJavaProperties props = loadMsoProperties (propertiesFile);
97             if (props == null) {
98                 subMsoLogger.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.ServiceNotAvailable, "Configuration file can not be loaded");
99                 return false;
100             }
101         }
102         return true;
103     }
104
105
106     private MsoJavaProperties loadMsoProperties (String fileName) {
107         MsoJavaProperties msoProperties;
108         try {
109             msoProperties = msoPropertiesFactory.getMsoJavaProperties(fileName);
110         } catch (Exception e) {
111             msoLogger.error (MessageEnum.LOAD_PROPERTIES_FAIL, fileName, "", HEALTH_CHECK, MsoLogger.ErrorCode.DataError, "Failed to load topology properties", e);
112             return null;
113         }
114         if (msoProperties !=null && msoProperties.size() > 0) {
115             return msoProperties;
116         } else {
117             msoLogger.error (MessageEnum.NO_PROPERTIES, fileName, "", HEALTH_CHECK, MsoLogger.ErrorCode.DataError, "No topology properties");
118             return  null;
119         }
120     }
121
122     protected boolean verifyLocalHealth(String ip, String apiPort, String url, String sslEnabled, String requestId) {
123         String finalUrl = getFinalUrl(ip, apiPort, url, sslEnabled);
124         long startTime = System.currentTimeMillis ();
125         if (null != requestId) {
126             finalUrl = finalUrl + "?requestId=" + requestId;
127         }
128         try {
129             HttpResponse response;
130             CloseableHttpClient client = getHttpClient ();
131             HttpGet get = new HttpGet(finalUrl);
132             msoLogger.debug("Get url is: " + finalUrl);
133             response = client.execute(get);
134             msoLogger.debug("Get response is: " + response);
135             client.close (); //shut down the connection
136             if (response.getStatusLine().getStatusCode() == HttpStatus.SC_OK) {
137                 msoLogger.debug("verifyLocalHealth - Successfully communicate with APIH/BPMN/RA");
138                 return true;
139             }
140             msoLogger.debug("verifyLocalHealth - Service not available");
141         } catch (Exception e) {
142             msoLogger.error(MessageEnum.GENERAL_EXCEPTION, "", HEALTH_CHECK, MsoLogger.ErrorCode.UnknownError, "Error in local HealthCheck", e);
143             msoLogger.recordMetricEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.CommunicationError, "Exception while communicate with APIH/BPMN/RA", url, HEALTH_CHECK, null);
144             msoLogger.debug("Exception while triggering local health check api:" + finalUrl);
145         }
146         return false;
147     }
148
149     protected CloseableHttpClient getHttpClient () {
150         // set the connection timeout value to 30 seconds (30000 milliseconds)
151         RequestConfig.Builder requestBuilder = RequestConfig.custom();
152         requestBuilder = requestBuilder.setConnectTimeout(30000);
153         requestBuilder = requestBuilder.setConnectionRequestTimeout(30000);
154         HttpClientBuilder builder = HttpClientBuilder.create ();
155         builder.setDefaultRequestConfig (requestBuilder.build ());
156
157         return builder.build ();
158     }
159
160     public MsoJavaProperties loadTopologyProperties() {
161         MsoJavaProperties msoProperties;
162         try {
163             msoProperties = msoPropertiesFactory.getMsoJavaProperties(MSO_PROP_TOPOLOGY);
164         } catch (Exception e) {
165             msoLogger.error(MessageEnum.LOAD_PROPERTIES_FAIL, MSO_PROP_TOPOLOGY, "", HEALTH_CHECK, MsoLogger.ErrorCode.DataError, "Not able to load topology properties", e);
166             return null;
167         }
168
169         if (msoProperties != null && msoProperties.size() > 0) {
170             return msoProperties;
171         } else {
172             msoLogger.error(MessageEnum.LOAD_PROPERTIES_FAIL, MSO_PROP_TOPOLOGY, "", HEALTH_CHECK, MsoLogger.ErrorCode.DataError, "Not able to load topology properties");
173             return null;
174         }
175     }
176
177     public boolean verifyNodeHealthCheck (HealthCheckUtils.NodeType type, String requestId) {
178         // Get info from topology properties file
179         MsoJavaProperties topologyProp = this.loadTopologyProperties();
180         if (null == topologyProp) {
181             return false;
182         }
183
184         checkHealthForProperty(topologyProp, "", requestId);
185
186         boolean healthCheck = false;
187         switch (type) {
188             case APIH:
189                 healthCheck = checkHealthForProperty(topologyProp, "apih-healthcheck-urn", requestId);
190                 break;
191             case RA:
192                 healthCheck = checkHealthForProperty(topologyProp, "jra-healthcheck-urn", requestId);
193                 break;
194             case BPMN:
195                 healthCheck = checkHealthForProperty(topologyProp, "camunda-healthcheck-urn", requestId);
196                 break;
197             default:
198                 msoLogger.error(MessageEnum.GENERAL_EXCEPTION_ARG, "Unknown NodeType:" + type, "", HEALTH_CHECK, MsoLogger.ErrorCode.DataError, "Unknown NodeType:" + type);
199                 break;
200         }
201
202         return healthCheck;
203     }
204
205     public boolean verifyGlobalHealthCheck(boolean verifyBpmn, String requestId) {
206         // Get info from topology properties file
207         MsoJavaProperties topologyProp = this.loadTopologyProperties();
208         if (null == topologyProp) {
209             msoLogger.error (MessageEnum.GENERAL_EXCEPTION_ARG, "Not able to find the topology file", "", HEALTH_CHECK, MsoLogger.ErrorCode.PermissionError, "Not able to find the topology file");
210             return false;
211         }
212
213         return verifyApihServersHealthCheck(topologyProp, requestId) &&
214                 verifyCamundaServersHealthCheck(topologyProp, requestId, verifyBpmn) &&
215                 verifyRaServersHealthCheck(topologyProp, requestId);
216     }
217
218     public String getProperty (String name) {
219         MsoJavaProperties prop = this.loadTopologyProperties();
220
221         return prop.getProperty(name, null);
222     }
223
224     protected String getFinalUrl (String ip, String port, String url, String sslEnabled) {
225         if (null == port && null == sslEnabled) {
226             int length = ip.length();
227             if ("/".equals(ip.substring(length - 1))) {
228                 ip = ip.substring(0, length - 1);
229             }
230             return ip + url;
231         } else if ("true".equalsIgnoreCase(sslEnabled)) {
232             return "https://" + ip + ":" + port + url;
233         } else {
234             return "http://" + ip + ":" + port + url;
235         }
236     }
237
238     private boolean verifyRaServersHealthCheck(MsoJavaProperties topologyProp, String requestId) {
239         String jraLB = topologyProp.getProperty("jra-load-balancer", null);
240         String jraApi = topologyProp.getProperty("jra-nodehealthcheck-urn", null);
241
242         if (null == jraLB || null == jraApi || jraLB.isEmpty() || jraApi.isEmpty()) {
243             msoLogger.error(MessageEnum.GENERAL_EXCEPTION_ARG, "Key parameters are missing from the topology file", "", HEALTH_CHECK, MsoLogger.ErrorCode.DataError, "Key parameters are missing from the topology file");
244             return false;
245         }
246
247         return verifyLocalHealth(jraLB, null, jraApi, null, requestId);
248     }
249
250     private boolean verifyCamundaServersHealthCheck(MsoJavaProperties topologyProp, String requestId, boolean verifyBpmn) {
251         String bpmnLB = topologyProp.getProperty("camunda-load-balancer", null);
252         String bpmnApi = topologyProp.getProperty("camunda-nodehealthcheck-urn", null);
253
254         if (null == bpmnLB || null == bpmnApi || bpmnLB.isEmpty() || bpmnApi.isEmpty()) {
255             msoLogger.error(MessageEnum.GENERAL_EXCEPTION_ARG, "Key parameters are missing from the topology file", "", HEALTH_CHECK, MsoLogger.ErrorCode.DataError, "Key parameters are missing from the topology file");
256             return false;
257         }
258
259         return !verifyBpmn || verifyLocalHealth(bpmnLB, null, bpmnApi, null, requestId);
260     }
261
262     private boolean verifyApihServersHealthCheck(MsoJavaProperties topologyProp, String requestId) {
263         String apihLB = topologyProp.getProperty("apih-load-balancer", null);
264         String apihApi = topologyProp.getProperty("apih-nodehealthcheck-urn", null);
265
266         if (null == apihLB || null == apihApi || apihLB.isEmpty() || apihApi.isEmpty()) {
267             msoLogger.error(MessageEnum.GENERAL_EXCEPTION_ARG, "Key parameters are missing from the topology file", "", HEALTH_CHECK, MsoLogger.ErrorCode.DataError, "Key parameters are missing from the topology file");
268             return false;
269         }
270
271         return verifyLocalHealth(apihLB, null, apihApi, null, requestId);
272     }
273
274     private boolean checkHealthForProperty(MsoJavaProperties topologyProp, String property, String requestId) {
275         String apiList = topologyProp.getProperty(property, null);
276         if (apiList == null) {
277             String errorDescription = "Not able to get " + property + " parameter";
278             msoLogger.error(MessageEnum.GENERAL_EXCEPTION_ARG, errorDescription, "", HEALTH_CHECK, MsoLogger.ErrorCode.DataError, errorDescription);
279             return false;
280         }
281         String[] apis = apiList.split(",");
282         return checkHealthForEachApi(topologyProp, apis, requestId);
283     }
284
285     private boolean checkHealthForEachApi(MsoJavaProperties topologyProp, String[] apis, String requestId) {
286
287         String port = topologyProp.getProperty("server-port", null);
288         String ip = System.getProperty("jboss.qualified.host.name");
289         String sslEnabled = topologyProp.getProperty("ssl-enable", null);
290
291         if (null == port || null == ip || ip.isEmpty() || port.isEmpty()) {
292             msoLogger.error(MessageEnum.GENERAL_EXCEPTION_ARG, "Not able to get the IP or the Port value. IP:" + ip + "; Port:" + port, "", HEALTH_CHECK, MsoLogger.ErrorCode.DataError, "Not able to get the IP or the Port value. IP:" + ip + "; Port:" + port);
293             return false;
294         }
295
296         for (String url : apis) {
297             // if any of the parameters is null or empty, no need to establish the health check request, just go to the next iteration
298             if ((url == null) || url.isEmpty()) {
299                 continue;
300             }
301             // Exit the loop if local health check returns false from any of the sub component
302             if (!this.verifyLocalHealth(ip, port, url, sslEnabled, requestId)) {
303                 return false;
304             }
305         }
306         return true;
307     }
308 }