SO and heatbridge integration for delete flow 11/97711/8
authorMunir Ahmad <munir.ahmad@bell.ca>
Tue, 29 Oct 2019 21:01:21 +0000 (17:01 -0400)
committerMunir Ahmad <munir.ahmad@bell.ca>
Mon, 2 Dec 2019 14:46:25 +0000 (09:46 -0500)
Issue-ID: SO-2272

Signed-off-by: Munir Ahmad <munir.ahmad@bell.ca>
Change-Id: Ie1b7ebdd1758478655779d940eabe0836834fcc4

13 files changed:
adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/vnf/MsoVnfAdapter.java
adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/vnf/MsoVnfAdapterImpl.java
adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/vnf/MsoVnfCloudifyAdapterImpl.java
adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/vnf/MsoVnfPluginAdapterImpl.java
adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/vnf/VnfAdapterRest.java
adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/vnf/VnfAdapterRestV2.java
adapters/mso-openstack-adapters/src/main/java/org/onap/so/heatbridge/HeatBridgeApi.java
adapters/mso-openstack-adapters/src/main/java/org/onap/so/heatbridge/HeatBridgeImpl.java
adapters/mso-openstack-adapters/src/main/java/org/onap/so/heatbridge/utils/HeatBridgeUtils.java
adapters/mso-openstack-adapters/src/test/java/org/onap/so/adapters/vnf/MsoVnfAdapterImplTest.java
adapters/mso-openstack-adapters/src/test/java/org/onap/so/adapters/vnf/MsoVnfCloudifyAdapterImplTest.java
adapters/mso-openstack-adapters/src/test/java/org/onap/so/adapters/vnf/MsoVnfMulticloudAdapterImplTest.java
adapters/mso-openstack-adapters/src/test/java/org/onap/so/adapters/vnf/MsoVnfPluginAdapterImplTest.java

index f6ea226..39a380d 100644 (file)
@@ -121,6 +121,8 @@ public interface MsoVnfAdapter {
             @WebParam(name = "cloudOwner") @XmlElement(required = false) String cloudOwner,
             @WebParam(name = "tenantId") @XmlElement(required = true) String tenantId,
             @WebParam(name = "vfName") @XmlElement(required = true) String vfName,
+            @WebParam(name = "vnfId") @XmlElement(required = true) String vnfId,
+            @WebParam(name = "vfModuleId") @XmlElement(required = true) String vfModuleId,
             @WebParam(name = "request") MsoRequest msoRequest,
             @WebParam(name = "vfModuleOutputs", mode = Mode.OUT) Holder<Map<String, String>> vfModuleOutputs)
             throws VnfException;
index 9d50273..77b3ca9 100644 (file)
@@ -63,6 +63,7 @@ import org.onap.so.db.catalog.data.repository.VFModuleCustomizationRepository;
 import org.onap.so.db.catalog.data.repository.VnfResourceRepository;
 import org.onap.so.db.catalog.utils.MavenLikeVersioning;
 import org.onap.so.entity.MsoRequest;
+import org.onap.so.heatbridge.HeatBridgeException;
 import org.onap.so.heatbridge.HeatBridgeApi;
 import org.onap.so.heatbridge.HeatBridgeImpl;
 import org.onap.so.logger.ErrorCode;
@@ -1137,8 +1138,8 @@ public class MsoVnfAdapterImpl implements MsoVnfAdapter {
     }
 
     @Override
-    public void deleteVfModule(String cloudSiteId, String cloudOwner, String tenantId, String vnfName,
-            MsoRequest msoRequest, Holder<Map<String, String>> outputs) throws VnfException {
+    public void deleteVfModule(String cloudSiteId, String cloudOwner, String tenantId, String vnfName, String vnfId,
+            String vfModuleId, MsoRequest msoRequest, Holder<Map<String, String>> outputs) throws VnfException {
         Map<String, Object> stackOutputs;
         try {
             stackOutputs = msoHeatUtils.queryStackForOutputs(cloudSiteId, cloudOwner, tenantId, vnfName);
@@ -1203,6 +1204,12 @@ public class MsoVnfAdapterImpl implements MsoVnfAdapter {
                 logger.error("Exception encountered while sending Confirm to Valet ", e);
             }
         }
+        // call heatbridge delete
+        try {
+            new HeatBridgeImpl().deleteVfModuleData(vnfId, vfModuleId);
+        } catch (HeatBridgeException e) {
+            logger.error("Heatbridge failed to delete AAI data for vf-module: " + vfModuleId, e);
+        }
     }
 
     @Override
index d2d8caa..d35c34a 100644 (file)
@@ -1081,8 +1081,8 @@ public class MsoVnfCloudifyAdapterImpl implements MsoVnfAdapter {
 
     }
 
-    public void deleteVfModule(String cloudSiteId, String cloudOwner, String tenantId, String vnfName,
-            MsoRequest msoRequest, Holder<Map<String, String>> outputs) throws VnfException {
+    public void deleteVfModule(String cloudSiteId, String cloudOwner, String tenantId, String vnfName, String vnfId,
+            String vfModuleId, MsoRequest msoRequest, Holder<Map<String, String>> outputs) throws VnfException {
         logger.debug("Deleting VF " + vnfName + " in " + cloudOwner + "/" + cloudSiteId + "/" + tenantId);
 
         // 1702 capture the output parameters on a delete
index ce8e284..561b212 100644 (file)
@@ -1072,8 +1072,8 @@ public class MsoVnfPluginAdapterImpl implements MsoVnfAdapter {
     }
 
 
-    public void deleteVfModule(String cloudSiteId, String cloudOwner, String tenantId, String vfModuleId,
-            MsoRequest msoRequest, Holder<Map<String, String>> outputs) throws VnfException {
+    public void deleteVfModule(String cloudSiteId, String cloudOwner, String tenantId, String vfModuleId, String vnfId,
+            String aaiVfModuleId, MsoRequest msoRequest, Holder<Map<String, String>> outputs) throws VnfException {
 
         logger.debug("Deleting VF Module " + vfModuleId + " in " + cloudOwner + "/" + cloudSiteId + "/" + tenantId);
 
index 3d632ca..58899b7 100644 (file)
@@ -179,7 +179,8 @@ public class VnfAdapterRest {
                 Holder<Map<String, String>> outputs = new Holder<>();
                 if (cloudsite != null && !cloudsite.equals(TESTING_KEYWORD)) {
                     vnfAdapter.deleteVfModule(req.getCloudSiteId(), req.getCloudOwner(), req.getTenantId(),
-                            req.getVfModuleStackId(), req.getMsoRequest(), outputs);
+                            req.getVfModuleStackId(), req.getVnfId(), req.getVfModuleId(), req.getMsoRequest(),
+                            outputs);
                 }
                 response = new DeleteVfModuleResponse(req.getVnfId(), req.getVfModuleId(), Boolean.TRUE,
                         req.getMessageId(), outputs.value);
index 1a9d867..0e70c6b 100644 (file)
@@ -195,7 +195,8 @@ public class VnfAdapterRestV2 {
                     // Support different Adapter Implementations
                     MsoVnfAdapter adapter = vnfAdapterRestUtils.getVnfAdapterImpl(mode, cloudsite);
                     adapter.deleteVfModule(req.getCloudSiteId(), req.getCloudOwner(), req.getTenantId(),
-                            req.getVfModuleStackId(), req.getMsoRequest(), outputs);
+                            req.getVfModuleStackId(), req.getVnfId(), req.getVfModuleId(), req.getMsoRequest(),
+                            outputs);
                 }
                 response = new DeleteVfModuleResponse(req.getVnfId(), req.getVfModuleId(), Boolean.TRUE,
                         req.getMessageId(), outputs.value);
index d568bc2..7eff09b 100644 (file)
@@ -150,4 +150,11 @@ public interface HeatBridgeApi {
      * @throws HeatBridgeException when failing to add openstack resource PoJos to AAI
      */
     void submitToAai() throws HeatBridgeException;
+
+    /**
+     * Delete heatbridge data for a given vf-module
+     *
+     * @throws HeatBridgeException when failing to remove heatbridge data from AAI for a given vf-module
+     */
+    void deleteVfModuleData(String vnfId, String vfModuleId) throws HeatBridgeException;
 }
index a1b3305..5e3d36d 100644 (file)
@@ -58,9 +58,12 @@ import org.onap.aai.domain.yang.SriovVfs;
 import org.onap.aai.domain.yang.Vlan;
 import org.onap.aai.domain.yang.Vlans;
 import org.onap.aai.domain.yang.Vserver;
+import org.onap.aai.domain.yang.VfModule;
 import org.onap.so.client.aai.AAIObjectType;
 import org.onap.so.client.aai.AAIResourcesClient;
 import org.onap.so.client.aai.AAISingleTransactionClient;
+import org.onap.so.client.aai.entities.AAIResultWrapper;
+import org.onap.so.client.aai.entities.Relationships;
 import org.onap.so.client.aai.entities.uri.AAIResourceUri;
 import org.onap.so.client.aai.entities.uri.AAIUriFactory;
 import org.onap.so.client.graphinventory.entities.uri.Depth;
@@ -122,6 +125,11 @@ public class HeatBridgeImpl implements HeatBridgeApi {
         this.transaction = resourcesClient.beginSingleTransaction();
     }
 
+    public HeatBridgeImpl() {
+        this.resourcesClient = new AAIResourcesClient();
+        this.transaction = resourcesClient.beginSingleTransaction();
+    }
+
     @Override
     public OpenstackClient authenticate() throws HeatBridgeException {
         this.osClient = new MsoCloudClientFactoryImpl(new OpenstackClientFactoryImpl()).getOpenstackClient(
@@ -418,6 +426,78 @@ public class HeatBridgeImpl implements HeatBridgeApi {
         }
     }
 
+    @Override
+    public void deleteVfModuleData(@Nonnull final String vnfId, @Nonnull final String vfModuleId)
+            throws HeatBridgeException {
+        Objects.requireNonNull(vnfId, "Null vnf-id!");
+        Objects.requireNonNull(vfModuleId, "Null vf-module-id!");
+        try {
+            Optional<VfModule> vfModule = resourcesClient.get(VfModule.class,
+                    AAIUriFactory.createResourceUri(AAIObjectType.VF_MODULE, vnfId, vfModuleId).depth(Depth.ONE));
+            if (vfModule.isPresent()) {
+
+                AAIResultWrapper resultWrapper = new AAIResultWrapper(vfModule);
+                Optional<Relationships> relationships = resultWrapper.getRelationships();
+                if (relationships.isPresent()) {
+                    List<AAIResourceUri> vserverUris = relationships.get().getRelatedUris(AAIObjectType.VSERVER);
+                    createTransactionToDeleteSriovPfFromPserver(vserverUris);
+                    if (!vserverUris.isEmpty()) {
+                        for (AAIResourceUri vserverUri : vserverUris) {
+                            resourcesClient.delete(vserverUri);
+                        }
+                    }
+                }
+            }
+        } catch (Exception e) {
+            String msg = "Failed to commit delete heatbridge data transaction";
+            logger.debug(msg + " with error: " + e);
+            throw new HeatBridgeException(msg, e);
+        }
+    }
+
+    private void createTransactionToDeleteSriovPfFromPserver(List<AAIResourceUri> vserverUris) {
+        Map<String, List<String>> pserverToPciIdMap = getPserverToPciIdMap(vserverUris);
+        for (Map.Entry<String, List<String>> entry : pserverToPciIdMap.entrySet()) {
+            String pserverName = entry.getKey();
+            List<String> pciIds = entry.getValue();
+            Optional<Pserver> pserver = resourcesClient.get(Pserver.class,
+                    AAIUriFactory.createResourceUri(AAIObjectType.PSERVER, pserverName).depth(Depth.TWO));
+            if (pserver.isPresent()) {
+                // For each pserver/p-interface match sriov-vfs by pic-id and delete them.
+                pserver.get().getPInterfaces().getPInterface().stream().filter(
+                        pIf -> pIf.getSriovPfs() != null && CollectionUtils.isNotEmpty(pIf.getSriovPfs().getSriovPf()))
+                        .forEach(pIf -> pIf.getSriovPfs().getSriovPf().forEach(sriovPf -> {
+                            if (pciIds.contains(sriovPf.getPfPciId())) {
+                                logger.debug("creating transaction to delete SR-IOV PF: " + pIf.getInterfaceName()
+                                        + " from PServer: " + pserverName);
+                                resourcesClient.delete(AAIUriFactory.createResourceUri(AAIObjectType.SRIOV_PF,
+                                        pserverName, pIf.getInterfaceName(), sriovPf.getPfPciId()));
+                            }
+                        }));
+            }
+        }
+    }
+
+    private Map<String, List<String>> getPserverToPciIdMap(List<AAIResourceUri> vserverUris) {
+        Map<String, List<String>> pserverToPciIdMap = new HashMap<>();
+        for (AAIResourceUri vserverUri : vserverUris) {
+            AAIResultWrapper vserverWrapper = resourcesClient.get(vserverUri.depth(Depth.TWO));
+            Optional<Relationships> vserverRelationships = vserverWrapper.getRelationships();
+            if (vserverRelationships.isPresent()
+                    && CollectionUtils.isNotEmpty(vserverRelationships.get().getRelatedLinks(AAIObjectType.PSERVER))) {
+                Vserver vserver = vserverWrapper.asBean(Vserver.class).get();
+                List<String> pciIds = HeatBridgeUtils.extractPciIdsFromVServer(vserver);
+                if (CollectionUtils.isNotEmpty(pciIds)) {
+                    List<String> matchingPservers = vserverRelationships.get().getRelatedLinks(AAIObjectType.PSERVER);
+                    if (matchingPservers != null && matchingPservers.size() == 1) {
+                        pserverToPciIdMap.put(matchingPservers.get(0), pciIds);
+                    }
+                }
+            }
+        }
+        return pserverToPciIdMap;
+    }
+
     private <T> Predicate<T> distinctByProperty(Function<? super T, Object> keyExtractor) {
         Map<Object, Boolean> map = new ConcurrentHashMap<>();
         return t -> map.putIfAbsent(keyExtractor.apply(t), Boolean.TRUE) == null;
index be08667..1667f98 100644 (file)
@@ -35,10 +35,15 @@ package org.onap.so.heatbridge.utils;
 
 import com.google.common.base.Preconditions;
 import com.google.common.base.Strings;
+import java.util.List;
 import java.util.Optional;
+import java.util.stream.Collectors;
 import javax.annotation.Nonnull;
+import org.apache.commons.collections.CollectionUtils;
+import org.onap.aai.domain.yang.SriovVf;
+import org.onap.aai.domain.yang.Vserver;
 
-public class HeatBridgeUtils {
+public final class HeatBridgeUtils {
 
     /**
      * IaaS naming convention for compute/p-interface to openstack/physical-network name mapping
@@ -64,4 +69,13 @@ public class HeatBridgeUtils {
         }
         return Optional.empty();
     }
+
+    public static List<String> extractPciIdsFromVServer(Vserver vserver) {
+        return vserver.getLInterfaces().getLInterface().stream()
+                .filter(lInterface -> lInterface.getSriovVfs() != null
+                        && CollectionUtils.isNotEmpty(lInterface.getSriovVfs().getSriovVf()))
+                .flatMap(lInterface -> lInterface.getSriovVfs().getSriovVf().stream()).map(SriovVf::getPciId)
+                .collect(Collectors.toList());
+    }
+
 }
index f3cad76..01726ac 100644 (file)
@@ -484,7 +484,8 @@ public class MsoVnfAdapterImplTest extends BaseRestTestUtils {
         MsoVnfAdapterImpl instance = new MsoVnfAdapterImpl();
         MsoRequest msoRequest = getMsoRequest();
         try {
-            instance.deleteVfModule("mdt1", "CloudOwner", "88a6ca3ee0394ade9403f075db23167e", "vSAMP12", msoRequest,
+            instance.deleteVfModule("mdt1", "CloudOwner", "88a6ca3ee0394ade9403f075db23167e", "vSAMP12",
+                    "5aae1e49-805c-4f9f-bd78-055bf7451157", "11420693-3f69-4c61-b3ee-9787c744e760", msoRequest,
                     new Holder<Map<String, String>>());
         } catch (Exception e) {
 
index 16cc2c3..e7ef9d9 100644 (file)
@@ -101,7 +101,8 @@ public class MsoVnfCloudifyAdapterImplTest extends BaseRestTestUtils {
         msoRequest.setRequestId("12345");
         msoRequest.setServiceInstanceId("12345");
 
-        instance.deleteVfModule("mtn13", "CloudOwner", "1234", "vfname", msoRequest, new Holder<>());
+        instance.deleteVfModule("mtn13", "CloudOwner", "1234", "vfname", "5aae1e49-805c-4f9f-bd78-055bf7451157",
+                "11420693-3f69-4c61-b3ee-9787c744e760", msoRequest, new Holder<>());
     }
 
     @Test
@@ -124,7 +125,8 @@ public class MsoVnfCloudifyAdapterImplTest extends BaseRestTestUtils {
         wireMockServer.stubFor(get(urlPathEqualTo("/v2.0/api/v3/tokens"))
                 .willReturn(aResponse().withBodyFile("OpenstackResponse_Access.json").withStatus(HttpStatus.SC_OK)));
 
-        instance.deleteVfModule("mtn13", "CloudOwner", "1234", "vfname", msoRequest, new Holder<>());
+        instance.deleteVfModule("mtn13", "CloudOwner", "1234", "vfname", "5aae1e49-805c-4f9f-bd78-055bf7451157",
+                "11420693-3f69-4c61-b3ee-9787c744e760", msoRequest, new Holder<>());
     }
 
     @Test
index 48ca0fd..0ac30cb 100644 (file)
@@ -210,7 +210,8 @@ public class MsoVnfMulticloudAdapterImplTest extends BaseRestTestUtils {
         wireMockServer.stubFor(delete(urlPathEqualTo("/api/multicloud/v1/CloudOwner/MTN13/infra_workload/workload-id"))
                 .willReturn(aResponse().withStatus(HttpStatus.SC_NO_CONTENT)));
 
-        instance.deleteVfModule("MTN13", "CloudOwner", "123", "workload-id", msoRequest, new Holder<>());
+        instance.deleteVfModule("MTN13", "CloudOwner", "123", "workload-id", "5aae1e49-805c-4f9f-bd78-055bf7451157",
+                "11420693-3f69-4c61-b3ee-9787c744e760", msoRequest, new Holder<>());
     }
 
     @Test
index 7ec8e51..ede25c5 100644 (file)
@@ -134,7 +134,8 @@ public class MsoVnfPluginAdapterImplTest extends BaseRestTestUtils {
         expectedException.expect(VnfException.class);
         MsoRequest msoRequest = getMsoRequest();
         msoVnfPluginAdapter.deleteVfModule("mtn13", "CloudOwner", "88a6ca3ee0394ade9403f075db23167e", "vSAMP12",
-                msoRequest, new Holder<Map<String, String>>());
+                "5aae1e49-805c-4f9f-bd78-055bf7451157", "11420693-3f69-4c61-b3ee-9787c744e760", msoRequest,
+                new Holder<Map<String, String>>());
     }
 
     @Test
@@ -151,7 +152,8 @@ public class MsoVnfPluginAdapterImplTest extends BaseRestTestUtils {
                                 .withStatus(HttpStatus.SC_INTERNAL_SERVER_ERROR)));
         MsoRequest msoRequest = getMsoRequest();
         msoVnfPluginAdapter.deleteVfModule("mtn13", "CloudOwner", "88a6ca3ee0394ade9403f075db23167e", "vSAMP12",
-                msoRequest, new Holder<Map<String, String>>());
+                "5aae1e49-805c-4f9f-bd78-055bf7451157", "11420693-3f69-4c61-b3ee-9787c744e760", msoRequest,
+                new Holder<Map<String, String>>());
     }
 
     private MsoRequest getMsoRequest() {