Initial tapi notification implementation
[transportpce.git] / tapi / src / main / java / org / opendaylight / transportpce / tapi / utils / TapiContext.java
index 1fc8c5c50c0b905db4ecdc00b22d3fe63ad32cce..a44e508104b4d07b2bc8316b4420037f9d28f86f 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;
@@ -35,6 +38,7 @@ 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.context.ConnectivityContextBuilder;
 import org.opendaylight.yang.gen.v1.urn.onf.otcc.yang.tapi.connectivity.rev181210.context.topology.context.topology.node.owned.node.edge.point.CepList;
 import org.opendaylight.yang.gen.v1.urn.onf.otcc.yang.tapi.connectivity.rev181210.context.topology.context.topology.node.owned.node.edge.point.CepListBuilder;
+import org.opendaylight.yang.gen.v1.urn.onf.otcc.yang.tapi.notification.rev181210.context.NotificationContextBuilder;
 import org.opendaylight.yang.gen.v1.urn.onf.otcc.yang.tapi.topology.rev181210.context.TopologyContext;
 import org.opendaylight.yang.gen.v1.urn.onf.otcc.yang.tapi.topology.rev181210.context.TopologyContextBuilder;
 import org.opendaylight.yang.gen.v1.urn.onf.otcc.yang.tapi.topology.rev181210.node.OwnedNodeEdgePoint;
@@ -56,6 +60,7 @@ public class TapiContext {
 
     private static final Logger LOG = LoggerFactory.getLogger(TapiContext.class);
     public static final String TAPI_CONTEXT = "T-API context";
+    public static final String NODE_NOT_PRESENT = "Node is not present in datastore";
     private final NetworkTransactionService networkTransactionService;
 
     public TapiContext(NetworkTransactionService networkTransactionService) {
@@ -98,13 +103,22 @@ public class TapiContext {
                         .build())
                     .build();
 
+            org.opendaylight.yang.gen.v1.urn.onf.otcc.yang.tapi.notification.rev181210.Context1 notificationContext
+                = new org.opendaylight.yang.gen.v1.urn.onf.otcc.yang.tapi.notification.rev181210.Context1Builder()
+                    .setNotificationContext(new NotificationContextBuilder()
+                        .setNotification(new HashMap<>())
+                        .setNotifSubscription(new HashMap<>())
+                        .build())
+                    .build();
+
             ContextBuilder contextBuilder = new ContextBuilder()
                     .setName(Map.of(contextName.key(), contextName))
                     .setUuid(
                         new Uuid(UUID.nameUUIDFromBytes(TAPI_CONTEXT.getBytes(Charset.forName("UTF-8"))).toString()))
                     .setServiceInterfacePoint(new HashMap<>())
                     .addAugmentation(connectivityContext)
-                    .addAugmentation(topologyContext);
+                    .addAugmentation(topologyContext)
+                    .addAugmentation(notificationContext);
 
             // todo: add notification context
             InstanceIdentifier<Context> contextIID = InstanceIdentifier.builder(Context.class).build();
@@ -182,19 +196,19 @@ public class TapiContext {
         // TODO: verify this is correct. Should we identify the context IID with the context UUID??
         try {
             org.opendaylight.yang.gen.v1.urn.onf.otcc.yang.tapi.connectivity.rev181210.context.ConnectivityContext
-                    connectivityContext = new ConnectivityContextBuilder()
-                    .setConnectivityService(connServMap)
-                    .setConnection(connectionFullMap)
-                    .build();
+                connectivityContext = new ConnectivityContextBuilder()
+                .setConnectivityService(connServMap)
+                .setConnection(connectionFullMap)
+                .build();
             InstanceIdentifier<org.opendaylight.yang.gen.v1.urn
-                    .onf.otcc.yang.tapi.connectivity.rev181210.context.ConnectivityContext> connectivitycontextIID =
+                .onf.otcc.yang.tapi.connectivity.rev181210.context.ConnectivityContext> connectivitycontextIID =
                     InstanceIdentifier.builder(Context.class).augmentation(Context1.class)
-                            .child(org.opendaylight.yang.gen.v1.urn
-                                    .onf.otcc.yang.tapi.connectivity.rev181210.context.ConnectivityContext.class)
-                            .build();
+                        .child(org.opendaylight.yang.gen.v1.urn
+                            .onf.otcc.yang.tapi.connectivity.rev181210.context.ConnectivityContext.class)
+                        .build();
             // merge in datastore
             this.networkTransactionService.merge(LogicalDatastoreType.OPERATIONAL, connectivitycontextIID,
-                    connectivityContext);
+                connectivityContext);
             this.networkTransactionService.commit().get();
             LOG.info("TAPI connectivity merged successfully.");
         } catch (InterruptedException | ExecutionException e) {
@@ -256,11 +270,13 @@ public class TapiContext {
             Optional<Node> optNode = this.networkTransactionService.read(LogicalDatastoreType.OPERATIONAL, nodeIID)
                     .get();
             if (!optNode.isPresent()) {
-                LOG.error("Node is not present in datastore");
+                LOG.error(NODE_NOT_PRESENT);
                 return null;
             }
             // TODO -> Need to remove CEPs from NEPs. If not error from get Topology details output
             Node node = optNode.get();
+            LOG.debug("NEPs of node before creating map to be returned to the getTapiNode function = {}",
+                node.getOwnedNodeEdgePoint().size());
             Map<OwnedNodeEdgePointKey, OwnedNodeEdgePoint> onepMap = new HashMap<>();
             for (OwnedNodeEdgePoint onep: node.getOwnedNodeEdgePoint().values()) {
                 if (onep.augmentation(OwnedNodeEdgePoint1.class) == null) {
@@ -282,8 +298,11 @@ public class TapiContext {
                 if (onep.getMappedServiceInterfacePoint() != null) {
                     newOnepBuilder.setMappedServiceInterfacePoint(onep.getMappedServiceInterfacePoint());
                 }
-                onepMap.put(newOnepBuilder.key(), newOnepBuilder.build());
+                OwnedNodeEdgePoint newOnep = newOnepBuilder.build();
+                onepMap.put(newOnep.key(), newOnep);
             }
+            LOG.debug("NEPs of node after creating map to be returned to the getTapiNode function = {}",
+                onepMap.size());
             return new NodeBuilder(node)
                 .setOwnedNodeEdgePoint(onepMap)
                 .build();
@@ -305,7 +324,7 @@ public class TapiContext {
                     .read(LogicalDatastoreType.OPERATIONAL, nepIID)
                     .get();
             if (!optNode.isPresent()) {
-                LOG.error("Node is not present in datastore");
+                LOG.error(NODE_NOT_PRESENT);
                 return null;
             }
             return optNode.get();
@@ -325,7 +344,7 @@ public class TapiContext {
             Optional<Link> optLink = this.networkTransactionService.read(LogicalDatastoreType.OPERATIONAL, linkIID)
                     .get();
             if (!optLink.isPresent()) {
-                LOG.error("Node is not present in datastore");
+                LOG.error(NODE_NOT_PRESENT);
                 return null;
             }
             return optLink.get();
@@ -354,4 +373,230 @@ public class TapiContext {
             return null;
         }
     }
+
+    public ConnectivityService getConnectivityService(Uuid serviceUuid) {
+        try {
+            // First read connectivity service with service uuid and update info
+            InstanceIdentifier<ConnectivityService> connectivityServIID =
+                InstanceIdentifier.builder(Context.class).augmentation(Context1.class)
+                    .child(org.opendaylight.yang.gen.v1.urn
+                        .onf.otcc.yang.tapi.connectivity.rev181210.context.ConnectivityContext.class)
+                    .child(ConnectivityService.class, new ConnectivityServiceKey(serviceUuid))
+                    .build();
+
+            Optional<ConnectivityService> optConnServ =
+                this.networkTransactionService.read(LogicalDatastoreType.OPERATIONAL, connectivityServIID).get();
+            if (!optConnServ.isPresent()) {
+                LOG.error("Connectivity service not found in tapi context");
+                return null;
+            }
+            return optConnServ.get();
+        } catch (InterruptedException | ExecutionException e) {
+            LOG.error("Connectivity service not found in tapi context. Error:", e);
+            return null;
+        }
+    }
+
+    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");
+            return;
+        }
+        for (org.opendaylight.yang.gen.v1
+                .urn.onf.otcc.yang.tapi.connectivity.rev181210.connectivity.service.Connection connection:
+                    connectivityService.getConnection().values()) {
+            deleteConnection(connection.getConnectionUuid(), serviceUuid, connectivityService.getServiceLayer());
+        }
+        InstanceIdentifier<ConnectivityService> connectivityServIID =
+                InstanceIdentifier.builder(Context.class).augmentation(Context1.class)
+                        .child(org.opendaylight.yang.gen.v1.urn
+                                .onf.otcc.yang.tapi.connectivity.rev181210.context.ConnectivityContext.class)
+                        .child(ConnectivityService.class, new ConnectivityServiceKey(serviceUuid))
+                        .build();
+        try {
+            this.networkTransactionService.delete(LogicalDatastoreType.OPERATIONAL, connectivityServIID);
+            this.networkTransactionService.commit().get();
+            LOG.info("Connectivity service deleted");
+        } catch (InterruptedException | ExecutionException e) {
+            LOG.error("Failed to delete Connectivity service", e);
+        }
+    }
+
+    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 =
+            InstanceIdentifier.builder(Context.class).augmentation(Context1.class)
+                .child(org.opendaylight.yang.gen.v1.urn
+                    .onf.otcc.yang.tapi.connectivity.rev181210.context.ConnectivityContext.class)
+                .child(org.opendaylight.yang.gen.v1.urn
+                        .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))
+                .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();
+        } catch (InterruptedException | ExecutionException e) {
+            LOG.error("Failed to delete TAPI Connection", e);
+        }
+    }
+
+    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
+            InstanceIdentifier<Connection> connIID =
+                InstanceIdentifier.builder(Context.class).augmentation(Context1.class)
+                    .child(org.opendaylight.yang.gen.v1.urn
+                        .onf.otcc.yang.tapi.connectivity.rev181210.context.ConnectivityContext.class)
+                    .child(Connection.class, new ConnectionKey(connectionUuid))
+                    .build();
+
+            Optional<Connection> optConn =
+                this.networkTransactionService.read(LogicalDatastoreType.OPERATIONAL, connIID).get();
+            if (!optConn.isPresent()) {
+                LOG.error("Connection not found in tapi context");
+                return null;
+            }
+            return optConn.get();
+        } catch (InterruptedException | ExecutionException e) {
+            LOG.error("Connection not found in tapi context. Error:", e);
+            return null;
+        }
+    }
+
+    public Map<ConnectivityServiceKey, ConnectivityService> getConnectivityServices() {
+        try {
+            // First read connectivity service with service uuid and update info
+            InstanceIdentifier<org.opendaylight.yang.gen.v1.urn
+                .onf.otcc.yang.tapi.connectivity.rev181210.context.ConnectivityContext> connectivityContextIID =
+                InstanceIdentifier.builder(Context.class).augmentation(Context1.class)
+                    .child(org.opendaylight.yang.gen.v1.urn
+                        .onf.otcc.yang.tapi.connectivity.rev181210.context.ConnectivityContext.class)
+                    .build();
+
+            Optional<org.opendaylight.yang.gen.v1.urn
+                .onf.otcc.yang.tapi.connectivity.rev181210.context.ConnectivityContext> optConnContext =
+                    this.networkTransactionService.read(LogicalDatastoreType.OPERATIONAL, connectivityContextIID)
+                        .get();
+            if (!optConnContext.isPresent()) {
+                LOG.error("Connectivity context not found in tapi context");
+                return null;
+            }
+            return optConnContext.get().getConnectivityService();
+        } catch (InterruptedException | ExecutionException e) {
+            LOG.error("Connectivity context not found in tapi context. Error:", e);
+            return null;
+        }
+    }
+
+    public ConnectionEndPoint getTapiCEP(Uuid topoUuid, Uuid nodeUuid, Uuid nepUuid, Uuid cepUuid) {
+        InstanceIdentifier<OwnedNodeEdgePoint> nepIID = InstanceIdentifier.builder(Context.class)
+            .augmentation(org.opendaylight.yang.gen.v1.urn.onf.otcc.yang.tapi.topology.rev181210.Context1.class)
+            .child(org.opendaylight.yang.gen.v1.urn.onf.otcc.yang.tapi.topology.rev181210.context.TopologyContext.class)
+            .child(Topology.class, new TopologyKey(topoUuid))
+            .child(org.opendaylight.yang.gen.v1.urn.onf.otcc.yang.tapi.topology.rev181210.topology.Node.class,
+                new NodeKey(nodeUuid)).child(OwnedNodeEdgePoint.class, new OwnedNodeEdgePointKey(nepUuid)).build();
+        try {
+            Optional<OwnedNodeEdgePoint> optNode = this.networkTransactionService
+                .read(LogicalDatastoreType.OPERATIONAL, nepIID).get();
+            if (!optNode.isPresent()) {
+                LOG.error(NODE_NOT_PRESENT);
+                return null;
+            }
+            if (optNode.get().augmentation(OwnedNodeEdgePoint1.class) == null) {
+                LOG.error("Node doesnt have ceps");
+                return null;
+            }
+            return optNode.get().augmentation(OwnedNodeEdgePoint1.class).getCepList().getConnectionEndPoint()
+                .get(new ConnectionEndPointKey(cepUuid));
+        } catch (InterruptedException | ExecutionException e) {
+            LOG.error("Couldnt read node in topology", e);
+            return null;
+        }
+    }
 }