From 6fa01940a1dec7a323f87f7a141dbef04d8af3d3 Mon Sep 17 00:00:00 2001 From: KrupaNagabhushan Date: Wed, 21 Sep 2022 13:21:40 +0100 Subject: [PATCH] Service import - Import unknown interface types Issue-ID: SDC-4186 Signed-off-by: KrupaNagabhushan Change-Id: Idfbce90e795136ef2ea1a96f65e458db9206339f --- .../openecomp/sdc/be/components/csar/CsarInfo.java | 7 +++++ .../sdc/be/components/csar/OnboardedCsarInfo.java | 7 ++++- .../sdc/be/components/csar/ServiceCsarInfo.java | 6 +++++ .../impl/ServiceImportBusinessLogic.java | 30 +++++++++++++++++++-- .../be/components/csar/ServiceCsarInfoTest.java | 14 +++++++++- .../impl/ServiceImportBusinessLogicTest.java | 14 ++++++++++ .../resources/csars/service-Ser09080002-csar.csar | Bin 63922 -> 63966 bytes ...DataTypes.csar => serviceWithUnknownTypes.csar} | Bin 56980 -> 57080 bytes .../java/org/openecomp/sdc/be/utils/TypeUtils.java | 3 ++- 9 files changed, 76 insertions(+), 5 deletions(-) rename catalog-be/src/test/resources/csars/{serviceWithUnknownDataTypes.csar => serviceWithUnknownTypes.csar} (89%) 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 f92c1d10d2..c401660e27 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 @@ -183,6 +183,13 @@ public abstract class CsarInfo { public abstract Map getArtifactTypes(); + /** + * Get the interface types defined in the CSAR + * + * @return map with the interface type name as key and representation of the interface type definition as value + */ + public abstract Map getInterfaceTypes(); + public Map getPolicyTypes() { if (policytypeDefinitions == null) { policytypeDefinitions = new HashMap<>(); diff --git a/catalog-be/src/main/java/org/openecomp/sdc/be/components/csar/OnboardedCsarInfo.java b/catalog-be/src/main/java/org/openecomp/sdc/be/components/csar/OnboardedCsarInfo.java index 9ab767876d..7cb11806e4 100644 --- a/catalog-be/src/main/java/org/openecomp/sdc/be/components/csar/OnboardedCsarInfo.java +++ b/catalog-be/src/main/java/org/openecomp/sdc/be/components/csar/OnboardedCsarInfo.java @@ -24,6 +24,7 @@ package org.openecomp.sdc.be.components.csar; import static org.openecomp.sdc.be.components.impl.ImportUtils.findToscaElement; import static org.openecomp.sdc.be.utils.TypeUtils.ToscaTagNamesEnum.DATA_TYPES; import static org.openecomp.sdc.be.utils.TypeUtils.ToscaTagNamesEnum.GROUP_TYPES; +import static org.openecomp.sdc.be.utils.TypeUtils.ToscaTagNamesEnum.INTERFACE_TYPES; import fj.data.Either; import java.util.ArrayList; @@ -216,6 +217,11 @@ public class OnboardedCsarInfo extends CsarInfo { return getTypes(GROUP_TYPES); } + @Override + public Map getInterfaceTypes() { + return getTypes(INTERFACE_TYPES); + } + @Override public Map getCapabilityTypes() { return getTypes(ToscaTagNamesEnum.CAPABILITY_TYPES); @@ -230,5 +236,4 @@ public class OnboardedCsarInfo extends CsarInfo { types.putAll(getTypesFromTemplate(mappedToscaMainTemplate, toscaTag)); return types; } - } diff --git a/catalog-be/src/main/java/org/openecomp/sdc/be/components/csar/ServiceCsarInfo.java b/catalog-be/src/main/java/org/openecomp/sdc/be/components/csar/ServiceCsarInfo.java index 54cd29868b..3e0ea35713 100644 --- a/catalog-be/src/main/java/org/openecomp/sdc/be/components/csar/ServiceCsarInfo.java +++ b/catalog-be/src/main/java/org/openecomp/sdc/be/components/csar/ServiceCsarInfo.java @@ -41,6 +41,7 @@ import org.openecomp.sdc.be.components.impl.ImportUtils; import org.openecomp.sdc.be.components.impl.ImportUtils.ResultStatusEnum; import org.openecomp.sdc.be.components.impl.ImportUtils.ToscaElementTypeEnum; import org.openecomp.sdc.be.datatypes.enums.ResourceTypeEnum; +import org.openecomp.sdc.be.model.InterfaceDefinition; import org.openecomp.sdc.be.model.NodeTypeDefinition; import org.openecomp.sdc.be.model.NodeTypeInfo; import org.openecomp.sdc.be.model.NodeTypeMetadata; @@ -174,6 +175,11 @@ public class ServiceCsarInfo extends CsarInfo { return artifactsTypes; } + @Override + public Map getInterfaceTypes() { + return getTypes(ToscaTagNamesEnum.INTERFACE_TYPES); + } + public List getNodeTypesUsed() { if (nodeTypeDefinitions == null) { nodeTypeDefinitions = new ArrayList<>(); diff --git a/catalog-be/src/main/java/org/openecomp/sdc/be/components/impl/ServiceImportBusinessLogic.java b/catalog-be/src/main/java/org/openecomp/sdc/be/components/impl/ServiceImportBusinessLogic.java index 151717f9cd..04798ec40a 100644 --- a/catalog-be/src/main/java/org/openecomp/sdc/be/components/impl/ServiceImportBusinessLogic.java +++ b/catalog-be/src/main/java/org/openecomp/sdc/be/components/impl/ServiceImportBusinessLogic.java @@ -144,6 +144,7 @@ import org.openecomp.sdc.be.model.operations.api.StorageOperationStatus; import org.openecomp.sdc.be.model.operations.impl.ArtifactTypeOperation; import org.openecomp.sdc.be.model.operations.impl.CapabilityTypeOperation; import org.openecomp.sdc.be.model.operations.impl.GroupTypeOperation; +import org.openecomp.sdc.be.model.operations.impl.InterfaceLifecycleOperation; import org.openecomp.sdc.be.model.operations.impl.UniqueIdBuilder; import org.openecomp.sdc.be.model.tosca.ToscaPropertyType; import org.openecomp.sdc.be.resources.data.auditing.AuditingActionEnum; @@ -203,6 +204,8 @@ public class ServiceImportBusinessLogic { private final GroupTypeImportManager groupTypeImportManager; private final GroupTypeOperation groupTypeOperation; + private InterfaceLifecycleOperation interfaceLifecycleTypeOperation; + private InterfaceLifecycleTypeImportManager interfaceLifecycleTypeImportManager; private final CapabilityTypeImportManager capabilityTypeImportManager; private final CapabilityTypeOperation capabilityTypeOperation; @@ -219,6 +222,8 @@ public class ServiceImportBusinessLogic { final DataTypeBusinessLogic dataTypeBusinessLogic, final ArtifactTypeOperation artifactTypeOperation, final ArtifactTypeImportManager artifactTypeImportManager, final GroupTypeImportManager groupTypeImportManager, final GroupTypeOperation groupTypeOperation, + final InterfaceLifecycleOperation interfaceLifecycleTypeOperation, + final InterfaceLifecycleTypeImportManager interfaceLifecycleTypeImportManager, final CapabilityTypeImportManager capabilityTypeImportManager, final CapabilityTypeOperation capabilityTypeOperation) { this.componentsUtils = componentsUtils; @@ -242,6 +247,8 @@ public class ServiceImportBusinessLogic { this.artifactTypeImportManager = artifactTypeImportManager; this.groupTypeImportManager = groupTypeImportManager; this.groupTypeOperation = groupTypeOperation; + this.interfaceLifecycleTypeOperation = interfaceLifecycleTypeOperation; + this.interfaceLifecycleTypeImportManager = interfaceLifecycleTypeImportManager; this.capabilityTypeImportManager = capabilityTypeImportManager; this.capabilityTypeOperation = capabilityTypeOperation; } @@ -310,6 +317,12 @@ public class ServiceImportBusinessLogic { groupTypeImportManager.createGroupTypes(toscaTypeImportData, service.getModel(), true); } + final Map interfaceTypesToCreate = getInterfaceTypesToCreate(service.getModel(), csarInfo); + if (MapUtils.isNotEmpty(interfaceTypesToCreate)) { + interfaceLifecycleTypeImportManager + .createLifecycleTypes(new Yaml().dump(interfaceTypesToCreate), service.getModel(), true); + } + final Map capabilityTypesToCreate = getCapabilityTypesToCreate(service.getModel(), csarInfo); if (MapUtils.isNotEmpty(capabilityTypesToCreate)) { @@ -426,8 +439,21 @@ public class ServiceImportBusinessLogic { return artifactTypesToCreate; } - private boolean hasNewProperties(final Either result, - final Map> dataType) { + private Map getInterfaceTypesToCreate(final String model, final CsarInfo csarInfo) { + final Map interfaceTypesToCreate = new HashMap<>(); + Map interfacetypeMap = csarInfo.getInterfaceTypes(); + + interfacetypeMap.entrySet().forEach(interfacetypeDef -> { + Either interfaceDefinition = + interfaceLifecycleTypeOperation.getInterface(UniqueIdBuilder.buildInterfaceTypeUid(model, interfacetypeDef.getKey())); + if (interfaceDefinition.isRight() && interfaceDefinition.right().value().equals(StorageOperationStatus.NOT_FOUND)) { + interfaceTypesToCreate.put(interfacetypeDef.getKey(), interfacetypeDef.getValue()); + } + }); + return interfaceTypesToCreate; + } + + private boolean hasNewProperties(final Either result, final Map> dataType) { return result.isLeft() && dataType.containsKey("properties") && result.left().value().getProperties() != null && result.left().value().getProperties().size() != dataType.get("properties").size(); } diff --git a/catalog-be/src/test/java/org/openecomp/sdc/be/components/csar/ServiceCsarInfoTest.java b/catalog-be/src/test/java/org/openecomp/sdc/be/components/csar/ServiceCsarInfoTest.java index 80ecc212f1..add427d164 100644 --- a/catalog-be/src/test/java/org/openecomp/sdc/be/components/csar/ServiceCsarInfoTest.java +++ b/catalog-be/src/test/java/org/openecomp/sdc/be/components/csar/ServiceCsarInfoTest.java @@ -47,7 +47,7 @@ class ServiceCsarInfoTest { private User user; private static final String CSAR_UUID = "csarUUID"; - private static final String PAYLOAD_NAME = "csars/serviceWithUnknownDataTypes.csar"; + private static final String PAYLOAD_NAME = "csars/serviceWithUnknownTypes.csar"; private static final String SERVICE_NAME = "serviceWithDataType"; private static final String MAIN_TEMPLATE_NAME = "Definitions/service-Servicewithdatatype-template.yml"; @@ -78,4 +78,16 @@ return new ServiceCsarInfo(user, CSAR_UUID, payload, SERVICE_NAME, mainTemplateN ((Map) ((Map) dataTypeDefinition.get("properties")).get("prop2")).get("type")); } + @SuppressWarnings("unchecked") + @Test + void testGetInterfaceTypes() { + final Map interfaceTypes = csarInfo.getInterfaceTypes(); + assertEquals(9, interfaceTypes.size()); + final Map interfaceTypeDefinition = (Map) interfaceTypes.get( + "tosca.interfaces.test.node.lifecycle.Reconfigure"); + assertNotNull(interfaceTypeDefinition); + assertEquals("tosca.interfaces.Root", interfaceTypeDefinition.get("derived_from")); + assertEquals("reconfigure", ((Map) interfaceTypeDefinition.get("Reconfigure")).get("description")); + } + } diff --git a/catalog-be/src/test/java/org/openecomp/sdc/be/components/impl/ServiceImportBusinessLogicTest.java b/catalog-be/src/test/java/org/openecomp/sdc/be/components/impl/ServiceImportBusinessLogicTest.java index 944f51c244..faaa7e3162 100644 --- a/catalog-be/src/test/java/org/openecomp/sdc/be/components/impl/ServiceImportBusinessLogicTest.java +++ b/catalog-be/src/test/java/org/openecomp/sdc/be/components/impl/ServiceImportBusinessLogicTest.java @@ -143,6 +143,7 @@ class ServiceImportBusinessLogicTest extends ServiceImportBussinessLogicBaseTest private final GroupTypeOperation groupTypeOperation = mock(GroupTypeOperation.class); private final CapabilityTypeOperation capabilityTypeOperation = mock(CapabilityTypeOperation.class); private final CapabilityTypeImportManager capabilityTypeImportManager = mock(CapabilityTypeImportManager.class); + private final InterfaceLifecycleTypeImportManager interfaceLifecycleTypeImportManager = mock(InterfaceLifecycleTypeImportManager.class); @InjectMocks private ServiceImportBusinessLogic sIBL; @@ -256,6 +257,10 @@ class ServiceImportBusinessLogicTest extends ServiceImportBussinessLogicBaseTest when(artifactTypeOperation.getArtifactTypeByUid(contains("tosca.testartifacts.Name"))).thenReturn(Either.right(StorageOperationStatus.NOT_FOUND)); when(artifactTypeOperation.getArtifactTypeByUid(contains("tosca.artifacts"))).thenReturn(Either.left(null)); + when(interfaceLifecycleTypeOperation.getInterface(contains("tosca.interfaces"))).thenReturn(Either.left(new InterfaceDefinition())); + when(interfaceLifecycleTypeOperation.getInterface(contains("tosca.interfaces.test"))).thenReturn(Either.right(StorageOperationStatus.NOT_FOUND)); + + when(capabilityTypeOperation.getCapabilityType(anyString())) .thenReturn(Either.left(new CapabilityTypeDefinition())); when(capabilityTypeOperation.getCapabilityType(contains("tosca.testcapabilitytypes.Name"))) @@ -313,6 +318,15 @@ class ServiceImportBusinessLogicTest extends ServiceImportBussinessLogicBaseTest Map nodeTypesMap = nodeTypes.getValue(); Map newUpdatedNodeType = (Map) nodeTypesMap.get(updatedNodeType); assertEquals(8, ((Map) newUpdatedNodeType.get("properties")).size()); + + ArgumentCaptor interfaceTypes = ArgumentCaptor.forClass(String.class); + verify(interfaceLifecycleTypeImportManager).createLifecycleTypes(interfaceTypes.capture(), any(), anyBoolean()); + Map yamlInterfaceMap = new Yaml().load(interfaceTypes.getValue()); + assertEquals(3, yamlInterfaceMap.size()); + assertNotNull(yamlInterfaceMap.get("tosca.interfaces.test.node.lifecycle.Attach")); + assertNotNull(yamlInterfaceMap.get("tosca.interfaces.test.node.lifecycle.Detach")); + assertNotNull(yamlInterfaceMap.get("tosca.interfaces.test.node.lifecycle.Reconfigure")); + } @Test diff --git a/catalog-be/src/test/resources/csars/service-Ser09080002-csar.csar b/catalog-be/src/test/resources/csars/service-Ser09080002-csar.csar index c780e3484cf322b1831099f5aef673b1b7e90f78..de7d71fc376812e426fb9ec3f26faa775cefc1b4 100644 GIT binary patch delta 1759 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 FzX34FwnP8` delta 2150 zcmaKt3p87K9>;H@B;wH$#A^`siVotfs?|^xQl$i~W~@hpQ1RAAO0=pLCCgQ>GF7jR z&NeM!Nxh49)gvv_B8jwV)mDuT%G4~?x!rSiXXosi|2g-b-~V^N|KIO-?>*=H+31!k z>6TLWAxZ600gy-}P@K3)2L7{})ji-w2;`MJRjx*G0D$cRfSsh=bMR|2rU<0#1@d&V z3;^(ych&-cHUOpxbht-ktC5NbWE+^#dL0P>7B~RlzEDEJ)c$uA08jxyyikp+iZ&%d zGm*!`rcFoykh2Zjc_#nhC%&AKfB2@dD&N&2t=vV1xNaA4V>Ki+L1|8l*0yGr#HurAP>;(%)Q)RDGhzh zbK%I>MIBw)pYBsdX_pCj2HUapj?92gBO zs(oIw+-nv{UX0%TwJ|~IbkS(Z(qYq(nC#YwdetsJQG9a`%nZ#9N97vM3ruSKT_Ou=VnaL(eZG{QSG54ZCzk#dz6vIFOGiH=Eb})X-Z#dCRzb zym!EPd+W7=9*f~dTQ&;}aL%23?tb+S4HiZ^tWP31KKiq%WW~Af ztT;>b=wb|-^w^qSp70_$uhs^=H)ZgFI@-KLPAM# zn7q>UW!<|Ry@*#A+J%v0N2Kcg{JiYCYBdvG@PDnea|A8Df5u`4t9TD}+e4R!lsa0r z_Ii9jNH3JMr8fV=B*&k1#X|5z2pcew?2+b+HKKYuvn)Vu*%T6 zP?yp_fiHFmIdi^$Y&(6(IeOMhqxU zrsr8%9c%7u=IHLL(VF2JzQw)iJJ`~wIpuC!``F0)V*ob%ECmO5JQ3dbD&b=uQNoLS z&pM1uDKx$R?i^~>QxT`!Bfc%MLG4KP6l!vH zyHmomk73#-Uw@mS^PH1idA$0&Kh3?;8%njkNoNOlc6PeL+d|B7>?zmd98NO}o#7I! z?>*dL_fygFdjx@SEoFVwV&i|c@a7l*mkK^Dv5z|A=0m#t_ScvaQg>V)qi4Ttq(U@#Z+M1uBQ9G zl?lHU>Q~T`W7#!#SK6N;ipl@u^Fz31IqS_*4f+s&Wz zLxLvbi9K}(Vjs^mXLv=WNtsr5EF8;g!rZ<@i1vEDB~NB1T2IaHJmG5O#N6rdl4BP%}6Ka#Hq(tCp|lq{DD~} zyJmGU*yzc~t|0H4_zHrB^;@b8{$OoJuErY6hlD`dSQ2g8Art5S&IrNZc|PR8G4F|x z!|ItXjZF{%z;Oh=v%|h_ZQlcF<*yA)mF)(Y#AX6`wru9OD)1e+a5eNVdfrKBd!MIsPE^*=|34GOkd!hKo5JvvDid%!=4UsXFUKz!JV(3UPxFEtqd(BxaEFN^4je*~v1P{(y pfx_7@X?Zag#s