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