From 63ab11e3a5c635d69056d6f79156ce1d114fa1be Mon Sep 17 00:00:00 2001 From: MichaelMorris Date: Mon, 25 May 2020 17:08:23 +0100 Subject: [PATCH] Support the substitution_mappings in the VNFD Signed-off-by: MichaelMorris Issue-ID: SDC-2957 Change-Id: I8a385b02568b3bf3d83a250cbe36a7e7f61e710c --- .../openecomp/sdc/be/components/csar/CsarInfo.java | 28 +++++++++++++++++---- .../sdc/be/components/csar/CsarInfoTest.java | 26 +++++++++++++++---- catalog-be/src/test/resources/etsi_vnf.csar | Bin 0 -> 14280 bytes 3 files changed, 44 insertions(+), 10 deletions(-) create mode 100644 catalog-be/src/test/resources/etsi_vnf.csar diff --git a/catalog-be/src/main/java/org/openecomp/sdc/be/components/csar/CsarInfo.java b/catalog-be/src/main/java/org/openecomp/sdc/be/components/csar/CsarInfo.java index ce6d60bd3c..58beecbf20 100644 --- a/catalog-be/src/main/java/org/openecomp/sdc/be/components/csar/CsarInfo.java +++ b/catalog-be/src/main/java/org/openecomp/sdc/be/components/csar/CsarInfo.java @@ -43,12 +43,14 @@ import org.openecomp.sdc.common.log.wrappers.Logger; import org.yaml.snakeyaml.Yaml; import java.util.ArrayList; +import java.util.Collections; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Optional; import java.util.PriorityQueue; import java.util.Queue; +import java.util.Set; import java.util.regex.Pattern; import static org.openecomp.sdc.be.components.impl.ImportUtils.ResultStatusEnum; @@ -144,20 +146,25 @@ public class CsarInfo { @SuppressWarnings("unchecked") private void extractNodeTypeInfo(Map nodeTypesInfo, List> globalSubstitutes, Map.Entry entry) { - if (Pattern.compile(CsarUtils.SERVICE_TEMPLATE_PATH_PATTERN).matcher(entry.getKey()).matches()) { - if (!isGlobalSubstitute(entry.getKey())) { + if (isAServiceTemplate(entry.getKey())) { + if (isGlobalSubstitute(entry.getKey())) { + globalSubstitutes.add(entry); + } else { Map mappedToscaTemplate = (Map) new Yaml().load(new String(entry.getValue())); findToscaElement(mappedToscaTemplate, TypeUtils.ToscaTagNamesEnum.SUBSTITUTION_MAPPINGS, ToscaElementTypeEnum.MAP) .right() .on(sub->handleSubstitutionMappings(nodeTypesInfo, entry, mappedToscaTemplate, (Map)sub)); - }else { - globalSubstitutes.add(entry); } } } + + private boolean isAServiceTemplate(final String filePath) { + return Pattern.compile(CsarUtils.SERVICE_TEMPLATE_PATH_PATTERN).matcher(filePath).matches(); + } private ResultStatusEnum handleSubstitutionMappings(Map nodeTypesInfo, Map.Entry entry, Map mappedToscaTemplate, Map substitutionMappings) { - if (substitutionMappings.containsKey(TypeUtils.ToscaTagNamesEnum.NODE_TYPE.getElementName())) { + final Set nodeTypesDefinedInTemplate = findNodeTypesDefinedInTemplate(mappedToscaTemplate); + if (substitutionMappings.containsKey(TypeUtils.ToscaTagNamesEnum.NODE_TYPE.getElementName()) && !nodeTypesDefinedInTemplate.contains(substitutionMappings.get(TypeUtils.ToscaTagNamesEnum.NODE_TYPE.getElementName()))) { NodeTypeInfo nodeTypeInfo = new NodeTypeInfo(); nodeTypeInfo.setSubstitutionMapping(true); nodeTypeInfo.setType( @@ -168,6 +175,17 @@ public class CsarInfo { } return ResultStatusEnum.OK; } + + @SuppressWarnings("unchecked") + private Set findNodeTypesDefinedInTemplate(final Map mappedToscaTemplate) { + final Either nodeTypesEither = findToscaElement(mappedToscaTemplate, + TypeUtils.ToscaTagNamesEnum.NODE_TYPES, ToscaElementTypeEnum.MAP); + if (nodeTypesEither.isLeft()) { + final Map nodeTypes = (Map) nodeTypesEither.left().value(); + return nodeTypes.keySet(); + } + return Collections.emptySet(); + } private boolean isGlobalSubstitute(String fileName) { return fileName.equalsIgnoreCase(Constants.GLOBAL_SUBSTITUTION_TYPES_SERVICE_TEMPLATE) diff --git a/catalog-be/src/test/java/org/openecomp/sdc/be/components/csar/CsarInfoTest.java b/catalog-be/src/test/java/org/openecomp/sdc/be/components/csar/CsarInfoTest.java index 62fd3f9e78..a28e2efcdb 100644 --- a/catalog-be/src/test/java/org/openecomp/sdc/be/components/csar/CsarInfoTest.java +++ b/catalog-be/src/test/java/org/openecomp/sdc/be/components/csar/CsarInfoTest.java @@ -75,14 +75,19 @@ public class CsarInfoTest { @Before public void setup() throws ZipException, URISyntaxException { // given - final File csarFile = new File(CsarInfoTest.class.getClassLoader().getResource(PAYLOAD_NAME).toURI()); - final Map payload = ZipUtils.readZip(csarFile, false); - String mainTemplateContent = new String(payload.get(MAIN_TEMPLATE_NAME)); + csarInfo = createCsarInfo(PAYLOAD_NAME, MAIN_TEMPLATE_NAME); - csarInfo = new CsarInfo(user, CSAR_UUID, payload, RESOURCE_NAME, - MAIN_TEMPLATE_NAME, mainTemplateContent, true); new ConfigurationManager(new FSConfigurationSource(ExternalConfiguration.getChangeListener(), "src/test/resources/config/catalog-be")); } + + private CsarInfo createCsarInfo(final String csarFileName, final String mainTemplateName) throws URISyntaxException, ZipException { + final File csarFile = new File(CsarInfoTest.class.getClassLoader().getResource(csarFileName).toURI()); + final Map payload = ZipUtils.readZip(csarFile, false); + String mainTemplateContent = new String(payload.get(mainTemplateName)); + + return new CsarInfo(user, CSAR_UUID, payload, RESOURCE_NAME, + mainTemplateName, mainTemplateContent, true); + } @Test public void add2TimesTheSameNodeTest() { @@ -151,4 +156,15 @@ public class CsarInfoTest { final Optional softwareInformationPath = csarInfo.getSoftwareInformationPath(); assertThat("The software information yaml path should not be present", softwareInformationPath.isPresent(), is(false)); } + + @SuppressWarnings("unchecked") + @Test + public void testCreateCsarInfoEtsiVnf() throws URISyntaxException, ZipException { + final CsarInfo csarInfo = createCsarInfo("etsi_vnf.csar", "Definitions/MainServiceTemplate.yaml"); + + final String nodeTypeInSubstitutionMapping = (String) ((Map)((Map)csarInfo.getMappedToscaMainTemplate().get("topology_template")).get("substitution_mappings")).get("node_type"); + assertTrue(((Map) csarInfo.getMappedToscaMainTemplate().get("node_types")).containsKey(nodeTypeInSubstitutionMapping)); + + assertTrue(csarInfo.extractNodeTypesInfo().isEmpty()); + } } diff --git a/catalog-be/src/test/resources/etsi_vnf.csar b/catalog-be/src/test/resources/etsi_vnf.csar new file mode 100644 index 0000000000000000000000000000000000000000..93e62bc20e27ebf097b8e7e3e3199586caa7ee84 GIT binary patch literal 14280 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 literal 0 HcmV?d00001 -- 2.16.6