2 * ============LICENSE_START=======================================================
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
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 * ============LICENSE_END=========================================================
21 package org.openecomp.sdc.be.components.impl;
23 import java.io.IOException;
24 import java.lang.reflect.Type;
25 import java.util.ArrayList;
26 import java.util.HashMap;
27 import java.util.List;
29 import java.util.Map.Entry;
30 import java.util.concurrent.Executors;
31 import java.util.concurrent.ScheduledExecutorService;
32 import java.util.concurrent.ScheduledFuture;
33 import java.util.concurrent.ThreadFactory;
34 import java.util.concurrent.TimeUnit;
35 import java.util.stream.Collectors;
37 import javax.annotation.PostConstruct;
38 import javax.annotation.PreDestroy;
39 import javax.annotation.Resource;
41 import org.apache.http.HttpEntity;
42 import org.apache.http.HttpStatus;
43 import org.apache.http.client.config.RequestConfig;
44 import org.apache.http.client.methods.CloseableHttpResponse;
45 import org.apache.http.client.methods.HttpGet;
46 import org.apache.http.impl.client.CloseableHttpClient;
47 import org.apache.http.impl.client.HttpClientBuilder;
48 import org.apache.http.util.EntityUtils;
49 import org.openecomp.sdc.be.components.distribution.engine.DistributionEngineClusterHealth;
50 import org.openecomp.sdc.be.components.distribution.engine.UebHealthCheckCall;
51 import org.openecomp.sdc.be.config.BeEcompErrorManager;
52 import org.openecomp.sdc.be.config.Configuration;
53 import org.openecomp.sdc.be.config.ConfigurationManager;
54 import org.openecomp.sdc.be.dao.api.IEsHealthCheckDao;
55 import org.openecomp.sdc.be.dao.titan.TitanGenericDao;
56 import org.openecomp.sdc.be.switchover.detector.SwitchoverDetector;
57 import org.openecomp.sdc.common.api.HealthCheckInfo;
58 import org.openecomp.sdc.common.api.HealthCheckInfo.HealthCheckComponent;
59 import org.openecomp.sdc.common.api.HealthCheckInfo.HealthCheckStatus;
60 import org.openecomp.sdc.common.impl.ExternalConfiguration;
61 import org.slf4j.Logger;
62 import org.slf4j.LoggerFactory;
63 import org.springframework.beans.factory.annotation.Autowired;
64 import org.springframework.stereotype.Component;
66 import com.google.gson.Gson;
67 import com.google.gson.reflect.TypeToken;
69 @Component("healthCheckBusinessLogic")
70 public class HealthCheckBusinessLogic {
72 protected static String BE_HEALTH_LOG_CONTEXT = "be.healthcheck";
74 private static Logger healthLogger = LoggerFactory.getLogger(BE_HEALTH_LOG_CONTEXT);
76 private static final String BE_HEALTH_CHECK_STR = "beHealthCheck";
77 private static final String COMPONENT_CHANGED_MESSAGE = "BE Component %s state changed from %s to %s";
80 private TitanGenericDao titanGenericDao;
83 private IEsHealthCheckDao esHealthCheckDao;
86 private DistributionEngineClusterHealth distributionEngineClusterHealth;
89 private CassandraHealthCheck cassandraHealthCheck;
92 private SwitchoverDetector switchoverDetector;
94 private static Logger log = LoggerFactory.getLogger(HealthCheckBusinessLogic.class.getName());
96 private volatile List<HealthCheckInfo> prevBeHealthCheckInfos = null;
98 public HealthCheckBusinessLogic() {
102 private ScheduledFuture<?> scheduledFuture = null;
104 ScheduledExecutorService healthCheckScheduler = Executors.newSingleThreadScheduledExecutor(new ThreadFactory() {
106 public Thread newThread(Runnable r) {
107 return new Thread(r, "BE-Health-Check-Task");
111 HealthCheckScheduledTask healthCheckScheduledTask = null;
116 prevBeHealthCheckInfos = getBeHealthCheckInfos();
118 log.debug("After initializing prevBeHealthCheckInfos: {}", prevBeHealthCheckInfos);
120 healthCheckScheduledTask = new HealthCheckScheduledTask();
122 if (this.scheduledFuture == null) {
123 this.scheduledFuture = this.healthCheckScheduler.scheduleAtFixedRate(healthCheckScheduledTask, 0, 3, TimeUnit.SECONDS);
128 public boolean isDistributionEngineUp() {
130 HealthCheckInfo healthCheckInfo = distributionEngineClusterHealth.getHealthCheckInfo();
131 if (healthCheckInfo.getHealthCheckStatus().equals(HealthCheckStatus.DOWN)) {
137 public List<HealthCheckInfo> getBeHealthCheckInfosStatus() {
139 return prevBeHealthCheckInfos;
143 private List<HealthCheckInfo> getBeHealthCheckInfos() {
145 log.trace("In getBeHealthCheckInfos");
147 List<HealthCheckInfo> healthCheckInfos = new ArrayList<HealthCheckInfo>();
150 getBeHealthCheck(healthCheckInfos);
153 getEsHealthCheck(healthCheckInfos);*/
156 getTitanHealthCheck(healthCheckInfos);
158 // Distribution Engine
159 getDistributionEngineCheck(healthCheckInfos);
162 getCassandraHealthCheck(healthCheckInfos);
165 getAmdocsHealthCheck(healthCheckInfos);
167 return healthCheckInfos;
170 private List<HealthCheckInfo> getBeHealthCheck(List<HealthCheckInfo> healthCheckInfos) {
171 String appVersion = ExternalConfiguration.getAppVersion();
172 String description = "OK";
173 healthCheckInfos.add(new HealthCheckInfo(HealthCheckComponent.BE, HealthCheckStatus.UP, appVersion, description));
174 return healthCheckInfos;
177 //Removed from aggregate HC - TDP 293490
178 /* private List<HealthCheckInfo> getEsHealthCheck(List<HealthCheckInfo> healthCheckInfos) {
180 // ES health check and version
181 HealthCheckStatus healthCheckStatus;
185 healthCheckStatus = esHealthCheckDao.getClusterHealthStatus();
186 } catch (Exception e) {
187 healthCheckStatus = HealthCheckStatus.DOWN;
188 description = "ES cluster error: " + e.getMessage();
189 healthCheckInfos.add(new HealthCheckInfo(HealthCheckComponent.ES, healthCheckStatus, null, description));
190 return healthCheckInfos;
192 if (healthCheckStatus.equals(HealthCheckStatus.DOWN)) {
193 description = "ES cluster is down";
197 healthCheckInfos.add(new HealthCheckInfo(HealthCheckComponent.ES, healthCheckStatus, null, description));
198 return healthCheckInfos;
201 public List<HealthCheckInfo> getTitanHealthCheck(List<HealthCheckInfo> healthCheckInfos) {
202 // Titan health check and version
207 isTitanUp = titanGenericDao.isGraphOpen();
208 } catch (Exception e) {
209 description = "Titan error: " + e.getMessage();
210 healthCheckInfos.add(new HealthCheckInfo(HealthCheckComponent.TITAN, HealthCheckStatus.DOWN, null, description));
211 return healthCheckInfos;
215 healthCheckInfos.add(new HealthCheckInfo(HealthCheckComponent.TITAN, HealthCheckStatus.UP, null, description));
217 description = "Titan graph is down";
218 healthCheckInfos.add(new HealthCheckInfo(HealthCheckComponent.TITAN, HealthCheckStatus.DOWN, null, description));
220 return healthCheckInfos;
223 private List<HealthCheckInfo> getCassandraHealthCheck(List<HealthCheckInfo> healthCheckInfos) {
226 boolean isCassandraUp;
229 isCassandraUp = cassandraHealthCheck.getCassandraStatus();
230 } catch (Exception e) {
231 isCassandraUp = false;
232 description = "Cassandra error: " + e.getMessage();
236 healthCheckInfos.add(new HealthCheckInfo(HealthCheckComponent.CASSANDRA, HealthCheckStatus.UP, null, description));
238 description = "Cassandra is down";
239 healthCheckInfos.add(new HealthCheckInfo(HealthCheckComponent.CASSANDRA, HealthCheckStatus.DOWN, null, description));
241 return healthCheckInfos;
245 private void getDistributionEngineCheck(List<HealthCheckInfo> healthCheckInfos) {
247 HealthCheckInfo healthCheckInfo = distributionEngineClusterHealth.getHealthCheckInfo();
249 healthCheckInfos.add(healthCheckInfo);
253 private List<HealthCheckInfo> getAmdocsHealthCheck(List<HealthCheckInfo> healthCheckInfos) {
254 HealthCheckStatus healthCheckStatus;
256 Map<String, Object> amdocsHC = null;
257 String version = null;
258 List<HealthCheckInfo> componentsInfo = null;
259 CloseableHttpClient httpClient = getHttpClient();
260 String amdocsHealtchCheckUrl = buildHealthCheckUrl();
261 HttpGet httpGet = new HttpGet(amdocsHealtchCheckUrl);
262 CloseableHttpResponse beResponse;
265 beResponse = httpClient.execute(httpGet);
266 beStatus = beResponse.getStatusLine().getStatusCode();
268 HttpEntity entity = beResponse.getEntity();
269 String beJsonResponse = EntityUtils.toString(entity);
270 Gson gson = new Gson();
271 amdocsHC = gson.fromJson(beJsonResponse, Map.class);
272 version = amdocsHC.get("sdcVersion") != null ? amdocsHC.get("sdcVersion").toString() : null;
273 Object object = amdocsHC.get("componentsInfo");
274 Type listType = new TypeToken<List<HealthCheckInfo>>(){}.getType();
275 componentsInfo = gson.fromJson(object.toString(), listType);
277 if (beStatus != HttpStatus.SC_OK) {
278 healthCheckStatus = HealthCheckStatus.DOWN;
279 StringBuilder sb = new StringBuilder();
280 componentsInfo.forEach(x -> {
281 if (x.getHealthCheckStatus()==HealthCheckStatus.DOWN){
282 sb.append("Component "+x.getHealthCheckComponent().name()+" is Down,");
285 //Removing the last comma
286 description = sb.length()>0
287 ? sb.substring(0, sb.length()-1)
288 : "Onboarding is Down, specific reason unknown";//No Amdocs inner component returned DOWN, but the status of Amdocs HC is still DOWN.
290 healthCheckStatus = HealthCheckStatus.UP;
296 } catch (Exception e) {
297 healthCheckStatus = HealthCheckStatus.DOWN;
298 description = "Onboarding unexpected response: " + e.getMessage();
300 if (httpClient != null) {
303 } catch (IOException e) {
309 healthCheckInfos.add(new HealthCheckInfo(HealthCheckComponent.ON_BOARDING, healthCheckStatus, version, description, componentsInfo));
310 return healthCheckInfos;
313 private CloseableHttpClient getHttpClient() {
315 RequestConfig.Builder requestBuilder = RequestConfig.custom();
316 requestBuilder.setConnectTimeout(timeout).setConnectionRequestTimeout(timeout).setSocketTimeout(timeout);
318 HttpClientBuilder builder = HttpClientBuilder.create();
319 builder.setDefaultRequestConfig(requestBuilder.build());
320 return builder.build();
324 private void destroy() {
326 if (scheduledFuture != null) {
327 scheduledFuture.cancel(true);
328 scheduledFuture = null;
331 if (healthCheckScheduler != null) {
332 healthCheckScheduler.shutdown();
337 public class HealthCheckScheduledTask implements Runnable {
339 List<UebHealthCheckCall> healthCheckCalls = new ArrayList<>();
341 public HealthCheckScheduledTask() {
348 healthLogger.trace("Executing BE Health Check Task");
350 List<HealthCheckInfo> currentBeHealthCheckInfos = getBeHealthCheckInfos();
351 boolean healthStatus = getAggregateBeStatus(currentBeHealthCheckInfos);
353 boolean prevHealthStatus = getAggregateBeStatus(prevBeHealthCheckInfos);
355 boolean anyStatusChanged = anyStatusChanged(currentBeHealthCheckInfos, prevBeHealthCheckInfos);
357 if (prevHealthStatus != healthStatus || anyStatusChanged) {
358 log.trace("BE Health State Changed to {}. Issuing alarm / recovery alarm...", healthStatus);
360 prevBeHealthCheckInfos = currentBeHealthCheckInfos;
361 logAlarm(healthStatus);
366 private boolean getAggregateBeStatus(List<HealthCheckInfo> beHealthCheckInfos) {
368 boolean status = true;
370 for (HealthCheckInfo healthCheckInfo : beHealthCheckInfos) {
371 if (healthCheckInfo.getHealthCheckStatus().equals(HealthCheckStatus.DOWN) && healthCheckInfo.getHealthCheckComponent() != HealthCheckComponent.DE) {
381 private void logAlarm(boolean prevHealthState) {
382 if (prevHealthState) {
383 BeEcompErrorManager.getInstance().logBeHealthCheckRecovery(BE_HEALTH_CHECK_STR);
385 BeEcompErrorManager.getInstance().logBeHealthCheckError(BE_HEALTH_CHECK_STR);
389 private void logAlarm(String componentChangedMsg) {
390 BeEcompErrorManager.getInstance().logBeHealthCheckRecovery(componentChangedMsg);
394 public String getSiteMode() {
395 return switchoverDetector.getSiteMode();
398 public boolean anyStatusChanged(List<HealthCheckInfo> beHealthCheckInfos, List<HealthCheckInfo> prevBeHealthCheckInfos) {
400 boolean result = false;
402 if (beHealthCheckInfos != null && prevBeHealthCheckInfos != null) {
404 Map<HealthCheckComponent, HealthCheckStatus> currentValues = beHealthCheckInfos.stream().collect(Collectors.toMap(p -> p.getHealthCheckComponent(), p -> p.getHealthCheckStatus()));
405 Map<HealthCheckComponent, HealthCheckStatus> prevValues = prevBeHealthCheckInfos.stream().collect(Collectors.toMap(p -> p.getHealthCheckComponent(), p -> p.getHealthCheckStatus()));
407 if (currentValues != null && prevValues != null) {
408 int currentSize = currentValues.size();
409 int prevSize = prevValues.size();
411 if (currentSize != prevSize) {
413 result = true; //extra/missing component
415 Map<HealthCheckComponent, HealthCheckStatus> notPresent = null;
416 if (currentValues.keySet().containsAll(prevValues.keySet())) {
417 notPresent = new HashMap<>(currentValues);
418 notPresent.keySet().removeAll(prevValues.keySet());
420 notPresent = new HashMap<>(prevValues);
421 notPresent.keySet().removeAll(currentValues.keySet());
424 for (HealthCheckComponent component : notPresent.keySet()) {
425 logAlarm(String.format(COMPONENT_CHANGED_MESSAGE, component, prevValues.get(component), currentValues.get(component)));
427 // HealthCheckComponent changedComponent = notPresent.keySet().iterator().next();
431 for (Entry<HealthCheckComponent, HealthCheckStatus> entry : currentValues.entrySet()) {
432 HealthCheckComponent key = entry.getKey();
433 HealthCheckStatus value = entry.getValue();
435 if (!prevValues.containsKey(key)) {
436 result = true; //component missing
437 logAlarm(String.format(COMPONENT_CHANGED_MESSAGE, key, prevValues.get(key), currentValues.get(key)));
441 HealthCheckStatus prevHealthCheckStatus = prevValues.get(key);
443 if (value != prevHealthCheckStatus) {
444 result = true; //component status changed
445 logAlarm(String.format(COMPONENT_CHANGED_MESSAGE, key, prevValues.get(key), currentValues.get(key)));
452 } else if (beHealthCheckInfos == null && prevBeHealthCheckInfos == null) {
455 logAlarm(String.format(COMPONENT_CHANGED_MESSAGE, "", prevBeHealthCheckInfos == null ? "null" : "true", prevBeHealthCheckInfos == null ? "true" : "null"));
462 private String buildHealthCheckUrl() {
464 Configuration.OnboardingConfig onboardingConfig = ConfigurationManager.getConfigurationManager().getConfiguration().getOnboarding();
466 String protocol = onboardingConfig.getProtocol();
467 String host = onboardingConfig.getHost();
468 Integer port = onboardingConfig.getPort();
469 String uri = onboardingConfig.getHealthCheckUri();
471 return protocol + "://" + host + ":" + port + uri;