Merge "improvements to audit inventory feature"
[so.git] / mso-api-handlers / mso-api-handler-infra / src / main / java / org / onap / so / apihandlerinfra / ServiceInstances.java
index 676dca1..0b2b1e7 100644 (file)
@@ -5,6 +5,8 @@
  * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved.
  * Copyright (C) 2017 Huawei Technologies Co., Ltd. All rights reserved.
  * ================================================================================
+ * Modifications Copyright (c) 2019 Samsung
+ * ================================================================================
  * 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
@@ -44,6 +46,7 @@ import org.onap.so.apihandler.common.ResponseHandler;
 import org.onap.so.apihandlerinfra.exceptions.ApiException;
 import org.onap.so.apihandlerinfra.exceptions.BPMNFailureException;
 import org.onap.so.apihandlerinfra.exceptions.ClientConnectionException;
+import org.onap.so.apihandlerinfra.exceptions.ContactCamundaException;
 import org.onap.so.apihandlerinfra.exceptions.DuplicateRequestException;
 import org.onap.so.apihandlerinfra.exceptions.RecipeNotFoundException;
 import org.onap.so.apihandlerinfra.exceptions.RequestDbFailureException;
@@ -51,6 +54,7 @@ import org.onap.so.apihandlerinfra.exceptions.ValidateException;
 import org.onap.so.apihandlerinfra.exceptions.VfModuleNotFoundException;
 import org.onap.so.apihandlerinfra.logging.ErrorLoggerInfo;
 import org.onap.so.db.catalog.beans.NetworkResource;
+import org.onap.so.db.catalog.beans.NetworkResourceCustomization;
 import org.onap.so.db.catalog.beans.Recipe;
 import org.onap.so.db.catalog.beans.ServiceRecipe;
 import org.onap.so.db.catalog.beans.VfModule;
@@ -62,6 +66,7 @@ import org.onap.so.db.catalog.client.CatalogDbClient;
 import org.onap.so.db.request.beans.InfraActiveRequests;
 import org.onap.so.db.request.client.RequestsDbClient;
 import org.onap.so.exceptions.ValidationException;
+import org.onap.so.logger.LogConstants;
 import org.onap.so.logger.MessageEnum;
 import org.onap.so.logger.MsoLogger;
 import org.onap.so.serviceinstancebeans.CloudConfiguration;
@@ -78,10 +83,23 @@ import org.onap.so.serviceinstancebeans.ServiceInstancesRequest;
 import org.onap.so.serviceinstancebeans.ServiceInstancesResponse;
 import org.onap.so.serviceinstancebeans.VfModules;
 import org.onap.so.serviceinstancebeans.Vnfs;
+import org.onap.so.utils.CryptoUtils;
 import org.onap.so.utils.UUIDChecker;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.slf4j.MDC;
 import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.core.ParameterizedTypeReference;
 import org.springframework.core.env.Environment;
+import org.springframework.http.HttpEntity;
+import org.springframework.http.HttpHeaders;
+import org.springframework.http.HttpMethod;
+import org.springframework.http.ResponseEntity;
 import org.springframework.stereotype.Component;
+import org.springframework.web.client.HttpStatusCodeException;
+import org.springframework.web.client.RestTemplate;
+import org.camunda.bpm.engine.history.HistoricProcessInstance;
+import org.camunda.bpm.engine.impl.persistence.entity.HistoricProcessInstanceEntity;
 
 import javax.transaction.Transactional;
 import javax.ws.rs.Consumes;
@@ -96,8 +114,10 @@ import javax.ws.rs.core.Context;
 import javax.ws.rs.core.MediaType;
 import javax.ws.rs.core.MultivaluedMap;
 import javax.ws.rs.core.Response;
+import javax.xml.bind.DatatypeConverter;
 import java.io.IOException;
 import java.net.URL;
+import java.security.GeneralSecurityException;
 import java.sql.Timestamp;
 import java.util.ArrayList;
 import java.util.HashMap;
@@ -110,7 +130,7 @@ import java.util.Optional;
 @Api(value="/onap/so/infra/serviceInstantiation",description="Infrastructure API Requests for Service Instances")
 public class ServiceInstances {
 
-       private static MsoLogger msoLogger = MsoLogger.getMsoLogger (MsoLogger.Catalog.APIH,MsoRequest.class);
+       private static Logger logger = LoggerFactory.getLogger(MsoRequest.class);
        private static String NAME = "name";
        private static String VALUE = "value";
        private static final String SAVE_TO_DB = "save instance to db";
@@ -133,6 +153,9 @@ public class ServiceInstances {
        @Autowired
        private MsoRequest msoRequest;
        
+       @Autowired
+       private RestTemplate restTemplate;
+       
        @POST
     @Path("/{version:[vV][5-7]}/serviceInstances")
        @Consumes(MediaType.APPLICATION_JSON)
@@ -666,6 +689,8 @@ public class ServiceInstances {
 
        public String getRequestUri(ContainerRequestContext context){
                String requestUri = context.getUriInfo().getPath();
+               String httpUrl = MDC.get(LogConstants.URI_BASE).concat(requestUri);
+               MDC.put(LogConstants.HTTP_URL, httpUrl);
                requestUri = requestUri.substring(requestUri.indexOf("/serviceInstantiation/") + 22);
                return requestUri;
        }
@@ -714,11 +739,15 @@ public class ServiceInstances {
                }
                
                InfraActiveRequests dup = null;
-                               
+               boolean inProgress = false;             
 
                dup = duplicateCheck(action, instanceIdMap, startTime, msoRequest, instanceName,requestScope, currentActiveReq);
 
-               if (dup != null) {
+               if(dup != null){
+                       inProgress = camundaHistoryCheck(dup, currentActiveReq);
+               }
+               
+               if (dup != null && inProgress) {
             buildErrorOnDuplicateRecord(currentActiveReq, action, instanceIdMap, startTime, msoRequest, instanceName, requestScope, dup);
                }
                ServiceInstancesResponse serviceResponse = new ServiceInstancesResponse();
@@ -784,7 +813,7 @@ public class ServiceInstances {
                String vfModuleId = "";
                String volumeGroupId = "";
                String networkId = "";
-               String correlationId = "";
+               String pnfCorrelationId = "";
                String instanceGroupId = null;
                if(sir.getServiceInstanceId () != null){
                        serviceInstanceId = sir.getServiceInstanceId ();
@@ -809,7 +838,7 @@ public class ServiceInstances {
                        instanceGroupId = sir.getInstanceGroupId();
                }
 
-        correlationId = getCorrelationId(sir);
+        pnfCorrelationId = getPnfCorrelationId(sir);
 
         try{
             infraActiveRequestsClient.save(currentActiveReq);
@@ -833,7 +862,7 @@ public class ServiceInstances {
                                                .setRecipeTimeout(recipeLookupResult.getRecipeTimeout())
                                                .setRequestAction(action.toString())
                                                .setServiceInstanceId(serviceInstanceId)
-                                               .setCorrelationId(correlationId)
+                                               .setPnfCorrelationId(pnfCorrelationId)
                                                .setVnfId(vnfId)
                                                .setVfModuleId(vfModuleId)
                                                .setVolumeGroupId(volumeGroupId)
@@ -868,7 +897,7 @@ public class ServiceInstances {
                try {
                        validateHeaders(requestContext);
                } catch (ValidationException e) {
-                       msoLogger.error(e);
+                       logger.error("Exception occurred", e);
             ErrorLoggerInfo errorLoggerInfo = new ErrorLoggerInfo.Builder(MessageEnum.APIH_VALIDATION_ERROR, MsoLogger.ErrorCode.SchemaError).errorSource(Constants.MSO_PROP_APIHANDLER_INFRA).build();
             ValidateException validateException = new ValidateException.Builder(e.getMessage(), HttpStatus.SC_BAD_REQUEST, ErrorNumbers.SVC_BAD_PARAMETER).cause(e)
                         .errorInfo(errorLoggerInfo).build();
@@ -877,8 +906,13 @@ public class ServiceInstances {
                }
                
                InfraActiveRequests dup = duplicateCheck(action, instanceIdMap, startTime, msoRequest, null, requestScope, currentActiveReq);
-
-               if (dup != null) {
+               boolean inProgress = false;
+               
+               if(dup != null){
+                       inProgress = camundaHistoryCheck(dup, currentActiveReq);
+               }
+               
+               if (dup != null && inProgress) {
             buildErrorOnDuplicateRecord(currentActiveReq, action, instanceIdMap, startTime, msoRequest, null, requestScope, dup);
                }
                
@@ -914,7 +948,7 @@ public class ServiceInstances {
                return postBPELRequest(currentActiveReq, requestClientParameter, recipeLookupResult.getOrchestrationURI(), requestScope);
        }
 
-       private String getCorrelationId(ServiceInstancesRequest sir) {
+       private String getPnfCorrelationId(ServiceInstancesRequest sir) {
                return Optional.of(sir)
                                .map(ServiceInstancesRequest::getRequestDetails)
                                .map(RequestDetails::getRequestParameters)
@@ -986,7 +1020,7 @@ public class ServiceInstances {
             respHandler = new ResponseHandler (response, requestClient.getType ());
             bpelStatus = respHandler.getStatus ();
         } catch (ApiException e) {
-            msoLogger.error(e);
+            logger.error("Exception occurred", e);
             ErrorLoggerInfo errorLoggerInfo = new ErrorLoggerInfo.Builder(MessageEnum.APIH_BPEL_RESPONSE_ERROR, MsoLogger.ErrorCode.SchemaError).errorSource(Constants.MSO_PROP_APIHANDLER_INFRA).build();
             ValidateException validateException = new ValidateException.Builder("Exception caught mapping Camunda JSON response to object", HttpStatus.SC_INTERNAL_SERVER_ERROR, ErrorNumbers.SVC_BAD_PARAMETER).cause(e)
                         .errorInfo(errorLoggerInfo).build();
@@ -1011,7 +1045,7 @@ public class ServiceInstances {
                                            jsonResponse.getRequestReferences().setRequestSelfLink(null);
                                        }    
                                } catch (IOException e) {
-                                       msoLogger.error(e);
+                                       logger.error("Exception occurred", e);
                                        ErrorLoggerInfo errorLoggerInfo = new ErrorLoggerInfo.Builder(MessageEnum.APIH_BPEL_RESPONSE_ERROR, MsoLogger.ErrorCode.SchemaError).errorSource(Constants.MSO_PROP_APIHANDLER_INFRA).build();
                                        ValidateException validateException = new ValidateException.Builder("Exception caught mapping Camunda JSON response to object", HttpStatus.SC_NOT_ACCEPTABLE, ErrorNumbers.SVC_BAD_PARAMETER).cause(e)
                                            .errorInfo(errorLoggerInfo).build();
@@ -1100,7 +1134,7 @@ public class ServiceInstances {
                        sir.getRequestDetails().setCloudConfiguration(serviceInstRequest.getRequestDetails().getCloudConfiguration());
                        sir.getRequestDetails().getRequestParameters().setUserParams(serviceInstRequest.getRequestDetails().getRequestParameters().getUserParams());
                }
-               msoLogger.debug("Value as string: " + mapper.writeValueAsString(sir));
+               logger.debug("Value as string: {}", mapper.writeValueAsString(sir));
                return mapper.writeValueAsString(sir);
        }
        return null;
@@ -1145,6 +1179,49 @@ public class ServiceInstances {
                }
                return dup;
        }
+    protected boolean camundaHistoryCheck(InfraActiveRequests duplicateRecord, InfraActiveRequests currentActiveReq) throws RequestDbFailureException, ContactCamundaException{
+       String requestId = duplicateRecord.getRequestId();
+       String path = env.getProperty("mso.camunda.rest.history.uri") + requestId;
+       String targetUrl = env.getProperty("mso.camundaURL") + path;
+       HttpHeaders headers = setCamundaHeaders(env.getRequiredProperty("mso.camundaAuth"), env.getRequiredProperty("mso.msoKey")); 
+       HttpEntity<?> requestEntity = new HttpEntity<>(headers);
+       ResponseEntity<List<HistoricProcessInstanceEntity>> response = null;
+       try{
+               response = restTemplate.exchange(targetUrl, HttpMethod.GET, requestEntity, new ParameterizedTypeReference<List<HistoricProcessInstanceEntity>>(){});
+       }catch(HttpStatusCodeException e){
+               ErrorLoggerInfo errorLoggerInfo = new ErrorLoggerInfo.Builder(MessageEnum.APIH_DUPLICATE_CHECK_EXC, MsoLogger.ErrorCode.DataError).errorSource(Constants.MSO_PROP_APIHANDLER_INFRA).build();
+            ContactCamundaException contactCamundaException= new ContactCamundaException.Builder(requestId, e.toString(), HttpStatus.SC_INTERNAL_SERVER_ERROR, ErrorNumbers.SVC_DETAILED_SERVICE_ERROR).cause(e)
+                    .errorInfo(errorLoggerInfo).build();
+            updateStatus(currentActiveReq, Status.FAILED, contactCamundaException.getMessage());
+            throw contactCamundaException;
+               }
+       if(response.getBody().isEmpty()){
+               updateStatus(duplicateRecord, Status.COMPLETE, "Request Completed");
+       }
+               for(HistoricProcessInstance instance : response.getBody()){
+                       if(instance.getState().equals("ACTIVE")){
+                               return true;
+                       }else{
+                               updateStatus(duplicateRecord, Status.COMPLETE, "Request Completed");
+                       }
+       }       
+               return false;
+       }
+    protected HttpHeaders setCamundaHeaders(String auth, String msoKey) {
+               HttpHeaders headers = new HttpHeaders();
+               List<org.springframework.http.MediaType> acceptableMediaTypes = new ArrayList<>();
+               acceptableMediaTypes.add(org.springframework.http.MediaType.APPLICATION_JSON);
+               headers.setAccept(acceptableMediaTypes);
+               try {
+                       String userCredentials = CryptoUtils.decrypt(auth, msoKey);
+                       if(userCredentials != null) {
+                               headers.add(HttpHeaders.AUTHORIZATION, "Basic " + DatatypeConverter.printBase64Binary(userCredentials.getBytes()));
+                       }
+        } catch(GeneralSecurityException e) {
+                logger.error("Security exception", e);
+        }
+               return headers;
+       }
 
        private ServiceInstancesRequest convertJsonToServiceInstanceRequest(String requestJSON, Actions action, long startTime,
                                                                         ServiceInstancesRequest sir, MsoRequest msoRequest, String requestId, String requestUri) throws ApiException {
@@ -1172,6 +1249,7 @@ public class ServiceInstances {
                try {
                        msoRequest.parse(sir, instanceIdMap, action, version, requestJSON, reqVersion, aLaCarte);
                } catch (Exception e) {
+                       logger.error("failed to parse request", e);
                        ErrorLoggerInfo errorLoggerInfo = new ErrorLoggerInfo.Builder(MessageEnum.APIH_REQUEST_VALIDATION_ERROR, MsoLogger.ErrorCode.SchemaError).errorSource(Constants.MSO_PROP_APIHANDLER_INFRA).build();
                ValidateException validateException = new ValidateException.Builder("Error parsing request: " + e.getMessage(), HttpStatus.SC_BAD_REQUEST, ErrorNumbers.SVC_BAD_PARAMETER).cause(e)
                  .errorInfo(errorLoggerInfo).build();
@@ -1380,7 +1458,7 @@ public class ServiceInstances {
        }
 
        protected List<Map<String, Object>> configureUserParams(RequestParameters reqParams) throws IOException {
-       msoLogger.debug("Configuring UserParams for Macro Request");
+       logger.debug("Configuring UserParams for Macro Request");
        Map<String, Object> userParams = new HashMap<>();
        
        for(Map<String, Object> params : reqParams.getUserParams()){
@@ -1668,7 +1746,9 @@ public class ServiceInstances {
                Recipe recipe = null;
 
                if(modelInfo.getModelCustomizationId()!=null){
-            NetworkResource networkResource = catalogDbClient.getNetworkResourceCustomizationByModelCustomizationUUID(modelInfo.getModelCustomizationId()).getNetworkResource();
+            NetworkResourceCustomization networkResourceCustomization = catalogDbClient.getNetworkResourceCustomizationByModelCustomizationUUID(modelInfo.getModelCustomizationId());
+                       if(networkResourceCustomization != null){
+                               NetworkResource networkResource = networkResourceCustomization.getNetworkResource();
                        if(networkResource!=null){
                                if(modelInfo.getModelVersionId() == null) {
                                        modelInfo.setModelVersionId(networkResource.getModelUUID());
@@ -1677,6 +1757,9 @@ public class ServiceInstances {
                        }else{
                                throw new ValidationException("no catalog entry found");
                        }
+                       }else if(action != Action.deleteInstance){
+                               throw new ValidationException("modelCustomizationId for networkResourceCustomization lookup", true);
+                       }
                }else{
                        //ok for version < 3 and action delete
                        if(modelName != null){
@@ -1711,7 +1794,7 @@ public class ServiceInstances {
                        testApi = TestApi.valueOf(requestTestApi);
                        return Optional.of(testApi.getModelName());
                } catch (Exception e) {
-                       msoLogger.warnSimple("Catching the exception on the valueOf enum call and continuing", e);
+                       logger.warn("Catching the exception on the valueOf enum call and continuing", e);
                        throw new IllegalArgumentException("Invalid TestApi is provided", e);
                }
     }
@@ -1729,6 +1812,7 @@ public class ServiceInstances {
                String serviceInstanceId = (instanceIdMap ==null)? null:instanceIdMap.get("serviceInstanceId");
                Boolean aLaCarte = null;
                String apiVersion = version.substring(1);
+               boolean inProgress = false;
                
                long startTime = System.currentTimeMillis ();
                ServiceInstancesRequest sir = null;             
@@ -1746,8 +1830,12 @@ public class ServiceInstances {
                InfraActiveRequests dup = null;
                
                dup = duplicateCheck(action, instanceIdMap, startTime, msoRequest, instanceName,requestScope, currentActiveReq);
+               
+               if(dup != null){
+                       inProgress = camundaHistoryCheck(dup, currentActiveReq);
+               }
 
-               if (instanceIdMap != null && dup != null) {
+               if (instanceIdMap != null && dup != null && inProgress) {
             buildErrorOnDuplicateRecord(currentActiveReq, action, instanceIdMap, startTime, msoRequest, instanceName, requestScope, dup);
                }
                
@@ -1777,7 +1865,7 @@ public class ServiceInstances {
                
                serviceInstanceId = "";
                String configurationId = "";
-               String correlationId = "";
+               String pnfCorrelationId = "";
 
                if(sir.getServiceInstanceId () != null){
                        serviceInstanceId = sir.getServiceInstanceId ();
@@ -1787,7 +1875,7 @@ public class ServiceInstances {
             configurationId = sir.getConfigurationId();
         }
 
-        correlationId = getCorrelationId(sir);
+        pnfCorrelationId = getPnfCorrelationId(sir);
 
                try{
                        infraActiveRequestsClient.save(currentActiveReq);
@@ -1810,7 +1898,7 @@ public class ServiceInstances {
                                .setRecipeTimeout(Integer.parseInt(timeOut))
                                .setRequestAction(action.toString())
                                .setServiceInstanceId(serviceInstanceId)
-                               .setCorrelationId(correlationId)
+                               .setPnfCorrelationId(pnfCorrelationId)
                                .setConfigurationId(configurationId)
                                .setRequestDetails(mapJSONtoMSOStyle(requestJSON, sir, aLaCarte, action))
                                .setApiVersion(apiVersion)
@@ -1825,7 +1913,7 @@ public class ServiceInstances {
                        return postBPELRequest(currentActiveReq, requestClientParameter, orchestrationUri, requestScope);
        }
 
-    public String getRequestId(ContainerRequestContext requestContext) throws ValidateException {
+       public String getRequestId(ContainerRequestContext requestContext) throws ValidateException {
        String requestId = null;
        if (requestContext.getProperty("requestId") != null) {
                requestId = requestContext.getProperty("requestId").toString();