Fix interface types creation 90/108190/2
authorandre.schmid <andre.schmid@est.tech>
Wed, 20 May 2020 13:24:40 +0000 (14:24 +0100)
committerOfir Sonsino <ofir.sonsino@intl.att.com>
Thu, 28 May 2020 07:57:32 +0000 (07:57 +0000)
Interface types creation logic was not interpreting some allowed TOSCA
entries, that, when declared, were breaking the interface type
creation. Every entry under the interface type was being considered
as an interface operation, but it is possible to have "derived_from",
"version", "metadata" and "description". Also it is not considering
the Interface Type entries "inputs", "operations" and "notifications".
Another thing is that TOSCA 1.3 changes the way operations should be
declared, deprecating the previous way. Now there should be an entry
"operations" with the operations entries under it, instead of having
the operations entries direct under the interface type. The change
allows both types, following the TOSCA rule: if operations entry is
not present, then the deprecated way is considered.

Change-Id: I13218bda60b29d19b9c5565cbfd63ae3250a78bf
Issue-ID: SDC-3075
Signed-off-by: andre.schmid <andre.schmid@est.tech>
catalog-be/src/main/java/org/openecomp/sdc/be/components/impl/InterfaceLifecycleTypeImportManager.java
catalog-be/src/main/resources/import/tosca/interface-lifecycle-types/interfaceLifecycleTypes.yml
catalog-be/src/test/java/org/openecomp/sdc/be/components/impl/InterfaceLifecycleTypeImportManagerTest.java
catalog-be/src/test/resources/types/interfaceLifecycleTypes.yml
catalog-model/src/main/java/org/openecomp/sdc/be/model/InterfaceDefinition.java
common-be/src/main/java/org/openecomp/sdc/be/datatypes/elements/InterfaceDataDefinition.java
common-be/src/main/java/org/openecomp/sdc/be/utils/TypeUtils.java

index f6a2e5b..f1b4442 100644 (file)
 package org.openecomp.sdc.be.components.impl;
 
 import fj.data.Either;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.stream.Collectors;
+import javax.annotation.Resource;
+import org.apache.commons.collections.MapUtils;
 import org.openecomp.sdc.be.dao.api.ActionStatus;
+import org.openecomp.sdc.be.datatypes.enums.JsonPresentationFields;
 import org.openecomp.sdc.be.impl.ComponentsUtils;
 import org.openecomp.sdc.be.model.InterfaceDefinition;
 import org.openecomp.sdc.be.model.Operation;
 import org.openecomp.sdc.be.model.operations.api.IInterfaceLifecycleOperation;
 import org.openecomp.sdc.be.model.operations.api.StorageOperationStatus;
+import org.openecomp.sdc.be.utils.TypeUtils.ToscaTagNamesEnum;
 import org.openecomp.sdc.common.log.wrappers.Logger;
 import org.openecomp.sdc.exception.ResponseFormat;
 import org.springframework.stereotype.Component;
 
-import javax.annotation.Resource;
-import java.util.ArrayList;
-import java.util.HashMap;
-import java.util.Iterator;
-import java.util.List;
-import java.util.Map;
-
 @Component("interfaceLifecycleTypeImportManager")
 public class InterfaceLifecycleTypeImportManager {
 
@@ -53,7 +58,7 @@ public class InterfaceLifecycleTypeImportManager {
 
     public Either<List<InterfaceDefinition>, ResponseFormat> createLifecycleTypes(String interfaceLifecycleTypesYml) {
 
-        Either<List<InterfaceDefinition>, ActionStatus> interfaces = createLifecyclyTypeFromYml(interfaceLifecycleTypesYml);
+        Either<List<InterfaceDefinition>, ActionStatus> interfaces = createInterfaceTypeFromYml(interfaceLifecycleTypesYml);
         if (interfaces.isRight()) {
             ActionStatus status = interfaces.right().value();
             ResponseFormat responseFormat = componentsUtils.getResponseFormatByGroupType(status, null);
@@ -63,8 +68,8 @@ public class InterfaceLifecycleTypeImportManager {
 
     }
 
-    private Either<List<InterfaceDefinition>, ActionStatus> createLifecyclyTypeFromYml(String interfaceLifecycleTypesYml) {
-        return commonImportManager.createElementTypesFromYml(interfaceLifecycleTypesYml, this::createLifecycleType);
+    private Either<List<InterfaceDefinition>, ActionStatus> createInterfaceTypeFromYml(final String interfaceTypesYml) {
+        return commonImportManager.createElementTypesFromYml(interfaceTypesYml, this::createInterfaceDefinition);
 
     }
 
@@ -97,20 +102,59 @@ public class InterfaceLifecycleTypeImportManager {
         return eitherResult;
     }
 
-    private InterfaceDefinition createLifecycleType(String interfaceDefinition, Map<String, Object> toscaJson) {
-        InterfaceDefinition interfaceDef = new InterfaceDefinition();
+    private InterfaceDefinition createInterfaceDefinition(final String interfaceDefinition,
+                                                          final Map<String, Object> toscaJson) {
+        final InterfaceDefinition interfaceDef = new InterfaceDefinition();
         interfaceDef.setType(interfaceDefinition);
+        final Object descriptionObj = toscaJson.get(ToscaTagNamesEnum.DESCRIPTION.getElementName());
+        if (descriptionObj instanceof String) {
+            interfaceDef.setDescription((String) descriptionObj);
+        }
+        final Object derivedFromObj = toscaJson.get(ToscaTagNamesEnum.DERIVED_FROM.getElementName());
+        if (derivedFromObj instanceof String) {
+            interfaceDef.setDerivedFrom((String) derivedFromObj);
+        }
+        final Object versionObj = toscaJson.get(ToscaTagNamesEnum.VERSION.getElementName());
+        if (versionObj instanceof String) {
+            interfaceDef.setVersion((String) versionObj);
+        }
 
-        Map<String, Operation> operations = new HashMap<>();
-
-        for (Map.Entry<String, Object> entry : toscaJson.entrySet()) {
-            Operation operation = new Operation();
-            Map<String, Object> opProp = (Map<String, Object>) entry.getValue();
+        final Object metadataObj = toscaJson.get(ToscaTagNamesEnum.METADATA.getElementName());
+        if (metadataObj instanceof Map) {
+            interfaceDef.setToscaPresentationValue(JsonPresentationFields.METADATA, metadataObj);
+        }
 
-            operation.setDescription((String) opProp.get("description"));
-            operations.put(entry.getKey(), operation);
+        final Map<String, Object> operationsMap;
+        if (toscaJson.containsKey(ToscaTagNamesEnum.OPERATIONS.getElementName())) {
+            operationsMap = (Map<String, Object>) toscaJson.get(ToscaTagNamesEnum.OPERATIONS.getElementName());
+        } else {
+            final List<String> entitySchemaEntryList = Arrays
+                .asList(ToscaTagNamesEnum.DERIVED_FROM.getElementName(),
+                    ToscaTagNamesEnum.DESCRIPTION.getElementName(),
+                    ToscaTagNamesEnum.VERSION.getElementName(),
+                    ToscaTagNamesEnum.METADATA.getElementName(),
+                    ToscaTagNamesEnum.INPUTS.getElementName(),
+                    ToscaTagNamesEnum.NOTIFICATIONS.getElementName());
+            operationsMap = toscaJson.entrySet().stream()
+                .filter(interfaceEntry -> !entitySchemaEntryList.contains(interfaceEntry.getKey()))
+                .collect(Collectors.toMap(Entry::getKey, Entry::getValue));
         }
-        interfaceDef.setOperationsMap(operations);
+        interfaceDef.setOperationsMap(handleOperations(operationsMap));
         return interfaceDef;
     }
+
+    private Map<String, Operation> handleOperations(final Map<String, Object> operationsToscaEntry) {
+        if (MapUtils.isEmpty(operationsToscaEntry)) {
+            return Collections.emptyMap();
+        }
+        return operationsToscaEntry.entrySet().stream()
+            .collect(Collectors.toMap(Entry::getKey,
+                operationEntry -> createOperation((Map<String, Object>) operationEntry.getValue())));
+    }
+
+    private Operation createOperation(final Map<String, Object> toscaOperationMap) {
+        final Operation operation = new Operation();
+        operation.setDescription((String) toscaOperationMap.get(ToscaTagNamesEnum.DESCRIPTION.getElementName()));
+        return operation;
+    }
 }
index 35d67bf..9cc6c8c 100644 (file)
@@ -1,4 +1,9 @@
+tosca.interfaces.Root:
+  derived_from: tosca.entity.Root
+  description: The TOSCA root Interface Type all other TOSCA Interface Types derive from
+
 tosca.interfaces.nfv.vnf.lifecycle.Nfv:
+  derived_from: tosca.interfaces.Root
   instantiate:
     description: Invoked upon receipt of an Instantiate VNF request
   instantiate_start:
@@ -53,7 +58,9 @@ tosca.interfaces.nfv.vnf.lifecycle.Nfv:
     description: Invoked before scale_to_level
   scale_to_level_end:
     description: Invoked after scale_to_level
+
 tosca.interfaces.node.lifecycle.Standard:
+  derived_from: tosca.interfaces.Root
   create:
     description: Standard lifecycle create operation.
   configure:
@@ -65,10 +72,28 @@ tosca.interfaces.node.lifecycle.Standard:
   delete:
     description: Standard lifecycle delete operation.
 
+tosca.interfaces.relationship.Configure:
+  derived_from: tosca.interfaces.Root
+  pre_configure_source:
+    description: Operation to pre-configure the source endpoint.
+  pre_configure_target:
+    description: Operation to pre-configure the target endpoint.
+  post_configure_source:
+    description: Operation to post-configure the source endpoint.
+  post_configure_target:
+    description: Operation to post-configure the target endpoint.
+  add_target:
+    description: Operation to notify the source node of a target node being added via a relationship.
+  add_source:
+    description: Operation to notify the target node of a source node which is now available via a relationship.
+  target_changed:
+    description: Operation to notify source some property or attribute of the target changed
+  remove_target:
+    description: Operation to remove a target node.
 # NFV interface types
 tosca.interfaces.nfv.Vnflcm:
-  #derived_from: tosca.interfaces.Root
-  #description: This interface encompasses a set of TOSCA operations corresponding to the VNF LCM operations defined in ETSI GS NFV-IFA 007 as well as to preamble and postamble procedures to the execution of the VNF LCM operations.
+  derived_from: tosca.interfaces.Root
+  description: This interface encompasses a set of TOSCA operations corresponding to the VNF LCM operations defined in ETSI GS NFV-IFA 007 as well as to preamble and postamble procedures to the execution of the VNF LCM operations.
   instantiate:
     description: Invoked upon receipt of an Instantiate VNF request
     # inputs:
index 454f534..21307ad 100644 (file)
@@ -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.
 package org.openecomp.sdc.be.components.impl;
 
 import fj.data.Either;
+import java.util.Optional;
+import java.util.Set;
+import java.util.stream.Collectors;
+import java.util.stream.Stream;
 import org.junit.Before;
 import org.junit.BeforeClass;
 import org.junit.Test;
@@ -41,6 +45,12 @@ import java.nio.file.Path;
 import java.nio.file.Paths;
 import java.util.List;
 
+import static org.hamcrest.MatcherAssert.assertThat;
+import static org.hamcrest.Matchers.containsInAnyOrder;
+import static org.hamcrest.Matchers.empty;
+import static org.hamcrest.Matchers.hasSize;
+import static org.hamcrest.Matchers.not;
+import static org.hamcrest.core.Is.is;
 import static org.junit.Assert.assertTrue;
 import static org.mockito.Mockito.when;
 
@@ -62,6 +72,7 @@ public class InterfaceLifecycleTypeImportManagerTest {
 
         });
         when(commonImportManager.createElementTypesFromYml(Mockito.anyString(), Mockito.any())).thenCallRealMethod();
+        when(commonImportManager.createElementTypesFromToscaJsonMap(Mockito.any(), Mockito.any())).thenCallRealMethod();
     }
 
     @Before
@@ -70,11 +81,55 @@ public class InterfaceLifecycleTypeImportManagerTest {
     }
 
     @Test
-    public void importLiecycleTest() throws IOException {
-        String ymlContent = getYmlContent();
-        Either<List<InterfaceDefinition>, ResponseFormat> createCapabilityTypes = importManager.createLifecycleTypes(ymlContent);
+    public void createLifecycleTypesTest() throws IOException {
+        final String ymlContent = getYmlContent();
+        final Either<List<InterfaceDefinition>, ResponseFormat> createCapabilityTypes =
+            importManager.createLifecycleTypes(ymlContent);
         assertTrue(createCapabilityTypes.isLeft());
+        final List<InterfaceDefinition> interfaceDefinitionList = createCapabilityTypes.left().value();
+        assertThat("Interface definitions should not be empty", interfaceDefinitionList, is(not(empty())));
+        final int expectedSize = 2;
+        assertThat(String.format("Interface definitions should have the size %s", expectedSize),
+            interfaceDefinitionList, hasSize(expectedSize));
+        final String standardInterfaceType = "tosca.interfaces.node.lifecycle.Standard";
+        final String nslcmInterfaceType = "tosca.interfaces.nfv.Nslcm";
+        final Optional<InterfaceDefinition> standardInterfaceOpt = interfaceDefinitionList.stream().filter(
+            interfaceDefinition -> standardInterfaceType.equals(interfaceDefinition.getType()))
+            .findFirst();
+        final Optional<InterfaceDefinition> nslcmInterfaceOpt = interfaceDefinitionList.stream().filter(
+            interfaceDefinition -> nslcmInterfaceType.equals(interfaceDefinition.getType()))
+            .findFirst();
+        assertThat("", standardInterfaceOpt.isPresent(), is(true));
+        assertThat("", nslcmInterfaceOpt.isPresent(), is(true));
+        final InterfaceDefinition standardInterface = standardInterfaceOpt.get();
+        final Set<String> expectedStandardInterfaceOperationSet = Stream
+            .of("create", "configure", "start", "stop", "delete").collect(Collectors.toSet());
+        assertThat(String.format("%s derived_from should be as expected", standardInterfaceType),
+            standardInterface.getDerivedFrom(), is("tosca.interfaces.Root"));
+        assertThat(String.format("%s operations should have the expected size", standardInterfaceType),
+            standardInterface.getOperationsMap().keySet(), hasSize(expectedStandardInterfaceOperationSet.size()));
+        assertThat(String.format("%s should contains the expected operations", standardInterfaceType),
+            standardInterface.getOperationsMap().keySet(),
+            containsInAnyOrder(expectedStandardInterfaceOperationSet.toArray()));
 
+        final InterfaceDefinition nslcmInterface = nslcmInterfaceOpt.get();
+        assertThat(String.format("%s derived_from should be as expected", nslcmInterfaceType),
+            nslcmInterface.getDerivedFrom(), is("tosca.interfaces.Root"));
+        assertThat(String.format("%s description should be as expected", nslcmInterfaceType),
+            nslcmInterface.getDescription(),
+            is("This interface encompasses a set of TOSCA "
+                + "operations corresponding to NS LCM operations defined in ETSI GS NFV-IFA 013. as well as to preamble "
+                + "and postamble procedures to the execution of the NS LCM operations."));
+        final Set<String> expectedNsclmInterfaceOperationSet = Stream
+            .of("instantiate_start", "instantiate", "instantiate_end", "terminate_start", "terminate",
+                "terminate_end", "update_start", "update", "update_end", "scale_start", "scale", "scale_end",
+                "heal_start", "heal", "heal_end").collect(Collectors.toSet());
+        assertThat(String.format("%s operations should have the expected size", nslcmInterfaceType),
+            nslcmInterface.getOperationsMap().keySet(),
+            hasSize(expectedNsclmInterfaceOperationSet.size()));
+        assertThat(String.format("%s should contains the expected operations", nslcmInterfaceType),
+            nslcmInterface.getOperationsMap().keySet(),
+            containsInAnyOrder(expectedNsclmInterfaceOperationSet.toArray()));
     }
 
     private String getYmlContent() throws IOException {
index 1b67118..696e1d0 100644 (file)
@@ -1,4 +1,5 @@
 tosca.interfaces.node.lifecycle.Standard:
+  derived_from: tosca.interfaces.Root
   create:
     description: Standard lifecycle create operation.
   configure:
@@ -8,4 +9,47 @@ tosca.interfaces.node.lifecycle.Standard:
   stop:
     description: Standard lifecycle stop operation.
   delete:
-    description: Standard lifecycle delete operation.
\ No newline at end of file
+    description: Standard lifecycle delete operation.
+tosca.interfaces.nfv.Nslcm:
+  derived_from: tosca.interfaces.Root
+  description: This interface encompasses a set of TOSCA operations corresponding to NS LCM operations defined in ETSI GS NFV-IFA 013. as well as to preamble and postamble procedures to the execution of the NS LCM operations.
+  version: "1.0.0"
+  metadata:
+    meta1: meta1
+  inputs:
+    input1:
+      type: string
+  operations:
+    instantiate_start:
+      description: Preamble to execution of the instantiate operation
+    instantiate:
+      description: Base procedure for instantiating an NS, corresponding to the Instantiate NS operation defined in GS NFV-IFA 013.
+    instantiate_end:
+      description: Postamble to the execution of the instantiate operation
+    terminate_start:
+      description: Preamble to execution of the terminate operation
+    terminate:
+      description: Base procedure for terminating an NS, corresponding to the Terminate NS operation defined in GS NFV-IFA 013.
+    terminate_end:
+      description: Postamble to the execution of the terminate operation
+    update_start:
+      description: Preamble to execution of the update operation
+    update:
+      description: Base procedure for updating an NS, corresponding to the Update NS operation defined in GS NFV-IFA 013.
+    update_end:
+      description: Postamble to the execution of the update operation
+    scale_start:
+      description: Preamble to execution of the scale operation
+    scale:
+      description: Base procedure for scaling an NS, corresponding to the Scale NS operation defined in GS NFV-IFA 013.
+    scale_end:
+      description: Postamble to the execution of the scale operation
+    heal_start:
+      description: Preamble to execution of the heal operation
+    heal:
+      description: Base procedure for healing an NS, corresponding to the Heal NS operation defined in GS NFV-IFA 013.
+    heal_end:
+      description: Postamble to the execution of the heal operation
+  notifications:
+    notification1:
+      description: notification1 description
\ No newline at end of file
index 3afd422..e3b5d08 100644 (file)
@@ -21,6 +21,7 @@
 package org.openecomp.sdc.be.model;
 
 import com.fasterxml.jackson.annotation.JsonIgnore;
+import org.apache.commons.collections.MapUtils;
 import org.openecomp.sdc.be.datatypes.elements.InterfaceDataDefinition;
 import org.openecomp.sdc.be.datatypes.elements.OperationDataDefinition;
 
@@ -68,11 +69,13 @@ public class InterfaceDefinition extends InterfaceDataDefinition implements IOpe
     }
 
     @JsonIgnore
-    public void setOperationsMap(Map<String, Operation> operations) {
-        Map<String, OperationDataDefinition> convertedOperation = operations.entrySet()
-                                                                            .stream()
-                                                                            .collect(Collectors.toMap(Map.Entry::getKey, e -> new OperationDataDefinition(e
-                                                                                    .getValue())));
+    public void setOperationsMap(final Map<String, Operation> operations) {
+        if (MapUtils.isEmpty(operations)) {
+            return;
+        }
+        final Map<String, OperationDataDefinition> convertedOperation = operations.entrySet()
+            .stream()
+            .collect(Collectors.toMap(Map.Entry::getKey, e -> new OperationDataDefinition(e.getValue())));
         setOperations(convertedOperation);
     }
 
index d263771..a264d46 100644 (file)
@@ -77,6 +77,18 @@ public class InterfaceDataDefinition extends ToscaDataDefinition implements Seri
         setToscaPresentationValue(JsonPresentationFields.DESCRIPTION, description);
     }
 
+    public String getDerivedFrom() {
+        return (String) getToscaPresentationValue(JsonPresentationFields.DERIVED_FROM);
+    }
+
+    public void setDerivedFrom(final String derivedFrom) {
+        setToscaPresentationValue(JsonPresentationFields.DERIVED_FROM, derivedFrom);
+    }
+
+    public void setVersion(final String version) {
+        setToscaPresentationValue(JsonPresentationFields.VERSION, version);
+    }
+
     public String getToscaResourceName() {
         return (String) getToscaPresentationValue(TOSCA_RESOURCE_NAME);
     }
index 5198be9..f58c8fa 100644 (file)
@@ -61,11 +61,11 @@ public class TypeUtils {
         SUBSTITUTION_MAPPINGS("substitution_mappings"), NODE_TYPE("node_type"), DIRECTIVES("directives"),
         // Attributes
         ATTRIBUTES("attributes"), LABEL("label"), HIDDEN("hidden"), IMMUTABLE("immutable"), ANNOTATIONS("annotations"),
+        VERSION("version"), OPERATIONS("operations"), NOTIFICATIONS("notifications"),
         //functions
         GET_INPUT("get_input");
 
-
-        private String elementName;
+        private final String elementName;
 
         ToscaTagNamesEnum(final String elementName) {
             this.elementName = elementName;