[SDC] rebase 1710 code
[sdc.git] / catalog-fe / src / main / java / org / openecomp / sdc / fe / servlets / HealthCheckService.java
1 /*-
2  * ============LICENSE_START=======================================================
3  * SDC
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.sdc.fe.servlets;
22
23 import java.io.IOException;
24 import java.lang.reflect.Type;
25 import java.util.ArrayList;
26 import java.util.List;
27 import java.util.concurrent.Executors;
28 import java.util.concurrent.ScheduledExecutorService;
29 import java.util.concurrent.ThreadFactory;
30 import java.util.concurrent.TimeUnit;
31
32 import javax.servlet.ServletContext;
33 import javax.ws.rs.core.Response;
34
35 import org.apache.http.client.config.RequestConfig;
36 import org.apache.http.client.methods.CloseableHttpResponse;
37 import org.apache.http.client.methods.HttpGet;
38 import org.apache.http.impl.client.CloseableHttpClient;
39 import org.apache.http.impl.client.HttpClientBuilder;
40 import org.apache.http.util.EntityUtils;
41 import org.openecomp.sdc.common.api.Constants;
42 import org.openecomp.sdc.common.api.HealthCheckInfo;
43 import org.openecomp.sdc.common.api.HealthCheckWrapper;
44 import org.openecomp.sdc.common.api.HealthCheckInfo.HealthCheckComponent;
45 import org.openecomp.sdc.common.api.HealthCheckInfo.HealthCheckStatus;
46 import org.openecomp.sdc.common.config.EcompErrorName;
47 import org.openecomp.sdc.common.impl.ExternalConfiguration;
48 import org.openecomp.sdc.fe.config.Configuration;
49 import org.openecomp.sdc.fe.config.ConfigurationManager;
50 import org.openecomp.sdc.fe.config.FeEcompErrorManager;
51 import org.slf4j.Logger;
52 import org.slf4j.LoggerFactory;
53
54 import com.google.gson.Gson;
55 import com.google.gson.GsonBuilder;
56 import com.google.gson.reflect.TypeToken;
57
58 public class HealthCheckService {
59
60         private class HealthStatus {
61                 public String body;
62                 public int statusCode;
63
64                 public HealthStatus(int code, String body) {
65                         this.body = body;
66                         this.statusCode = code;
67                 }
68         }
69
70         private static final String URL = "%s://%s:%s/sdc2/rest/healthCheck";
71         private static Logger healthLogger = LoggerFactory.getLogger("asdc.fe.healthcheck");
72         private static Logger log = LoggerFactory.getLogger(HealthCheckService.class.getName());
73
74         private HealthStatus lastHealthStatus = new HealthStatus(500, "{}");
75
76         private class HealthCheckScheduledTask implements Runnable {
77                 @Override
78                 public void run() {
79                         healthLogger.trace("Executing FE Health Check Task - Start");
80                         HealthStatus currentHealth = checkHealth();
81                         int currentHealthStatus = currentHealth.statusCode;
82                         healthLogger.trace("Executing FE Health Check Task - Status = {}", currentHealthStatus);
83
84                         // In case health status was changed, issue alarm/recovery
85                         if (currentHealthStatus != lastHealthStatus.statusCode) {
86                                 log.trace("FE Health State Changed to {}. Issuing alarm / recovery alarm...", currentHealthStatus);
87                                 logFeAlarm(currentHealthStatus);
88                         }
89
90                         // Anyway, update latest response
91                         lastHealthStatus = currentHealth;
92                 }
93         }
94
95         /**
96          * This executor will execute the health check task.
97          */
98         ScheduledExecutorService healthCheckExecutor = Executors.newSingleThreadScheduledExecutor(new ThreadFactory() {
99                 @Override
100                 public Thread newThread(Runnable r) {
101                         return new Thread(r, "FE-Health-Check-Thread");
102                 }
103         });
104         private ServletContext context;
105
106         public HealthCheckService(ServletContext context) {
107                 this.context = context;
108         }
109
110         public void start(int interval) {
111                 this.healthCheckExecutor.scheduleAtFixedRate(new HealthCheckScheduledTask(), 0, interval, TimeUnit.SECONDS);
112         }
113
114         /**
115          * To be used by the HealthCheckServlet
116          * 
117          * @return
118          */
119         public Response getFeHealth() {
120                 return this.buildResponse(lastHealthStatus.statusCode, lastHealthStatus.body);
121         }
122
123         private HealthStatus checkHealth() {
124                 CloseableHttpClient httpClient = null;
125                 try {
126                         Gson gson = new GsonBuilder().setPrettyPrinting().create();
127                         Configuration config = ((ConfigurationManager) context.getAttribute(Constants.CONFIGURATION_MANAGER_ATTR))
128                                         .getConfiguration();
129                         String redirectedUrl = String.format(URL, config.getBeProtocol(), config.getBeHost(),
130                                         config.getBeHttpPort());
131                         httpClient = getHttpClient(config);
132                         HttpGet httpGet = new HttpGet(redirectedUrl);
133                         CloseableHttpResponse beResponse;
134                         int beStatus;
135                         String feAggHealthCheck;
136                         try {
137                                 beResponse = httpClient.execute(httpGet);
138                                 beStatus = beResponse.getStatusLine().getStatusCode();
139                                 String beJsonResponse = EntityUtils.toString(beResponse.getEntity());
140                                 feAggHealthCheck = getFeHealthCheckInfos(gson, beJsonResponse);
141                         } catch (Exception e) {
142                                 log.error("Health Check error when trying to connect to BE", e);
143                                 String beDowneResponse = gson.toJson(getBeDownCheckInfos());
144                                 return new HealthStatus(500, beDowneResponse);
145                         }
146                         return new HealthStatus(beStatus, feAggHealthCheck);
147                 } catch (Exception e) {
148                         FeEcompErrorManager.getInstance().processEcompError(EcompErrorName.FeHealthCheckGeneralError, "Unexpected FE Health check error");
149                         FeEcompErrorManager.getInstance().logFeHealthCheckGeneralError("Unexpected FE Health check error");
150                         log.error("Unexpected FE health check error {}", e.getMessage());
151                         return new HealthStatus(500, e.getMessage());
152                 } finally {
153                         if (httpClient != null) {
154                                 try {
155                                         httpClient.close();
156                                 } catch (IOException e) {
157                                 }
158                         }
159                 }
160         }
161
162         private Response buildResponse(int status, String jsonResponse) {
163                 healthLogger.trace("FE and BE health check status: {}", jsonResponse);
164                 return Response.status(status).entity(jsonResponse).build();
165         }
166
167         private void logFeAlarm(int lastFeStatus) {
168
169                 switch (lastFeStatus) {
170                 case 200:
171                         FeEcompErrorManager.getInstance().processEcompError(EcompErrorName.FeHealthCheckRecovery,
172                                         "FE Health Recovered");
173                         FeEcompErrorManager.getInstance().logFeHealthCheckRecovery("FE Health Recovered");
174                         break;
175                 case 500:
176                         FeEcompErrorManager.getInstance().processEcompError(EcompErrorName.FeHealthCheckConnectionError,
177                                         "Connection with ASDC-BE is probably down");
178                         FeEcompErrorManager.getInstance().logFeHealthCheckError("Connection with ASDC-BE is probably down");
179                         break;
180                 default:
181                         break;
182                 }
183
184         }
185
186         private String getFeHealthCheckInfos(Gson gson, String responseString) {
187                 Type wrapperType = new TypeToken<HealthCheckWrapper>() {
188                 }.getType();
189                 HealthCheckWrapper healthCheckWrapper = gson.fromJson(responseString, wrapperType);
190                 String appVersion = ExternalConfiguration.getAppVersion();
191                 String description = "OK";
192                 healthCheckWrapper.getComponentsInfo()
193                                 .add(new HealthCheckInfo(HealthCheckComponent.FE, HealthCheckStatus.UP, appVersion, description));
194                 return gson.toJson(healthCheckWrapper);
195         }
196
197         private HealthCheckWrapper getBeDownCheckInfos() {
198                 List<HealthCheckInfo> healthCheckInfos = new ArrayList<HealthCheckInfo>();
199                 healthCheckInfos.add(new HealthCheckInfo(HealthCheckComponent.FE, HealthCheckStatus.UP,
200                                 ExternalConfiguration.getAppVersion(), "OK"));
201                 healthCheckInfos.add(new HealthCheckInfo(HealthCheckComponent.BE, HealthCheckStatus.DOWN, null, null));
202                 healthCheckInfos.add(new HealthCheckInfo(HealthCheckComponent.TITAN, HealthCheckStatus.UNKNOWN, null, null));
203                 healthCheckInfos.add(new HealthCheckInfo(HealthCheckComponent.CASSANDRA, HealthCheckStatus.UNKNOWN, null, null));
204                 healthCheckInfos.add(new HealthCheckInfo(HealthCheckComponent.DE, HealthCheckStatus.UNKNOWN, null, null));
205                 healthCheckInfos.add(new HealthCheckInfo(HealthCheckComponent.ON_BOARDING, HealthCheckStatus.UNKNOWN, null, null));
206                 HealthCheckWrapper hcWrapper = new HealthCheckWrapper(healthCheckInfos, "UNKNOWN", "UNKNOWN");
207                 return hcWrapper;
208         }
209
210         private CloseableHttpClient getHttpClient(Configuration config) {
211                 int timeout = 3000;
212                 int socketTimeout = config.getHealthCheckSocketTimeoutInMs(5000);
213                 RequestConfig.Builder requestBuilder = RequestConfig.custom();
214                 requestBuilder.setConnectTimeout(timeout).setConnectionRequestTimeout(timeout).setSocketTimeout(socketTimeout);
215
216                 HttpClientBuilder builder = HttpClientBuilder.create();
217                 builder.setDefaultRequestConfig(requestBuilder.build());
218                 return builder.build();
219         }
220 }