Manage OTN links at 400G
[transportpce.git] / networkmodel / src / main / java / org / opendaylight / transportpce / networkmodel / service / NetworkModelServiceImpl.java
1 /*
2  * Copyright © 2016 AT&T 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.networkmodel.service;
9
10 import com.google.common.util.concurrent.ListenableFuture;
11 import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
12 import java.util.ArrayList;
13 import java.util.HashMap;
14 import java.util.List;
15 import java.util.Map;
16 import java.util.Optional;
17 import java.util.concurrent.ExecutionException;
18 import java.util.concurrent.TimeUnit;
19 import java.util.concurrent.TimeoutException;
20 import java.util.stream.Collectors;
21 import org.eclipse.jdt.annotation.Nullable;
22 import org.opendaylight.mdsal.binding.api.NotificationPublishService;
23 import org.opendaylight.mdsal.common.api.LogicalDatastoreType;
24 import org.opendaylight.transportpce.common.InstanceIdentifiers;
25 import org.opendaylight.transportpce.common.NetworkUtils;
26 import org.opendaylight.transportpce.common.mapping.PortMapping;
27 import org.opendaylight.transportpce.common.network.NetworkTransactionService;
28 import org.opendaylight.transportpce.networkmodel.R2RLinkDiscovery;
29 import org.opendaylight.transportpce.networkmodel.dto.TopologyShard;
30 import org.opendaylight.transportpce.networkmodel.util.ClliNetwork;
31 import org.opendaylight.transportpce.networkmodel.util.LinkIdUtil;
32 import org.opendaylight.transportpce.networkmodel.util.OpenRoadmNetwork;
33 import org.opendaylight.transportpce.networkmodel.util.OpenRoadmOtnTopology;
34 import org.opendaylight.transportpce.networkmodel.util.OpenRoadmTopology;
35 import org.opendaylight.transportpce.networkmodel.util.TopologyUtils;
36 import org.opendaylight.yang.gen.v1.http.org.opendaylight.transportpce.networkmodel.rev201116.TopologyUpdateResult;
37 import org.opendaylight.yang.gen.v1.http.org.opendaylight.transportpce.networkmodel.rev201116.TopologyUpdateResultBuilder;
38 import org.opendaylight.yang.gen.v1.http.org.opendaylight.transportpce.networkmodel.rev201116.topology.update.result.TopologyChanges;
39 import org.opendaylight.yang.gen.v1.http.org.opendaylight.transportpce.networkmodel.rev201116.topology.update.result.TopologyChangesBuilder;
40 import org.opendaylight.yang.gen.v1.http.org.opendaylight.transportpce.networkmodel.rev201116.topology.update.result.TopologyChangesKey;
41 import org.opendaylight.yang.gen.v1.http.org.opendaylight.transportpce.portmapping.rev210426.OpenroadmNodeVersion;
42 import org.opendaylight.yang.gen.v1.http.org.opendaylight.transportpce.portmapping.rev210426.mapping.Mapping;
43 import org.opendaylight.yang.gen.v1.http.org.opendaylight.transportpce.portmapping.rev210426.network.nodes.NodeInfo;
44 import org.opendaylight.yang.gen.v1.http.org.openroadm.device.types.rev191129.NodeTypes;
45 import org.opendaylight.yang.gen.v1.http.org.openroadm.otn.network.topology.rev200529.Link1;
46 import org.opendaylight.yang.gen.v1.http.org.openroadm.otn.network.topology.rev200529.TerminationPoint1;
47 import org.opendaylight.yang.gen.v1.http.org.transportpce.common.types.rev210618.link.tp.LinkTp;
48 import org.opendaylight.yang.gen.v1.http.org.transportpce.common.types.rev210618.link.tp.LinkTpBuilder;
49 import org.opendaylight.yang.gen.v1.http.transportpce.topology.rev210511.OtnLinkType;
50 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.network.rev180226.NetworkId;
51 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.network.rev180226.Networks;
52 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.network.rev180226.NodeId;
53 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.network.rev180226.networks.Network;
54 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.network.rev180226.networks.NetworkKey;
55 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.network.rev180226.networks.network.Node;
56 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.network.rev180226.networks.network.NodeKey;
57 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.network.topology.rev180226.LinkId;
58 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.network.topology.rev180226.Network1;
59 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.network.topology.rev180226.Node1;
60 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.network.topology.rev180226.TpId;
61 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.network.topology.rev180226.networks.network.Link;
62 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.network.topology.rev180226.networks.network.LinkKey;
63 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.network.topology.rev180226.networks.network.node.TerminationPoint;
64 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.network.topology.rev180226.networks.network.node.TerminationPointKey;
65 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.network.topology.rev180226.networks.network.node.termination.point.SupportingTerminationPoint;
66 import org.opendaylight.yang.gen.v1.urn.opendaylight.netconf.node.topology.rev150114.NetconfNodeConnectionStatus;
67 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
68 import org.opendaylight.yangtools.yang.common.Uint32;
69 import org.slf4j.Logger;
70 import org.slf4j.LoggerFactory;
71
72 public class NetworkModelServiceImpl implements NetworkModelService {
73
74     private static final Logger LOG = LoggerFactory.getLogger(NetworkModelServiceImpl.class);
75
76     private NetworkTransactionService networkTransactionService;
77     private final R2RLinkDiscovery linkDiscovery;
78     private final PortMapping portMapping;
79     private Map<String, TopologyShard> topologyShardMountedDevice;
80     private Map<String, TopologyShard> otnTopologyShardMountedDevice;
81     // Variables for creating and sending topology update notification
82     private final NotificationPublishService notificationPublishService;
83     private Map<TopologyChangesKey, TopologyChanges> topologyChanges;
84     private TopologyUpdateResult notification = null;
85
86     public NetworkModelServiceImpl(final NetworkTransactionService networkTransactionService,
87             final R2RLinkDiscovery linkDiscovery, PortMapping portMapping,
88             final NotificationPublishService notificationPublishService) {
89
90         this.networkTransactionService = networkTransactionService;
91         this.linkDiscovery = linkDiscovery;
92         this.portMapping = portMapping;
93         this.topologyShardMountedDevice = new HashMap<String, TopologyShard>();
94         this.otnTopologyShardMountedDevice = new HashMap<String, TopologyShard>();
95         this.notificationPublishService = notificationPublishService;
96         this.topologyChanges = new HashMap<TopologyChangesKey, TopologyChanges>();
97     }
98
99     public void init() {
100         LOG.info("init ...");
101     }
102
103     public void close() {
104     }
105
106     @Override
107     public void createOpenRoadmNode(String nodeId, String openRoadmVersion) {
108         try {
109             LOG.info("createOpenROADMNode: {} ", nodeId);
110
111             if (!portMapping.createMappingData(nodeId, openRoadmVersion)) {
112                 LOG.warn("Could not generate port mapping for {} skipping network model creation", nodeId);
113                 return;
114             }
115             NodeInfo nodeInfo = portMapping.getNode(nodeId).getNodeInfo();
116             // node creation in clli-network
117             Node clliNode = ClliNetwork.createNode(nodeId, nodeInfo);
118             InstanceIdentifier<Node> iiClliNode = InstanceIdentifier.builder(Networks.class)
119                 .child(Network.class, new NetworkKey(new NetworkId(NetworkUtils.CLLI_NETWORK_ID)))
120                 .child(Node.class, clliNode.key())
121                 .build();
122             LOG.info("creating node in {}", NetworkUtils.CLLI_NETWORK_ID);
123             networkTransactionService.merge(LogicalDatastoreType.CONFIGURATION, iiClliNode, clliNode);
124
125             // node creation in openroadm-network
126             Node openroadmNetworkNode = OpenRoadmNetwork.createNode(nodeId, nodeInfo);
127             InstanceIdentifier<Node> iiopenroadmNetworkNode = InstanceIdentifier.builder(Networks.class)
128                 .child(Network.class, new NetworkKey(new NetworkId(NetworkUtils.UNDERLAY_NETWORK_ID)))
129                 .child(Node.class, openroadmNetworkNode.key())
130                 .build();
131             LOG.info("creating node in {}", NetworkUtils.UNDERLAY_NETWORK_ID);
132             networkTransactionService.merge(LogicalDatastoreType.CONFIGURATION, iiopenroadmNetworkNode,
133                 openroadmNetworkNode);
134
135             // nodes/links creation in openroadm-topology
136             TopologyShard topologyShard = OpenRoadmTopology.createTopologyShard(portMapping.getNode(nodeId));
137             if (topologyShard != null) {
138                 this.topologyShardMountedDevice.put(nodeId, topologyShard);
139                 for (Node openRoadmTopologyNode : topologyShard.getNodes()) {
140                     LOG.info("creating node {} in {}", openRoadmTopologyNode.getNodeId().getValue(),
141                         NetworkUtils.OVERLAY_NETWORK_ID);
142                     InstanceIdentifier<Node> iiOpenRoadmTopologyNode = InstanceIdentifier.builder(Networks.class)
143                         .child(Network.class, new NetworkKey(new NetworkId(NetworkUtils.OVERLAY_NETWORK_ID)))
144                         .child(Node.class, openRoadmTopologyNode.key())
145                         .build();
146                     networkTransactionService.merge(LogicalDatastoreType.CONFIGURATION, iiOpenRoadmTopologyNode,
147                         openRoadmTopologyNode);
148                 }
149                 for (Link openRoadmTopologyLink : topologyShard.getLinks()) {
150                     LOG.info("creating link {} in {}", openRoadmTopologyLink.getLinkId().getValue(),
151                         NetworkUtils.OVERLAY_NETWORK_ID);
152                     InstanceIdentifier<Link> iiOpenRoadmTopologyLink = InstanceIdentifier.builder(Networks.class)
153                         .child(Network.class, new NetworkKey(new NetworkId(NetworkUtils.OVERLAY_NETWORK_ID)))
154                         .augmentation(Network1.class)
155                         .child(Link.class, openRoadmTopologyLink.key())
156                         .build();
157                     networkTransactionService.merge(LogicalDatastoreType.CONFIGURATION, iiOpenRoadmTopologyLink,
158                         openRoadmTopologyLink);
159                 }
160             } else {
161                 LOG.error("Unable to create openroadm-topology shard for node {}!", nodeId);
162             }
163             // nodes/links creation in otn-topology
164             if (nodeInfo.getNodeType().getIntValue() == 2 && (nodeInfo.getOpenroadmVersion().getIntValue() != 1)) {
165                 createOpenRoadmOtnNode(nodeId);
166             }
167             networkTransactionService.commit().get();
168             // neighbour links through LLDP
169             if (nodeInfo.getNodeType().getIntValue() == 1) {
170                 this.linkDiscovery.readLLDP(new NodeId(nodeId), openRoadmVersion);
171             }
172             LOG.info("all nodes and links created");
173         } catch (InterruptedException | ExecutionException e) {
174             LOG.error("ERROR: ", e);
175         }
176     }
177
178     @Override
179     public void setOpenRoadmNodeStatus(String nodeId, NetconfNodeConnectionStatus.ConnectionStatus connectionStatus) {
180         LOG.info("setOpenROADMNodeStatus: {} {}", nodeId, connectionStatus.name());
181         /*
182           TODO: set connection status of the device in model,
183           TODO: so we don't need to keep it in memory (Set<String> currentMountedDevice)
184           TODO: unfortunately there is no connection status OpenROADM in network models
185           TODO: waiting for new model version
186          */
187     }
188
189     /*
190      @see org.opendaylight.transportpce.networkmodel.service.NetworkModelService# deleteOpenROADMnode(java.lang.String)
191      */
192
193     @Override
194     public void deleteOpenRoadmnode(String nodeId) {
195         try {
196             NodeKey nodeIdKey = new NodeKey(new NodeId(nodeId));
197
198             LOG.info("deleting node in {}", NetworkUtils.UNDERLAY_NETWORK_ID);
199             InstanceIdentifier<Node> iiopenroadmNetworkNode = InstanceIdentifier.builder(Networks.class)
200                 .child(Network.class, new NetworkKey(new NetworkId(NetworkUtils.UNDERLAY_NETWORK_ID)))
201                 .child(Node.class, nodeIdKey)
202                 .build();
203             this.networkTransactionService.delete(LogicalDatastoreType.CONFIGURATION, iiopenroadmNetworkNode);
204
205             TopologyShard topologyShard = this.topologyShardMountedDevice.get(nodeId);
206             if (topologyShard != null) {
207                 for (Node openRoadmTopologyNode : topologyShard.getNodes()) {
208                     LOG.info("deleting node {} in {}", openRoadmTopologyNode.getNodeId().getValue(),
209                         NetworkUtils.OVERLAY_NETWORK_ID);
210                     InstanceIdentifier<Node> iiOpenRoadmTopologyNode = InstanceIdentifier.builder(Networks.class)
211                         .child(Network.class, new NetworkKey(new NetworkId(NetworkUtils.OVERLAY_NETWORK_ID)))
212                         .child(Node.class, openRoadmTopologyNode.key())
213                         .build();
214                     this.networkTransactionService.delete(LogicalDatastoreType.CONFIGURATION, iiOpenRoadmTopologyNode);
215                 }
216                 for (Link openRoadmTopologyLink : topologyShard.getLinks()) {
217                     LOG.info("deleting link {} in {}", openRoadmTopologyLink.getLinkId().getValue(),
218                         NetworkUtils.OVERLAY_NETWORK_ID);
219                     InstanceIdentifier<Link> iiOpenRoadmTopologyLink = InstanceIdentifier.builder(Networks.class)
220                         .child(Network.class, new NetworkKey(new NetworkId(NetworkUtils.OVERLAY_NETWORK_ID)))
221                         .augmentation(Network1.class)
222                         .child(Link.class, openRoadmTopologyLink.key())
223                         .build();
224                     this.networkTransactionService.delete(LogicalDatastoreType.CONFIGURATION, iiOpenRoadmTopologyLink);
225                 }
226             } else {
227                 LOG.warn("TopologyShard for node '{}' is not present", nodeId);
228             }
229             @Nullable
230             OpenroadmNodeVersion deviceVersion = this.portMapping.getNode(nodeId).getNodeInfo().getOpenroadmVersion();
231             @Nullable
232             NodeTypes nodeType = this.portMapping.getNode(nodeId).getNodeInfo().getNodeType();
233             if (nodeType.getIntValue() == 2 && deviceVersion.getIntValue() != 1) {
234                 TopologyShard otnTopologyShard = this.otnTopologyShardMountedDevice.get(nodeId);
235                 if (otnTopologyShard != null) {
236                     LOG.info("suppression de otnTopologyShard = {}", otnTopologyShard.toString());
237                     for (Node otnTopologyNode : otnTopologyShard.getNodes()) {
238                         LOG.info("deleting node {} in {}", otnTopologyNode.getNodeId().getValue(),
239                             NetworkUtils.OTN_NETWORK_ID);
240                         InstanceIdentifier<Node> iiotnTopologyNode = InstanceIdentifier.builder(Networks.class)
241                             .child(Network.class, new NetworkKey(new NetworkId(NetworkUtils.OTN_NETWORK_ID)))
242                             .child(Node.class, otnTopologyNode.key())
243                             .build();
244                         this.networkTransactionService.delete(LogicalDatastoreType.CONFIGURATION, iiotnTopologyNode);
245                     }
246                     for (Link otnTopologyLink : otnTopologyShard.getLinks()) {
247                         LOG.info("deleting link {} in {}", otnTopologyLink.getLinkId().getValue(),
248                             NetworkUtils.OTN_NETWORK_ID);
249                         InstanceIdentifier<Link> iiotnTopologyLink = InstanceIdentifier.builder(Networks.class)
250                             .child(Network.class, new NetworkKey(new NetworkId(NetworkUtils.OTN_NETWORK_ID)))
251                             .augmentation(Network1.class)
252                             .child(Link.class, otnTopologyLink.key())
253                             .build();
254                         this.networkTransactionService.delete(LogicalDatastoreType.CONFIGURATION, iiotnTopologyLink);
255                     }
256                 }
257             }
258
259             LOG.info("deleteOpenROADMnode: {} version {}", nodeId, deviceVersion.getName());
260             this.portMapping.deleteMappingData(nodeId);
261
262             this.networkTransactionService.commit().get(1, TimeUnit.SECONDS);
263             LOG.info("all nodes and links deleted ! ");
264         } catch (InterruptedException | ExecutionException | TimeoutException e) {
265             LOG.error("Error when trying to delete node : {}", nodeId, e);
266         }
267     }
268
269     @Override
270     public void updateOpenRoadmTopologies(String nodeId, Mapping mapping) {
271         LOG.info("update OpenRoadm topologies after change update from: {} ", nodeId);
272         this.topologyChanges.clear();
273         Network openroadmTopology = null;
274         Network otnTopology = null;
275         Map<LinkKey, Link> openroadmTopologyLinks = null;
276         Map<LinkKey, Link> otnTopologyLinks = null;
277         try {
278             openroadmTopology = this.networkTransactionService
279                 .read(LogicalDatastoreType.CONFIGURATION, InstanceIdentifiers.OVERLAY_NETWORK_II)
280                 .get().get();
281             if (openroadmTopology.augmentation(Network1.class) != null) {
282                 openroadmTopologyLinks = openroadmTopology.augmentation(Network1.class).getLink();
283             }
284             otnTopology = this.networkTransactionService
285                 .read(LogicalDatastoreType.CONFIGURATION, InstanceIdentifiers.OTN_NETWORK_II)
286                 .get().get();
287             if (otnTopology.augmentation(Network1.class) != null) {
288                 otnTopologyLinks = otnTopology.augmentation(Network1.class).getLink();
289             }
290         } catch (InterruptedException | ExecutionException e) {
291             LOG.error("Error when trying to update node : {}", nodeId, e);
292         }
293         if (openroadmTopology == null || otnTopology == null) {
294             LOG.warn("Error getting topologies from datastore");
295             return;
296         }
297         String abstractNodeid = String.join("-", nodeId, mapping.getLogicalConnectionPoint().split("-")[0]);
298         // nodes/links update in openroadm-topology
299         if (openroadmTopology.getNode() != null) {
300             TopologyShard topologyShard = TopologyUtils.updateTopologyShard(abstractNodeid, mapping,
301                 openroadmTopology.getNode(), openroadmTopologyLinks);
302             if (topologyShard.getLinks() != null) {
303                 for (Link link : topologyShard.getLinks()) {
304                     LOG.info("updating links {} in {}", link.getLinkId().getValue(),
305                         NetworkUtils.OVERLAY_NETWORK_ID);
306                     InstanceIdentifier<Link> iiTopologyLink = InstanceIdentifier.builder(Networks.class)
307                         .child(Network.class, new NetworkKey(new NetworkId(NetworkUtils.OVERLAY_NETWORK_ID)))
308                         .augmentation(Network1.class)
309                         .child(Link.class, link.key())
310                         .build();
311                     networkTransactionService.merge(LogicalDatastoreType.CONFIGURATION, iiTopologyLink, link);
312                 }
313             }
314             if (topologyShard.getTps() != null) {
315                 for (TerminationPoint tp : topologyShard.getTps()) {
316                     LOG.info("updating TP {} in openroadm-topology", tp.getTpId().getValue());
317                     InstanceIdentifier<TerminationPoint> iiTopologyTp = InstanceIdentifier.builder(Networks.class)
318                         .child(Network.class, new NetworkKey(new NetworkId(NetworkUtils.OVERLAY_NETWORK_ID)))
319                         .child(Node.class, new NodeKey(new NodeId(abstractNodeid)))
320                         .augmentation(Node1.class)
321                         .child(TerminationPoint.class, new TerminationPointKey(tp.getTpId()))
322                         .build();
323                     networkTransactionService.merge(LogicalDatastoreType.CONFIGURATION, iiTopologyTp, tp);
324                     TopologyChanges tc = new TopologyChangesBuilder()
325                         .withKey(new TopologyChangesKey(abstractNodeid, tp.getTpId().getValue()))
326                         .setNodeId(abstractNodeid)
327                         .setTpId(tp.getTpId().getValue())
328                         .setState(tp.augmentation(
329                             org.opendaylight.yang.gen.v1.http.org.openroadm.common.network.rev200529.TerminationPoint1
330                                 .class).getOperationalState())
331                         .build();
332                     if (!this.topologyChanges.containsKey(tc.key())) {
333                         this.topologyChanges.put(tc.key(), tc);
334                     }
335                 }
336             }
337         }
338         // nodes/links update in otn-topology
339         if (otnTopology.getNode() != null
340             && otnTopology.getNode().containsKey(new NodeKey(new NodeId(abstractNodeid)))) {
341             TopologyShard otnShard = TopologyUtils.updateTopologyShard(abstractNodeid, mapping,
342                 otnTopology.getNode(), otnTopologyLinks);
343             if (otnShard.getLinks() != null) {
344                 for (Link link : otnShard.getLinks()) {
345                     LOG.info("updating links {} in {}", link.getLinkId().getValue(),
346                         NetworkUtils.OVERLAY_NETWORK_ID);
347                     InstanceIdentifier<Link> iiTopologyLink = InstanceIdentifier.builder(Networks.class)
348                         .child(Network.class, new NetworkKey(new NetworkId(NetworkUtils.OTN_NETWORK_ID)))
349                         .augmentation(Network1.class)
350                         .child(Link.class, link.key())
351                         .build();
352                     networkTransactionService.merge(LogicalDatastoreType.CONFIGURATION, iiTopologyLink, link);
353                 }
354             }
355             if (otnShard.getTps() != null) {
356                 for (TerminationPoint tp : otnShard.getTps()) {
357                     LOG.info("updating TP {} in otn-topology", tp.getTpId().getValue());
358                     InstanceIdentifier<TerminationPoint> iiTopologyTp = InstanceIdentifier.builder(Networks.class)
359                         .child(Network.class, new NetworkKey(new NetworkId(NetworkUtils.OTN_NETWORK_ID)))
360                         .child(Node.class, new NodeKey(new NodeId(abstractNodeid)))
361                         .augmentation(Node1.class)
362                         .child(TerminationPoint.class, new TerminationPointKey(tp.getTpId()))
363                         .build();
364                     networkTransactionService.merge(LogicalDatastoreType.CONFIGURATION, iiTopologyTp, tp);
365                     TopologyChanges tc = new TopologyChangesBuilder()
366                         .withKey(new TopologyChangesKey(abstractNodeid, tp.getTpId().getValue()))
367                         .setNodeId(abstractNodeid)
368                         .setTpId(tp.getTpId().getValue())
369                         .setState(tp.augmentation(
370                             org.opendaylight.yang.gen.v1.http.org.openroadm.common.network.rev200529.TerminationPoint1
371                                 .class).getOperationalState())
372                         .build();
373                     if (!this.topologyChanges.containsKey(tc.key())) {
374                         this.topologyChanges.put(tc.key(), tc);
375                     }
376                 }
377             }
378         }
379         // commit datastore updates
380         try {
381             networkTransactionService.commit().get();
382             sendNotification();
383         } catch (InterruptedException | ExecutionException e) {
384             LOG.error("Error updating openroadm-topology", e);
385         }
386     }
387
388     @Override
389     public void createOtnLinks(String nodeA, String tpA, String nodeZ, String tpZ, OtnLinkType linkType) {
390         TopologyShard otnTopologyShard;
391         switch (linkType) {
392             case OTU4:
393             case OTUC4:
394                 otnTopologyShard = OpenRoadmOtnTopology.createOtnLinks(nodeA, tpA, nodeZ, tpZ, linkType);
395                 break;
396             case ODTU4:
397             case ODUC4:
398                 String nodeTopoA = new StringBuilder(nodeA).append("-").append(tpA.split("-")[0]).toString();
399                 String nodeTopoZ = new StringBuilder(nodeZ).append("-").append(tpZ.split("-")[0]).toString();
400                 List<LinkId> linkIdList = new ArrayList<>();
401                 String prefix;
402                 if (OtnLinkType.ODTU4.equals(linkType)) {
403                     prefix = OtnLinkType.OTU4.getName();
404                 } else {
405                     prefix = OtnLinkType.OTUC4.getName();
406                 }
407                 linkIdList.add(LinkIdUtil.buildOtnLinkId(nodeTopoA, tpA, nodeTopoZ, tpZ, prefix));
408                 linkIdList.add(LinkIdUtil.buildOtnLinkId(nodeTopoZ, tpZ, nodeTopoA, tpA, prefix));
409                 List<Link> supportedOtu4links = getOtnLinks(linkIdList);
410                 List<TerminationPoint> tps = getOtnNodeTps(nodeTopoA, tpA, nodeTopoZ, tpZ);
411                 otnTopologyShard = OpenRoadmOtnTopology.createOtnLinks(supportedOtu4links, tps, linkType);
412                 break;
413             default:
414                 LOG.error("unknown otn link type {}", linkType);
415                 otnTopologyShard = new TopologyShard(null, null);
416         }
417         if (otnTopologyShard.getLinks() != null) {
418             for (Link otnTopologyLink : otnTopologyShard.getLinks()) {
419                 LOG.info("creating and updating otn links {} in {}", otnTopologyLink.getLinkId().getValue(),
420                     NetworkUtils.OVERLAY_NETWORK_ID);
421                 InstanceIdentifier<Link> iiOtnTopologyLink = InstanceIdentifier.builder(Networks.class)
422                     .child(Network.class, new NetworkKey(new NetworkId(NetworkUtils.OTN_NETWORK_ID)))
423                     .augmentation(Network1.class)
424                     .child(Link.class, otnTopologyLink.key())
425                     .build();
426                 networkTransactionService.merge(LogicalDatastoreType.CONFIGURATION, iiOtnTopologyLink, otnTopologyLink);
427             }
428         }
429         if (otnTopologyShard.getTps() != null) {
430             for (TerminationPoint otnTopologyTp : otnTopologyShard.getTps()) {
431                 LOG.info("updating otn nodes TP {} in otn-topology", otnTopologyTp.getTpId().getValue());
432                 List<SupportingTerminationPoint> supportingTerminationPoint =
433                     new ArrayList<>(otnTopologyTp.nonnullSupportingTerminationPoint().values());
434                 InstanceIdentifier<TerminationPoint> iiOtnTopologyTp = InstanceIdentifier.builder(Networks.class)
435                     .child(Network.class, new NetworkKey(new NetworkId(NetworkUtils.OTN_NETWORK_ID)))
436                     .child(Node.class, new NodeKey(supportingTerminationPoint.get(0).getNodeRef()))
437                     .augmentation(Node1.class)
438                     .child(TerminationPoint.class, new TerminationPointKey(otnTopologyTp.getTpId()))
439                     .build();
440                 networkTransactionService.merge(LogicalDatastoreType.CONFIGURATION, iiOtnTopologyTp, otnTopologyTp);
441             }
442         }
443         try {
444             networkTransactionService.commit().get();
445         } catch (InterruptedException | ExecutionException e) {
446             LOG.error("Error adding OTN links in otn-topology", e);
447         }
448         LOG.info("OTN links created");
449     }
450
451     @Override
452     public void deleteOtnLinks(String nodeA, String tpA, String nodeZ, String tpZ, OtnLinkType linkType) {
453         TopologyShard otnTopologyShard;
454         String nodeTopoA = new StringBuilder(nodeA).append("-").append(tpA.split("-")[0]).toString();
455         String nodeTopoZ = new StringBuilder(nodeZ).append("-").append(tpZ.split("-")[0]).toString();
456         List<Link> otuLinks;
457         List<LinkId> linkIdList = new ArrayList<>();
458         String prefix;
459         switch (linkType) {
460             case OTU4:
461             case OTUC4:
462                 if (OtnLinkType.OTU4.equals(linkType)) {
463                     prefix = OtnLinkType.OTU4.getName();
464                 } else {
465                     prefix = OtnLinkType.OTUC4.getName();
466                 }
467                 linkIdList.add(LinkIdUtil.buildOtnLinkId(nodeTopoA, tpA, nodeTopoZ, tpZ, prefix));
468                 linkIdList.add(LinkIdUtil.buildOtnLinkId(nodeTopoZ, tpZ, nodeTopoA, tpA, prefix));
469                 otuLinks = getOtnLinks(linkIdList);
470                 if (checkLinks(otuLinks)) {
471                     deleteLinks(otuLinks);
472                 } else {
473                     LOG.error("Error deleting OTU4 links");
474                 }
475                 otnTopologyShard = new TopologyShard(null, null);
476                 break;
477             case ODTU4:
478             case ODUC4:
479                 String prefix2;
480                 if (OtnLinkType.ODTU4.equals(linkType)) {
481                     prefix = OtnLinkType.ODTU4.getName();
482                     prefix2 = OtnLinkType.OTU4.getName();
483                 } else {
484                     prefix = OtnLinkType.ODUC4.getName();
485                     prefix2 = OtnLinkType.OTUC4.getName();
486                 }
487                 linkIdList.add(LinkIdUtil.buildOtnLinkId(nodeTopoA, tpA, nodeTopoZ, tpZ, prefix));
488                 linkIdList.add(LinkIdUtil.buildOtnLinkId(nodeTopoZ, tpZ, nodeTopoA, tpA, prefix));
489                 List<Link> oduLinks = getOtnLinks(linkIdList);
490                 List<TerminationPoint> tps = getOtnNodeTps(nodeTopoA, tpA, nodeTopoZ, tpZ);
491                 if (checkLinks(oduLinks) && checkTerminationPoints(tps)) {
492                     deleteLinks(oduLinks);
493                     linkIdList.clear();
494                     linkIdList.add(LinkIdUtil.buildOtnLinkId(nodeTopoA, tpA, nodeTopoZ, tpZ, prefix2));
495                     linkIdList.add(LinkIdUtil.buildOtnLinkId(nodeTopoZ, tpZ, nodeTopoA, tpA, prefix2));
496                     otuLinks = getOtnLinks(linkIdList);
497                     otnTopologyShard = OpenRoadmOtnTopology.deleteOtnLinks(otuLinks, tps, linkType);
498                 } else {
499                     LOG.error("Error deleting ODU4 links");
500                     otnTopologyShard = new TopologyShard(null, null);
501                 }
502                 break;
503             default:
504                 LOG.error("unknown otn link type {}", linkType);
505                 otnTopologyShard = new TopologyShard(null, null);
506         }
507         if (otnTopologyShard.getLinks() != null) {
508             for (Link otnTopologyLink : otnTopologyShard.getLinks()) {
509                 LOG.info("deleting and updating otn links {} in {}", otnTopologyLink.getLinkId().getValue(),
510                     NetworkUtils.OVERLAY_NETWORK_ID);
511                 InstanceIdentifier<Link> iiOtnTopologyLink = InstanceIdentifier.builder(Networks.class)
512                     .child(Network.class, new NetworkKey(new NetworkId(NetworkUtils.OTN_NETWORK_ID)))
513                     .augmentation(Network1.class)
514                     .child(Link.class, otnTopologyLink.key())
515                     .build();
516                 networkTransactionService.merge(LogicalDatastoreType.CONFIGURATION, iiOtnTopologyLink, otnTopologyLink);
517             }
518         }
519         if (otnTopologyShard.getTps() != null) {
520             for (TerminationPoint otnTopologyTp : otnTopologyShard.getTps()) {
521                 LOG.info("updating otn nodes TP {} in otn-topology", otnTopologyTp.getTpId().getValue());
522                 List<SupportingTerminationPoint> supportingTerminationPoint =
523                     new ArrayList<>(otnTopologyTp.nonnullSupportingTerminationPoint().values());
524                 InstanceIdentifier<TerminationPoint> iiOtnTopologyTp = InstanceIdentifier.builder(Networks.class)
525                     .child(Network.class, new NetworkKey(new NetworkId(NetworkUtils.OTN_NETWORK_ID)))
526                     .child(Node.class, new NodeKey(supportingTerminationPoint.get(0).getNodeRef()))
527                     .augmentation(Node1.class)
528                     .child(TerminationPoint.class, new TerminationPointKey(otnTopologyTp.getTpId()))
529                     .build();
530                 networkTransactionService.put(LogicalDatastoreType.CONFIGURATION, iiOtnTopologyTp, otnTopologyTp);
531             }
532         }
533         try {
534             networkTransactionService.commit().get();
535         } catch (InterruptedException | ExecutionException e) {
536             LOG.error("Error deleting OTN links in otn-topology", e);
537         }
538         LOG.info("OTN links deletion terminated");
539     }
540
541     @Override
542     public void updateOtnLinks(
543         org.opendaylight.yang.gen.v1.http.org.opendaylight.transportpce.renderer.rev210618.renderer.rpc.result.sp.Link
544             notifLink, Uint32 serviceRate, Short tribPortNb, Short minTribSoltNb, Short maxTribSlotNb,
545             boolean isDeletion) {
546
547         LinkTp atermination = new LinkTpBuilder()
548             .setNodeId(notifLink.getATermination().getNodeId())
549             .setTpId(notifLink.getATermination().getTpId())
550             .build();
551         LinkTp ztermination = new LinkTpBuilder()
552             .setNodeId(notifLink.getZTermination().getNodeId())
553             .setTpId(notifLink.getZTermination().getTpId())
554             .build();
555         List<LinkTp> linkTerminations = new ArrayList<>();
556         linkTerminations.add(atermination);
557         linkTerminations.add(ztermination);
558
559         List<Link> supportedOdu4Links = getSupportingOdu4Links(linkTerminations);
560         List<TerminationPoint> tps = getOtnNodeTps(linkTerminations);
561         TopologyShard otnTopologyShard;
562         otnTopologyShard = OpenRoadmOtnTopology.updateOtnLinks(supportedOdu4Links, tps, serviceRate, tribPortNb,
563             minTribSoltNb, maxTribSlotNb, isDeletion);
564         if (otnTopologyShard.getLinks() != null) {
565             for (Link otnTopologyLink : otnTopologyShard.getLinks()) {
566                 LOG.info("creating and updating otn links {} in {}", otnTopologyLink.getLinkId().getValue(),
567                     NetworkUtils.OVERLAY_NETWORK_ID);
568                 InstanceIdentifier<Link> iiOtnTopologyLink = InstanceIdentifier.builder(Networks.class)
569                     .child(Network.class, new NetworkKey(new NetworkId(NetworkUtils.OTN_NETWORK_ID)))
570                     .augmentation(Network1.class)
571                     .child(Link.class, new LinkKey(new LinkId(otnTopologyLink.getLinkId().getValue())))
572                     .build();
573                 networkTransactionService.merge(LogicalDatastoreType.CONFIGURATION, iiOtnTopologyLink, otnTopologyLink);
574             }
575         }
576         if (otnTopologyShard.getTps() != null) {
577             for (TerminationPoint otnTopologyTp : otnTopologyShard.getTps()) {
578                 LOG.info("updating otn nodes TP {} in otn-topology", otnTopologyTp.getTpId().getValue());
579                 List<SupportingTerminationPoint> supportingTerminationPoint =
580                     new ArrayList<>(otnTopologyTp.nonnullSupportingTerminationPoint().values());
581                 InstanceIdentifier<TerminationPoint> iiOtnTopologyTp = InstanceIdentifier.builder(Networks.class)
582                     .child(Network.class, new NetworkKey(new NetworkId(NetworkUtils.OTN_NETWORK_ID)))
583                     .child(Node.class, new NodeKey(supportingTerminationPoint.get(0).getNodeRef()))
584                     .augmentation(Node1.class)
585                     .child(TerminationPoint.class, new TerminationPointKey(new TpId(otnTopologyTp.getTpId()
586                         .getValue())))
587                     .build();
588                 if (isDeletion) {
589                     networkTransactionService.merge(LogicalDatastoreType.CONFIGURATION, iiOtnTopologyTp, otnTopologyTp);
590                 } else {
591                     networkTransactionService.put(LogicalDatastoreType.CONFIGURATION, iiOtnTopologyTp, otnTopologyTp);
592                 }
593             }
594         }
595         try {
596             networkTransactionService.commit().get();
597         } catch (InterruptedException | ExecutionException e) {
598             LOG.error("Error updating OTN links in otn-topology", e);
599         }
600     }
601
602     private List<Link> getOtnLinks(List<LinkId> linkIds) {
603         List<Link> links = new ArrayList<>();
604         for (LinkId linkId : linkIds) {
605             InstanceIdentifier<Link> iiLink = InstanceIdentifier.builder(Networks.class)
606                 .child(Network.class, new NetworkKey(new NetworkId(NetworkUtils.OTN_NETWORK_ID)))
607                 .augmentation(Network1.class)
608                 .child(Link.class, new LinkKey(linkId))
609                 .build();
610             ListenableFuture<Optional<Link>> linkOptLf = networkTransactionService
611                 .read(LogicalDatastoreType.CONFIGURATION, iiLink);
612             if (linkOptLf.isDone()) {
613                 try {
614                     if (linkOptLf.get().isPresent()) {
615                         links.add(linkOptLf.get().get());
616                     }
617                 } catch (InterruptedException | ExecutionException e) {
618                     LOG.error("Error retreiving OTN links from otn-topology", e);
619                 }
620             } else {
621                 LOG.error("Error retreiving link {} from otn-topology", linkId.getValue());
622             }
623         }
624         return links;
625     }
626
627     private boolean checkLinks(List<Link> links) {
628         if (links.isEmpty()) {
629             return false;
630         }
631         for (Link link : links) {
632             if (link.augmentation(Link1.class) != null
633                     && !link.augmentation(Link1.class).getUsedBandwidth().equals(Uint32.valueOf(0))) {
634                 return false;
635             }
636         }
637         return true;
638     }
639
640     private boolean checkTerminationPoints(List<TerminationPoint> tps) {
641         if (tps.isEmpty()) {
642             return false;
643         }
644         for (TerminationPoint tp : tps) {
645             if (tp.augmentation(TerminationPoint1.class) != null && tp.augmentation(TerminationPoint1.class)
646                     .getXpdrTpPortConnectionAttributes().getTsPool() != null && tp.augmentation(TerminationPoint1.class)
647                     .getXpdrTpPortConnectionAttributes().getTsPool().size() != 80) {
648                 return false;
649             }
650         }
651         return true;
652     }
653
654     private List<TerminationPoint> getOtnNodeTps(String nodeTopoA, String tpA, String nodeTopoZ, String tpZ) {
655         List<TerminationPoint> tps = new ArrayList<>();
656         InstanceIdentifier<TerminationPoint> iiTpA = InstanceIdentifier.builder(Networks.class)
657             .child(Network.class, new NetworkKey(new NetworkId(NetworkUtils.OTN_NETWORK_ID)))
658             .child(Node.class, new NodeKey(new NodeId(nodeTopoA)))
659             .augmentation(Node1.class)
660             .child(TerminationPoint.class, new TerminationPointKey(new TpId(tpA)))
661             .build();
662         Optional<TerminationPoint> tpAOpt = Optional.empty();
663         InstanceIdentifier<TerminationPoint> iiTpZ = InstanceIdentifier.builder(Networks.class)
664             .child(Network.class, new NetworkKey(new NetworkId(NetworkUtils.OTN_NETWORK_ID)))
665             .child(Node.class, new NodeKey(new NodeId(nodeTopoZ)))
666             .augmentation(Node1.class)
667             .child(TerminationPoint.class, new TerminationPointKey(new TpId(tpZ)))
668             .build();
669         Optional<TerminationPoint> tpZOpt = Optional.empty();
670
671         if (networkTransactionService.read(LogicalDatastoreType.CONFIGURATION, iiTpA).isDone()
672                 && networkTransactionService.read(LogicalDatastoreType.CONFIGURATION, iiTpZ).isDone()) {
673             try {
674                 tpAOpt = networkTransactionService.read(LogicalDatastoreType.CONFIGURATION, iiTpA).get();
675                 tpZOpt = networkTransactionService.read(LogicalDatastoreType.CONFIGURATION, iiTpZ).get();
676             } catch (InterruptedException | ExecutionException e) {
677                 LOG.error("Error retreiving tp {} of node {} or tp {} from node {} from otn-topology", tpA, nodeTopoA,
678                     tpZ, nodeTopoZ, e);
679             }
680         } else {
681             LOG.error("error getting node termination points from the datastore");
682         }
683
684         if (tpAOpt.isPresent() && tpZOpt.isPresent()) {
685             tps.add(tpAOpt.get());
686             tps.add(tpZOpt.get());
687         }
688         return tps;
689     }
690
691     private List<TerminationPoint> getOtnNodeTps(List<LinkTp> linkTerminations) {
692         List<TerminationPoint> tps = new ArrayList<>();
693         for (LinkTp linkTp : linkTerminations) {
694             String tp = linkTp.getTpId();
695             String nodeId = new StringBuilder(linkTp.getNodeId()).append("-")
696                 .append(tp.split("-")[0]).toString();
697             InstanceIdentifier<TerminationPoint> iiTp = InstanceIdentifier.builder(Networks.class)
698                 .child(Network.class, new NetworkKey(new NetworkId(NetworkUtils.OTN_NETWORK_ID)))
699                 .child(Node.class, new NodeKey(new NodeId(nodeId)))
700                 .augmentation(Node1.class)
701                 .child(TerminationPoint.class, new TerminationPointKey(new TpId(tp)))
702                 .build();
703             Optional<TerminationPoint> tpOpt;
704             if (networkTransactionService.read(LogicalDatastoreType.CONFIGURATION, iiTp).isDone()) {
705                 try {
706                     tpOpt = networkTransactionService.read(LogicalDatastoreType.CONFIGURATION, iiTp).get();
707                     if (tpOpt.isPresent()) {
708                         tps.add(tpOpt.get());
709                     }
710                 } catch (InterruptedException | ExecutionException e) {
711                     LOG.error("Error retreiving tp {} of node {} from otn-topology", tp, nodeId, e);
712                 }
713             } else {
714                 LOG.error("error getting node termination points from the datastore");
715             }
716         }
717         if (tps.isEmpty()) {
718             LOG.warn("returning null");
719             return null;
720         } else {
721             LOG.info("returning tps = {}", tps.toString());
722             return tps;
723         }
724     }
725
726     private void deleteLinks(List<Link> links) {
727         for (Link otnTopologyLink : links) {
728             LOG.info("deleting link {} from {}", otnTopologyLink.getLinkId().getValue(),
729                 NetworkUtils.OVERLAY_NETWORK_ID);
730             InstanceIdentifier<Link> iiOtnTopologyLink = InstanceIdentifier.builder(Networks.class)
731                 .child(Network.class, new NetworkKey(new NetworkId(NetworkUtils.OTN_NETWORK_ID)))
732                 .augmentation(Network1.class)
733                 .child(Link.class, otnTopologyLink.key())
734                 .build();
735             networkTransactionService.delete(LogicalDatastoreType.CONFIGURATION, iiOtnTopologyLink);
736         }
737         try {
738             networkTransactionService.commit().get();
739         } catch (InterruptedException | ExecutionException e) {
740             LOG.error("Error deleting OTN links from otn-topology", e);
741         }
742     }
743
744     private List<Link> getSupportingOdu4Links(List<LinkTp> nodesTopoTps) {
745         InstanceIdentifier<Network1> iiOtnTopologyLinks = InstanceIdentifier.builder(Networks.class)
746             .child(Network.class, new NetworkKey(new NetworkId(NetworkUtils.OTN_NETWORK_ID)))
747             .augmentation(Network1.class)
748             .build();
749         ListenableFuture<Optional<Network1>> netw1Fl = networkTransactionService
750             .read(LogicalDatastoreType.CONFIGURATION, iiOtnTopologyLinks);
751         Optional<Network1> netw1Opt = Optional.empty();
752         if (netw1Fl.isDone()) {
753             try {
754                 netw1Opt = netw1Fl.get();
755             } catch (InterruptedException | ExecutionException e) {
756                 LOG.error("Error retreiving list of links from otn-topology", e);
757             }
758         }
759         List<Link> odu4links = null;
760         if (netw1Opt.isPresent() && netw1Opt.get().getLink() != null) {
761             odu4links = netw1Opt
762                 .get()
763                 .nonnullLink().values()
764                 .stream().filter(lk -> lk.getLinkId().getValue().startsWith("ODTU4"))
765                 .collect(Collectors.toList());
766         }
767         List<Link> links = new ArrayList<>();
768         if (odu4links != null) {
769             for (LinkTp linkTp : nodesTopoTps) {
770                 String tp = linkTp.getTpId();
771                 String nodeId = new StringBuilder(linkTp.getNodeId()).append("-")
772                     .append(tp.split("-")[0]).toString();
773                 Link slink = odu4links.stream().filter(lk -> lk.getSource().getSourceNode().getValue()
774                     .equals(nodeId) && lk.getSource().getSourceTp().toString().equals(tp)).findFirst().get();
775                 if (!links.contains(slink)) {
776                     links.add(slink);
777                 }
778                 Link dlink = odu4links.stream().filter(lk -> lk.getDestination().getDestNode().getValue()
779                     .equals(nodeId) && lk.getDestination().getDestTp().toString().equals(tp)).findFirst().get();
780                 if (!links.contains(dlink)) {
781                     links.add(dlink);
782                 }
783             }
784             LOG.debug("odu4links = {}", links.toString());
785             return links;
786         } else {
787             return null;
788         }
789     }
790
791     private void createOpenRoadmOtnNode(String nodeId) {
792         TopologyShard otnTopologyShard = OpenRoadmOtnTopology.createTopologyShard(portMapping.getNode(nodeId));
793         if (otnTopologyShard != null) {
794             this.otnTopologyShardMountedDevice.put(nodeId, otnTopologyShard);
795             for (Node otnTopologyNode : otnTopologyShard.getNodes()) {
796                 LOG.info("creating otn node {} in {}", otnTopologyNode.getNodeId().getValue(),
797                     NetworkUtils.OTN_NETWORK_ID);
798                 InstanceIdentifier<Node> iiOtnTopologyNode = InstanceIdentifier.builder(Networks.class)
799                     .child(Network.class, new NetworkKey(new NetworkId(NetworkUtils.OTN_NETWORK_ID)))
800                     .child(Node.class, otnTopologyNode.key())
801                     .build();
802                 networkTransactionService.merge(LogicalDatastoreType.CONFIGURATION, iiOtnTopologyNode, otnTopologyNode);
803             }
804             for (Link otnTopologyLink : otnTopologyShard.getLinks()) {
805                 LOG.info("creating otn link {} in {}", otnTopologyLink.getLinkId().getValue(),
806                     NetworkUtils.OVERLAY_NETWORK_ID);
807                 InstanceIdentifier<Link> iiOtnTopologyLink = InstanceIdentifier.builder(Networks.class)
808                     .child(Network.class, new NetworkKey(new NetworkId(NetworkUtils.OTN_NETWORK_ID)))
809                     .augmentation(Network1.class)
810                     .child(Link.class, otnTopologyLink.key())
811                     .build();
812                 networkTransactionService.merge(LogicalDatastoreType.CONFIGURATION, iiOtnTopologyLink, otnTopologyLink);
813             }
814         } else {
815             LOG.error("Unable to create OTN topology shard for node {}!", nodeId);
816         }
817     }
818
819     @SuppressFBWarnings(
820             value = "UPM_UNCALLED_PRIVATE_METHOD",
821             justification = "false positive, this method is used by public updateOpenRoadmNetworkTopology")
822     private void sendNotification() {
823         if (topologyChanges.isEmpty()) {
824             LOG.warn("Empty Topology Change List. No updates in topology");
825             return;
826         }
827         this.notification = new TopologyUpdateResultBuilder()
828             .setTopologyChanges(topologyChanges)
829             .build();
830         try {
831             notificationPublishService.putNotification(this.notification);
832         } catch (InterruptedException e) {
833             LOG.error("Notification offer rejected. Error={}", e.getMessage());
834         }
835     }
836 }