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