Merge "flow validators can be skipped via an annotation"
[so.git] / mso-api-handlers / mso-api-handler-infra / src / main / java / org / onap / so / apihandlerinfra / ServiceInstances.java
index 79d2a86..1f9f5f5 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;
        }
@@ -692,7 +717,7 @@ public class ServiceInstances {
                
                sir = convertJsonToServiceInstanceRequest(requestJSON, action, startTime, sir, msoRequest, requestId, requestUri);
                String requestScope = deriveRequestScope(action, sir, requestUri);
-               InfraActiveRequests currentActiveReq =  msoRequest.createRequestObject (sir,  action, requestId, Status.PENDING, requestJSON, requestScope);
+               InfraActiveRequests currentActiveReq =  msoRequest.createRequestObject (sir,  action, requestId, Status.IN_PROGRESS, requestJSON, requestScope);
                if(sir.getRequestDetails().getRequestParameters() != null){
                        aLaCarte = sir.getRequestDetails().getRequestParameters().getALaCarte();
                }
@@ -705,7 +730,6 @@ public class ServiceInstances {
                String vnfType = msoRequest.getVnfType(sir,requestScope,action,requestVersion);
                String networkType = msoRequest.getNetworkType(sir,requestScope);
                String sdcServiceModelVersion = msoRequest.getSDCServiceModelVersion(sir);
-               String serviceInstanceType = msoRequest.getServiceInstanceType(sir,requestScope);
                String vfModuleType = msoRequest.getVfModuleType(sir,requestScope,action,requestVersion);
                
                if(requestScope.equalsIgnoreCase(ModelType.vnf.name()) && vnfType != null){
@@ -715,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();
@@ -732,7 +760,7 @@ public class ServiceInstances {
                Boolean isBaseVfModule = false;
 
         RecipeLookupResult recipeLookupResult = getServiceInstanceOrchestrationURI(sir, action, alaCarteFlag, currentActiveReq);
-                                                               
+        String serviceInstanceType = getServiceType(requestScope, sir, alaCarteFlag);                                          
                        ModelType modelType;
                        ModelInfo modelInfo =  sir.getRequestDetails().getModelInfo();
                        if (action == Action.applyUpdatedConfig || action == Action.inPlaceSoftwareUpdate) {
@@ -785,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 ();
@@ -810,7 +838,7 @@ public class ServiceInstances {
                        instanceGroupId = sir.getInstanceGroupId();
                }
 
-        correlationId = getCorrelationId(sir);
+        pnfCorrelationId = getPnfCorrelationId(sir);
 
         try{
             infraActiveRequestsClient.save(currentActiveReq);
@@ -834,7 +862,7 @@ public class ServiceInstances {
                                                .setRecipeTimeout(recipeLookupResult.getRecipeTimeout())
                                                .setRequestAction(action.toString())
                                                .setServiceInstanceId(serviceInstanceId)
-                                               .setCorrelationId(correlationId)
+                                               .setPnfCorrelationId(pnfCorrelationId)
                                                .setVnfId(vnfId)
                                                .setVfModuleId(vfModuleId)
                                                .setVolumeGroupId(volumeGroupId)
@@ -864,12 +892,12 @@ public class ServiceInstances {
                sir.setInstanceGroupId(instanceGroupId);
        
                String requestScope = ModelType.instanceGroup.toString();
-               InfraActiveRequests currentActiveReq =  msoRequest.createRequestObject (sir,  action, requestId, Status.PENDING, null, requestScope);
+               InfraActiveRequests currentActiveReq =  msoRequest.createRequestObject (sir,  action, requestId, Status.IN_PROGRESS, null, requestScope);
                setInstanceId(currentActiveReq, requestScope, null, instanceIdMap);
                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();
@@ -878,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);
                }
                
@@ -915,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)
@@ -987,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();
@@ -1012,25 +1045,13 @@ 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();
                                        updateStatus(currentActiveReq, Status.FAILED, validateException.getMessage());
                                        throw validateException;
-                               }
-                       
-                               currentActiveReq.setRequestStatus(Status.IN_PROGRESS.name());
-                               setInstanceId(currentActiveReq, requestScope, jsonResponse.getRequestReferences().getInstanceId(), new HashMap<>());
-                               
-                               try{
-                                       infraActiveRequestsClient.save(currentActiveReq);
-                               }catch(Exception e){
-                                       ErrorLoggerInfo errorLoggerInfo = new ErrorLoggerInfo.Builder(MessageEnum.APIH_DB_ACCESS_EXC, MsoLogger.ErrorCode.DataError).errorSource(Constants.MSO_PROP_APIHANDLER_INFRA).build();
-                           throw new RequestDbFailureException.Builder(SAVE_TO_DB, e.toString(), HttpStatus.SC_INTERNAL_SERVER_ERROR, ErrorNumbers.SVC_DETAILED_SERVICE_ERROR).cause(e)
-                                   .errorInfo(errorLoggerInfo).build();
-                               }
-                               
+                               }       
                                return builder.buildResponse(HttpStatus.SC_ACCEPTED, requestClientParameter.getRequestId(), jsonResponse, requestClientParameter.getApiVersion());
                        } 
                }
@@ -1113,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;
@@ -1158,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 {
@@ -1393,7 +1457,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()){
@@ -1681,7 +1745,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());
@@ -1690,6 +1756,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){
@@ -1724,7 +1793,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);
                }
     }
@@ -1742,6 +1811,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;             
@@ -1759,8 +1829,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);
                }
                
@@ -1790,7 +1864,7 @@ public class ServiceInstances {
                
                serviceInstanceId = "";
                String configurationId = "";
-               String correlationId = "";
+               String pnfCorrelationId = "";
 
                if(sir.getServiceInstanceId () != null){
                        serviceInstanceId = sir.getServiceInstanceId ();
@@ -1800,7 +1874,7 @@ public class ServiceInstances {
             configurationId = sir.getConfigurationId();
         }
 
-        correlationId = getCorrelationId(sir);
+        pnfCorrelationId = getPnfCorrelationId(sir);
 
                try{
                        infraActiveRequestsClient.save(currentActiveReq);
@@ -1823,7 +1897,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)
@@ -1838,7 +1912,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();
@@ -1869,4 +1943,30 @@ public class ServiceInstances {
                        }
                }
        }
+       protected String getServiceType(String requestScope, ServiceInstancesRequest sir, Boolean aLaCarteFlag){
+               String serviceType = null;
+               if(requestScope.equalsIgnoreCase(ModelType.service.toString())){
+                       String defaultServiceModelName = getDefaultModel(sir);
+                       org.onap.so.db.catalog.beans.Service serviceRecord;
+                       if(aLaCarteFlag){
+                                serviceRecord = catalogDbClient.getFirstByModelNameOrderByModelVersionDesc(defaultServiceModelName);
+                                if(serviceRecord != null){
+                                        serviceType = serviceRecord.getServiceType();
+                                }
+                       }else{
+                               serviceRecord = catalogDbClient.getServiceByID(sir.getRequestDetails().getModelInfo().getModelVersionId());
+                               if(serviceRecord != null){
+                                        serviceType = serviceRecord.getServiceType();
+                                }else{
+                                        serviceRecord = catalogDbClient.getFirstByModelNameOrderByModelVersionDesc(defaultServiceModelName);
+                                        if(serviceRecord != null){
+                                                serviceType = serviceRecord.getServiceType();
+                                        }
+                                }
+                       }
+               }else{
+                       serviceType = msoRequest.getServiceInstanceType(sir, requestScope);
+               }
+               return serviceType;
+       }
 }