Unable to import service template with interface
[sdc.git] / catalog-be / src / main / java / org / openecomp / sdc / be / components / impl / ServiceImportBusinessLogic.java
index bf27d03..8671d9e 100644 (file)
@@ -20,6 +20,8 @@ import static java.util.stream.Collectors.joining;
 import static java.util.stream.Collectors.toList;
 import static java.util.stream.Collectors.toMap;
 import static org.apache.commons.collections.CollectionUtils.isNotEmpty;
+import static org.openecomp.sdc.be.components.impl.CsarValidationUtils.TOSCA_METADATA_PATH_PATTERN;
+import static org.openecomp.sdc.be.components.impl.CsarValidationUtils.TOSCA_META_ENTRY_DEFINITIONS;
 import static org.openecomp.sdc.be.components.impl.ImportUtils.findFirstToscaMapElement;
 import static org.openecomp.sdc.be.components.impl.ImportUtils.findFirstToscaStringElement;
 import static org.openecomp.sdc.be.components.impl.ImportUtils.getPropertyJsonStringValue;
@@ -30,6 +32,9 @@ import com.google.gson.JsonElement;
 import com.google.gson.JsonObject;
 import com.google.gson.JsonParser;
 import fj.data.Either;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.StringReader;
 import java.lang.reflect.Method;
 import java.util.ArrayList;
 import java.util.Arrays;
@@ -44,11 +49,13 @@ import java.util.List;
 import java.util.Map;
 import java.util.Map.Entry;
 import java.util.Optional;
+import java.util.Properties;
 import java.util.Set;
 import java.util.TreeSet;
 import java.util.concurrent.atomic.AtomicReference;
 import java.util.regex.Pattern;
 import java.util.stream.Collectors;
+import javax.validation.constraints.NotNull;
 import lombok.Getter;
 import lombok.Setter;
 import org.apache.commons.collections.CollectionUtils;
@@ -168,6 +175,8 @@ import org.openecomp.sdc.common.datastructure.Wrapper;
 import org.openecomp.sdc.common.kpi.api.ASDCKpiApi;
 import org.openecomp.sdc.common.log.wrappers.Logger;
 import org.openecomp.sdc.common.util.ValidationUtils;
+import org.openecomp.sdc.common.zip.ZipUtils;
+import org.openecomp.sdc.common.zip.exception.ZipException;
 import org.openecomp.sdc.exception.ResponseFormat;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.yaml.snakeyaml.Yaml;
@@ -212,10 +221,10 @@ public class ServiceImportBusinessLogic {
     private final GroupTypeOperation groupTypeOperation;
     private final CapabilityTypeImportManager capabilityTypeImportManager;
     private final CapabilityTypeOperation capabilityTypeOperation;
-    private ApplicationDataTypeCache applicationDataTypeCache;
     private final InterfaceLifecycleOperation interfaceLifecycleTypeOperation;
     private final InterfaceLifecycleTypeImportManager interfaceLifecycleTypeImportManager;
     private final ModelOperation modelOperation;
+    private ApplicationDataTypeCache applicationDataTypeCache;
 
     public ServiceImportBusinessLogic(final GroupBusinessLogic groupBusinessLogic, final ArtifactsBusinessLogic artifactsBusinessLogic,
                                       final ComponentsUtils componentsUtils, final ToscaOperationFacade toscaOperationFacade,
@@ -283,6 +292,50 @@ public class ServiceImportBusinessLogic {
         return createService(newService, AuditingActionEnum.UPDATE_SERVICE_TOSCA_TEMPLATE, modifier, payload, null);
     }
 
+    public Service updateServiceFromToscaModel(final String serviceId, final User modifier, final @NotNull InputStream fileToUpload) {
+        final Either<Service, ResponseFormat> serviceResponseFormatEither = serviceBusinessLogic.getService(serviceId, modifier);
+        if (serviceResponseFormatEither.isRight()) {
+            throw new ByActionStatusComponentException(ActionStatus.SERVICE_NOT_FOUND, serviceId);
+        }
+        final Service serviceOriginal = serviceResponseFormatEither.left().value();
+        Map<String, byte[]> csar = null;
+        try {
+            csar = ZipUtils.readZip(fileToUpload.readAllBytes(), false);
+        } catch (final ZipException | IOException e) {
+            log.info("Failed to unzip received csar {}", serviceId, e);
+        }
+        if (csar == null) {
+            throw new ByActionStatusComponentException(ActionStatus.CSAR_NOT_FOUND);
+        }
+        final byte[] mainYamlBytes = readMainYamlFile(csar);
+        final Map<String, String> metadata = (Map<String, String>) new Yaml().loadAs(new String(mainYamlBytes), Map.class).get("metadata");
+        validateServiceMetadataBeforeCreate(serviceOriginal, metadata);
+        final Service newService = cloneServiceIdentifications(serviceOriginal);
+        updateServiceMetadata(newService, metadata);
+        return createService(newService, AuditingActionEnum.UPDATE_SERVICE_TOSCA_MODEL, modifier, csar, null);
+    }
+
+    private byte[] readMainYamlFile(final Map<String, byte[]> csar) {
+        final Pattern pattern = Pattern.compile(TOSCA_METADATA_PATH_PATTERN);
+        final Optional<String> keyOp = csar.keySet().stream().filter(k -> pattern.matcher(k).matches()).findAny();
+        if (keyOp.isEmpty()) {
+            throw new ByActionStatusComponentException(ActionStatus.ARTIFACT_NOT_FOUND_IN_CSAR, TOSCA_METADATA_PATH_PATTERN, "");
+        }
+        final Properties props = new Properties();
+        try {
+            final String propStr = new String(csar.get(keyOp.get()));
+            props.load(new StringReader(propStr.replace("\\", "\\\\")));
+        } catch (IOException e) {
+            throw new ByActionStatusComponentException(ActionStatus.ARTIFACT_NOT_FOUND_IN_CSAR, TOSCA_META_ENTRY_DEFINITIONS, "");
+        }
+        final String mainYamlFileName = props.getProperty(TOSCA_META_ENTRY_DEFINITIONS);
+        final byte[] mainYamlBytes = csar.get(mainYamlFileName);
+        if (mainYamlBytes == null) {
+            throw new ByActionStatusComponentException(ActionStatus.ARTIFACT_NOT_FOUND_IN_CSAR, mainYamlFileName, "");
+        }
+        return mainYamlBytes;
+    }
+
     private Service cloneServiceIdentifications(final Service serviceOriginal) {
         final Service newService = new Service(serviceOriginal.getComponentMetadataDefinition());
         newService.setCategories(serviceOriginal.getCategories());
@@ -2104,6 +2157,7 @@ public class ServiceImportBusinessLogic {
         if (originResource.getAttributes() != null && !originResource.getAttributes().isEmpty()) {
             instAttributes.put(resourceInstanceId, originResource.getAttributes());
             addAttributeValueToResourceInstance(instAttributes, uploadComponentInstanceInfo.getAttributes());
+            instAttributes.get(resourceInstanceId).addAll(addImplicitAttributeValues(originResource, uploadComponentInstanceInfo));
         }
         if (uploadComponentInstanceInfo.getUploadNodeFilterInfo() == null) {
             instNodeFilter.put(resourceInstanceId, new UploadNodeFilterInfo());
@@ -2134,6 +2188,44 @@ public class ServiceImportBusinessLogic {
         }
     }
 
+    private List<AttributeDefinition> addImplicitAttributeValues(Resource originResource, UploadComponentInstanceInfo uploadComponentInstanceInfo) {
+        if (uploadComponentInstanceInfo.getAttributes() == null) {
+            return Collections.emptyList();
+        }
+        List<String> origAttributes = originResource.getAttributes().stream().map(AttributeDefinition::getName).collect(toList());
+        Map<String, UploadAttributeInfo> uploadAttributes = uploadComponentInstanceInfo.getAttributes();
+        List<String> newAttributesToAdd =
+            uploadAttributes.keySet().stream().filter(newAttribute -> !origAttributes.contains(newAttribute))
+                .collect(toList());
+        List<PropertyDefinition> propsToAddAsAttributes =
+            originResource.getProperties().stream().filter(prop -> newAttributesToAdd.contains(prop.getName())).collect(toList());
+        propsToAddAsAttributes.stream().forEach(prop -> {
+            Object value = uploadAttributes.get(prop.getName()).getValue();
+            if (value instanceof Collection<?> || value instanceof Map<?, ?>) {
+                Gson gson = new Gson();
+                String json = gson.toJson(value);
+                prop.setValue(json);
+            } else {
+                prop.setValue(String.valueOf(value));
+            }
+        });
+        List<AttributeDefinition> attributesToAdd = new ArrayList<>();
+        for (PropertyDefinition prop : propsToAddAsAttributes) {
+            attributesToAdd.add(getPropertyAsAttribute(prop));
+        }
+        return attributesToAdd;
+    }
+
+    private AttributeDefinition getPropertyAsAttribute(PropertyDefinition property) {
+        AttributeDefinition attribute = new AttributeDefinition();
+        attribute.setName(property.getName());
+        attribute.setType(property.getType());
+        attribute.setSchema(property.getSchema());
+        attribute.setValue(property.getValue());
+        attribute.setDefaultValue(property.getDefaultValue());
+        return attribute;
+    }
+
     protected void addInputsValuesToRi(UploadComponentInstanceInfo uploadComponentInstanceInfo, Component component, Resource originResource,
                                        ComponentInstance currentCompInstance, Map<String, List<ComponentInstanceInput>> instInputs,
                                        Map<String, DataTypeDefinition> allDataTypes) {
@@ -2371,13 +2463,13 @@ public class ServiceImportBusinessLogic {
         Map<String, UploadInterfaceInfo> instanceInterfacesMap = uploadComponentInstanceInfo.getInterfaces();
         Map<String, InterfaceDefinition> currInterfacesMap = new HashMap<>();
         Map<String, InterfaceDefinition> interfacesFromNodeType = originResource.getInterfaces();
-        if ((MapUtils.isNotEmpty(instanceInterfacesMap)) && (MapUtils.isEmpty(interfacesFromNodeType))) {
+        if (interfacesFromNodeType == null) {
+            interfacesFromNodeType = new HashMap<>();
+        }
+        if (MapUtils.isEmpty(instanceInterfacesMap) && MapUtils.isEmpty(instanceInterfacesMap)) {
             log.debug("failed to find interfaces ");
             return componentsUtils.getResponseFormat(ActionStatus.INTERFACE_NOT_FOUND_IN_COMPONENT);
         }
-        if (interfacesFromNodeType == null || interfacesFromNodeType.isEmpty()) {
-            return componentsUtils.getResponseFormat(ActionStatus.OK);
-        }
         for (Map.Entry<String, InterfaceDefinition> entryInstances : interfacesFromNodeType.entrySet()) {
             String interfaceName = entryInstances.getKey().substring(entryInstances.getKey().lastIndexOf(".") + 1);
             if (!currInterfacesMap.containsKey(interfaceName)) {
@@ -2389,11 +2481,16 @@ public class ServiceImportBusinessLogic {
         if (MapUtils.isNotEmpty(instanceInterfacesMap)) {
             for (UploadInterfaceInfo uploadInterfaceInfo : instanceInterfacesMap.values()) {
                 String interfaceName = uploadInterfaceInfo.getName();
+                InterfaceDefinition currentInterfaceDef;
                 if (!currInterfacesMap.containsKey(interfaceName)) {
-                    log.debug("failed to find interface {} ", interfaceName);
-                    return componentsUtils.getResponseFormat(ActionStatus.INTERFACE_NOT_FOUND_IN_COMPONENT, interfaceName);
+                    currentInterfaceDef = getInterfaceDef(interfaceName, component.getModel());
+                    if (currentInterfaceDef == null) {
+                        log.debug("failed to find interface {} ", interfaceName);
+                        return componentsUtils.getResponseFormat(ActionStatus.INTERFACE_NOT_FOUND_IN_COMPONENT, interfaceName);
+                    }
+                } else {
+                    currentInterfaceDef = currInterfacesMap.get(interfaceName);
                 }
-                InterfaceDefinition currentInterfaceDef = currInterfacesMap.get(interfaceName);
                 Map<String, OperationDataDefinition> operationsToAdd = new HashMap<>();
 
                 Map<String, OperationDataDefinition> operations = uploadInterfaceInfo.getOperations();
@@ -2419,6 +2516,7 @@ public class ServiceImportBusinessLogic {
                     templateOperation.setImplementation(instanceOperation.getImplementation());
                     //Description
                     templateOperation.setDescription(instanceOperation.getDescription());
+                    templateOperation.setMilestones(instanceOperation.getMilestones());
                     operationsToAdd.put(operation.getKey(), templateOperation);
                 }
                 InterfaceDefinition interfaceDef = new InterfaceDefinition();
@@ -2440,6 +2538,21 @@ public class ServiceImportBusinessLogic {
         return componentsUtils.getResponseFormat(ActionStatus.OK);
     }
 
+    private InterfaceDefinition getInterfaceDef(String interfaceName, String model) {
+        Either<Map<String, InterfaceDefinition>, StorageOperationStatus> interfaceLifecycleTypesEither =
+            interfaceLifecycleTypeOperation.getAllInterfaceLifecycleTypes(model);
+        if (interfaceLifecycleTypesEither.isRight()) {
+            return null;
+        }
+        Map<String, InterfaceDefinition> interfaceLifecycleTypes = interfaceLifecycleTypesEither.left().value();
+        Optional<InterfaceDefinition> interfaceType =
+            interfaceLifecycleTypes.values().stream().filter(interfaceDef -> interfaceDef.getUniqueId().contains(interfaceName)).findFirst();
+        if (interfaceType.isEmpty()) {
+            return null;
+        }
+        return interfaceType.get();
+    }
+
     private void mergeOperationInputDefinitions(ListDataDefinition<OperationInputDefinition> inputsFromNodeType,
                                                 ListDataDefinition<OperationInputDefinition> instanceInputs) {
         if (inputsFromNodeType == null || CollectionUtils.isEmpty(inputsFromNodeType.getListToscaDataDefinition()) || instanceInputs == null