Fix ETSI NSD requirement handling 39/120539/2
authorMichaelMorris <michael.morris@est.tech>
Tue, 23 Mar 2021 12:22:19 +0000 (12:22 +0000)
committerChristophe Closset <christophe.closset@intl.att.com>
Thu, 15 Apr 2021 09:49:56 +0000 (09:49 +0000)
Signed-off-by: MichaelMorris <michael.morris@est.tech>
Issue-ID: SDC-3528
Change-Id: Ied1466e6708dfd18bcb15dfe55558c1248f920f7
(cherry picked from commit 0358e1dfa8f3b3b83ccfca68209ec36c0d25ca8b)

catalog-be-plugins/etsi-nfv-nsd-csar-plugin/src/main/java/org/openecomp/sdc/be/plugins/etsi/nfv/nsd/generator/NsDescriptorGeneratorImpl.java
catalog-be-plugins/etsi-nfv-nsd-csar-plugin/src/test/java/org/openecomp/sdc/be/plugins/etsi/nfv/nsd/generator/NsDescriptorGeneratorImplTest.java

index 62f8e25..f024d8f 100644 (file)
@@ -21,6 +21,7 @@ package org.openecomp.sdc.be.plugins.etsi.nfv.nsd.generator;
 
 import com.google.common.collect.ImmutableMap;
 import fj.data.Either;
+import groovy.util.MapEntry;
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.Collection;
@@ -30,6 +31,7 @@ import java.util.List;
 import java.util.Map;
 import java.util.Map.Entry;
 import java.util.Optional;
+import java.util.stream.Collectors;
 import org.apache.commons.collections4.CollectionUtils;
 import org.apache.commons.collections4.MapUtils;
 import org.openecomp.sdc.be.config.ConfigurationManager;
@@ -48,7 +50,9 @@ import org.openecomp.sdc.be.tosca.model.ToscaNodeType;
 import org.openecomp.sdc.be.tosca.model.ToscaProperty;
 import org.openecomp.sdc.be.tosca.model.ToscaPropertyConstraint;
 import org.openecomp.sdc.be.tosca.model.ToscaPropertyConstraintValidValues;
+import org.openecomp.sdc.be.tosca.model.ToscaRequirement;
 import org.openecomp.sdc.be.tosca.model.ToscaTemplate;
+import org.openecomp.sdc.be.tosca.model.ToscaTemplateRequirement;
 import org.openecomp.sdc.be.tosca.model.ToscaTopolgyTemplate;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
@@ -164,14 +168,13 @@ public class NsDescriptorGeneratorImpl implements NsDescriptorGenerator {
         final String nsNodeTypeName = firstNodeTypeEntry.getKey();
         final ToscaNodeType nsNodeType = firstNodeTypeEntry.getValue();
         final Map<String, ToscaNodeType> nodeTypeMap = new HashMap<>();
-        nodeTypeMap.put(nsNodeTypeName, createEtsiSolNsNodeType(nsNodeType));
+        nodeTypeMap.put(nsNodeTypeName, createEtsiSolNsNodeType(nsNodeType, componentToscaTemplate));
         if (componentToscaTemplate.getNode_types() == null) {
             componentToscaTemplate.setNode_types(nodeTypeMap);
         } else {
             componentToscaTemplate.getNode_types().putAll(nodeTypeMap);
         }
-        setPropertiesForNodeTemplates(componentToscaTemplate);
-        removeCapabilitiesFromNodeTemplates(componentToscaTemplate);
+        handleNodeTemplates(componentToscaTemplate);
         removeOnapPropertiesFromInputs(componentToscaTemplate);
         handleSubstitutionMappings(componentToscaTemplate, nsNodeTypeName);
         final Map<String, ToscaNodeTemplate> nodeTemplates = new HashMap<>();
@@ -192,12 +195,23 @@ public class NsDescriptorGeneratorImpl implements NsDescriptorGenerator {
         final SubstitutionMapping substitutionMapping = new SubstitutionMapping();
         substitutionMapping.setNode_type(nsNodeTypeName);
         final SubstitutionMapping onapSubstitutionMapping = componentToscaTemplate.getTopology_template().getSubstitution_mappings();
-        if (onapSubstitutionMapping != null) {
-            substitutionMapping.setRequirements(onapSubstitutionMapping.getRequirements());
-            substitutionMapping.setCapabilities(onapSubstitutionMapping.getCapabilities());
+        if (onapSubstitutionMapping != null && onapSubstitutionMapping.getRequirements() != null) {
+            substitutionMapping.setRequirements(adjustRequirementNamesToMatchVnfd(onapSubstitutionMapping.getRequirements()));
         }
         componentToscaTemplate.getTopology_template().setSubstitution_mappings(substitutionMapping);
     }
+    
+    private Map<String, String[]> adjustRequirementNamesToMatchVnfd(final Map<String, String[]> requirements) {
+        for (final Map.Entry<String, String[]> entry : requirements.entrySet()) {
+            try {
+                final String[] adjustedValue = {entry.getValue()[0], entry.getValue()[1].substring(entry.getValue()[1].lastIndexOf('.') + 1)};
+                entry.setValue(adjustedValue);
+            } catch (final ArrayIndexOutOfBoundsException exception) {
+                LOGGER.error("Malformed requirement: {}", entry);
+            }
+        }
+        return requirements;
+    }
 
     private void setNodeTemplateTypesForVnfs(final ToscaTemplate template, final List<VnfDescriptor> vnfDescriptorList) {
         if (CollectionUtils.isEmpty(vnfDescriptorList)) {
@@ -212,42 +226,56 @@ public class NsDescriptorGeneratorImpl implements NsDescriptorGenerator {
                 .ifPresent(vnfDescriptor -> toscaNodeTemplate.setType(vnfDescriptor.getNodeType())));
     }
 
-    private void setPropertiesForNodeTemplates(final ToscaTemplate template) {
+    private void handleNodeTemplates(final ToscaTemplate template) {
         final Map<String, ToscaNodeTemplate> nodeTemplateMap = template.getTopology_template().getNode_templates();
         if (MapUtils.isEmpty(nodeTemplateMap)) {
             return;
         }
         for (final Entry<String, ToscaNodeTemplate> nodeTemplate : nodeTemplateMap.entrySet()) {
-            final Map<String, Object> propertyMap = nodeTemplate.getValue().getProperties();
-            if (MapUtils.isEmpty(propertyMap)) {
-                nodeTemplate.getValue().setProperties(null);
-                continue;
-            }
-            final Map<String, Object> editedPropertyMap = new HashMap<>();
-            for (final Entry<String, Object> property : propertyMap.entrySet()) {
-                if (!PROPERTIES_TO_EXCLUDE_FROM_ETSI_SOL_NSD_NS_NODE_TEMPLATE.contains(property.getKey()) && propertyIsDefinedInNodeType(
-                    property.getKey())) {
-                    editedPropertyMap.put(property.getKey().substring(property.getKey().indexOf('_') + 1), property.getValue());
-                }
-            }
-            if (editedPropertyMap.isEmpty()) {
-                nodeTemplate.getValue().setProperties(null);
-            } else {
-                nodeTemplate.getValue().setProperties(editedPropertyMap);
-            }
+            setPropertiesForNodeTemplate(nodeTemplate);
+            setRequirementsForNodeTemplate(nodeTemplate);
+            removeCapabilitiesFromNodeTemplate(nodeTemplate);
         }
     }
-
-    private void removeCapabilitiesFromNodeTemplates(final ToscaTemplate template) {
-        final Map<String, ToscaNodeTemplate> nodeTemplateMap = template.getTopology_template().getNode_templates();
-        if (MapUtils.isEmpty(nodeTemplateMap)) {
+    
+    private void setPropertiesForNodeTemplate(final Entry<String, ToscaNodeTemplate> nodeTemplate) {
+        final Map<String, Object> propertyMap = nodeTemplate.getValue().getProperties();
+        if (MapUtils.isEmpty(propertyMap)) {
+            nodeTemplate.getValue().setProperties(null);
             return;
         }
-        for (final Entry<String, ToscaNodeTemplate> nodeTemplate : nodeTemplateMap.entrySet()) {
-            nodeTemplate.getValue().setCapabilities(null);
+        final Map<String, Object> editedPropertyMap = new HashMap<>();
+        for (final Entry<String, Object> property : propertyMap.entrySet()) {
+            if (!PROPERTIES_TO_EXCLUDE_FROM_ETSI_SOL_NSD_NS_NODE_TEMPLATE.contains(property.getKey()) && propertyIsDefinedInNodeType(
+                property.getKey())) {
+                editedPropertyMap.put(property.getKey().substring(property.getKey().indexOf('_') + 1), property.getValue());
+            }
+        }
+        if (editedPropertyMap.isEmpty()) {
+            nodeTemplate.getValue().setProperties(null);
+        } else {
+            nodeTemplate.getValue().setProperties(editedPropertyMap);
         }
     }
 
+    private void setRequirementsForNodeTemplate(final Entry<String, ToscaNodeTemplate> nodeTemplateMap) {
+        final List<Map<String,ToscaTemplateRequirement>> requirementAssignments = nodeTemplateMap.getValue().getRequirements();
+        if (requirementAssignments != null) {  
+            final List<Map<String,ToscaTemplateRequirement>> requirementAssignmentsMatchingVnfdRequirements = new ArrayList<>();
+            for (final Map<String, ToscaTemplateRequirement> requirementAssignment: requirementAssignments) {
+                final Map<String, ToscaTemplateRequirement> requirementAssignmentMatchingVnfd = 
+                        requirementAssignment.entrySet().stream().collect(Collectors.toMap(entry -> entry.getKey().substring(entry.getKey().lastIndexOf('.') + 1), Map.Entry::getValue));
+                requirementAssignmentsMatchingVnfdRequirements.add(requirementAssignmentMatchingVnfd);
+            }
+            nodeTemplateMap.getValue().setRequirements(requirementAssignmentsMatchingVnfdRequirements);
+        }
+    }
+
+
+    private void removeCapabilitiesFromNodeTemplate(final Entry<String, ToscaNodeTemplate> nodeTemplate) {
+        nodeTemplate.getValue().setCapabilities(null);
+    }
+
     private void removeOnapPropertiesFromInputs(final ToscaTemplate template) {
         final ToscaTopolgyTemplate topologyTemplate = template.getTopology_template();
         final Map<String, ToscaProperty> inputMap = topologyTemplate.getInputs();
@@ -290,7 +318,7 @@ public class NsDescriptorGeneratorImpl implements NsDescriptorGenerator {
         return ImmutableMap.of("etsi_nfv_sol001_nsd_types", ImmutableMap.of("file", "etsi_nfv_sol001_nsd_types.yaml"));
     }
 
-    private ToscaNodeType createEtsiSolNsNodeType(final ToscaNodeType nsNodeType) {
+    private ToscaNodeType createEtsiSolNsNodeType(final ToscaNodeType nsNodeType, final ToscaTemplate componentToscaTemplate) {
         final ToscaNodeType toscaNodeType = new ToscaNodeType();
         toscaNodeType.setDerived_from(NS_TOSCA_TYPE);
         final Map<String, ToscaProperty> propertiesInNsNodeType = nsNodeType.getProperties();
@@ -304,8 +332,30 @@ public class NsDescriptorGeneratorImpl implements NsDescriptorGenerator {
         }
         propertiesInNsNodeType.entrySet().removeIf(entry -> PROPERTIES_TO_EXCLUDE_FROM_ETSI_SOL_NSD_NS_NODE_TYPE.contains(entry.getKey()));
         toscaNodeType.setProperties(propertiesInNsNodeType);
+        
+        final List<Map<String, ToscaRequirement>> requirementsInNsNodeType = getRequirementsForNsNodeType(nsNodeType.getRequirements(), componentToscaTemplate);
+        if (!requirementsInNsNodeType.isEmpty()) {
+            toscaNodeType.setRequirements(requirementsInNsNodeType);  
+        }
+
         return toscaNodeType;
     }
+    
+    private List<Map<String,ToscaRequirement>> getRequirementsForNsNodeType(final List<Map<String,ToscaRequirement>> requirements, final ToscaTemplate componentToscaTemplate) {
+        final Map<String, String[]> requirementsInSubstitutionMapping = componentToscaTemplate.getTopology_template().getSubstitution_mappings().getRequirements();
+        if (requirements == null || MapUtils.isEmpty(requirementsInSubstitutionMapping)) {
+            return Collections.emptyList();
+        }
+        final List<Map<String,ToscaRequirement>> requirementsToAdd = new ArrayList<>();
+        for (final Map<String,ToscaRequirement> requirementMap : requirements) {
+            final Map<String,ToscaRequirement> neededRequirements = requirementMap.entrySet().stream().filter(entry -> requirementsInSubstitutionMapping.containsKey(entry.getKey())).collect(Collectors.toMap(Entry::getKey, Entry::getValue));
+            if (!neededRequirements.isEmpty()) {
+                requirementsToAdd.add(neededRequirements);
+            }
+        }
+        return requirementsToAdd;
+       
+    }
 
     private boolean propertyIsDefinedInNodeType(final String propertyName) {
         // This will achieve what we want for now, but will look into a more generic solution which would involve
index 69d9b0f..cfd0ef7 100644 (file)
@@ -26,6 +26,10 @@ import static org.hamcrest.Matchers.not;
 import static org.hamcrest.core.Is.is;
 import static org.hamcrest.core.IsNull.notNullValue;
 import static org.hamcrest.core.IsNull.nullValue;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
 import static org.mockito.ArgumentMatchers.any;
 import static org.mockito.ArgumentMatchers.anyBoolean;
 import static org.mockito.Mockito.mock;
@@ -59,6 +63,7 @@ import org.openecomp.sdc.be.tosca.model.ToscaNodeType;
 import org.openecomp.sdc.be.tosca.model.ToscaProperty;
 import org.openecomp.sdc.be.tosca.model.ToscaPropertyConstraint;
 import org.openecomp.sdc.be.tosca.model.ToscaPropertyConstraintValidValues;
+import org.openecomp.sdc.be.tosca.model.ToscaRequirement;
 import org.openecomp.sdc.be.tosca.model.ToscaTemplate;
 import org.openecomp.sdc.be.tosca.model.ToscaTemplateCapability;
 import org.openecomp.sdc.be.tosca.model.ToscaTopolgyTemplate;
@@ -70,6 +75,9 @@ class NsDescriptorGeneratorImplTest {
 
     private static final String VNFD_AMF_NODE_NAME = "vnfd_amf";
     private static final String VIRTUAL_LINK_REQUIREMENT_NAME = "virtual_link";
+    private static final String VIRTUAL_BINDING_REQUIREMENT_NAME = "virtual_binding";
+    private static final String DOT = ".";
+    private static final String PREFIX = "VNF";
     private final ObjectProvider<ToscaTemplateYamlGenerator> toscaTemplateYamlGeneratorProvider = new ObjectProvider<>() {
         @Override
         public ToscaTemplateYamlGenerator getObject(Object... args) {
@@ -142,8 +150,8 @@ class NsDescriptorGeneratorImplTest {
         componentToscaTopologyTemplate.setNode_templates(nodeTemplateMap);
         final SubstitutionMapping substitutionMapping = mock(SubstitutionMapping.class);
         Map<String, String[]> requirements = new HashMap<>();
-        String[] requirementAssignment = {"VNF1", VIRTUAL_LINK_REQUIREMENT_NAME};
-        requirements.put(VIRTUAL_LINK_REQUIREMENT_NAME, requirementAssignment);
+        String[] requirementAssignmentVl = {"VNF1", PREFIX + DOT + VIRTUAL_LINK_REQUIREMENT_NAME};
+        requirements.put("VNF1" + DOT + VIRTUAL_LINK_REQUIREMENT_NAME, requirementAssignmentVl);
         when(substitutionMapping.getRequirements()).thenReturn(requirements);
         Map<String, String[]> capabilities = new HashMap<>();
         String[] capabilitiesAssignment = {"VNF1", "capability1"};
@@ -157,6 +165,12 @@ class NsDescriptorGeneratorImplTest {
         final String invariantIdPropertyValue = "invariantIdValue";
         final ToscaNodeType interfaceToscaNodeType = createDefaultInterfaceToscaNodeType(designerPropertyValue, versionPropertyValue,
             namePropertyValue, invariantIdPropertyValue);
+        List<Map<String, ToscaRequirement>> interfaceNodeTypeRequirements = new ArrayList<>();
+        Map<String, ToscaRequirement> interfaceNodeTypeRequirementMap = new HashMap<>();
+        interfaceNodeTypeRequirementMap.put("VNF1" + DOT + VIRTUAL_LINK_REQUIREMENT_NAME, mock(ToscaRequirement.class));
+        interfaceNodeTypeRequirementMap.put("VNF1" + DOT + VIRTUAL_BINDING_REQUIREMENT_NAME, mock(ToscaRequirement.class));
+        interfaceNodeTypeRequirements.add(interfaceNodeTypeRequirementMap);
+        interfaceToscaNodeType.setRequirements(interfaceNodeTypeRequirements);
         final String nsNodeTypeName = "nsNodeTypeName";
         componentInterfaceToscaTemplate.setNode_types(ImmutableMap.of(nsNodeTypeName, interfaceToscaNodeType));
         when(toscaExportHandler.convertToToscaTemplate(component)).thenReturn(Either.left(componentToscaTemplate));
@@ -185,14 +199,15 @@ class NsDescriptorGeneratorImplTest {
         assertThat("substitution_mappings->node_type should not be null", substitutionMappings.get("node_type"), is(notNullValue()));
         assertThat("substitution_mappings->node_type should be as expected", substitutionMappings.get("node_type"), is(nsNodeTypeName));
         final Map<String, List<String>> subMappingRequirements = (Map<String, List<String>>) substitutionMappings.get("requirements");
-        assertThat(subMappingRequirements.get(VIRTUAL_LINK_REQUIREMENT_NAME).get(0), is("VNF1"));
-        assertThat(subMappingRequirements.get(VIRTUAL_LINK_REQUIREMENT_NAME).get(1), is(VIRTUAL_LINK_REQUIREMENT_NAME));
+        assertThat(subMappingRequirements.get("VNF1" + DOT + VIRTUAL_LINK_REQUIREMENT_NAME).get(0), is("VNF1"));
+        assertThat(subMappingRequirements.get("VNF1" + DOT + VIRTUAL_LINK_REQUIREMENT_NAME).get(1), is(VIRTUAL_LINK_REQUIREMENT_NAME));
+        assertEquals(1, subMappingRequirements.size());
         final Map<String, List<String>> subMappingCapabilities = (Map<String, List<String>>) substitutionMappings.get("capabilities");
-        assertThat(subMappingCapabilities.get("capability").get(0), is("VNF1"));
-        assertThat(subMappingCapabilities.get("capability").get(1), is("capability1"));
-        @SuppressWarnings("unchecked") final Map<String, Object> nodeTemplates = (Map<String, Object>) topologyTemplate.get("node_templates");
-        @SuppressWarnings("unchecked") final Map<String, Object> nodeTemplate = (Map<String, Object>) nodeTemplates.get(VNFD_AMF_NODE_NAME);
-        assertThat("capabilities should be null", nodeTemplate.get("capabilities"), is(nullValue()));
+        assertNull(subMappingCapabilities);
+        
+        @SuppressWarnings("unchecked") final Map<String, Object> nodeType = (Map<String, Object>) ((Map<String, Object>) toscaTemplateYaml.get("node_types")).get(nsNodeTypeName);
+        assertTrue(((List<Map<String, Map>>)nodeType.get("requirements")).get(0).containsKey("VNF1" + DOT + VIRTUAL_LINK_REQUIREMENT_NAME));
+        assertFalse(((List<Map<String, Map>>)nodeType.get("requirements")).get(0).containsKey("VNF1" + DOT + VIRTUAL_BINDING_REQUIREMENT_NAME));
     }
 
     private ToscaNodeType createDefaultInterfaceToscaNodeType(final String designerPropertyValue, final String versionPropertyValue,