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