Refactor TAPI 2.4
[transportpce.git] / tapi / src / main / java / org / opendaylight / transportpce / tapi / topology / TopologyUtils.java
1 /*
2  * Copyright © 2021 Nokia, Inc. and others.  All rights reserved.
3  *
4  * This program and the accompanying materials are made available under the
5  * terms of the Eclipse Public License v1.0 which accompanies this distribution,
6  * and is available at http://www.eclipse.org/legal/epl-v10.html
7  */
8 package org.opendaylight.transportpce.tapi.topology;
9
10 import com.google.common.util.concurrent.FluentFuture;
11 import com.google.common.util.concurrent.ListenableFuture;
12 import java.nio.charset.Charset;
13 import java.util.ArrayList;
14 import java.util.HashMap;
15 import java.util.Iterator;
16 import java.util.List;
17 import java.util.Map;
18 import java.util.NoSuchElementException;
19 import java.util.Optional;
20 import java.util.Set;
21 import java.util.UUID;
22 import java.util.concurrent.ExecutionException;
23 import java.util.stream.Collectors;
24 import org.eclipse.jdt.annotation.NonNull;
25 import org.eclipse.jdt.annotation.Nullable;
26 import org.opendaylight.mdsal.binding.api.DataBroker;
27 import org.opendaylight.mdsal.common.api.LogicalDatastoreType;
28 import org.opendaylight.transportpce.common.InstanceIdentifiers;
29 import org.opendaylight.transportpce.common.NetworkUtils;
30 import org.opendaylight.transportpce.common.network.NetworkTransactionService;
31 import org.opendaylight.transportpce.tapi.TapiStringConstants;
32 import org.opendaylight.transportpce.tapi.utils.TapiLink;
33 import org.opendaylight.yang.gen.v1.http.org.opendaylight.transportpce.portmapping.rev231221.mapping.Mapping;
34 import org.opendaylight.yang.gen.v1.http.org.opendaylight.transportpce.portmapping.rev231221.mapping.MappingKey;
35 import org.opendaylight.yang.gen.v1.http.org.opendaylight.transportpce.portmapping.rev231221.network.Nodes;
36 import org.opendaylight.yang.gen.v1.http.org.opendaylight.transportpce.portmapping.rev231221.network.NodesKey;
37 import org.opendaylight.yang.gen.v1.http.org.openroadm.common.network.rev230526.Link1;
38 import org.opendaylight.yang.gen.v1.http.org.openroadm.common.network.rev230526.TerminationPoint1;
39 import org.opendaylight.yang.gen.v1.http.org.openroadm.network.types.rev230526.OpenroadmLinkType;
40 import org.opendaylight.yang.gen.v1.http.org.openroadm.network.types.rev230526.OpenroadmNodeType;
41 import org.opendaylight.yang.gen.v1.http.org.openroadm.network.types.rev230526.OpenroadmTpType;
42 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.network.rev180226.NodeId;
43 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.network.rev180226.networks.Network;
44 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.network.topology.rev180226.Network1;
45 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.network.topology.rev180226.Node1;
46 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.network.topology.rev180226.networks.network.Link;
47 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.network.topology.rev180226.networks.network.node.TerminationPoint;
48 import org.opendaylight.yang.gen.v1.urn.onf.otcc.yang.tapi.common.rev221121.Context;
49 import org.opendaylight.yang.gen.v1.urn.onf.otcc.yang.tapi.common.rev221121.LayerProtocolName;
50 import org.opendaylight.yang.gen.v1.urn.onf.otcc.yang.tapi.common.rev221121.Uuid;
51 import org.opendaylight.yang.gen.v1.urn.onf.otcc.yang.tapi.common.rev221121.global._class.Name;
52 import org.opendaylight.yang.gen.v1.urn.onf.otcc.yang.tapi.common.rev221121.global._class.NameBuilder;
53 import org.opendaylight.yang.gen.v1.urn.onf.otcc.yang.tapi.common.rev221121.global._class.NameKey;
54 import org.opendaylight.yang.gen.v1.urn.onf.otcc.yang.tapi.common.rev221121.tapi.context.ServiceInterfacePoint;
55 import org.opendaylight.yang.gen.v1.urn.onf.otcc.yang.tapi.common.rev221121.tapi.context.ServiceInterfacePointKey;
56 //import org.opendaylight.yang.gen.v1.urn.onf.otcc.yang.tapi.connectivity.rev221121.OwnedNodeEdgePoint1;
57 import org.opendaylight.yang.gen.v1.urn.onf.otcc.yang.tapi.topology.rev221121.context.TopologyContext;
58 import org.opendaylight.yang.gen.v1.urn.onf.otcc.yang.tapi.topology.rev221121.node.OwnedNodeEdgePoint;
59 import org.opendaylight.yang.gen.v1.urn.onf.otcc.yang.tapi.topology.rev221121.node.OwnedNodeEdgePointBuilder;
60 import org.opendaylight.yang.gen.v1.urn.onf.otcc.yang.tapi.topology.rev221121.node.OwnedNodeEdgePointKey;
61 import org.opendaylight.yang.gen.v1.urn.onf.otcc.yang.tapi.topology.rev221121.topology.LinkKey;
62 import org.opendaylight.yang.gen.v1.urn.onf.otcc.yang.tapi.topology.rev221121.topology.Node;
63 import org.opendaylight.yang.gen.v1.urn.onf.otcc.yang.tapi.topology.rev221121.topology.NodeBuilder;
64 import org.opendaylight.yang.gen.v1.urn.onf.otcc.yang.tapi.topology.rev221121.topology.NodeKey;
65 import org.opendaylight.yang.gen.v1.urn.onf.otcc.yang.tapi.topology.rev221121.topology.context.Topology;
66 import org.opendaylight.yang.gen.v1.urn.onf.otcc.yang.tapi.topology.rev221121.topology.context.TopologyBuilder;
67 import org.opendaylight.yang.gen.v1.urn.onf.otcc.yang.tapi.topology.rev221121.topology.context.TopologyKey;
68 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
69 import org.opendaylight.yangtools.yang.binding.KeyedInstanceIdentifier;
70 import org.slf4j.Logger;
71 import org.slf4j.LoggerFactory;
72
73 public final class TopologyUtils {
74
75     private final NetworkTransactionService networkTransactionService;
76     private final DataBroker dataBroker;
77     private static final Logger LOG = LoggerFactory.getLogger(TopologyUtils.class);
78     private Map<ServiceInterfacePointKey, ServiceInterfacePoint> tapiSips;
79     private final TapiLink tapiLink;
80     private String topologicalMode;
81     public static final String NOOPMODEDECLARED = "No operational mode declared in Topo for Tp {}, assumes by default ";
82
83     public TopologyUtils(NetworkTransactionService networkTransactionService, DataBroker dataBroker,
84                          TapiLink tapiLink) {
85         this.networkTransactionService = networkTransactionService;
86         this.dataBroker = dataBroker;
87         this.tapiSips = new HashMap<>();
88         this.tapiLink = tapiLink;
89         // TODO: Initially set topological mode to Full. Shall be set through the setter at controller initialization
90         this.topologicalMode = "Full";
91     }
92
93     public Network readTopology(InstanceIdentifier<Network> networkIID) throws TapiTopologyException {
94         Network topology = null;
95         ListenableFuture<Optional<Network>> topologyFuture =
96                 this.networkTransactionService.read(LogicalDatastoreType.CONFIGURATION, networkIID);
97         try {
98             topology = topologyFuture.get().orElseThrow();
99         } catch (InterruptedException e) {
100             Thread.currentThread().interrupt();
101             throw new TapiTopologyException("Unable to get from mdsal topology: " + networkIID
102                     .firstKeyOf(Network.class).getNetworkId().getValue(), e);
103         } catch (ExecutionException e) {
104             throw new TapiTopologyException("Unable to get from mdsal topology: " + networkIID
105                     .firstKeyOf(Network.class).getNetworkId().getValue(), e);
106         } catch (NoSuchElementException e) {
107             return null;
108         }
109         return topology;
110     }
111
112     public List<String> readTopologyName(Uuid topoUuid) throws TapiTopologyException {
113         Topology topology = null;
114         InstanceIdentifier<Topology> topoIID = InstanceIdentifier.builder(
115                 Context.class).augmentation(org.opendaylight.yang.gen.v1.urn
116                 .onf.otcc.yang.tapi.topology.rev221121.Context1.class).child(TopologyContext.class)
117                 .child(Topology.class, new TopologyKey(topoUuid)).build();
118
119         ListenableFuture<Optional<Topology>> topologyFuture =
120                 this.networkTransactionService.read(LogicalDatastoreType.OPERATIONAL, topoIID);
121         try {
122             topology = topologyFuture.get().orElseThrow();
123         } catch (InterruptedException e) {
124             Thread.currentThread().interrupt();
125             throw new TapiTopologyException("Unable to get from mdsal topology: " + topoIID
126                     .firstKeyOf(Topology.class).getUuid().getValue(), e);
127         } catch (ExecutionException e) {
128             throw new TapiTopologyException("Unable to get from mdsal topology: " + topoIID
129                 .firstKeyOf(Topology.class).getUuid().getValue(), e);
130         } catch (NoSuchElementException e) {
131             return null;
132         }
133         List<String> nameList = new ArrayList<>();
134         for (Map.Entry<NameKey, Name> entry : topology.getName().entrySet()) {
135             nameList.add(entry.getValue().getValue());
136         }
137         LOG.debug("Topology nameList {} = ", nameList.toString());
138         return nameList;
139     }
140
141     public Topology createFullOtnTopology() throws TapiTopologyException {
142         // read openroadm-topology
143         Network openroadmTopo = readTopology(InstanceIdentifiers.OVERLAY_NETWORK_II);
144         String topoType = this.topologicalMode.equals("Full") ? TapiStringConstants.T0_FULL_MULTILAYER
145             : TapiStringConstants.T0_TAPI_MULTILAYER;
146         Uuid topoUuid = new Uuid(UUID.nameUUIDFromBytes(topoType.getBytes(Charset.forName("UTF-8"))).toString());
147         Name name = new NameBuilder()
148             .setValue(topoType)
149             .setValueName("TAPI Topology Name")
150             .build();
151         if (openroadmTopo != null) {
152             List<Link> linkList = new ArrayList<>();
153             if (openroadmTopo.augmentation(Network1.class) != null) {
154                 linkList.addAll(openroadmTopo.augmentation(Network1.class).getLink().values());
155             }
156             List<Link> xponderOutLinkList = linkList.stream()
157                 .filter(lk -> lk.augmentation(Link1.class).getLinkType().equals(OpenroadmLinkType.XPONDEROUTPUT))
158                 .collect(Collectors.toList());
159             List<Link> xponderInLinkList = linkList.stream()
160                 .filter(lk -> lk.augmentation(Link1.class).getLinkType().equals(OpenroadmLinkType.XPONDERINPUT))
161                 .collect(Collectors.toList());
162             // read otn-topology
163             Network otnTopo = readTopology(InstanceIdentifiers.OTN_NETWORK_II);
164             Map<NodeId, org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang
165                 .ietf.network.rev180226.networks.network.Node> otnNodeMap = otnTopo.nonnullNode()
166                 .values().stream().collect(Collectors.toMap(org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang
167                     .ietf.network.rev180226.networks.network.Node::getNodeId, node -> node));
168
169             Map<String, List<String>> networkPortMap = new HashMap<>();
170             Iterator<Map.Entry<NodeId, org.opendaylight.yang.gen.v1.urn
171                 .ietf.params.xml.ns.yang.ietf.network.rev180226.networks.network.Node>> itOtnNodeMap = otnNodeMap
172                 .entrySet().iterator();
173             while (itOtnNodeMap.hasNext()) {
174                 Map.Entry<NodeId, org.opendaylight.yang.gen.v1.urn
175                     .ietf.params.xml.ns.yang.ietf.network.rev180226.networks.network.Node> entry = itOtnNodeMap.next();
176                 String portMappingNodeId = entry.getValue().getSupportingNode().values().stream()
177                     .filter(sn -> sn.getNetworkRef().getValue().equals(NetworkUtils.UNDERLAY_NETWORK_ID))
178                     .findFirst()
179                     .orElseThrow().getNodeRef().getValue();
180                 List<String> networkPortList = new ArrayList<>();
181                 for (TerminationPoint tp: entry.getValue().augmentation(Node1.class).getTerminationPoint().values()) {
182                     // TODO -> why are we checking with respect to XPDR links?? Is there a real purpose on doing that?
183                     if (tp.augmentation(TerminationPoint1.class).getTpType().equals(OpenroadmTpType.XPONDERNETWORK)
184                         && checkTp(entry.getKey().getValue(), portMappingNodeId, tp, xponderOutLinkList,
185                         xponderInLinkList)) {
186                         networkPortList.add(tp.getTpId().getValue());
187                     }
188                 }
189                 if (!networkPortList.isEmpty()) {
190                     networkPortMap.put(entry.getKey().getValue(), networkPortList);
191                 }
192             }
193             Map<NodeKey, org.opendaylight.yang.gen.v1.urn.onf.otcc.yang.tapi.topology.rev221121.topology.Node>
194                 tapiNodeList = new HashMap<>();
195             Map<LinkKey, org.opendaylight.yang.gen.v1.urn.onf.otcc.yang.tapi.topology.rev221121.topology.Link>
196                 tapiLinkList = new HashMap<>();
197             ConvertORTopoToTapiFullTopo tapiFullFactory = new ConvertORTopoToTapiFullTopo(topoUuid, this.tapiLink);
198             ConvertORToTapiTopology tapiFactory = new ConvertORToTapiTopology(topoUuid);
199             Iterator<Map.Entry<String, List<String>>> it = networkPortMap.entrySet().iterator();
200             while (it.hasNext()) {
201                 String nodeId = it.next().getKey();
202                 tapiFactory.convertNode(otnNodeMap.get(new NodeId(nodeId)), networkPortMap.get(nodeId));
203                 this.tapiSips.putAll(tapiFactory.getTapiSips());
204                 tapiFullFactory.setTapiNodes(tapiFactory.getTapiNodes());
205                 tapiFullFactory.setTapiSips(tapiFactory.getTapiSips());
206                 tapiNodeList.putAll(tapiFactory.getTapiNodes());
207                 tapiLinkList.putAll(tapiFullFactory.getTapiLinks());
208             }
209             // roadm infrastructure not abstracted
210             // read openroadm-network
211             Network openroadmNet = readTopology(InstanceIdentifiers.UNDERLAY_NETWORK_II);
212             if (openroadmNet != null && openroadmNet.nonnullNode().values().stream()
213                 .filter(nt -> nt
214                     .augmentation(org.opendaylight.yang.gen.v1.http.org.openroadm.common.network.rev230526.Node1.class)
215                     .getNodeType()
216                     .equals(OpenroadmNodeType.ROADM))
217                 .count() > 0) {
218                 // map roadm nodes
219                 if (this.topologicalMode.equals("Full")) {
220                     for (org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.network.rev180226.networks
221                         .network.Node roadm:openroadmNet.nonnullNode().values().stream()
222                         .filter(nt -> nt
223                             .augmentation(
224                                 org.opendaylight.yang.gen.v1.http.org.openroadm.common.network.rev230526.Node1.class)
225                             .getNodeType()
226                             .equals(OpenroadmNodeType.ROADM))
227                         .collect(Collectors.toList())) {
228                         tapiFullFactory.convertRoadmNode(roadm, openroadmTopo, "Full");
229                         this.tapiSips.putAll(tapiFullFactory.getTapiSips());
230                         tapiNodeList.putAll(tapiFullFactory.getTapiNodes());
231                         tapiLinkList.putAll(tapiFullFactory.getTapiLinks());
232                         // map roadm to roadm link
233                         List<Link> rdmTordmLinkList = linkList.stream()
234                             .filter(lk -> lk.augmentation(Link1.class).getLinkType()
235                                 .equals(OpenroadmLinkType.ROADMTOROADM))
236                             .collect(Collectors.toList());
237                         tapiFullFactory.convertRdmToRdmLinks(rdmTordmLinkList);
238                         tapiLinkList.putAll(tapiFullFactory.getTapiLinks());
239                     }
240                 } else {
241                     tapiFullFactory.convertRoadmNode(null, openroadmTopo, "Abstracted");
242                     this.tapiSips.putAll(tapiFullFactory.getTapiSips());
243                     tapiNodeList.putAll(tapiFullFactory.getTapiNodes());
244                     tapiLinkList.putAll(tapiFullFactory.getTapiLinks());
245                 }
246
247             } else {
248                 LOG.warn("No roadm nodes exist in the network");
249             }
250
251             // map xpdr_input to roadm and xpdr_output to roadm links.
252             xponderInLinkList.addAll(xponderOutLinkList);
253             tapiFullFactory.convertXpdrToRdmLinks(xponderInLinkList);
254             tapiLinkList.putAll(tapiFullFactory.getTapiLinks());
255
256             // Retrieve created sips map in TapiFactory when mapping all the nodes
257             this.tapiSips.putAll(tapiFullFactory.getTapiSips());
258             return new TopologyBuilder()
259                 .setName(Map.of(name.key(), name))
260                 .setUuid(topoUuid)
261                 .setNode(tapiNodeList)
262                 .setLayerProtocolName(Set.of(LayerProtocolName.PHOTONICMEDIA, LayerProtocolName.ODU,
263                     LayerProtocolName.DSR, LayerProtocolName.DIGITALOTN))
264                 .setLink(tapiLinkList).build();
265         }
266         return new TopologyBuilder()
267             .setName(Map.of(name.key(), name))
268             .setUuid(topoUuid)
269             .setLayerProtocolName(Set.of(LayerProtocolName.PHOTONICMEDIA, LayerProtocolName.ODU,
270                 LayerProtocolName.DSR, LayerProtocolName.DIGITALOTN))
271             .build();
272     }
273
274     public boolean checkTp(String nodeIdTopo, String nodeIdPortMap, TerminationPoint tp, List<Link> xpdOut,
275                            List<Link> xpdIn) {
276         LOG.info("Inside Checktp for node {}-{}", nodeIdTopo, nodeIdPortMap);
277         String networkLcp;
278         if (tp.augmentation(TerminationPoint1.class).getTpType().equals(OpenroadmTpType.XPONDERCLIENT)) {
279             networkLcp = tp.augmentation(
280                     org.opendaylight.yang.gen.v1.http.org.openroadm.common.network.rev230526.TerminationPoint1.class)
281                 .getAssociatedConnectionMapTp().iterator().next().getValue();
282         } else {
283             networkLcp = tp.getTpId().getValue();
284         }
285         LOG.info("Network LCP associated = {}", networkLcp);
286         @NonNull
287         KeyedInstanceIdentifier<Mapping, MappingKey> pmIID = InstanceIdentifier.create(
288                 org.opendaylight.yang.gen.v1.http.org.opendaylight.transportpce.portmapping.rev231221.Network.class)
289                 .child(Nodes.class, new NodesKey(nodeIdPortMap)).child(Mapping.class, new MappingKey(networkLcp));
290         @NonNull
291         FluentFuture<Optional<Mapping>> mappingOpt = this.dataBroker.newReadOnlyTransaction().read(
292                 LogicalDatastoreType.CONFIGURATION, pmIID);
293         Mapping mapping = null;
294         if (mappingOpt.isDone()) {
295             try {
296                 mapping = mappingOpt.get().orElseThrow();
297             } catch (InterruptedException | ExecutionException e) {
298                 LOG.error("Error getting mapping for {}", networkLcp,e);
299                 return false;
300             }
301         } else {
302             LOG.error("Impossible to get mapping of associated network port {} of tp {}", networkLcp, tp.getTpId()
303                     .getValue());
304             return false;
305         }
306         LOG.info("Mapping found = {}", mapping);
307         String networkPortDirection = mapping.getPortDirection();
308         switch (networkPortDirection) {
309             // TODO -> remove the part of counting only if the Network LCP is part of a Link.
310             //  We want to have all OTN nodes in the TAPI topology
311             case "bidirectional":
312                 return true;
313             case "tx":
314             case "rx":
315                 @Nullable
316                 String partnerLcp = mapping.getPartnerLcp();
317                 LOG.info("PartnerLCP = {}", partnerLcp);
318                 return true;
319             default:
320                 LOG.error("Invalid port direction for {}", networkLcp);
321                 return false;
322         }
323     }
324
325     public org.opendaylight.yang.gen.v1.urn.onf.otcc.yang.tapi.topology.rev221121.get.topology.details.output.Topology
326             transformTopology(Topology topology) {
327         org.opendaylight.yang.gen.v1.urn.onf.otcc.yang.tapi.topology.rev221121
328             .get.topology.details.output.TopologyBuilder topologyBuilder =
329                 new org.opendaylight.yang.gen.v1.urn.onf.otcc.yang.tapi.topology.rev221121
330             .get.topology.details.output.TopologyBuilder()
331                 .setUuid(topology.getUuid())
332                 .setName(topology.getName())
333                 .setLayerProtocolName(topology.getLayerProtocolName())
334                 .setLink(topology.getLink());
335         if (topology.nonnullNode().isEmpty()) {
336             return topologyBuilder.build();
337         }
338         Map<NodeKey, Node> mapNode = new HashMap<>();
339         for (Node node: topology.nonnullNode().values()) {
340             Map<OwnedNodeEdgePointKey, OwnedNodeEdgePoint> onepMap = new HashMap<>();
341             for (OwnedNodeEdgePoint onep: node.nonnullOwnedNodeEdgePoint().values()) {
342 //                    OwnedNodeEdgePoint1 onep1 = onep.augmentation(OwnedNodeEdgePoint1.class);
343 //                    if (onep1 == null) {
344 //                        onepMap.put(onep.key(), onep);
345 //                        continue;
346 //                    }
347                 OwnedNodeEdgePoint newOnep = new OwnedNodeEdgePointBuilder()
348                         .setUuid(onep.getUuid())
349                         .setLayerProtocolName(onep.getLayerProtocolName())
350                         .setName(onep.getName())
351                         .setSupportedCepLayerProtocolQualifierInstances(onep
352                             .getSupportedCepLayerProtocolQualifierInstances())
353                         .setAdministrativeState(onep.getAdministrativeState())
354                         .setOperationalState(onep.getOperationalState())
355                         .setLifecycleState(onep.getLifecycleState())
356 //                            .setTerminationDirection(onep.getTerminationDirection())
357 //                            .setTerminationState(onep.getTerminationState())
358                         .setDirection(onep.getDirection())
359                         .setSupportedPayloadStructure(onep.getSupportedPayloadStructure())
360                         .setAvailablePayloadStructure(onep.getAvailablePayloadStructure())
361                         .setLinkPortRole(onep.getLinkPortRole())
362                         .setMappedServiceInterfacePoint(onep.nonnullMappedServiceInterfacePoint())
363                         .build();
364                 onepMap.put(newOnep.key(), newOnep);
365             }
366             Node newNode = new NodeBuilder()
367                     .setUuid(node.getUuid())
368                     .setName(node.getName())
369                     .setOperationalState(node.getOperationalState())
370                     .setAdministrativeState(node.getAdministrativeState())
371                     .setLifecycleState(node.getLifecycleState())
372                     .setLayerProtocolName(node.getLayerProtocolName())
373                     .setNodeRuleGroup(node.getNodeRuleGroup())
374                     .setInterRuleGroup(node.getInterRuleGroup())
375                     .setOwnedNodeEdgePoint(onepMap)
376                     .build();
377             mapNode.put(newNode.key(), newNode);
378         }
379         topologyBuilder.setNode(mapNode);
380         return topologyBuilder.build();
381     }
382
383     public Map<ServiceInterfacePointKey, ServiceInterfacePoint> getSipMap() {
384         return tapiSips;
385     }
386
387     public void setTopologicalMode(String topoMode) {
388         this.topologicalMode = topoMode;
389     }
390
391     public String getTopologicalMode() {
392         return topologicalMode;
393     }
394
395 }