Refactor tapi-delete-connectivity service rpc 74/100474/12
authorJavier Errea <errea@eurecom.fr>
Thu, 7 Apr 2022 13:53:30 +0000 (15:53 +0200)
committerJavier Errea <errea@eurecom.fr>
Tue, 28 Jun 2022 10:37:53 +0000 (12:37 +0200)
- Delete connections from connectivity-context
  on delete-tapi-connectivity-service
- Add check to verify that the connection is not
  used by another service before deletion
- Delete only connections that correspond to the
  connectivity service layer

JIRA: TRNSPRTPCE-650
Signed-off-by: errea <errea@eurecom.fr>
Change-Id: Id9a31ca595156d93b59fded7476442614e3d9e07

tapi/src/main/java/org/opendaylight/transportpce/tapi/topology/TapiPortMappingListener.java
tapi/src/main/java/org/opendaylight/transportpce/tapi/utils/TapiContext.java
tests/transportpce_tests/tapi/test02_full_topology.py

index 1e2e7ce4d57baef642421bc6c0479fe471894c3b..0d1fbeee843ffedb29711fd5c6b19052605b57cc 100644 (file)
@@ -58,6 +58,9 @@ public class TapiPortMappingListener implements DataTreeChangeListener<Nodes> {
                     for (Map.Entry<MappingKey, Mapping> entry : mappingAft.entrySet()) {
                         Mapping oldMapping = mappingBef.get(entry.getKey());
                         Mapping newMapping = mappingAft.get(entry.getKey());
+                        if (oldMapping == null || newMapping == null) {
+                            continue;
+                        }
                         if (!oldMapping.getPortAdminState().equals(newMapping.getPortAdminState())
                                 || !oldMapping.getPortOperState().equals(newMapping.getPortOperState())) {
                             this.tapiNetworkModelService.updateTapiTopology(nodeId, entry.getValue());
index 045577c1fb29fdcf5c54b28af39fe70bd682456a..12f86017532d5590df78c032c001bd151f973563 100644 (file)
@@ -17,6 +17,7 @@ import org.opendaylight.mdsal.common.api.LogicalDatastoreType;
 import org.opendaylight.transportpce.common.network.NetworkTransactionService;
 import org.opendaylight.yang.gen.v1.urn.onf.otcc.yang.tapi.common.rev181210.Context;
 import org.opendaylight.yang.gen.v1.urn.onf.otcc.yang.tapi.common.rev181210.ContextBuilder;
+import org.opendaylight.yang.gen.v1.urn.onf.otcc.yang.tapi.common.rev181210.LayerProtocolName;
 import org.opendaylight.yang.gen.v1.urn.onf.otcc.yang.tapi.common.rev181210.Uuid;
 import org.opendaylight.yang.gen.v1.urn.onf.otcc.yang.tapi.common.rev181210.global._class.Name;
 import org.opendaylight.yang.gen.v1.urn.onf.otcc.yang.tapi.common.rev181210.global._class.NameBuilder;
@@ -28,6 +29,8 @@ import org.opendaylight.yang.gen.v1.urn.onf.otcc.yang.tapi.connectivity.rev18121
 import org.opendaylight.yang.gen.v1.urn.onf.otcc.yang.tapi.connectivity.rev181210.OwnedNodeEdgePoint1Builder;
 import org.opendaylight.yang.gen.v1.urn.onf.otcc.yang.tapi.connectivity.rev181210.cep.list.ConnectionEndPoint;
 import org.opendaylight.yang.gen.v1.urn.onf.otcc.yang.tapi.connectivity.rev181210.cep.list.ConnectionEndPointKey;
+import org.opendaylight.yang.gen.v1.urn.onf.otcc.yang.tapi.connectivity.rev181210.connection.LowerConnection;
+import org.opendaylight.yang.gen.v1.urn.onf.otcc.yang.tapi.connectivity.rev181210.connection.LowerConnectionKey;
 import org.opendaylight.yang.gen.v1.urn.onf.otcc.yang.tapi.connectivity.rev181210.connectivity.context.Connection;
 import org.opendaylight.yang.gen.v1.urn.onf.otcc.yang.tapi.connectivity.rev181210.connectivity.context.ConnectionKey;
 import org.opendaylight.yang.gen.v1.urn.onf.otcc.yang.tapi.connectivity.rev181210.connectivity.context.ConnectivityService;
@@ -385,6 +388,7 @@ public class TapiContext {
     }
 
     public void deleteConnectivityService(Uuid serviceUuid) {
+        // TODO: handle case where the infrastructure service is removed before the top level service?
         ConnectivityService connectivityService = getConnectivityService(serviceUuid);
         if (connectivityService == null) {
             LOG.error("Service doesnt exist in tapi context");
@@ -393,7 +397,7 @@ public class TapiContext {
         for (org.opendaylight.yang.gen.v1
                 .urn.onf.otcc.yang.tapi.connectivity.rev181210.connectivity.service.Connection connection:
                     connectivityService.getConnection().values()) {
-            deleteConnection(connection.getConnectionUuid());
+            deleteConnection(connection.getConnectionUuid(), serviceUuid, connectivityService.getServiceLayer());
         }
         InstanceIdentifier<ConnectivityService> connectivityServIID =
                 InstanceIdentifier.builder(Context.class).augmentation(Context1.class)
@@ -410,7 +414,7 @@ public class TapiContext {
         }
     }
 
-    private void deleteConnection(Uuid connectionUuid) {
+    private void deleteConnection(Uuid connectionUuid, Uuid serviceUuid, LayerProtocolName serviceLayer) {
         // First read connectivity service with service uuid and update info
         InstanceIdentifier<org.opendaylight.yang.gen.v1
             .urn.onf.otcc.yang.tapi.connectivity.rev181210.connectivity.context.Connection> connectionIID =
@@ -421,8 +425,49 @@ public class TapiContext {
                         .onf.otcc.yang.tapi.connectivity.rev181210.connectivity.context.Connection.class,
                     new org.opendaylight.yang.gen.v1.urn
                         .onf.otcc.yang.tapi.connectivity.rev181210.connectivity.context.ConnectionKey(
-                            connectionUuid))
+                        connectionUuid))
                 .build();
+        Connection connection = getConnection(connectionUuid);
+        if (connection != null && isNotUsedByOtherService(connection, serviceUuid)) {
+            Map<LowerConnectionKey, LowerConnection> lowerConnectionMap = connection.getLowerConnection();
+            if (lowerConnectionMap != null) {
+                for (LowerConnection lowerConnection:lowerConnectionMap.values()) {
+                    // check layer of connection, for DSR service we only need to delete DSR layer
+                    // connection and XC at ODU. For ODU, only need to delete ODU connections and for
+                    // photonic media services all the photonic media. And when it is ETH we need to delete
+                    // everything and also without checking the lower connection layer
+                    Connection conn1 = getConnection(lowerConnection.getConnectionUuid());
+                    if (conn1 == null) {
+                        // connection not found in tapi context
+                        continue;
+                    }
+                    LayerProtocolName lowerConnLayer = conn1.getLayerProtocolName();
+                    switch (serviceLayer.getIntValue()) {
+                        case 0:
+                        case 3:
+                            // PHOTONIC & ODU
+                            if (lowerConnLayer.equals(serviceLayer)) {
+                                deleteConnection(lowerConnection.getConnectionUuid(), serviceUuid, serviceLayer);
+                            }
+                            break;
+                        case 1:
+                            // ETH
+                            deleteConnection(lowerConnection.getConnectionUuid(), serviceUuid, serviceLayer);
+                            break;
+                        case 2:
+                            // DSR
+                            if (lowerConnLayer.equals(serviceLayer) || (lowerConnLayer.equals(LayerProtocolName.ODU)
+                                    && conn1.getName().values().stream().anyMatch(
+                                            name -> name.getValue().contains("XC")))) {
+                                deleteConnection(lowerConnection.getConnectionUuid(), serviceUuid, serviceLayer);
+                            }
+                            break;
+                        default:
+                            LOG.info("Unknown service Layer: {}", serviceLayer.getName());
+                    }
+                }
+            }
+        }
         try {
             this.networkTransactionService.delete(LogicalDatastoreType.OPERATIONAL, connectionIID);
             this.networkTransactionService.commit().get();
@@ -431,6 +476,46 @@ public class TapiContext {
         }
     }
 
+    private boolean isNotUsedByOtherService(Connection connection, Uuid serviceUuid) {
+        Map<ConnectivityServiceKey, ConnectivityService> connServicesMap = getConnectivityServices();
+        if (connServicesMap == null) {
+            LOG.info("isNotUsedByOtherService: No service in tapi context!");
+            return true;
+        }
+        for (ConnectivityService connService: connServicesMap.values()) {
+            if (connService.getConnection() == null || connService.getUuid().equals(serviceUuid)) {
+                LOG.info("isNotUsedByOtherService: There are no connections in service {} or service in loop is the "
+                        + "service to be deleted", connService.getUuid().getValue());
+                continue;
+            }
+            if (connService.getConnection().containsKey(
+                    new org.opendaylight.yang.gen.v1
+                        .urn.onf.otcc.yang.tapi.connectivity.rev181210.connectivity.service.ConnectionKey(
+                            connection.getUuid()))) {
+                LOG.info("isNotUsedByOtherService: Connection {} is in used by service {}. Cannot remove it from "
+                        + "context", connection.getUuid().getValue(), connService.getUuid().getValue());
+                return false;
+            }
+            LOG.info("isNotUsedByOtherService: Going to check lower connections");
+            for (org.opendaylight.yang.gen.v1.urn
+                        .onf.otcc.yang.tapi.connectivity.rev181210.connectivity.service.Connection
+                    conn:connService.getConnection().values()) {
+                Connection connection1 = getConnection(conn.getConnectionUuid());
+                if (connection1 == null || connection1.getLowerConnection() == null) {
+                    continue;
+                }
+                if (connection1.getLowerConnection().containsKey(new LowerConnectionKey(connection.getUuid()))) {
+                    LOG.info("isNotUsedByOtherService: Lower Connection {} is in used by service {}. Cannot remove it "
+                            + "from context", connection.getUuid().getValue(), connService.getUuid().getValue());
+                    return false;
+                }
+            }
+        }
+        LOG.info("isNotUsedByOtherService: No other service uses connection {}, therefore it can be safely deleted",
+                connection.getUuid());
+        return true;
+    }
+
     public Connection getConnection(Uuid connectionUuid) {
         try {
             // First read connectivity service with service uuid and update info
index 910ba2899952b88360e6c4e48cf9cb8857731f07..93d1eb5dd219d3bfb3f279e17f8bb898ab8b1041 100644 (file)
@@ -136,12 +136,14 @@ class TransportPCEtesting(unittest.TestCase):
         response = test_utils.mount_tapi_device("SPDR-SA1", ('spdra', self.NODE_VERSION))
         self.assertEqual(response.status_code,
                          requests.codes.created, test_utils.CODE_SHOULD_BE_201)
+        time.sleep(2)
 
     def test_02_connect_spdrC(self):
         print("Connecting SPDRC")
         response = test_utils.mount_tapi_device("SPDR-SC1", ('spdrc', self.NODE_VERSION))
         self.assertEqual(response.status_code,
                          requests.codes.created, test_utils.CODE_SHOULD_BE_201)
+        time.sleep(2)
 
     def test_03_connect_rdmA(self):
         print("Connecting ROADMA")
@@ -155,6 +157,7 @@ class TransportPCEtesting(unittest.TestCase):
         response = test_utils.mount_tapi_device("ROADM-C1", ('roadmc', self.NODE_VERSION))
         self.assertEqual(response.status_code,
                          requests.codes.created, test_utils.CODE_SHOULD_BE_201)
+        time.sleep(2)
 
     def test_05_connect_sprdA_1_N1_to_roadmA_PP1(self):
         response = test_utils.connect_xpdr_to_rdm_request("SPDR-SA1", "1", "1",
@@ -319,6 +322,7 @@ class TransportPCEtesting(unittest.TestCase):
         self.cr_serv_sample_data["input"]["end-point"][1]["layer-protocol-name"] = "ODU"
         self.cr_serv_sample_data["input"]["end-point"][1]["service-interface-point"]["service-interface-point-uuid"] = "8116d0af-39fa-3df5-bed2-dd2cd5e8217d"
         self.cr_serv_sample_data["input"]["connectivity-constraint"]["service-layer"] = "ODU"
+        self.cr_serv_sample_data["input"]["connectivity-constraint"]["service-level"] = self.uuid_services.pm
 
         response = test_utils.tapi_create_connectivity_request(self.cr_serv_sample_data)
         time.sleep(self.WAITING)
@@ -373,6 +377,7 @@ class TransportPCEtesting(unittest.TestCase):
         self.cr_serv_sample_data["input"]["end-point"][1]["service-interface-point"]["service-interface-point-uuid"] = "25812ef2-625d-3bf8-af55-5e93946d1c22"
         self.cr_serv_sample_data["input"]["connectivity-constraint"]["service-layer"] = "DSR"
         self.cr_serv_sample_data["input"]["connectivity-constraint"]["requested-capacity"]["total-size"]["value"] = "10"
+        self.cr_serv_sample_data["input"]["connectivity-constraint"]["service-level"] = self.uuid_services.odu
 
         response = test_utils.tapi_create_connectivity_request(self.cr_serv_sample_data)
         time.sleep(self.WAITING)