From 9b2ceb347a3371819fcad6bbe2268203afecaf4e Mon Sep 17 00:00:00 2001 From: "Stone, Avi (as206k)" Date: Thu, 12 Apr 2018 16:36:39 +0300 Subject: DCAE-D fe initial commit DCAE-D fe initial commit Change-Id: Ica8ccb7c7ef769c969664d1e168d205eb9fc67f2 Issue-ID: SDC-1218 Signed-off-by: Stone, Avi (as206k) --- src/main/java/org/onap/sdc/dcae/FeApp.java | 73 ++++++++++ .../dcae/controller/health/HealthController.java | 72 ++++++++++ .../onap/sdc/dcae/controller/proxy/DcaeProxy.java | 152 +++++++++++++++++++++ 3 files changed, 297 insertions(+) create mode 100644 src/main/java/org/onap/sdc/dcae/FeApp.java create mode 100644 src/main/java/org/onap/sdc/dcae/controller/health/HealthController.java create mode 100644 src/main/java/org/onap/sdc/dcae/controller/proxy/DcaeProxy.java (limited to 'src/main/java/org/onap') diff --git a/src/main/java/org/onap/sdc/dcae/FeApp.java b/src/main/java/org/onap/sdc/dcae/FeApp.java new file mode 100644 index 0000000..01d757c --- /dev/null +++ b/src/main/java/org/onap/sdc/dcae/FeApp.java @@ -0,0 +1,73 @@ +package org.onap.sdc.dcae; + +import org.onap.sdc.dcae.controller.proxy.DcaeProxy; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.boot.CommandLineRunner; +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.EnableAutoConfiguration; +import org.springframework.boot.web.servlet.ServletRegistrationBean; +import org.springframework.boot.web.support.SpringBootServletInitializer; +import org.springframework.context.annotation.*; + +import javax.servlet.ServletContext; +import java.io.IOException; +import java.io.InputStream; +import java.util.jar.Attributes; +import java.util.jar.Manifest; + + +@Configuration +@ComponentScan() +@EnableAutoConfiguration +@PropertySource("file:${jetty.base}/config/dcae-fe/application.properties") +public class FeApp extends SpringBootServletInitializer implements CommandLineRunner{ + + private static final String SPECIFICATION_VERSION = "Specification-Version"; + @Autowired + ServletContext servletContext; + + private static final String MANIFEST_FILE_NAME = "/META-INF/MANIFEST.MF"; + private static String dcaeVersion; + + @Value("${beUrl}") + private String beUrl; + + public static void main(String[] args) { + SpringApplication.run(FeApp.class, args); + } + + public void run(String... arg0) throws Exception { + InputStream inputStream = servletContext.getResourceAsStream(MANIFEST_FILE_NAME); + + System.out.println("Server is starting..reading DCAE version..."); + + String version = null; + try { + Manifest mf = new Manifest(inputStream); + Attributes atts = mf.getMainAttributes(); + version = atts.getValue(SPECIFICATION_VERSION); + if (version == null || version.isEmpty()) { + System.err.println("failed to read DCAE version from MANIFEST."); + } else { + System.out.println("DCAE version from MANIFEST is "+ version); + dcaeVersion = version; + } + + } catch (IOException e) { + System.err.println("failed to read DCAE version from MANIFEST: "+ e.getMessage()); + } + } + + public static String getDcaeVersion() { + return dcaeVersion; + } + + + @Bean + public ServletRegistrationBean dcaeProxyBean() { + ServletRegistrationBean bean = new ServletRegistrationBean(new DcaeProxy(beUrl), "/dcaeProxy/*"); + bean.setLoadOnStartup(1); + return bean; + } +} diff --git a/src/main/java/org/onap/sdc/dcae/controller/health/HealthController.java b/src/main/java/org/onap/sdc/dcae/controller/health/HealthController.java new file mode 100644 index 0000000..1ddec2d --- /dev/null +++ b/src/main/java/org/onap/sdc/dcae/controller/health/HealthController.java @@ -0,0 +1,72 @@ +package org.onap.sdc.dcae.controller.health; + +import java.util.ArrayList; +import java.util.List; + +import org.onap.sdc.dcae.FeApp; +import org.onap.sdc.dcae.composition.restmodels.health.ComponentsInfo; +import org.onap.sdc.dcae.composition.restmodels.health.HealthResponse; +import org.onap.sdc.dcae.composition.util.DcaeFeConstants; +import org.springframework.boot.autoconfigure.EnableAutoConfiguration; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.CrossOrigin; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestMethod; +import org.springframework.web.bind.annotation.RestController; + +import com.google.gson.Gson; + + +/** + * + * @author lezer + * Example: + * { + "healthCheckComponent": "DCAE Designer", + "healthCheckStatus": "UP", + "description": "OK", + "componentsInfo": [{ + "healthCheckComponent": "FE", + "healthCheckStatus": "UP", + "description": "OK" + }] +} + * + */ +@RestController +@EnableAutoConfiguration +@CrossOrigin +public class HealthController { + Gson gson = new Gson(); + + @RequestMapping(value = "/healthCheck", method = RequestMethod.GET) + public ResponseEntity healthCheck() { + try{ + HealthResponse healthResponse = new HealthResponse(); + healthResponse.setHealthCheckComponent(DcaeFeConstants.Health.APP_NAME); + healthResponse.setHealthCheckStatus(DcaeFeConstants.Health.UP); + healthResponse.setSdcVersion(FeApp.getDcaeVersion()); + healthResponse.setDescription(DcaeFeConstants.Health.OK); + + List componentsInfoList = new ArrayList(); + ComponentsInfo componentsInfo = new ComponentsInfo(); + componentsInfo.setHealthCheckComponent(DcaeFeConstants.Health.FE); + componentsInfo.setHealthCheckStatus(DcaeFeConstants.Health.UP); + componentsInfo.setVersion(FeApp.getDcaeVersion()); + componentsInfo.setDescription(DcaeFeConstants.Health.OK); + componentsInfoList.add(componentsInfo); + + healthResponse.setComponentsInfo(componentsInfoList); + String json = gson.toJson(healthResponse, HealthResponse.class); + System.out.println("Health Check response: "+json); + + return new ResponseEntity(json, HttpStatus.OK); + } + catch(Exception e){ + System.err.println("Error occured while performing HealthCheck: "+e.getLocalizedMessage()); + return new ResponseEntity(e.getMessage(), HttpStatus.INTERNAL_SERVER_ERROR); + } + } + +} diff --git a/src/main/java/org/onap/sdc/dcae/controller/proxy/DcaeProxy.java b/src/main/java/org/onap/sdc/dcae/controller/proxy/DcaeProxy.java new file mode 100644 index 0000000..94279f2 --- /dev/null +++ b/src/main/java/org/onap/sdc/dcae/controller/proxy/DcaeProxy.java @@ -0,0 +1,152 @@ +package org.onap.sdc.dcae.controller.proxy; + +import com.google.common.cache.Cache; +import com.google.common.cache.CacheBuilder; +import org.eclipse.jetty.client.HttpClient; +import org.eclipse.jetty.client.api.Response; +import org.eclipse.jetty.proxy.ProxyServlet; +import org.eclipse.jetty.util.ssl.SslContextFactory; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.slf4j.MDC; +import org.springframework.util.StringUtils; + +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import java.util.concurrent.TimeUnit; + + +public class DcaeProxy extends ProxyServlet { + + private static Logger log = LoggerFactory.getLogger(DcaeProxy.class); + private static Cache mdcDataCache = CacheBuilder.newBuilder().expireAfterWrite(10, TimeUnit.SECONDS).build(); + + + //TODO proper configuration class + private String beHostUrl; + + public DcaeProxy(String beHostUrl){ + this.beHostUrl = beHostUrl; + } + + @Override + protected HttpClient newHttpClient() { + SslContextFactory factory = new SslContextFactory(true); + return new HttpClient(factory); + } + + @Override + protected String rewriteTarget(HttpServletRequest request) { + try{ + logRequest(request); + }catch (Exception e){ + log.error("Unexpected FE request logging error :", e); + } + String uri = request.getRequestURI(); + uri = uri.replace("/dcaeProxy", ""); + String query = request.getQueryString(); + StringBuilder url = new StringBuilder(); + url.append(beHostUrl).append(uri); + if(null != query) + url.append("?").append(query); + String urlString = url.toString(); + log.info("Proxy outgoing request={}", urlString); + return urlString; + } + + @Override + protected void onProxyResponseSuccess(HttpServletRequest clientRequest, HttpServletResponse proxyResponse, Response serverResponse) { + try{ + logResponse(clientRequest, serverResponse); + }catch (Exception e){ + log.error("Unexpected FE response logging error :", e); + } + super.onProxyResponseSuccess(clientRequest, proxyResponse, serverResponse); + } + + + private void logRequest(HttpServletRequest httpRequest) { + MDC.clear(); + Long transactionStartTime = System.currentTimeMillis(); + String requestId = httpRequest.getHeader("X-ECOMP-RequestID"); + String serviceInstanceID = httpRequest.getHeader("X-ECOMP-ServiceID"); + if (!StringUtils.isEmpty(requestId)) { + String userId = httpRequest.getHeader("USER_ID"); + String remoteAddr = httpRequest.getRemoteAddr(); + String localAddr = httpRequest.getLocalAddr(); + mdcDataCache.put(requestId, new MdcData(serviceInstanceID, userId, remoteAddr, localAddr, transactionStartTime)); + updateMdc(requestId, serviceInstanceID, userId, remoteAddr, localAddr, null); + } + inHttpRequest(httpRequest); + } + + private void logResponse(HttpServletRequest request, Response proxyResponse) { + String requestId = request.getHeader("X-ECOMP-RequestID"); + if (requestId != null) { + MdcData mdcData = mdcDataCache.getIfPresent(requestId); + if (mdcData != null) { + Long transactionStartTime = mdcData.getTransactionStartTime(); + String transactionRoundTime = Long.toString(System.currentTimeMillis() - transactionStartTime); + updateMdc(requestId, mdcData.getServiceInstanceID(), mdcData.getUserId(), mdcData.getRemoteAddr(), mdcData.getLocalAddr(), transactionRoundTime); + } + } + outHttpResponse(proxyResponse); + MDC.clear(); + } + + private class MdcData { + private String serviceInstanceID; + private String userId; + private String remoteAddr; + private String localAddr; + private Long transactionStartTime; + + MdcData(String serviceInstanceID, String userId, String remoteAddr, String localAddr, Long transactionStartTime) { + this.serviceInstanceID = serviceInstanceID; + this.userId = userId; + this.remoteAddr = remoteAddr; + this.localAddr = localAddr; + this.transactionStartTime = transactionStartTime; + } + + Long getTransactionStartTime() { + return transactionStartTime; + } + + public String getUserId() { + return userId; + } + + String getRemoteAddr() { + return remoteAddr; + } + + String getLocalAddr() { + return localAddr; + } + + String getServiceInstanceID() { + return serviceInstanceID; + } + } + + private void updateMdc(String uuid, String serviceInstanceID, String userId, String remoteAddr, String localAddr, String transactionStartTime) { + MDC.put("uuid", uuid); + MDC.put("serviceInstanceID", serviceInstanceID); + MDC.put("userId", userId); + MDC.put("remoteAddr", remoteAddr); + MDC.put("localAddr", localAddr); + MDC.put("timer", transactionStartTime); + } + + // Extracted for purpose of clear method name, for logback %M parameter + private void inHttpRequest(HttpServletRequest httpRequest) { + log.info("{} {} {}", httpRequest.getMethod(), httpRequest.getRequestURI(), httpRequest.getProtocol()); + } + + // Extracted for purpose of clear method name, for logback %M parameter + private void outHttpResponse(Response proxyResponse) { + log.info("SC=\"{}\"", proxyResponse.getStatus()); + } + +} -- cgit 1.2.3-korg