0a2a612fa94301c84b8fdca87b747ca13acffcce
[transportpce.git] / renderer / src / main / java / org / opendaylight / transportpce / renderer / provisiondevice / OpenRoadmInterfaces.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
9 package org.opendaylight.transportpce.renderer.provisiondevice;
10
11 import com.google.common.base.Optional;
12 import com.google.common.util.concurrent.CheckedFuture;
13
14 import java.util.concurrent.ExecutionException;
15
16 import org.apache.commons.lang3.StringUtils;
17 import org.opendaylight.controller.md.sal.binding.api.DataBroker;
18 import org.opendaylight.controller.md.sal.binding.api.MountPointService;
19 import org.opendaylight.controller.md.sal.binding.api.ReadOnlyTransaction;
20 import org.opendaylight.controller.md.sal.binding.api.WriteTransaction;
21 import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
22 import org.opendaylight.controller.md.sal.common.api.data.TransactionCommitFailedException;
23 import org.opendaylight.transportpce.renderer.mapping.PortMapping;
24 import org.opendaylight.yang.gen.v1.http.org.openroadm.device.rev170206.circuit.pack.Ports;
25 import org.opendaylight.yang.gen.v1.http.org.openroadm.device.rev170206.circuit.pack.PortsKey;
26 import org.opendaylight.yang.gen.v1.http.org.openroadm.device.rev170206.circuit.packs.CircuitPacks;
27 import org.opendaylight.yang.gen.v1.http.org.openroadm.device.rev170206.circuit.packs.CircuitPacksKey;
28 import org.opendaylight.yang.gen.v1.http.org.openroadm.device.rev170206.interfaces.grp.Interface;
29 import org.opendaylight.yang.gen.v1.http.org.openroadm.device.rev170206.interfaces.grp.InterfaceBuilder;
30 import org.opendaylight.yang.gen.v1.http.org.openroadm.device.rev170206.interfaces.grp.InterfaceKey;
31 import org.opendaylight.yang.gen.v1.http.org.openroadm.device.rev170206.org.openroadm.device.container.OrgOpenroadmDevice;
32 import org.opendaylight.yang.gen.v1.http.org.openroadm.device.rev170206.port.Interfaces;
33 import org.opendaylight.yang.gen.v1.http.org.openroadm.interfaces.rev161014.OpticalChannel;
34 import org.opendaylight.yang.gen.v1.http.org.openroadm.optical.channel.interfaces.rev161014.Interface1;
35 import org.opendaylight.yang.gen.v1.http.org.openroadm.optical.channel.interfaces.rev161014.Interface1Builder;
36 import org.opendaylight.yang.gen.v1.http.org.openroadm.optical.channel.interfaces.rev161014.och.container.OchBuilder;
37 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.portmapping.rev170228.Network;
38 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.portmapping.rev170228.network.Nodes;
39 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.portmapping.rev170228.network.NodesKey;
40 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.portmapping.rev170228.network.nodes.Mapping;
41 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.portmapping.rev170228.network.nodes.MappingBuilder;
42 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.portmapping.rev170228.network.nodes.MappingKey;
43 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
44
45
46 import org.slf4j.Logger;
47 import org.slf4j.LoggerFactory;
48
49 public class OpenRoadmInterfaces {
50
51     private final DataBroker db;
52     private final String nodeId;
53     private final String logicalConnPoint;
54     private static final Logger LOG = LoggerFactory.getLogger(OpenRoadmInterfaces.class);
55     private final DataBroker netconfNodeDataBroker;
56
57     public OpenRoadmInterfaces(DataBroker db, MountPointService mps, String nodeId, String logicalConnPoint) {
58         this.db = db;
59         this.logicalConnPoint = logicalConnPoint;
60         this.nodeId = nodeId;
61         netconfNodeDataBroker = PortMapping.getDeviceDataBroker(nodeId, mps);
62
63     }
64
65     /**
66      * This methods creates an OCH interface on the ROADM nodes's termination point
67      * based on following steps:
68      *
69      *  <p>
70      *  1. Get the physical mapping corresponding to logical port.
71      *  2. Create generic interface object based on data in mapping object.
72      *  3. Set the value for supporting interface (OMS) if present in the local mapping
73      *     otherwise fetch it for the first time and update the local mapping.
74      *  4. Add Och interface specific augmentation such as waveNumber etc.
75      *
76      * @param waveNumber wavelength number of the Och interface.
77      *
78      * @return Name of the interface if successful, otherwise return null.
79      */
80     public String createOchInterface(Long waveNumber) {
81
82         // Add OOCH augmentation to the interface
83         Mapping portMap = getMapping(nodeId, logicalConnPoint);
84         if (portMap != null) {
85             InterfaceBuilder ifBuilder = intfBuilder(portMap);
86             // OCH interface specific data
87             OchBuilder ocIfBuilder = new OchBuilder();
88             ocIfBuilder.setWavelengthNumber(waveNumber);
89             Interface1Builder optbld1 = new Interface1Builder();
90             ifBuilder.setKey(new InterfaceKey(logicalConnPoint + "-" + waveNumber.toString()));
91             ifBuilder.addAugmentation(Interface1.class, optbld1.setOch(ocIfBuilder.build()).build());
92             ifBuilder.setName(logicalConnPoint + "-" + waveNumber.toString());
93             InstanceIdentifier<Interface> interfacesIID = InstanceIdentifier.create(OrgOpenroadmDevice.class).child(
94                 Interface.class, new InterfaceKey(logicalConnPoint + "-" + waveNumber.toString()));
95             if (logicalConnPoint.toUpperCase().contains("TTP") && StringUtils.isNotEmpty(portMap.getSupportingOms())) {
96                 LOG.info("Oms interface present in local mapping for " + logicalConnPoint);
97                 ifBuilder.setSupportingInterface(portMap.getSupportingOms());
98             } else if (logicalConnPoint.toUpperCase().contains("TTP") && StringUtils.isEmpty(portMap
99                 .getSupportingOms())) {
100                 Ports port = getPort(portMap);
101                 if (port != null && port.getInterfaces() != null) {
102                     LOG.info("Oms interface not present in local mapping, getting it for the first time for "
103                         + logicalConnPoint);
104                     LOG.info(port.toString());
105                     for (Interfaces intf : port.getInterfaces()) {
106                         LOG.info(intf.toString());
107                         //TODO: This method assumes the name of the interface contains OMS substring in it
108                         //update it to fetch OMS interface more efficiently.
109                         if (intf.getInterfaceName().toUpperCase().contains("OMS")) {
110                             String omsInterface = intf.getInterfaceName();
111                             LOG.info("found oms interface for {} with name {}", logicalConnPoint, omsInterface);
112                             ifBuilder.setSupportingInterface(omsInterface);
113                             MappingBuilder mapBldr = new MappingBuilder();
114                             InstanceIdentifier<Mapping> mapIID = InstanceIdentifier.create(Network.class).child(
115                                 Nodes.class, new NodesKey(nodeId)).child(Mapping.class, new MappingKey(portMap
116                                     .getLogicalConnectionPoint()));
117                             mapBldr.setSupportingOms(omsInterface);
118                             mapBldr.setKey(new MappingKey(portMap.getLogicalConnectionPoint()));
119                             try {
120                                 final WriteTransaction writeTransaction = db.newWriteOnlyTransaction();
121                                 writeTransaction.merge(LogicalDatastoreType.CONFIGURATION, mapIID, mapBldr.build());
122                                 CheckedFuture<Void, TransactionCommitFailedException> submit = writeTransaction
123                                     .submit();
124                                 LOG.info("Updated mapping for " + port.getPortName() + "at " + portMap
125                                     .getSupportingCircuitPackName() + " with support oms interface " + intf
126                                         .getInterfaceName());
127                                 submit.checkedGet();
128                                 break;
129                             } catch (TransactionCommitFailedException ex) {
130                                 // TODO Auto-generated catch block
131                                 LOG.info("unable to save mapping for " + port.getPortName() + " at " + portMap
132                                     .getSupportingCircuitPackName());
133                             }
134                         }
135                     }
136                 } else {
137                     LOG.error("Interface is missing for Port " + port.getPortName() + " @ " + portMap
138                         .getSupportingCircuitPackName());
139                     return null;
140                 }
141             }
142             if (postInterface(interfacesIID, ifBuilder)) {
143                 return ifBuilder.getName();
144             } else {
145                 return null;
146             }
147         }
148
149         // TODO: implement OCH facility for xponder
150         return null;
151     }
152
153     public String createODU4Interface() {
154         // Add ODU4 augmentation to the interface
155
156         // TODO: implement this method
157         return null;
158
159     }
160
161     public String createOTU4Interface() {
162         // Add OTU4 augmentation to the interface
163
164         // TODO: implement this method
165
166         return null;
167     }
168
169     public String createETHInterface() {
170         // Add ETH augmentation to the interface
171
172         // TODO: implement this method
173
174         return null;
175
176     }
177
178     /**
179      * This methods does a get operation on the port subtree of the device's
180      * operational data store.This method will be called once for each Degree port
181      * in order to fetch the OMS interface for the first time.
182      *
183      * @param portMap Mapping object
184      *
185      * @return Ports object read from the device.
186      */
187     public Ports getPort(Mapping portMap) {
188         // Get Port subtree corresponding to the logical connection point
189         if (netconfNodeDataBroker != null) {
190             ReadOnlyTransaction rtx = netconfNodeDataBroker.newReadOnlyTransaction();
191             InstanceIdentifier<Ports> portIID = InstanceIdentifier.create(OrgOpenroadmDevice.class).child(
192                 CircuitPacks.class, new CircuitPacksKey(portMap.getSupportingCircuitPackName())).child(Ports.class,
193                     new PortsKey(portMap.getSupportingPort()));
194             Optional<Ports> portObject;
195             try {
196                 portObject = rtx.read(LogicalDatastoreType.OPERATIONAL, portIID).get();
197                 if (portObject.isPresent()) {
198                     return portObject.get();
199                 }
200             } catch (InterruptedException | ExecutionException ex) {
201                 LOG.info("Error getting port subtree from the device ");
202                 return null;
203             }
204         }
205         return null;
206     }
207
208     /**
209      * This methods creates a generic interface builder object
210      * to set the value that are common irrespective of the interface type.
211      *
212      * @param portMap Mapping object containing attributes required to create
213      *        interface on the device.
214      *
215      * @return InterfaceBuilder object with the data.
216      */
217     public InterfaceBuilder intfBuilder(Mapping portMap) {
218
219         InterfaceBuilder ifBuilder = new InterfaceBuilder();
220         ifBuilder.setType(OpticalChannel.class);
221         ifBuilder.setDescription("  TBD   ");
222         ifBuilder.setCircuitId("   TBD    ");
223         ifBuilder.setSupportingCircuitPackName(portMap.getSupportingCircuitPackName());
224         ifBuilder.setSupportingPort(portMap.getSupportingPort());
225         return ifBuilder;
226     }
227
228     /**
229      * This methods does an edit-config operation on the openROADM
230      * device in order to create the given interface.
231      *
232      * @param interfacesIID Instance identifier for the interfaces subtree in the device.
233      * @param ifBuilder Builder object containing the data to post.
234      *
235      * @return Result of operation true/false based on success/failure.
236      */
237     public boolean postInterface(InstanceIdentifier<Interface> interfacesIID, InterfaceBuilder ifBuilder) {
238         // Post interface with its specific augmentation to the device
239         if (netconfNodeDataBroker != null) {
240             final WriteTransaction writeTransaction = netconfNodeDataBroker.newWriteOnlyTransaction();
241             writeTransaction.put(LogicalDatastoreType.CONFIGURATION, interfacesIID, ifBuilder.build());
242             final CheckedFuture<Void, TransactionCommitFailedException> submit = writeTransaction.submit();
243             try {
244
245                 submit.checkedGet();
246                 LOG.info("Successfully posted interface " + ifBuilder.getName());
247                 return true;
248             } catch (TransactionCommitFailedException ex) {
249                 LOG.warn("Failed to post {} ", ifBuilder.getName());
250                 return false;
251             }
252
253         } else {
254             return false;
255         }
256     }
257
258     /**
259      * This method for a given node's termination point returns the Mapping
260      * object based on portmapping.yang model stored in the MD-SAL
261      * data store which is created when the node is connected for the first time.
262      * The mapping object basically contains the following attributes of interest:
263      *
264      * <p>
265      * 1. Supporting circuit pack
266      * 2. Supporting port
267      * 3. Supporting OMS interface (if port on ROADM)
268      *
269      * @param nodeId unique Identifier for the node of interest.
270      * @param logicalConnPoint Name of the logical point
271      *
272      * @return Result Mapping object if success otherwise null.
273      */
274     public Mapping getMapping(String nodeId, String logicalConnPoint) {
275
276         // Getting circuit pack and port corresponding to logical connection
277         // point
278         InstanceIdentifier<Mapping> portMapping = InstanceIdentifier.builder(Network.class).child(Nodes.class,
279             new NodesKey(nodeId)).child(Mapping.class, new MappingKey(logicalConnPoint)).build();
280         ReadOnlyTransaction readTx = db.newReadOnlyTransaction();
281         Optional<Mapping> mapObject;
282         try {
283             mapObject = readTx.read(LogicalDatastoreType.CONFIGURATION, portMapping).get();
284             if (mapObject.isPresent()) {
285                 LOG.info("Found mapping for the logical port " + mapObject.get().toString());
286                 return mapObject.get();
287             } else {
288                 LOG.info("Could not find mapping for logical connection point : " + logicalConnPoint + " for nodeId "
289                     + nodeId);
290                 return null;
291             }
292         } catch (InterruptedException | ExecutionException ex) {
293             LOG.info("Unable to read mapping for logical connection point : " + logicalConnPoint + " for nodeId "
294                 + nodeId);
295         }
296         return null;
297     }
298 }