From a5445100050e49e83f73424198d73cd72d672a4d Mon Sep 17 00:00:00 2001 From: Michael Lando Date: Sun, 4 Mar 2018 14:53:33 +0200 Subject: Sync Integ to Master Change-Id: I71e3acc26fa612127756ac04073a522b9cc6cd74 Issue-ID: SDC-977 Signed-off-by: Gitelman, Tal (tg851x) --- .../org/openecomp/sdc/fe/client/BackendClient.java | 179 ------ .../sdc/fe/servlets/FeHealthCheckServlet.java | 11 +- .../openecomp/sdc/fe/servlets/FeProxyServlet.java | 2 - .../sdc/fe/servlets/HealthCheckService.java | 627 ++++++++++----------- .../openecomp/sdc/fe/servlets/PortalServlet.java | 1 - .../src/main/resources/config/configuration.yaml | 7 + .../openecomp/sdc/fe/client/BackendClientTest.java | 26 - .../sdc/fe/servlets/PortalServletTest.java | 29 - .../openecomp/sdc/servlets/PortalServletTest.java | 2 +- 9 files changed, 326 insertions(+), 558 deletions(-) delete mode 100644 catalog-fe/src/main/java/org/openecomp/sdc/fe/client/BackendClient.java delete mode 100644 catalog-fe/src/test/java/org/openecomp/sdc/fe/client/BackendClientTest.java delete mode 100644 catalog-fe/src/test/java/org/openecomp/sdc/fe/servlets/PortalServletTest.java (limited to 'catalog-fe/src') diff --git a/catalog-fe/src/main/java/org/openecomp/sdc/fe/client/BackendClient.java b/catalog-fe/src/main/java/org/openecomp/sdc/fe/client/BackendClient.java deleted file mode 100644 index 92e497d278..0000000000 --- a/catalog-fe/src/main/java/org/openecomp/sdc/fe/client/BackendClient.java +++ /dev/null @@ -1,179 +0,0 @@ -/*- - * ============LICENSE_START======================================================= - * SDC - * ================================================================================ - * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. - * ================================================================================ - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * ============LICENSE_END========================================================= - */ - -package org.openecomp.sdc.fe.client; - -import java.io.IOException; -import java.util.List; -import java.util.Map; - -import javax.net.ssl.HostnameVerifier; -import javax.net.ssl.SSLContext; -import javax.net.ssl.SSLSession; -import javax.ws.rs.container.AsyncResponse; -import javax.ws.rs.core.Response; - -import org.apache.http.HttpStatus; -import org.apache.http.client.methods.CloseableHttpResponse; -import org.apache.http.client.methods.HttpPost; -import org.apache.http.conn.ssl.TrustSelfSignedStrategy; -import org.apache.http.entity.InputStreamEntity; -import org.apache.http.impl.client.CloseableHttpClient; -import org.apache.http.impl.client.HttpClientBuilder; -import org.apache.http.impl.client.HttpClients; -import org.apache.http.ssl.SSLContextBuilder; -import org.openecomp.sdc.common.api.Constants; -import org.openecomp.sdc.common.api.ResponseInfo; -import org.openecomp.sdc.common.api.ResponseInfo.ResponseStatusEnum; -import org.openecomp.sdc.fe.impl.Audit; -import org.openecomp.sdc.fe.impl.HttpRequestInfo; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -public class BackendClient { - - private static Logger log = LoggerFactory.getLogger(BackendClient.class.getName()); - - private HostnameVerifier hostnameVerifier = null; - - private CloseableHttpClient backendHttpClient; - private String backendHost; - private String backendContext; - - public BackendClient(String protocol, String backendHost, String backendContext) { - - this.backendContext = backendContext; - hostnameVerifier = new HostnameVerifier() { - - public boolean verify(String hostname, SSLSession session) { - - return true; - } - }; - - if (protocol == null || protocol.isEmpty() || protocol.equals(Constants.HTTP)) { - backendHttpClient = HttpClients.createDefault(); - this.backendHost = Constants.HTTP + "://" + backendHost; - } else { - // NULL can be returned in case of error - backendHttpClient = getSslClient(); - this.backendHost = Constants.HTTPS + "://" + backendHost; - } - - } - - public HostnameVerifier getHostnameVerifier() { - return hostnameVerifier; - } - - private CloseableHttpClient getSslClient() { - - CloseableHttpClient httpClient = null; - try { - - // SSLContextBuilder is not thread safe - SSLContextBuilder builder = new SSLContextBuilder(); - builder.loadTrustMaterial(null, new TrustSelfSignedStrategy()); - SSLContext sslContext = builder.build(); - - httpClient = HttpClientBuilder.create().setSSLHostnameVerifier(hostnameVerifier).setSslcontext(sslContext) - .build(); - - } catch (Exception e) { - log.error("Failed to create https client", e); - return null; - } - - return httpClient; - - } - - public ResponseInfo forwardRequestToBackend(HttpRequestInfo requestInfo, List requiredHeaders, - AsyncResponse asyncResponse) { - - ResponseInfo responseInfo = null; - log.debug("forwardRequestToBackend"); - if (backendHttpClient == null) { - responseInfo = new ResponseInfo(ResponseStatusEnum.INTERNAL_ERROR, "Failed to create https client"); - Audit.error(log, requestInfo, HttpStatus.SC_INTERNAL_SERVER_ERROR); - asyncResponse.resume( - Response.status(HttpStatus.SC_INTERNAL_SERVER_ERROR).entity(responseInfo.toString()).build()); - return responseInfo; - } - - CloseableHttpResponse response = null; - int status = HttpStatus.SC_INTERNAL_SERVER_ERROR; - HttpPost httpPost = new HttpPost(backendHost + backendContext); - try { - - log.debug("Executing request {}", httpPost.getRequestLine()); - httpPost.setEntity(new InputStreamEntity(requestInfo.getRequestData())); - boolean allHeadersAreSet = copyHeadersToRequest(requiredHeaders, requestInfo, httpPost); - if (!allHeadersAreSet) { - responseInfo = new ResponseInfo(ResponseStatusEnum.MISSING_HEADERS, "Required headers are missing"); - asyncResponse - .resume(Response.status(HttpStatus.SC_BAD_REQUEST).entity(responseInfo.toString()).build()); - Audit.error(log, requestInfo, HttpStatus.SC_BAD_REQUEST); - } else { - response = backendHttpClient.execute(httpPost); - status = response.getStatusLine().getStatusCode(); - asyncResponse.resume(Response.status(status).entity(response.getEntity()).build()); - } - Audit.info(log, requestInfo, status); - - } catch (IOException e) { - log.error("connection with backend failed with exception", e); - responseInfo = new ResponseInfo(ResponseStatusEnum.INTERNAL_ERROR, e.getMessage()); - Audit.error(log, requestInfo, HttpStatus.SC_INTERNAL_SERVER_ERROR); - asyncResponse.resume( - Response.status(HttpStatus.SC_INTERNAL_SERVER_ERROR).entity(responseInfo.toString()).build()); - } finally { - try { - if (response != null) { - response.close(); - } - backendHttpClient.close(); - } catch (IOException e) { - log.error("failed to close httpClient: {}", e.getMessage()); - } - - } - - return responseInfo; - - } - - private boolean copyHeadersToRequest(List requiredHeaders, HttpRequestInfo requestInfo, HttpPost httpPost) { - boolean allHeadersAreSet = false; - Map originalHeaders = requestInfo.getHeaders(); - for (String headerName : requiredHeaders) { - String headerValue = originalHeaders.get(headerName); - if (headerValue != null) { - httpPost.setHeader(headerName, headerValue); - } else { - log.error("missing required header {}", headerName); - return allHeadersAreSet; - } - } - allHeadersAreSet = true; - return allHeadersAreSet; - } - -} diff --git a/catalog-fe/src/main/java/org/openecomp/sdc/fe/servlets/FeHealthCheckServlet.java b/catalog-fe/src/main/java/org/openecomp/sdc/fe/servlets/FeHealthCheckServlet.java index 1ed6ac5c07..563af73ebe 100644 --- a/catalog-fe/src/main/java/org/openecomp/sdc/fe/servlets/FeHealthCheckServlet.java +++ b/catalog-fe/src/main/java/org/openecomp/sdc/fe/servlets/FeHealthCheckServlet.java @@ -20,6 +20,9 @@ package org.openecomp.sdc.fe.servlets; +import com.jcabi.aspects.Loggable; +import org.openecomp.sdc.common.servlets.BasicServlet; + import javax.servlet.ServletContext; import javax.servlet.http.HttpServletRequest; import javax.ws.rs.GET; @@ -27,10 +30,7 @@ import javax.ws.rs.Path; import javax.ws.rs.core.Context; import javax.ws.rs.core.Response; -import org.openecomp.sdc.common.api.Constants; -import org.openecomp.sdc.common.servlets.BasicServlet; - -import com.jcabi.aspects.Loggable; +import static org.openecomp.sdc.common.api.Constants.HEALTH_CHECK_SERVICE_ATTR; @Loggable(prepend = true, value = Loggable.TRACE, trim = false) @Path("/healthCheck") @@ -38,8 +38,7 @@ public class FeHealthCheckServlet extends BasicServlet { @GET public Response getFEandBeHealthCheck(@Context final HttpServletRequest request) { ServletContext context = request.getSession().getServletContext(); - HealthCheckService hcs = ((HealthCheckService) context.getAttribute(Constants.HEALTH_CHECK_SERVICE_ATTR)); + HealthCheckService hcs = ((HealthCheckService) context.getAttribute(HEALTH_CHECK_SERVICE_ATTR)); return hcs.getFeHealth(); } - } diff --git a/catalog-fe/src/main/java/org/openecomp/sdc/fe/servlets/FeProxyServlet.java b/catalog-fe/src/main/java/org/openecomp/sdc/fe/servlets/FeProxyServlet.java index 11d4abf4af..f9ac666933 100644 --- a/catalog-fe/src/main/java/org/openecomp/sdc/fe/servlets/FeProxyServlet.java +++ b/catalog-fe/src/main/java/org/openecomp/sdc/fe/servlets/FeProxyServlet.java @@ -50,7 +50,6 @@ public class FeProxyServlet extends SSLProxyServlet { try { logFeRequest(request); } catch (Exception e) { - FeEcompErrorManager.getInstance().processEcompError(EcompErrorName.FeHttpLoggingError, "FE Request"); FeEcompErrorManager.getInstance().logFeHttpLoggingError("FE Request"); log.error("Unexpected FE request logging error :", e); } @@ -67,7 +66,6 @@ public class FeProxyServlet extends SSLProxyServlet { try { logFeResponse(request, proxyResponse); } catch (Exception e) { - FeEcompErrorManager.getInstance().processEcompError(EcompErrorName.FeHttpLoggingError, "FE Response"); FeEcompErrorManager.getInstance().logFeHttpLoggingError("FE Response"); log.error("Unexpected FE response logging error :", e); } diff --git a/catalog-fe/src/main/java/org/openecomp/sdc/fe/servlets/HealthCheckService.java b/catalog-fe/src/main/java/org/openecomp/sdc/fe/servlets/HealthCheckService.java index 7010034214..fce5d35d20 100644 --- a/catalog-fe/src/main/java/org/openecomp/sdc/fe/servlets/HealthCheckService.java +++ b/catalog-fe/src/main/java/org/openecomp/sdc/fe/servlets/HealthCheckService.java @@ -7,9 +7,9 @@ * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at - * + * * http://www.apache.org/licenses/LICENSE-2.0 - * + * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. @@ -20,327 +20,326 @@ package org.openecomp.sdc.fe.servlets; -import java.io.IOException; -import java.lang.reflect.Type; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.List; -import java.util.Map; -import java.util.concurrent.Executors; -import java.util.concurrent.ScheduledExecutorService; -import java.util.concurrent.ThreadFactory; -import java.util.concurrent.TimeUnit; - -import javax.servlet.ServletContext; -import javax.ws.rs.core.Response; - -import org.apache.http.HttpStatus; -import org.apache.http.client.config.RequestConfig; -import org.apache.http.client.methods.CloseableHttpResponse; -import org.apache.http.client.methods.HttpGet; -import org.apache.http.impl.client.CloseableHttpClient; -import org.apache.http.impl.client.HttpClientBuilder; -import org.apache.http.util.EntityUtils; -import org.openecomp.sdc.common.api.Constants; +import com.fasterxml.jackson.core.type.TypeReference; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.google.gson.Gson; +import com.google.gson.GsonBuilder; +import com.google.gson.JsonSyntaxException; +import com.google.gson.reflect.TypeToken; import org.openecomp.sdc.common.api.HealthCheckInfo; -import org.openecomp.sdc.common.api.HealthCheckInfo.HealthCheckStatus; import org.openecomp.sdc.common.api.HealthCheckWrapper; -import org.openecomp.sdc.common.config.EcompErrorName; -import org.openecomp.sdc.common.impl.ExternalConfiguration; +import org.openecomp.sdc.common.config.EcompErrorEnum; +import org.openecomp.sdc.common.http.client.api.HttpResponse; +import org.openecomp.sdc.common.http.config.HttpClientConfig; +import org.openecomp.sdc.common.http.config.Timeouts; import org.openecomp.sdc.common.util.HealthCheckUtil; import org.openecomp.sdc.fe.config.Configuration; import org.openecomp.sdc.fe.config.ConfigurationManager; import org.openecomp.sdc.fe.config.FeEcompErrorManager; import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import com.fasterxml.jackson.core.type.TypeReference; -import com.fasterxml.jackson.databind.ObjectMapper; -import com.google.gson.Gson; -import com.google.gson.GsonBuilder; -import com.google.gson.JsonSyntaxException; -import com.google.gson.reflect.TypeToken; +import javax.servlet.ServletContext; +import javax.ws.rs.core.Response; +import java.io.IOException; +import java.lang.reflect.Type; +import java.util.ArrayList; +import java.util.List; +import java.util.Map; +import java.util.concurrent.ScheduledExecutorService; +import java.util.concurrent.TimeUnit; + +import static java.util.Arrays.asList; +import static java.util.concurrent.Executors.newSingleThreadScheduledExecutor; +import static org.apache.http.HttpStatus.SC_INTERNAL_SERVER_ERROR; +import static org.apache.http.HttpStatus.SC_OK; +import static org.openecomp.sdc.common.api.Constants.*; +import static org.openecomp.sdc.common.api.HealthCheckInfo.HealthCheckStatus.*; +import static org.openecomp.sdc.common.http.client.api.HttpRequest.get; +import static org.openecomp.sdc.common.impl.ExternalConfiguration.getAppVersion; +import static org.slf4j.LoggerFactory.getLogger; public class HealthCheckService { - private class HealthStatus { - public String body; - public int statusCode; - - public HealthStatus(int code, String body) { - this.body = body; - this.statusCode = code; - } - } - - private static final String URL = "%s://%s:%s/sdc2/rest/healthCheck"; - private static Logger healthLogger = LoggerFactory.getLogger("asdc.fe.healthcheck"); - private static Logger log = LoggerFactory.getLogger(HealthCheckService.class.getName()); - - private HealthStatus lastHealthStatus = new HealthStatus(500, "{}"); - private final List healthCheckFeComponents = Arrays.asList(Constants.HC_COMPONENT_ON_BOARDING, Constants.HC_COMPONENT_DCAE); - - private class HealthCheckScheduledTask implements Runnable { - @Override - public void run() { - healthLogger.trace("Executing FE Health Check Task - Start"); - HealthStatus currentHealth = checkHealth(); - int currentHealthStatus = currentHealth.statusCode; - healthLogger.trace("Executing FE Health Check Task - Status = {}", currentHealthStatus); - - // In case health status was changed, issue alarm/recovery - if (currentHealthStatus != lastHealthStatus.statusCode) { - log.trace("FE Health State Changed to {}. Issuing alarm / recovery alarm...", currentHealthStatus); - logFeAlarm(currentHealthStatus); - } - - // Anyway, update latest response - lastHealthStatus = currentHealth; - } - } - - /** - * This executor will execute the health check task. - */ - ScheduledExecutorService healthCheckExecutor = Executors.newSingleThreadScheduledExecutor(new ThreadFactory() { - @Override - public Thread newThread(Runnable r) { - return new Thread(r, "FE-Health-Check-Thread"); - } - }); - private ServletContext context; - - public HealthCheckService(ServletContext context) { - this.context = context; - } - - public void start(int interval) { - this.healthCheckExecutor.scheduleAtFixedRate(new HealthCheckScheduledTask(), 0, interval, TimeUnit.SECONDS); - } - - /** - * To be used by the HealthCheckServlet - * - * @return - */ - public Response getFeHealth() { - return this.buildResponse(lastHealthStatus.statusCode, lastHealthStatus.body); - } - - private HealthStatus checkHealth() { - CloseableHttpClient httpClient = null; - try { - Gson gson = new GsonBuilder().setPrettyPrinting().create(); - Configuration config = ((ConfigurationManager) context.getAttribute(Constants.CONFIGURATION_MANAGER_ATTR)) - .getConfiguration(); - String redirectedUrl = String.format(URL, config.getBeProtocol(), config.getBeHost(), - config.getBeHttpPort()); - httpClient = getHttpClient(config); - HttpGet httpGet = new HttpGet(redirectedUrl); - CloseableHttpResponse beResponse; - HealthCheckWrapper feAggHealthCheck; - try { - beResponse = httpClient.execute(httpGet); - log.debug("HC call to BE - status code is {}", beResponse.getStatusLine().getStatusCode()); - String beJsonResponse = EntityUtils.toString(beResponse.getEntity()); - feAggHealthCheck = getFeHealthCheckInfos(gson, beJsonResponse); - } catch (Exception e) { - log.debug("Health Check error when trying to connect to BE or external FE. Error: {}", e.getMessage()); - log.error("Health Check error when trying to connect to BE or external FE.", e); - String beDowneResponse = gson.toJson(getBeDownCheckInfos()); - return new HealthStatus(HttpStatus.SC_INTERNAL_SERVER_ERROR, beDowneResponse); - } - - //Getting aggregate FE status - boolean aggregateFeStatus = HealthCheckUtil.getAggregateStatus(feAggHealthCheck.getComponentsInfo()); - return new HealthStatus(aggregateFeStatus ? HttpStatus.SC_OK : HttpStatus.SC_INTERNAL_SERVER_ERROR, gson.toJson(feAggHealthCheck)); - } catch (Exception e) { - FeEcompErrorManager.getInstance().processEcompError(EcompErrorName.FeHealthCheckGeneralError, "Unexpected FE Health check error"); - FeEcompErrorManager.getInstance().logFeHealthCheckGeneralError("Unexpected FE Health check error"); - log.error("Unexpected FE health check error {}", e.getMessage()); - return new HealthStatus(HttpStatus.SC_INTERNAL_SERVER_ERROR, e.getMessage()); - } finally { - if (httpClient != null) { - try { - httpClient.close(); - } catch (IOException e) { - log.error("Couldn't close HC HTTP Client: ", e); - } - } - } - } - - - - - - private Response buildResponse(int status, String jsonResponse) { - healthLogger.trace("FE and BE health check status: {}", jsonResponse); - return Response.status(status).entity(jsonResponse).build(); - } - - private void logFeAlarm(int lastFeStatus) { - - switch (lastFeStatus) { - case 200: - FeEcompErrorManager.getInstance().processEcompError(EcompErrorName.FeHealthCheckRecovery, - "FE Health Recovered"); - FeEcompErrorManager.getInstance().logFeHealthCheckRecovery("FE Health Recovered"); - break; - case 500: - FeEcompErrorManager.getInstance().processEcompError(EcompErrorName.FeHealthCheckConnectionError, - "Connection with ASDC-BE is probably down"); - FeEcompErrorManager.getInstance().logFeHealthCheckError("Connection with ASDC-BE is probably down"); - break; - default: - break; - } - - } - - private HealthCheckWrapper getFeHealthCheckInfos(Gson gson, String responseString) { - Type wrapperType = new TypeToken() { - }.getType(); - HealthCheckWrapper healthCheckWrapper = gson.fromJson(responseString, wrapperType); - String appVersion = ExternalConfiguration.getAppVersion(); - String description = "OK"; - healthCheckWrapper.getComponentsInfo() - .add(new HealthCheckInfo(Constants.HC_COMPONENT_FE, HealthCheckStatus.UP, appVersion, description)); - - //add hosted components fe component - for (String component: healthCheckFeComponents) { - List feComponentsInfo = addHostedComponentsFeHealthCheck(component); - HealthCheckInfo baseComponentHCInfo = healthCheckWrapper.getComponentsInfo().stream().filter(c -> c.getHealthCheckComponent().equals(component)).findFirst().orElse(null); - if (baseComponentHCInfo != null) { - if (baseComponentHCInfo.getComponentsInfo() == null) { - baseComponentHCInfo.setComponentsInfo(new ArrayList<>()); - } - baseComponentHCInfo.getComponentsInfo().addAll(feComponentsInfo); - boolean status = HealthCheckUtil.getAggregateStatus(baseComponentHCInfo.getComponentsInfo()); - baseComponentHCInfo.setHealthCheckStatus(status ? HealthCheckStatus.UP : HealthCheckStatus.DOWN); - - String componentsDesc = HealthCheckUtil.getAggregateDescription(baseComponentHCInfo.getComponentsInfo(), baseComponentHCInfo.getDescription()); - if (componentsDesc.length() > 0) { //aggregated description contains all the internal components desc - baseComponentHCInfo.setDescription(componentsDesc); - } - } else { - log.error("{} not exists in HealthCheck info", component); - } - } - return healthCheckWrapper; - } - - private List addHostedComponentsFeHealthCheck(String baseComponent) { - Configuration config = ((ConfigurationManager) context.getAttribute(Constants.CONFIGURATION_MANAGER_ATTR)) - .getConfiguration(); - - String healthCheckUrl = null; - switch(baseComponent) { - case Constants.HC_COMPONENT_ON_BOARDING: - healthCheckUrl = buildOnboardingHealthCheckUrl(config); - break; - case Constants.HC_COMPONENT_DCAE: - healthCheckUrl = buildDcaeHealthCheckUrl(config); - break; - } - - String description; - - if (healthCheckUrl != null) { - ObjectMapper mapper = new ObjectMapper(); - CloseableHttpClient httpClient = getHttpClient(config); - HttpGet httpGet = new HttpGet(healthCheckUrl); - CloseableHttpResponse beResponse; - - try { - beResponse = httpClient.execute(httpGet); - int beStatus = beResponse.getStatusLine().getStatusCode(); - if (beStatus == HttpStatus.SC_OK || beStatus == HttpStatus.SC_INTERNAL_SERVER_ERROR) { - try { - String beJsonResponse = EntityUtils.toString(beResponse.getEntity()); - - Map healthCheckMap = mapper.readValue(beJsonResponse, new TypeReference>(){}); - if (healthCheckMap.containsKey("componentsInfo")) { - List componentsInfo = mapper.convertValue(healthCheckMap.get("componentsInfo"), new TypeReference>() {}); - return componentsInfo; - } else { - description = "Internal components are missing"; - } - } catch (JsonSyntaxException e) { - log.error("{} Unexpected response body ", baseComponent, e); - description = baseComponent + " Unexpected response body. Response code: " + beStatus; - } - } else { - description = "Response code: " + beStatus; - log.trace("{} Health Check Response code: {}", baseComponent, beStatus); - } - } catch (Exception e) { - log.error("{} Unexpected response ", baseComponent, e); - description = baseComponent + " Unexpected response: " + e.getMessage(); - } - } else { - description = baseComponent + " health check Configuration is missing"; - } - - return Arrays.asList(new HealthCheckInfo(Constants.HC_COMPONENT_FE, HealthCheckStatus.DOWN, null, description)); - } - - private HealthCheckWrapper getBeDownCheckInfos() { - List healthCheckInfos = new ArrayList(); - healthCheckInfos.add(new HealthCheckInfo(Constants.HC_COMPONENT_FE, HealthCheckStatus.UP, - ExternalConfiguration.getAppVersion(), "OK")); - healthCheckInfos.add(new HealthCheckInfo(Constants.HC_COMPONENT_BE, HealthCheckStatus.DOWN, null, null)); - healthCheckInfos.add(new HealthCheckInfo(Constants.HC_COMPONENT_TITAN, HealthCheckStatus.UNKNOWN, null, null)); - healthCheckInfos.add(new HealthCheckInfo(Constants.HC_COMPONENT_CASSANDRA, HealthCheckStatus.UNKNOWN, null, null)); - healthCheckInfos.add(new HealthCheckInfo(Constants.HC_COMPONENT_DISTRIBUTION_ENGINE, HealthCheckStatus.UNKNOWN, null, null)); - healthCheckInfos.add(new HealthCheckInfo(Constants.HC_COMPONENT_ON_BOARDING, HealthCheckStatus.UNKNOWN, null, null)); - healthCheckInfos.add(new HealthCheckInfo(Constants.HC_COMPONENT_DCAE, HealthCheckStatus.UNKNOWN, null, null)); - HealthCheckWrapper hcWrapper = new HealthCheckWrapper(healthCheckInfos, "UNKNOWN", "UNKNOWN"); - return hcWrapper; - } - - private CloseableHttpClient getHttpClient(Configuration config) { - int timeout = 3000; - int socketTimeout = config.getHealthCheckSocketTimeoutInMs(5000); - RequestConfig.Builder requestBuilder = RequestConfig.custom(); - requestBuilder.setConnectTimeout(timeout).setConnectionRequestTimeout(timeout).setSocketTimeout(socketTimeout); - - HttpClientBuilder builder = HttpClientBuilder.create(); - builder.setDefaultRequestConfig(requestBuilder.build()); - return builder.build(); - } - - private String buildOnboardingHealthCheckUrl(Configuration config) { - - Configuration.OnboardingConfig onboardingConfig = config.getOnboarding(); - - if (onboardingConfig != null) { - String protocol = onboardingConfig.getProtocol(); - String host = onboardingConfig.getHost(); - Integer port = onboardingConfig.getPort(); - String uri = onboardingConfig.getHealthCheckUri(); - - return protocol + "://" + host + ":" + port + uri; - } - - log.error("onboarding health check configuration is missing."); - return null; - } - - private String buildDcaeHealthCheckUrl(Configuration config) { - - Configuration.DcaeConfig dcaeConfig = config.getDcae(); - - if (dcaeConfig != null) { - String protocol = dcaeConfig.getProtocol(); - String host = dcaeConfig.getHost(); - Integer port = dcaeConfig.getPort(); - String uri = dcaeConfig.getHealthCheckUri(); - - return protocol + "://" + host + ":" + port + uri; - } - - log.error("dcae health check configuration is missing."); - return null; - } + private static final String URL = "%s://%s:%s/sdc2/rest/healthCheck"; + private static Logger healthLogger = getLogger("asdc.fe.healthcheck"); + private static Logger log = getLogger(HealthCheckService.class.getName()); + private final List healthCheckFeComponents = asList(HC_COMPONENT_ON_BOARDING, HC_COMPONENT_DCAE); + private static final HealthCheckUtil healthCheckUtil = new HealthCheckUtil(); + private static final String DEBUG_CONTEXT = "HEALTH_FE"; + /** + * This executor will execute the health check task. + */ + ScheduledExecutorService healthCheckExecutor = newSingleThreadScheduledExecutor((Runnable r) -> new Thread(r, "FE-Health-Check-Thread")); + + public void setTask(HealthCheckScheduledTask task) { + this.task = task; + } + + private HealthCheckScheduledTask task ; + private HealthStatus lastHealthStatus = new HealthStatus(500, "{}"); + private ServletContext context; + + public HealthCheckService(ServletContext context) { + this.context = context; + this.task = new HealthCheckScheduledTask(); + } + + public void start(int interval) { + this.healthCheckExecutor.scheduleAtFixedRate( getTask() , 0, interval, TimeUnit.SECONDS); + } + + /** + * To be used by the HealthCheckServlet + * + * @return + */ + public Response getFeHealth() { + return this.buildResponse(lastHealthStatus.statusCode, lastHealthStatus.body); + } + + private Response buildResponse(int status, String jsonResponse) { + healthLogger.trace("FE and BE health check status: {}", jsonResponse); + return Response.status(status).entity(jsonResponse).build(); + } + + public HealthStatus getLastHealthStatus() { + return lastHealthStatus; + } + public HealthCheckScheduledTask getTask() { + return task; + } + + //immutable + protected static class HealthStatus { + + private String body; + private int statusCode; + + public HealthStatus(int code, String body) { + this.body = body; + this.statusCode = code; + } + + public int getStatusCode() { + return statusCode; + } + + public String getBody() { + return body; + } + } + + protected class HealthCheckScheduledTask implements Runnable { + @Override + public void run() { + healthLogger.trace("Executing FE Health Check Task - Start"); + HealthStatus currentHealth = checkHealth(); + int currentHealthStatus = currentHealth.statusCode; + healthLogger.trace("Executing FE Health Check Task - Status = {}", currentHealthStatus); + + // In case health status was changed, issue alarm/recovery + if (currentHealthStatus != lastHealthStatus.statusCode) { + log.trace("FE Health State Changed to {}. Issuing alarm / recovery alarm...", currentHealthStatus); + logFeAlarm(currentHealthStatus); + } + + // Anyway, update latest response + lastHealthStatus = currentHealth; + } + + private List addHostedComponentsFeHealthCheck(String baseComponent) { + Configuration config = getConfig(); + + String healthCheckUrl = null; + switch (baseComponent) { + case HC_COMPONENT_ON_BOARDING: + healthCheckUrl = buildOnboardingHealthCheckUrl(config); + break; + case HC_COMPONENT_DCAE: + healthCheckUrl = buildDcaeHealthCheckUrl(config); + break; + default: + log.debug("Unsupported base component {}", baseComponent); + } + + StringBuilder description = new StringBuilder(""); + int connectTimeoutMs = 3000; + int readTimeoutMs = config.getHealthCheckSocketTimeoutInMs(5000); + + if (healthCheckUrl != null) { + ObjectMapper mapper = new ObjectMapper(); + try { + HttpResponse response = get(healthCheckUrl, new HttpClientConfig(new Timeouts(connectTimeoutMs, readTimeoutMs))); + int beStatus = response.getStatusCode(); + if (beStatus == SC_OK || beStatus == SC_INTERNAL_SERVER_ERROR) { + String beJsonResponse = response.getResponse(); + return convertResponse(beJsonResponse, mapper, baseComponent, description, beStatus); + } else { + description.append("Response code: " + beStatus); + log.trace("{} Health Check Response code: {}", baseComponent, beStatus); + } + } catch (Exception e) { + log.error("{} Unexpected response ", baseComponent, e); + description.append(baseComponent + " Unexpected response: " + e.getMessage()); + } + } else { + description.append(baseComponent + " health check Configuration is missing"); + } + + return asList(new HealthCheckInfo(HC_COMPONENT_FE, DOWN, null, description.toString())); + } + + private void logFeAlarm(int lastFeStatus) { + switch (lastFeStatus) { + case 200: + FeEcompErrorManager.getInstance().processEcompError(DEBUG_CONTEXT, EcompErrorEnum.FeHealthCheckRecovery, "FE Health Recovered"); + FeEcompErrorManager.getInstance().logFeHealthCheckRecovery("FE Health Recovered"); + break; + case 500: + FeEcompErrorManager.getInstance().processEcompError(DEBUG_CONTEXT, EcompErrorEnum.FeHealthCheckError, "Connection with ASDC-BE is probably down"); + FeEcompErrorManager.getInstance().logFeHealthCheckError("Connection with ASDC-BE is probably down"); + break; + default: + break; + } + } + + protected HealthStatus checkHealth() { + HttpResponse response; + try { + Gson gson = new GsonBuilder().setPrettyPrinting().create(); + Configuration config = getConfig(); + String redirectedUrl = String.format(URL, config.getBeProtocol(), config.getBeHost(), + HTTPS.equals(config.getBeProtocol()) ? config.getBeSslPort() : config.getBeHttpPort()); + + int connectTimeoutMs = 3000; + int readTimeoutMs = config.getHealthCheckSocketTimeoutInMs(5000); + + HealthCheckWrapper feAggHealthCheck; + try { + response = get(redirectedUrl, new HttpClientConfig(new Timeouts(connectTimeoutMs, readTimeoutMs))); + log.debug("HC call to BE - status code is {}", response.getStatusCode()); + String beJsonResponse = response.getResponse(); + feAggHealthCheck = getFeHealthCheckInfos(gson, beJsonResponse); + } catch (Exception e) { + log.debug("Health Check error when trying to connect to BE or external FE. Error: {}", e.getMessage()); + log.error("Health Check error when trying to connect to BE or external FE.", e); + String beDowneResponse = gson.toJson(getBeDownCheckInfos()); + return new HealthStatus(SC_INTERNAL_SERVER_ERROR, beDowneResponse); + } + + //Getting aggregate FE status + boolean aggregateFeStatus = (response != null && response.getStatusCode() == SC_INTERNAL_SERVER_ERROR) ? false : healthCheckUtil.getAggregateStatus(feAggHealthCheck.getComponentsInfo(), config.getHealthStatusExclude()); + return new HealthStatus(aggregateFeStatus ? SC_OK : SC_INTERNAL_SERVER_ERROR, gson.toJson(feAggHealthCheck)); + } catch (Exception e) { + FeEcompErrorManager.getInstance().processEcompError(DEBUG_CONTEXT,EcompErrorEnum.FeHealthCheckGeneralError, "Unexpected FE Health check error"); + FeEcompErrorManager.getInstance().logFeHealthCheckGeneralError("Unexpected FE Health check error"); + log.error("Unexpected FE health check error {}", e.getMessage()); + return new HealthStatus(SC_INTERNAL_SERVER_ERROR, e.getMessage()); + } + } + + protected Configuration getConfig(){ + return ((ConfigurationManager) context.getAttribute(CONFIGURATION_MANAGER_ATTR)) + .getConfiguration(); + } + + protected HealthCheckWrapper getFeHealthCheckInfos(Gson gson, String responseString) { + Configuration config = getConfig(); + Type wrapperType = new TypeToken() { + }.getType(); + HealthCheckWrapper healthCheckWrapper = gson.fromJson(responseString, wrapperType); + String appVersion = getAppVersion(); + String description = "OK"; + healthCheckWrapper.getComponentsInfo() + .add(new HealthCheckInfo(HC_COMPONENT_FE, UP, appVersion, description)); + + //add hosted components fe component + for (String component : healthCheckFeComponents) { + List feComponentsInfo = addHostedComponentsFeHealthCheck(component); + HealthCheckInfo baseComponentHCInfo = healthCheckWrapper.getComponentsInfo().stream().filter(c -> c.getHealthCheckComponent().equals(component)).findFirst().orElse(null); + if (baseComponentHCInfo != null) { + if (baseComponentHCInfo.getComponentsInfo() == null) { + baseComponentHCInfo.setComponentsInfo(new ArrayList<>()); + } + baseComponentHCInfo.getComponentsInfo().addAll(feComponentsInfo); + boolean status = healthCheckUtil.getAggregateStatus(baseComponentHCInfo.getComponentsInfo() ,config.getHealthStatusExclude()); + baseComponentHCInfo.setHealthCheckStatus(status ? UP : DOWN); + + String componentsDesc = healthCheckUtil.getAggregateDescription(baseComponentHCInfo.getComponentsInfo(), baseComponentHCInfo.getDescription()); + if (componentsDesc.length() > 0) { //aggregated description contains all the internal components desc + baseComponentHCInfo.setDescription(componentsDesc); + } + } else { + log.error("{} not exists in HealthCheck info", component); + } + } + return healthCheckWrapper; + } + + private HealthCheckWrapper getBeDownCheckInfos() { + List healthCheckInfos = new ArrayList<>(); + healthCheckInfos.add(new HealthCheckInfo(HC_COMPONENT_FE, UP, + getAppVersion(), "OK")); + healthCheckInfos.add(new HealthCheckInfo(HC_COMPONENT_BE, DOWN, null, null)); + healthCheckInfos.add(new HealthCheckInfo(HC_COMPONENT_TITAN, UNKNOWN, null, null)); + healthCheckInfos.add(new HealthCheckInfo(HC_COMPONENT_CASSANDRA, UNKNOWN, null, null)); + healthCheckInfos.add(new HealthCheckInfo(HC_COMPONENT_DISTRIBUTION_ENGINE, UNKNOWN, null, null)); + healthCheckInfos.add(new HealthCheckInfo(HC_COMPONENT_ON_BOARDING, UNKNOWN, null, null)); + healthCheckInfos.add(new HealthCheckInfo(HC_COMPONENT_DCAE, UNKNOWN, null, null)); + return new HealthCheckWrapper(healthCheckInfos, "UNKNOWN", "UNKNOWN"); + } + + private String buildOnboardingHealthCheckUrl(Configuration config) { + + Configuration.OnboardingConfig onboardingConfig = config.getOnboarding(); + + if (onboardingConfig != null) { + String protocol = onboardingConfig.getProtocol(); + String host = onboardingConfig.getHost(); + Integer port = onboardingConfig.getPort(); + String uri = onboardingConfig.getHealthCheckUri(); + + return protocol + "://" + host + ":" + port + uri; + } + + log.error("onboarding health check configuration is missing."); + return null; + } + + private String buildDcaeHealthCheckUrl(Configuration config) { + + Configuration.DcaeConfig dcaeConfig = config.getDcae(); + + if (dcaeConfig != null) { + String protocol = dcaeConfig.getProtocol(); + String host = dcaeConfig.getHost(); + Integer port = dcaeConfig.getPort(); + String uri = dcaeConfig.getHealthCheckUri(); + + return protocol + "://" + host + ":" + port + uri; + } + + log.error("dcae health check configuration is missing."); + return null; + } + + private List convertResponse(String beJsonResponse, ObjectMapper mapper, String baseComponent, StringBuilder description, int beStatus) { + try { + Map healthCheckMap = mapper.readValue(beJsonResponse, new TypeReference>() { + }); + if (healthCheckMap.containsKey("componentsInfo")) { + return mapper.convertValue(healthCheckMap.get("componentsInfo"), new TypeReference>() { + }); + } else { + description.append("Internal components are missing"); + } + } catch (JsonSyntaxException | IOException e) { + log.error("{} Unexpected response body ", baseComponent, e); + description.append(baseComponent + " Unexpected response body. Response code: " + beStatus); + } + return new ArrayList<>(); + } + } + } diff --git a/catalog-fe/src/main/java/org/openecomp/sdc/fe/servlets/PortalServlet.java b/catalog-fe/src/main/java/org/openecomp/sdc/fe/servlets/PortalServlet.java index 53fbd04a43..ad5d08e209 100644 --- a/catalog-fe/src/main/java/org/openecomp/sdc/fe/servlets/PortalServlet.java +++ b/catalog-fe/src/main/java/org/openecomp/sdc/fe/servlets/PortalServlet.java @@ -67,7 +67,6 @@ public class PortalServlet extends HttpServlet { try { addRequestHeadersUsingWebseal(request, response); } catch (Exception e) { - FeEcompErrorManager.getInstance().processEcompError(EcompErrorName.FePortalServletError, "Portal Servlet"); FeEcompErrorManager.getInstance().logFePortalServletError("Portal Servlet"); log.error("Error during getting portal page", e); } diff --git a/catalog-fe/src/main/resources/config/configuration.yaml b/catalog-fe/src/main/resources/config/configuration.yaml index 0636e701af..b2dc6da63d 100644 --- a/catalog-fe/src/main/resources/config/configuration.yaml +++ b/catalog-fe/src/main/resources/config/configuration.yaml @@ -88,3 +88,10 @@ systemMonitoring: kibanaHost: localhost kibanaPort: 5601 kibanaProtocol: http + +healthStatusExclude: + - DE + - ES + - DMAPP + + \ No newline at end of file diff --git a/catalog-fe/src/test/java/org/openecomp/sdc/fe/client/BackendClientTest.java b/catalog-fe/src/test/java/org/openecomp/sdc/fe/client/BackendClientTest.java deleted file mode 100644 index 943385bb7f..0000000000 --- a/catalog-fe/src/test/java/org/openecomp/sdc/fe/client/BackendClientTest.java +++ /dev/null @@ -1,26 +0,0 @@ -package org.openecomp.sdc.fe.client; - -import javax.net.ssl.HostnameVerifier; - -import org.junit.Test; - - -public class BackendClientTest { - - private BackendClient createTestSubject() { - return new BackendClient("", "", ""); - } - - - @Test - public void testGetHostnameVerifier() throws Exception { - BackendClient testSubject; - HostnameVerifier result; - - // default test - testSubject = createTestSubject(); - result = testSubject.getHostnameVerifier(); - } - - -} \ No newline at end of file diff --git a/catalog-fe/src/test/java/org/openecomp/sdc/fe/servlets/PortalServletTest.java b/catalog-fe/src/test/java/org/openecomp/sdc/fe/servlets/PortalServletTest.java deleted file mode 100644 index c400ba2da3..0000000000 --- a/catalog-fe/src/test/java/org/openecomp/sdc/fe/servlets/PortalServletTest.java +++ /dev/null @@ -1,29 +0,0 @@ -package org.openecomp.sdc.fe.servlets; - -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; - -import org.junit.Test; - - -public class PortalServletTest { - - private PortalServlet createTestSubject() { - return new PortalServlet(); - } - - - @Test - public void testDoGet() throws Exception { - PortalServlet testSubject; - HttpServletRequest request = null; - HttpServletResponse response = null; - - // default test - testSubject = createTestSubject(); - testSubject.doGet(request, response); - } - - - -} \ No newline at end of file diff --git a/catalog-fe/src/test/java/org/openecomp/sdc/servlets/PortalServletTest.java b/catalog-fe/src/test/java/org/openecomp/sdc/servlets/PortalServletTest.java index f2ff870a91..02f685302e 100644 --- a/catalog-fe/src/test/java/org/openecomp/sdc/servlets/PortalServletTest.java +++ b/catalog-fe/src/test/java/org/openecomp/sdc/servlets/PortalServletTest.java @@ -38,7 +38,7 @@ import javax.servlet.http.HttpServletResponse; import javax.servlet.http.HttpSession; import javax.ws.rs.core.Application; -import org.glassfish.hk2.utilities.binding.AbstractBinder; +import org.glassfish.jersey.internal.inject.AbstractBinder; import org.glassfish.jersey.server.ResourceConfig; import org.glassfish.jersey.test.JerseyTest; import org.junit.BeforeClass; -- cgit 1.2.3-korg