From: Javier Errea Date: Thu, 7 Apr 2022 13:53:30 +0000 (+0200) Subject: Refactor tapi-delete-connectivity service rpc X-Git-Tag: 5.0.0~8 X-Git-Url: https://git.opendaylight.org/gerrit/gitweb?a=commitdiff_plain;h=9ad8ef509b97a3c8a4b14220c1c046a8a1171d2b;p=transportpce.git Refactor tapi-delete-connectivity service rpc - 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 Change-Id: Id9a31ca595156d93b59fded7476442614e3d9e07 --- diff --git a/tapi/src/main/java/org/opendaylight/transportpce/tapi/topology/TapiPortMappingListener.java b/tapi/src/main/java/org/opendaylight/transportpce/tapi/topology/TapiPortMappingListener.java index 1e2e7ce4d..0d1fbeee8 100644 --- a/tapi/src/main/java/org/opendaylight/transportpce/tapi/topology/TapiPortMappingListener.java +++ b/tapi/src/main/java/org/opendaylight/transportpce/tapi/topology/TapiPortMappingListener.java @@ -58,6 +58,9 @@ public class TapiPortMappingListener implements DataTreeChangeListener { for (Map.Entry 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()); diff --git a/tapi/src/main/java/org/opendaylight/transportpce/tapi/utils/TapiContext.java b/tapi/src/main/java/org/opendaylight/transportpce/tapi/utils/TapiContext.java index 045577c1f..12f860175 100644 --- a/tapi/src/main/java/org/opendaylight/transportpce/tapi/utils/TapiContext.java +++ b/tapi/src/main/java/org/opendaylight/transportpce/tapi/utils/TapiContext.java @@ -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 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 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 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 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 diff --git a/tests/transportpce_tests/tapi/test02_full_topology.py b/tests/transportpce_tests/tapi/test02_full_topology.py index 910ba2899..93d1eb5dd 100644 --- a/tests/transportpce_tests/tapi/test02_full_topology.py +++ b/tests/transportpce_tests/tapi/test02_full_topology.py @@ -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)