From 0358e1dfa8f3b3b83ccfca68209ec36c0d25ca8b Mon Sep 17 00:00:00 2001 From: MichaelMorris Date: Tue, 23 Mar 2021 12:22:19 +0000 Subject: Fix ETSI NSD requirement handling Signed-off-by: MichaelMorris Issue-ID: SDC-3528 Change-Id: Ied1466e6708dfd18bcb15dfe55558c1248f920f7 --- .../nsd/generator/NsDescriptorGeneratorImpl.java | 112 +++++++++++++++------ .../generator/NsDescriptorGeneratorImplTest.java | 33 ++++-- 2 files changed, 105 insertions(+), 40 deletions(-) (limited to 'catalog-be-plugins') diff --git a/catalog-be-plugins/etsi-nfv-nsd-csar-plugin/src/main/java/org/openecomp/sdc/be/plugins/etsi/nfv/nsd/generator/NsDescriptorGeneratorImpl.java b/catalog-be-plugins/etsi-nfv-nsd-csar-plugin/src/main/java/org/openecomp/sdc/be/plugins/etsi/nfv/nsd/generator/NsDescriptorGeneratorImpl.java index 62f8e25590..f024d8f52a 100644 --- a/catalog-be-plugins/etsi-nfv-nsd-csar-plugin/src/main/java/org/openecomp/sdc/be/plugins/etsi/nfv/nsd/generator/NsDescriptorGeneratorImpl.java +++ b/catalog-be-plugins/etsi-nfv-nsd-csar-plugin/src/main/java/org/openecomp/sdc/be/plugins/etsi/nfv/nsd/generator/NsDescriptorGeneratorImpl.java @@ -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 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 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 adjustRequirementNamesToMatchVnfd(final Map requirements) { + for (final Map.Entry 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 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 nodeTemplateMap = template.getTopology_template().getNode_templates(); if (MapUtils.isEmpty(nodeTemplateMap)) { return; } for (final Entry nodeTemplate : nodeTemplateMap.entrySet()) { - final Map propertyMap = nodeTemplate.getValue().getProperties(); - if (MapUtils.isEmpty(propertyMap)) { - nodeTemplate.getValue().setProperties(null); - continue; - } - final Map editedPropertyMap = new HashMap<>(); - for (final Entry 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 nodeTemplateMap = template.getTopology_template().getNode_templates(); - if (MapUtils.isEmpty(nodeTemplateMap)) { + + private void setPropertiesForNodeTemplate(final Entry nodeTemplate) { + final Map propertyMap = nodeTemplate.getValue().getProperties(); + if (MapUtils.isEmpty(propertyMap)) { + nodeTemplate.getValue().setProperties(null); return; } - for (final Entry nodeTemplate : nodeTemplateMap.entrySet()) { - nodeTemplate.getValue().setCapabilities(null); + final Map editedPropertyMap = new HashMap<>(); + for (final Entry 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 nodeTemplateMap) { + final List> requirementAssignments = nodeTemplateMap.getValue().getRequirements(); + if (requirementAssignments != null) { + final List> requirementAssignmentsMatchingVnfdRequirements = new ArrayList<>(); + for (final Map requirementAssignment: requirementAssignments) { + final Map 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 nodeTemplate) { + nodeTemplate.getValue().setCapabilities(null); + } + private void removeOnapPropertiesFromInputs(final ToscaTemplate template) { final ToscaTopolgyTemplate topologyTemplate = template.getTopology_template(); final Map 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 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> requirementsInNsNodeType = getRequirementsForNsNodeType(nsNodeType.getRequirements(), componentToscaTemplate); + if (!requirementsInNsNodeType.isEmpty()) { + toscaNodeType.setRequirements(requirementsInNsNodeType); + } + return toscaNodeType; } + + private List> getRequirementsForNsNodeType(final List> requirements, final ToscaTemplate componentToscaTemplate) { + final Map requirementsInSubstitutionMapping = componentToscaTemplate.getTopology_template().getSubstitution_mappings().getRequirements(); + if (requirements == null || MapUtils.isEmpty(requirementsInSubstitutionMapping)) { + return Collections.emptyList(); + } + final List> requirementsToAdd = new ArrayList<>(); + for (final Map requirementMap : requirements) { + final Map 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 diff --git a/catalog-be-plugins/etsi-nfv-nsd-csar-plugin/src/test/java/org/openecomp/sdc/be/plugins/etsi/nfv/nsd/generator/NsDescriptorGeneratorImplTest.java b/catalog-be-plugins/etsi-nfv-nsd-csar-plugin/src/test/java/org/openecomp/sdc/be/plugins/etsi/nfv/nsd/generator/NsDescriptorGeneratorImplTest.java index 69d9b0fd75..cfd0ef7b90 100644 --- a/catalog-be-plugins/etsi-nfv-nsd-csar-plugin/src/test/java/org/openecomp/sdc/be/plugins/etsi/nfv/nsd/generator/NsDescriptorGeneratorImplTest.java +++ b/catalog-be-plugins/etsi-nfv-nsd-csar-plugin/src/test/java/org/openecomp/sdc/be/plugins/etsi/nfv/nsd/generator/NsDescriptorGeneratorImplTest.java @@ -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 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 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 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> interfaceNodeTypeRequirements = new ArrayList<>(); + Map 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> subMappingRequirements = (Map>) 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> subMappingCapabilities = (Map>) substitutionMappings.get("capabilities"); - assertThat(subMappingCapabilities.get("capability").get(0), is("VNF1")); - assertThat(subMappingCapabilities.get("capability").get(1), is("capability1")); - @SuppressWarnings("unchecked") final Map nodeTemplates = (Map) topologyTemplate.get("node_templates"); - @SuppressWarnings("unchecked") final Map nodeTemplate = (Map) nodeTemplates.get(VNFD_AMF_NODE_NAME); - assertThat("capabilities should be null", nodeTemplate.get("capabilities"), is(nullValue())); + assertNull(subMappingCapabilities); + + @SuppressWarnings("unchecked") final Map nodeType = (Map) ((Map) toscaTemplateYaml.get("node_types")).get(nsNodeTypeName); + assertTrue(((List>)nodeType.get("requirements")).get(0).containsKey("VNF1" + DOT + VIRTUAL_LINK_REQUIREMENT_NAME)); + assertFalse(((List>)nodeType.get("requirements")).get(0).containsKey("VNF1" + DOT + VIRTUAL_BINDING_REQUIREMENT_NAME)); } private ToscaNodeType createDefaultInterfaceToscaNodeType(final String designerPropertyValue, final String versionPropertyValue, -- cgit 1.2.3-korg