Update transportpce-common-types model
[transportpce.git] / renderer / src / main / java / org / opendaylight / transportpce / renderer / provisiondevice / DeviceRendererServiceImpl.java
1 /*
2  * Copyright © 2017 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.renderer.provisiondevice;
9
10 import com.google.common.collect.Sets;
11 import com.google.common.util.concurrent.FluentFuture;
12 import java.util.ArrayList;
13 import java.util.Arrays;
14 import java.util.HashMap;
15 import java.util.HashSet;
16 import java.util.LinkedList;
17 import java.util.List;
18 import java.util.Map;
19 import java.util.Optional;
20 import java.util.Set;
21 import java.util.concurrent.ConcurrentHashMap;
22 import java.util.concurrent.ConcurrentLinkedQueue;
23 import java.util.concurrent.CopyOnWriteArrayList;
24 import java.util.concurrent.ExecutionException;
25 import java.util.concurrent.ForkJoinPool;
26 import java.util.concurrent.ForkJoinTask;
27 import java.util.concurrent.Future;
28 import java.util.concurrent.TimeUnit;
29 import java.util.concurrent.TimeoutException;
30 import java.util.concurrent.atomic.AtomicBoolean;
31 import org.eclipse.jdt.annotation.NonNull;
32 import org.opendaylight.mdsal.binding.api.DataBroker;
33 import org.opendaylight.mdsal.binding.api.ReadTransaction;
34 import org.opendaylight.mdsal.binding.api.WriteTransaction;
35 import org.opendaylight.mdsal.common.api.CommitInfo;
36 import org.opendaylight.mdsal.common.api.LogicalDatastoreType;
37 import org.opendaylight.transportpce.common.StringConstants;
38 import org.opendaylight.transportpce.common.Timeouts;
39 import org.opendaylight.transportpce.common.crossconnect.CrossConnect;
40 import org.opendaylight.transportpce.common.device.DeviceTransactionManager;
41 import org.opendaylight.transportpce.common.fixedflex.GridConstant;
42 import org.opendaylight.transportpce.common.fixedflex.GridUtils;
43 import org.opendaylight.transportpce.common.fixedflex.SpectrumInformation;
44 import org.opendaylight.transportpce.common.mapping.PortMapping;
45 import org.opendaylight.transportpce.common.openroadminterfaces.OpenRoadmInterfaceException;
46 import org.opendaylight.transportpce.common.openroadminterfaces.OpenRoadmInterfaces;
47 import org.opendaylight.transportpce.renderer.openroadminterface.OpenRoadmInterfaceFactory;
48 import org.opendaylight.transportpce.renderer.provisiondevice.servicepath.ServiceListTopology;
49 import org.opendaylight.transportpce.renderer.provisiondevice.servicepath.ServicePathDirection;
50 import org.opendaylight.yang.gen.v1.http.org.opendaylight.transportpce.alarmsuppression.rev171102.ServiceNodelist;
51 import org.opendaylight.yang.gen.v1.http.org.opendaylight.transportpce.alarmsuppression.rev171102.service.nodelist.NodelistBuilder;
52 import org.opendaylight.yang.gen.v1.http.org.opendaylight.transportpce.alarmsuppression.rev171102.service.nodelist.NodelistKey;
53 import org.opendaylight.yang.gen.v1.http.org.opendaylight.transportpce.device.renderer.rev211004.CreateOtsOmsInput;
54 import org.opendaylight.yang.gen.v1.http.org.opendaylight.transportpce.device.renderer.rev211004.CreateOtsOmsOutput;
55 import org.opendaylight.yang.gen.v1.http.org.opendaylight.transportpce.device.renderer.rev211004.CreateOtsOmsOutputBuilder;
56 import org.opendaylight.yang.gen.v1.http.org.opendaylight.transportpce.device.renderer.rev211004.RendererRollbackInput;
57 import org.opendaylight.yang.gen.v1.http.org.opendaylight.transportpce.device.renderer.rev211004.RendererRollbackOutput;
58 import org.opendaylight.yang.gen.v1.http.org.opendaylight.transportpce.device.renderer.rev211004.RendererRollbackOutputBuilder;
59 import org.opendaylight.yang.gen.v1.http.org.opendaylight.transportpce.device.renderer.rev211004.ServicePathInput;
60 import org.opendaylight.yang.gen.v1.http.org.opendaylight.transportpce.device.renderer.rev211004.ServicePathOutput;
61 import org.opendaylight.yang.gen.v1.http.org.opendaylight.transportpce.device.renderer.rev211004.ServicePathOutputBuilder;
62 import org.opendaylight.yang.gen.v1.http.org.opendaylight.transportpce.device.renderer.rev211004.az.api.info.AEndApiInfo;
63 import org.opendaylight.yang.gen.v1.http.org.opendaylight.transportpce.device.renderer.rev211004.az.api.info.ZEndApiInfo;
64 import org.opendaylight.yang.gen.v1.http.org.opendaylight.transportpce.device.renderer.rev211004.renderer.rollback.output.FailedToRollback;
65 import org.opendaylight.yang.gen.v1.http.org.opendaylight.transportpce.device.renderer.rev211004.renderer.rollback.output.FailedToRollbackBuilder;
66 import org.opendaylight.yang.gen.v1.http.org.opendaylight.transportpce.device.renderer.rev211004.renderer.rollback.output.FailedToRollbackKey;
67 import org.opendaylight.yang.gen.v1.http.org.opendaylight.transportpce.portmapping.rev220316.OpenroadmNodeVersion;
68 import org.opendaylight.yang.gen.v1.http.org.opendaylight.transportpce.portmapping.rev220316.mapping.Mapping;
69 import org.opendaylight.yang.gen.v1.http.org.openroadm.common.service.types.rev211210.service.Topology;
70 import org.opendaylight.yang.gen.v1.http.org.openroadm.service.rev211210.ServiceList;
71 import org.opendaylight.yang.gen.v1.http.org.openroadm.service.rev211210.service.list.Services;
72 import org.opendaylight.yang.gen.v1.http.org.openroadm.service.rev211210.service.list.ServicesBuilder;
73 import org.opendaylight.yang.gen.v1.http.org.openroadm.service.rev211210.service.list.ServicesKey;
74 import org.opendaylight.yang.gen.v1.http.org.transportpce.common.types.rev220926.link.tp.LinkTp;
75 import org.opendaylight.yang.gen.v1.http.org.transportpce.common.types.rev220926.link.tp.LinkTpBuilder;
76 import org.opendaylight.yang.gen.v1.http.org.transportpce.common.types.rev220926.node.interfaces.NodeInterface;
77 import org.opendaylight.yang.gen.v1.http.org.transportpce.common.types.rev220926.node.interfaces.NodeInterfaceBuilder;
78 import org.opendaylight.yang.gen.v1.http.org.transportpce.common.types.rev220926.node.interfaces.NodeInterfaceKey;
79 import org.opendaylight.yang.gen.v1.http.org.transportpce.common.types.rev220926.optical.renderer.nodes.Nodes;
80 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
81 import org.slf4j.Logger;
82 import org.slf4j.LoggerFactory;
83
84
85 public class DeviceRendererServiceImpl implements DeviceRendererService {
86     private static final String IS_NOT_MOUNTED_ON_THE_CONTROLLER = " is not mounted on the controller";
87     private static final Logger LOG = LoggerFactory.getLogger(DeviceRendererServiceImpl.class);
88     private static final String PT_07 = "07";
89     private final DataBroker dataBroker;
90     private final DeviceTransactionManager deviceTransactionManager;
91     private final OpenRoadmInterfaceFactory openRoadmInterfaceFactory;
92     private final OpenRoadmInterfaces openRoadmInterfaces;
93     private final CrossConnect crossConnect;
94     private final PortMapping portMapping;
95
96     public DeviceRendererServiceImpl(DataBroker dataBroker, DeviceTransactionManager deviceTransactionManager,
97             OpenRoadmInterfaceFactory openRoadmInterfaceFactory, OpenRoadmInterfaces openRoadmInterfaces,
98             CrossConnect crossConnect, PortMapping portMapping) {
99         this.dataBroker = dataBroker;
100         this.deviceTransactionManager = deviceTransactionManager;
101         this.openRoadmInterfaceFactory = openRoadmInterfaceFactory;
102         this.openRoadmInterfaces = openRoadmInterfaces;
103         this.crossConnect = crossConnect;
104         this.portMapping = portMapping;
105     }
106
107     @SuppressWarnings("rawtypes")
108     // FIXME check if the ForkJoinTask raw type can be avoided
109     // Raw types use are discouraged since they lack type safety.
110     // Resulting Problems are observed at run time and not at compile time
111     @Override
112     public ServicePathOutput setupServicePath(ServicePathInput input, ServicePathDirection direction) {
113         LOG.info("setup service path for input {} and direction {}", input, direction);
114         List<Nodes> nodes = new ArrayList<>();
115         if (input.getNodes() != null) {
116             nodes.addAll(input.getNodes());
117         }
118         SpectrumInformation spectrumInformation = GridUtils.initSpectrumInformationFromServicePathInput(input);
119         // Register node for suppressing alarms
120         if (!alarmSuppressionNodeRegistration(input)) {
121             LOG.warn("Alarm suppresion node registration failed!!!!");
122         }
123         ConcurrentLinkedQueue<String> results = new ConcurrentLinkedQueue<>();
124         Map<NodeInterfaceKey,NodeInterface> nodeInterfaces = new ConcurrentHashMap<>();
125         Set<String> nodesProvisioned = Sets.newConcurrentHashSet();
126         CopyOnWriteArrayList<LinkTp> otnLinkTps = new CopyOnWriteArrayList<>();
127         ServiceListTopology topology = new ServiceListTopology();
128         AtomicBoolean success = new AtomicBoolean(true);
129         ForkJoinPool forkJoinPool = new ForkJoinPool();
130         ForkJoinTask forkJoinTask = forkJoinPool.submit(() -> nodes.parallelStream().forEach(node -> {
131             String nodeId = node.getNodeId();
132             LOG.info("Starting provisioning for node : {}", nodeId);
133             AEndApiInfo apiInfoA = null;
134             ZEndApiInfo apiInfoZ = null;
135             if (input.getAEndApiInfo() != null && input.getAEndApiInfo().getNodeId().contains(nodeId)) {
136                 apiInfoA = input.getAEndApiInfo();
137             }
138             if (input.getZEndApiInfo() != null && input.getZEndApiInfo().getNodeId().contains(nodeId)) {
139                 apiInfoZ = input.getZEndApiInfo();
140             }
141             Set<String> createdEthInterfaces = new HashSet<>();
142             Set<String> createdOtuInterfaces = new HashSet<>();
143             Set<String> createdOduInterfaces = new HashSet<>();
144             Set<String> createdOchInterfaces = new HashSet<>();
145             Set<String> createdConnections = new HashSet<>();
146             int crossConnectFlag = 0;
147             try {
148                 // if the node is currently mounted then proceed
149                 if (this.deviceTransactionManager.isDeviceMounted(nodeId)) {
150                     String srcTp = node.getSrcTp();
151                     String destTp = node.getDestTp();
152                     if ((destTp != null) && destTp.contains(StringConstants.NETWORK_TOKEN)) {
153                         LOG.info("Adding supporting OCH interface for node {}, dest tp {}, spectrumInformation {}",
154                                 nodeId, destTp, spectrumInformation);
155                         crossConnectFlag++;
156                         String supportingOchInterface = this.openRoadmInterfaceFactory.createOpenRoadmOchInterface(
157                                 nodeId, destTp, spectrumInformation);
158                         // Split the string based on # pass the last element as the supported Interface
159                         // This is needed for 7.1 device models with B100G, we have OTSI, OTSI-group combined as OCH
160                         String[] listOfSuppOchInf = supportingOchInterface.split("#");
161                         createdOchInterfaces = Set.of(listOfSuppOchInf);
162                         // Taking the last element
163                         supportingOchInterface = listOfSuppOchInf[createdOchInterfaces.size() - 1];
164                         String supportingOtuInterface = this.openRoadmInterfaceFactory.createOpenRoadmOtu4Interface(
165                                 nodeId, destTp, supportingOchInterface, apiInfoA, apiInfoZ);
166                         createdOtuInterfaces.add(supportingOtuInterface);
167                         if (srcTp == null) {
168                             otnLinkTps.add(new LinkTpBuilder().setNodeId(nodeId).setTpId(destTp).build());
169                         } else {
170                             // This is needed for 7.1 device models for 400GE, since we have ODUC4 and ODUflex
171                             // are combined
172                             createdOduInterfaces = Set.of(this.openRoadmInterfaceFactory
173                                 .createOpenRoadmOdu4HOInterface(
174                                     nodeId, destTp, false, apiInfoA, apiInfoZ, PT_07).split("#"));
175                         }
176                     }
177                     if ((srcTp != null) && srcTp.contains(StringConstants.CLIENT_TOKEN)) {
178                         LOG.info("Adding supporting EThernet interface for node {}, src tp {}", nodeId, srcTp);
179                         crossConnectFlag++;
180                         // create OpenRoadm Xponder Client Interfaces
181                         createdEthInterfaces.add(this.openRoadmInterfaceFactory.createOpenRoadmEthInterface(
182                                 nodeId, srcTp));
183                     }
184                     if ((srcTp != null) && srcTp.contains(StringConstants.NETWORK_TOKEN)) {
185                         LOG.info("Adding supporting OCH interface for node {}, src tp {}, spectrumInformation {}",
186                                 nodeId, srcTp, spectrumInformation);
187                         crossConnectFlag++;
188                         // create OpenRoadm Xponder Line Interfaces
189                         String supportingOchInterface = this.openRoadmInterfaceFactory.createOpenRoadmOchInterface(
190                                 nodeId, srcTp, spectrumInformation);
191                         createdOchInterfaces.add(supportingOchInterface);
192                         // Split the string based on # pass the last element as the supported Interface
193                         // This is needed for 7.1 device models with B100G, we have OTSI, OTSI-group combined as OCH
194                         String[] listOfSuppOchInf = supportingOchInterface.split("#");
195                         List<String> tmpCreatedOchInterfaces = Arrays.asList(listOfSuppOchInf);
196                         createdOchInterfaces.addAll(tmpCreatedOchInterfaces);
197                         // Taking the last element
198                         supportingOchInterface = tmpCreatedOchInterfaces.get(tmpCreatedOchInterfaces.size() - 1);
199                         String supportingOtuInterface = this.openRoadmInterfaceFactory.createOpenRoadmOtu4Interface(
200                                 nodeId, srcTp, supportingOchInterface, apiInfoA, apiInfoZ);
201                         createdOtuInterfaces.add(supportingOtuInterface);
202                         if (destTp == null) {
203                             otnLinkTps.add(new LinkTpBuilder().setNodeId(nodeId).setTpId(srcTp).build());
204                         } else {
205                             createdOduInterfaces.add(this.openRoadmInterfaceFactory.createOpenRoadmOdu4HOInterface(
206                                     nodeId, srcTp, false, apiInfoA, apiInfoZ, PT_07));
207                         }
208                     }
209                     if ((destTp != null) && destTp.contains(StringConstants.CLIENT_TOKEN)) {
210                         LOG.info("Adding supporting EThernet interface for node {}, dest tp {}", nodeId, destTp);
211                         crossConnectFlag++;
212                         // create OpenRoadm Xponder Client Interfaces
213                         createdEthInterfaces.add(this.openRoadmInterfaceFactory.createOpenRoadmEthInterface(
214                                 nodeId, destTp));
215                     }
216                     if ((srcTp != null) && (srcTp.contains(StringConstants.TTP_TOKEN)
217                             || srcTp.contains(StringConstants.PP_TOKEN))) {
218                         LOG.info("Adding supporting OCH interface for node {}, src tp {}, spectrumInformation {}",
219                                 nodeId, srcTp, spectrumInformation);
220                         createdOchInterfaces.addAll(this.openRoadmInterfaceFactory.createOpenRoadmOchInterfaces(
221                                 nodeId, srcTp, spectrumInformation));
222                     }
223                     if ((destTp != null) && (destTp.contains(StringConstants.TTP_TOKEN)
224                             || destTp.contains(StringConstants.PP_TOKEN))) {
225                         LOG.info("Adding supporting OCH interface for node {}, dest tp {}, spectrumInformation {}",
226                                 nodeId, destTp, spectrumInformation);
227                         createdOchInterfaces.addAll(this.openRoadmInterfaceFactory.createOpenRoadmOchInterfaces(
228                                 nodeId, destTp, spectrumInformation));
229                     }
230                     if (crossConnectFlag < 1) {
231                         LOG.info("Creating cross connect between source {} and destination {} for node {}", srcTp,
232                                 destTp, nodeId);
233                         Optional<String> connectionNameOpt =
234                                 this.crossConnect.postCrossConnect(nodeId, srcTp, destTp, spectrumInformation);
235                         if (connectionNameOpt.isPresent()) {
236                             nodesProvisioned.add(nodeId);
237                             createdConnections.add(connectionNameOpt.get());
238                         } else {
239                             processErrorMessage("Unable to post Roadm-connection for node " + nodeId, forkJoinPool,
240                                     results);
241                             success.set(false);
242                         }
243                     }
244                 } else {
245                     processErrorMessage(nodeId + IS_NOT_MOUNTED_ON_THE_CONTROLLER, forkJoinPool, results);
246                     success.set(false);
247                 }
248             } catch (OpenRoadmInterfaceException ex) {
249                 processErrorMessage("Setup service path failed! Exception:" + ex.toString(), forkJoinPool, results);
250                 success.set(false);
251             }
252             NodeInterface nodeInterface = new NodeInterfaceBuilder()
253                 .withKey(new NodeInterfaceKey(nodeId))
254                 .setNodeId(nodeId)
255                 .setConnectionId(createdConnections)
256                 .setEthInterfaceId(createdEthInterfaces)
257                 .setOtuInterfaceId(createdOtuInterfaces)
258                 .setOduInterfaceId(createdOduInterfaces)
259                 .setOchInterfaceId(createdOchInterfaces)
260                 .build();
261             nodeInterfaces.put(nodeInterface.key(),nodeInterface);
262         }));
263         try {
264             forkJoinTask.get();
265         } catch (InterruptedException | ExecutionException e) {
266             LOG.error("Error while setting up service paths!", e);
267         }
268         forkJoinPool.shutdown();
269
270         if (success.get()) {
271             results.add("Interfaces created successfully for nodes: " + String.join(", ", nodesProvisioned));
272         }
273         // setting topology in the service list data store
274         try {
275             setTopologyForService(input.getServiceName(), topology.getTopology());
276         } catch (InterruptedException | TimeoutException | ExecutionException e) {
277             LOG.warn("Failed to write topologies for service {}.", input.getServiceName(), e);
278         }
279         if (!alarmSuppressionNodeRemoval(input.getServiceName())) {
280             LOG.error("Alarm suppresion node removal failed!!!!");
281         }
282         return new ServicePathOutputBuilder()
283                 .setNodeInterface(nodeInterfaces)
284                 .setSuccess(success.get())
285                 .setResult(String.join("\n", results))
286                 .setLinkTp(otnLinkTps)
287                 .build();
288     }
289
290     private ConcurrentLinkedQueue<String> processErrorMessage(String message, ForkJoinPool forkJoinPool,
291             ConcurrentLinkedQueue<String> messages) {
292         LOG.warn("Received error message {}", message);
293         messages.add(message);
294         forkJoinPool.shutdown();
295         return messages;
296     }
297
298     @SuppressWarnings("rawtypes")
299     // FIXME check if the ForkJoinTask raw type can be avoided
300     // Raw types use are discouraged since they lack type safety.
301     // Resulting Problems are observed at run time and not at compile time
302     @Override
303     public ServicePathOutput deleteServicePath(ServicePathInput input) {
304         if (!alarmSuppressionNodeRegistration(input)) {
305             LOG.warn("Alarm suppression node registration failed!!!!");
306         }
307         List<Nodes> nodes = input.getNodes();
308         AtomicBoolean success = new AtomicBoolean(true);
309         ConcurrentLinkedQueue<String> results = new ConcurrentLinkedQueue<>();
310         CopyOnWriteArrayList<LinkTp> otnLinkTps = new CopyOnWriteArrayList<>();
311         ForkJoinPool forkJoinPool = new ForkJoinPool();
312         ForkJoinTask forkJoinTask = forkJoinPool.submit(() -> nodes.parallelStream().forEach(node -> {
313             String nodeId = node.getNodeId();
314             LOG.info("Deleting service setup on node {}", nodeId);
315             if (node.getDestTp() == null) {
316                 LOG.error("Destination termination point must not be null.");
317                 return;
318             }
319             if (!this.deviceTransactionManager.isDeviceMounted(nodeId)) {
320                 String result = nodeId + IS_NOT_MOUNTED_ON_THE_CONTROLLER;
321                 results.add(result);
322                 success.set(false);
323                 LOG.warn(result);
324                 forkJoinPool.shutdown();
325                 return;
326                 //TODO should deletion end here?
327             }
328             // if the node is currently mounted then proceed.
329
330             String destTp = node.getDestTp();
331             String srcTp = "";
332             if (node.getSrcTp() == null) {
333                 otnLinkTps.add(new LinkTpBuilder()
334                         .setNodeId(nodeId)
335                         .setTpId(destTp)
336                         .build());
337             } else {
338                 srcTp = node.getSrcTp();
339             }
340             List<String> interfacesToDelete = new LinkedList<>();
341             interfacesToDelete.addAll(getInterfaces2delete(nodeId, srcTp, destTp,
342                     input.getLowerSpectralSlotNumber().intValue(),
343                     input.getHigherSpectralSlotNumber().intValue()));
344             for (String interfaceId : interfacesToDelete) {
345                 try {
346                     this.openRoadmInterfaces.deleteInterface(nodeId, interfaceId);
347                 } catch (OpenRoadmInterfaceException e) {
348                     String result = String.format("Failed to delete interface %s on node %s!", interfaceId, nodeId);
349                     success.set(false);
350                     LOG.error(result, e);
351                     results.add(result);
352                 }
353             }
354         }));
355         try {
356             forkJoinTask.get();
357         } catch (InterruptedException | ExecutionException e) {
358             LOG.error("Error while deleting service paths!", e);
359         }
360         forkJoinPool.shutdown();
361         if (!alarmSuppressionNodeRemoval(input.getServiceName())) {
362             LOG.error("Alarm suppresion node removal failed!!!!");
363         }
364         return new ServicePathOutputBuilder()
365                 .setSuccess(success.get())
366                 .setLinkTp(otnLinkTps)
367                 .setResult(
368                     results.isEmpty()
369                     ? "Request processed"
370                     : String.join("\n", results))
371                 .build();
372     }
373
374     private List<String> getInterfaces2delete(
375             String nodeId, String srcTp, String destTp, int lowerSpectralSlotNumber, int higherSpectralSlotNumber) {
376         String spectralSlotName = String.join(GridConstant.SPECTRAL_SLOT_SEPARATOR,
377                 String.valueOf(lowerSpectralSlotNumber),
378                 String.valueOf(higherSpectralSlotNumber));
379
380         if (destTp.contains(StringConstants.NETWORK_TOKEN)
381                 || srcTp.contains(StringConstants.CLIENT_TOKEN)
382                 || srcTp.contains(StringConstants.NETWORK_TOKEN)
383                 || destTp.contains(StringConstants.CLIENT_TOKEN)) {
384             return getInterfacesTodelete(nodeId, srcTp, destTp, spectralSlotName);
385         }
386
387         List<String> interfacesToDelete = new LinkedList<>();
388         String connectionNumber = String.join(GridConstant.NAME_PARAMETERS_SEPARATOR, srcTp, destTp, spectralSlotName);
389         List<String> intToDelete = this.crossConnect.deleteCrossConnect(nodeId, connectionNumber, false);
390         for (String interf : intToDelete == null ? new ArrayList<String>() : intToDelete) {
391             if (!this.openRoadmInterfaceFactory.isUsedByXc(
392                     nodeId, interf, connectionNumber, this.deviceTransactionManager)) {
393                 interfacesToDelete.add(interf);
394             }
395         }
396         return interfacesToDelete;
397     }
398
399     private List<String> getInterfacesTodelete(String nodeId, String srcTp, String destTp, String spectralSlotName) {
400
401         OpenroadmNodeVersion nodeOpenRoadmVersion =
402                 this.portMapping.getNode(nodeId).getNodeInfo().getOpenroadmVersion();
403
404         List<String> interfacesToDelete = new LinkedList<>();
405         Map<String, List<String>> suffixListMap =
406             nodeOpenRoadmVersion.equals(OpenroadmNodeVersion._71)
407                 ? Map.of(
408                     // We don't need ODUC2, ODUC3 here, since they are handled in OTN service-path
409                     // This has to be in an order of deletion
410                     "ODU",  List.of("ODU4", "ODUFLEX", "ODUC4", "ODUC1"),
411                     // Add intermediate OTUCn rates (OTUC2, OTUC3)
412                     // OTU4 is used in 100G service on 7.1 model
413                     "other", List.of("OTU4", "OTUC1", "OTUC2", "OTUC3", "OTUC4",
414                     "OTSIGROUP-400G", "OTSIGROUP-300G",  "OTSIGROUP-200G", "OTSIGROUP-100G",
415                     spectralSlotName))
416                 : Map.of(
417                     "ODU", List.of("ODU", "ODU4"),
418                     "other", List.of("OTU", spectralSlotName));
419         // this last suffix used to be retrieved from openRoadmInterfaceFactory.createOpenRoadmOchInterfaceName
420         // i.e. String.join(GridConstant.NAME_PARAMETERS_SEPARATOR, destTp, spectralSlotName) with
421         // common GridConstant that states NAME_PARAMETERS_SEPARATOR = "-"
422
423         if (destTp.contains(StringConstants.NETWORK_TOKEN)) {
424             try {
425                 for (String suffix : suffixListMap.get("ODU")) {
426                     if (this.openRoadmInterfaces.getInterface(
427                             nodeId, String.join(GridConstant.NAME_PARAMETERS_SEPARATOR, destTp, suffix)).isPresent()) {
428                         interfacesToDelete.add(String.join(GridConstant.NAME_PARAMETERS_SEPARATOR, destTp, suffix));
429                     }
430                 }
431             }
432             catch (OpenRoadmInterfaceException e) {
433                 LOG.error("impossible to get one of the interfaces {}",
434                     destTp + GridConstant.NAME_PARAMETERS_SEPARATOR + String.join(
435                         " or " + destTp + GridConstant.NAME_PARAMETERS_SEPARATOR,
436                         suffixListMap.get("ODU")),
437                     e);
438             }
439             try {
440                 for (String suffix : suffixListMap.get("other")) {
441                     if (this.openRoadmInterfaces.getInterface(
442                         nodeId, String.join(GridConstant.NAME_PARAMETERS_SEPARATOR, destTp, suffix)).isPresent()) {
443                         LOG.info("Deleting the interface {}",
444                             String.join(GridConstant.NAME_PARAMETERS_SEPARATOR, destTp, suffix));
445                         interfacesToDelete.add(String.join(GridConstant.NAME_PARAMETERS_SEPARATOR, destTp, suffix));
446                     }
447                 }
448             }
449             catch (OpenRoadmInterfaceException e) {
450                 LOG.error("impossible to get one of the interfaces {}",
451                     destTp + GridConstant.NAME_PARAMETERS_SEPARATOR + String.join(
452                         " or " + destTp + GridConstant.NAME_PARAMETERS_SEPARATOR,
453                         suffixListMap.get("ODU")),
454                     e);
455             }
456         }
457         if (srcTp.contains(StringConstants.NETWORK_TOKEN)) {
458             interfacesToDelete.add(
459                     String.join(GridConstant.NAME_PARAMETERS_SEPARATOR, srcTp, suffixListMap.get("ODU").get(0)));
460             for (String suffix : suffixListMap.get("other")) {
461                 interfacesToDelete.add(String.join(GridConstant.NAME_PARAMETERS_SEPARATOR, srcTp, suffix));
462             }
463         }
464
465         if (srcTp.contains(StringConstants.CLIENT_TOKEN)) {
466             interfacesToDelete.add(String.join(GridConstant.NAME_PARAMETERS_SEPARATOR, srcTp, "ETHERNET"));
467         }
468         if (destTp.contains(StringConstants.CLIENT_TOKEN)) {
469
470             interfacesToDelete.add(String.join(GridConstant.NAME_PARAMETERS_SEPARATOR, destTp, "ETHERNET"));
471         }
472         return interfacesToDelete;
473     }
474
475
476
477     @Override
478     public RendererRollbackOutput rendererRollback(RendererRollbackInput input) {
479         boolean success = true;
480         Map<FailedToRollbackKey,FailedToRollback> failedToRollbackList = new HashMap<>();
481         for (NodeInterface nodeInterfaces : input.nonnullNodeInterface().values()) {
482             Set<String> failedInterfaces = new HashSet<>();
483             String nodeId = nodeInterfaces.getNodeId();
484             for (String connectionId : nodeInterfaces.getConnectionId()) {
485                 List<String> listInter = this.crossConnect.deleteCrossConnect(nodeId, connectionId, false);
486                 if (listInter != null) {
487                     LOG.info("Cross connect {} on node {} successfully deleted.", connectionId, nodeId);
488                 } else {
489                     LOG.error("Failed to delete cross connect {} on node {}!", connectionId, nodeId);
490                     success = false;
491                     failedInterfaces.add(connectionId);
492                 }
493             }
494             // Interfaces needs to be in specific order to delete. Order is:
495             // 1. ODU interfaces
496             // 2. OTU interfaces
497             // 3. OCH interfaces
498             // 4. ETH interfaces
499             LinkedList<String> interfacesToDelete = new LinkedList<>();
500             if (nodeInterfaces.getOduInterfaceId() != null) {
501                 interfacesToDelete.addAll(nodeInterfaces.getOduInterfaceId());
502             }
503             if (nodeInterfaces.getOtuInterfaceId() != null) {
504                 interfacesToDelete.addAll(nodeInterfaces.getOtuInterfaceId());
505             }
506             if (nodeInterfaces.getOchInterfaceId() != null) {
507                 interfacesToDelete.addAll(nodeInterfaces.getOchInterfaceId());
508             }
509             if (nodeInterfaces.getEthInterfaceId() != null) {
510                 interfacesToDelete.addAll(nodeInterfaces.getEthInterfaceId());
511             }
512             LOG.info("Going to execute rollback on node {}. Interfaces to rollback: {}", nodeId,
513                     String.join(", ", interfacesToDelete));
514             for (String interfaceId : interfacesToDelete) {
515                 try {
516                     this.openRoadmInterfaces.deleteInterface(nodeId, interfaceId);
517                     LOG.info("Interface {} on node {} successfully deleted.", interfaceId, nodeId);
518                 } catch (OpenRoadmInterfaceException e) {
519                     LOG.error("Failed to delete interface {} on node {}!", interfaceId, nodeId);
520                     success = false;
521                     failedInterfaces.add(interfaceId);
522                 }
523             }
524             FailedToRollback failedToRollack = new FailedToRollbackBuilder().withKey(new FailedToRollbackKey(nodeId))
525                     .setNodeId(nodeId).setInterface(failedInterfaces).build();
526             failedToRollbackList.put(failedToRollack.key(),failedToRollack);
527         }
528         return new RendererRollbackOutputBuilder()
529                 .setSuccess(success)
530                 .setFailedToRollback(failedToRollbackList)
531                 .build();
532     }
533
534     private boolean alarmSuppressionNodeRegistration(ServicePathInput input) {
535         Map<org.opendaylight.yang.gen.v1.http.org.opendaylight.transportpce.alarmsuppression.rev171102.service
536                 .nodelist.nodelist.NodesKey,
537             org.opendaylight.yang.gen.v1.http.org.opendaylight.transportpce.alarmsuppression.rev171102.service
538                 .nodelist.nodelist.Nodes> nodeList = new HashMap<>();
539         if (input.getNodes() != null) {
540             for (Nodes node : input.getNodes()) {
541                 org.opendaylight.yang.gen.v1.http.org.opendaylight.transportpce.alarmsuppression.rev171102
542                     .service.nodelist.nodelist.Nodes nodes =
543                         new org.opendaylight.yang.gen.v1.http.org.opendaylight.transportpce.alarmsuppression.rev171102
544                             .service.nodelist.nodelist.NodesBuilder().setNodeId(node.getNodeId()).build();
545                 nodeList.put(nodes.key(),nodes);
546             }
547         }
548         InstanceIdentifier<org.opendaylight.yang.gen.v1.http.org.opendaylight.transportpce.alarmsuppression.rev171102
549             .service.nodelist.Nodelist> nodeListIID =
550                  InstanceIdentifier.create(ServiceNodelist.class)
551                      .child(org.opendaylight.yang.gen.v1.http.org.opendaylight.transportpce.alarmsuppression.rev171102
552                          .service.nodelist.Nodelist.class, new NodelistKey(input.getServiceName()));
553         final WriteTransaction writeTransaction = this.dataBroker.newWriteOnlyTransaction();
554         writeTransaction.merge(LogicalDatastoreType.CONFIGURATION,
555                 nodeListIID,
556                 new NodelistBuilder()
557                     .withKey(new NodelistKey(input.getServiceName()))
558                     .setServiceName(input.getServiceName())
559                     .setNodes(nodeList)
560                     .build());
561         FluentFuture<? extends @NonNull CommitInfo> commit = writeTransaction.commit();
562         try {
563             commit.get(Timeouts.DATASTORE_WRITE, TimeUnit.MILLISECONDS);
564             LOG.info("Nodes are register for alarm suppression for service: {}", input.getServiceName());
565             return true;
566         } catch (ExecutionException | InterruptedException | TimeoutException e) {
567             LOG.warn("Failed to alarm suppresslist for service: {}", input.getServiceName(), e);
568             return false;
569         }
570     }
571
572     private boolean alarmSuppressionNodeRemoval(String serviceName) {
573         InstanceIdentifier<org.opendaylight.yang.gen.v1.http.org.opendaylight.transportpce.alarmsuppression.rev171102
574             .service.nodelist.Nodelist> nodeListIID =
575                 InstanceIdentifier.create(ServiceNodelist.class)
576                     .child(org.opendaylight.yang.gen.v1.http.org.opendaylight.transportpce.alarmsuppression.rev171102
577                         .service.nodelist.Nodelist.class, new NodelistKey(serviceName));
578         final WriteTransaction writeTransaction = this.dataBroker.newWriteOnlyTransaction();
579         writeTransaction.delete(LogicalDatastoreType.CONFIGURATION, nodeListIID);
580         FluentFuture<? extends @NonNull CommitInfo> commit = writeTransaction.commit();
581         try {
582             commit.get(Timeouts.DATASTORE_DELETE, TimeUnit.MILLISECONDS);
583             LOG.info("Nodes are unregister for alarm suppression for service: {}", serviceName);
584             return true;
585         } catch (InterruptedException | TimeoutException | ExecutionException e) {
586             LOG.warn("Failed to alarm suppresslist for service: {}", serviceName, e);
587             return false;
588         }
589     }
590
591     private void setTopologyForService(String name, Topology topo)
592             throws InterruptedException, ExecutionException, TimeoutException {
593         ServicesBuilder servicesBuilder;
594         // Get the service from the service list inventory
595         ServicesKey serviceKey = new ServicesKey(name);
596         InstanceIdentifier<Services> iid =
597                 InstanceIdentifier.create(ServiceList.class).child(Services.class, serviceKey);
598         Optional<Services> services;
599         try (ReadTransaction readTx = this.dataBroker.newReadOnlyTransaction()) {
600             Future<java.util.Optional<Services>> future =
601                     readTx.read(LogicalDatastoreType.OPERATIONAL, iid);
602             services = future.get(Timeouts.DATASTORE_READ, TimeUnit.MILLISECONDS);
603         } catch (InterruptedException | ExecutionException | TimeoutException e) {
604             throw e;
605         }
606         if (services.isPresent()) {
607             LOG.info("service {} already exists", name);
608             servicesBuilder = new ServicesBuilder(services.get()).setTopology(topo);
609             WriteTransaction writeTx = this.dataBroker.newWriteOnlyTransaction();
610             writeTx.merge(LogicalDatastoreType.OPERATIONAL, iid, servicesBuilder.build());
611             writeTx.commit().get(Timeouts.DATASTORE_WRITE, TimeUnit.MILLISECONDS);
612         } else {
613             LOG.warn("Service {} does not exist - topology can not be updated", name);
614         }
615     }
616
617     @edu.umd.cs.findbugs.annotations.SuppressFBWarnings(
618         value = "SLF4J_FORMAT_SHOULD_BE_CONST",
619         justification = "Log messages content needs to be formatted before"
620             + "since they are used in the returned object")
621     @Override
622     public CreateOtsOmsOutput createOtsOms(CreateOtsOmsInput input) throws OpenRoadmInterfaceException {
623         if (!this.deviceTransactionManager.isDeviceMounted(input.getNodeId())) {
624             String result = input.getNodeId() + IS_NOT_MOUNTED_ON_THE_CONTROLLER;
625             LOG.warn(result);
626             return new CreateOtsOmsOutputBuilder().setResult(result).setSuccess(false).build();
627         }
628         // if the node is currently mounted then proceed.
629         Mapping oldMapping = this.portMapping.getMapping(input.getNodeId(), input.getLogicalConnectionPoint());
630         if (oldMapping == null) {
631             return new CreateOtsOmsOutputBuilder()
632                     .setResult(String.format("Logical Connection point %s does not exist for %s",
633                             input.getLogicalConnectionPoint(), input.getNodeId()))
634                     .setSuccess(false)
635                     .build();
636         }
637
638         String otsInterface = this.openRoadmInterfaceFactory.createOpenRoadmOtsInterface(input.getNodeId(), oldMapping);
639         int count = 0;
640         Mapping newMapping = this.portMapping.getMapping(input.getNodeId(), input.getLogicalConnectionPoint());
641         while (!isSupportingOtsPresent(newMapping)) {
642             LOG.info("waiting for post interface operation on node '{}'...", input.getNodeId());
643             try {
644                 Thread.sleep(10000);
645                 this.portMapping.updateMapping(input.getNodeId(), oldMapping);
646             } catch (InterruptedException e) {
647                 LOG.error("Failed to wait for post interface operation");
648             }
649             count++;
650             if (count >= 6) {
651                 String result = String.format("Unable to get ots interface from mapping %s - %s",
652                         oldMapping.getLogicalConnectionPoint(), input.getNodeId());
653                 LOG.error(result);
654                 return new CreateOtsOmsOutputBuilder().setResult(result).setSuccess(false).build();
655             }
656             newMapping = this.portMapping.getMapping(input.getNodeId(), input.getLogicalConnectionPoint());
657         }
658
659         String omsInterface = this.openRoadmInterfaceFactory.createOpenRoadmOmsInterface(input.getNodeId(), newMapping);
660         if (omsInterface == null) {
661             String result = String.format("Fail to create OpenRoadmOms Interface for node : %s", input.getNodeId());
662             LOG.error(result);
663             return new CreateOtsOmsOutputBuilder().setResult(result).setSuccess(false).build();
664         }
665         return new CreateOtsOmsOutputBuilder()
666                 .setResult(String.format("Interfaces %s - %s successfully created on node %s",
667                     otsInterface, omsInterface, input.getNodeId()))
668                 .setSuccess(true)
669                 .build();
670     }
671
672     private Boolean isSupportingOtsPresent(Mapping mapping) {
673         if (mapping == null) {
674             return false;
675         }
676         if (mapping.getSupportingOts() == null) {
677             LOG.warn("SupportingOts info is not present in mapping {}", mapping);
678             return false;
679         }
680         LOG.info("SupportingOts info is present in mapping {}", mapping);
681         return true;
682     }
683 }