b4bbc52f144079c1ece1085a1a7062729d5c0c5f
[transportpce.git] / renderer / src / main / java / org / opendaylight / transportpce / renderer / provisiondevice / DeviceRenderer.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
13 import java.util.HashSet;
14 import java.util.List;
15 import java.util.Set;
16 import java.util.concurrent.ExecutionException;
17 import java.util.concurrent.Future;
18 import java.util.concurrent.TimeUnit;
19 import java.util.concurrent.TimeoutException;
20
21 import org.opendaylight.controller.md.sal.binding.api.DataBroker;
22 import org.opendaylight.controller.md.sal.binding.api.MountPointService;
23 import org.opendaylight.controller.md.sal.binding.api.ReadOnlyTransaction;
24 import org.opendaylight.controller.md.sal.binding.api.WriteTransaction;
25 import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
26 import org.opendaylight.transportpce.renderer.mapping.PortMapping;
27 import org.opendaylight.transportpce.renderer.openroadminterface.OpenRoadmInterfaces;
28 import org.opendaylight.transportpce.renderer.openroadminterface.OpenRoadmOchInterface;
29 import org.opendaylight.transportpce.renderer.openroadminterface.OpenRoadmXponderInterface;
30 import org.opendaylight.yang.gen.v1.http.org.openroadm.device.rev170206.circuit.packs.CircuitPacks;
31 import org.opendaylight.yang.gen.v1.http.org.openroadm.device.rev170206.circuit.packs.CircuitPacksBuilder;
32 import org.opendaylight.yang.gen.v1.http.org.openroadm.device.rev170206.circuit.packs.CircuitPacksKey;
33 import org.opendaylight.yang.gen.v1.http.org.openroadm.device.rev170206.org.openroadm.device.container.OrgOpenroadmDevice;
34 import org.opendaylight.yang.gen.v1.http.org.openroadm.equipment.states.types.rev161014.States;
35 import org.opendaylight.yang.gen.v1.http.org.openroadm.optical.channel.interfaces.rev161014.OchAttributes.ModulationFormat;
36 import org.opendaylight.yang.gen.v1.http.org.openroadm.optical.channel.interfaces.rev161014.R100G;
37 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.renderer.rev170228.RendererService;
38 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.renderer.rev170228.ServicePathInput;
39 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.renderer.rev170228.ServicePathOutput;
40 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.renderer.rev170228.ServicePathOutputBuilder;
41 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.renderer.rev170228.service.path.input.Nodes;
42 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
43 import org.opendaylight.yangtools.yang.common.RpcResult;
44 import org.opendaylight.yangtools.yang.common.RpcResultBuilder;
45
46 import org.slf4j.Logger;
47 import org.slf4j.LoggerFactory;
48
49 public class DeviceRenderer implements RendererService {
50
51     private final DataBroker db;
52     private final MountPointService mps;
53     private static final Logger LOG = LoggerFactory.getLogger(RendererService.class);
54     private final Set<String> currentMountedDevice;
55     private final Set<String> nodesProvisioned;
56
57     public DeviceRenderer(DataBroker db, MountPointService mps, Set<String> currentMountedDevice) {
58         this.db = db;
59         this.mps = mps;
60         this.currentMountedDevice = currentMountedDevice;
61         this.nodesProvisioned = new HashSet<>();
62     }
63
64     /**
65      * This method is the implementation of the 'service-path' RESTCONF service,
66      * which is one of the external APIs into the renderer application. The
67      * service provides two functions:
68      *
69      * <p>
70      * 1. Create This operation results in provisioning the device for a given
71      * wavelength and a list of nodes with each node listing its termination
72      * points.
73      *
74      * <p>
75      * 2. Delete This operation results in de-provisioning the device for a
76      * given wavelength and a list of nodes with each node listing its
77      * termination points.
78      *
79      * <p>
80      * The signature for this method was generated by yang tools from the
81      * renderer API model.
82      *
83      * @param input
84      *            Input parameter from the service-path yang model
85      *
86      * @return Result of the request
87      */
88     @Override
89     public Future<RpcResult<ServicePathOutput>> servicePath(ServicePathInput input) {
90
91         if (input.getOperation().getIntValue() == 1) {
92             LOG.info("Create operation request received");
93             return RpcResultBuilder.success(setupServicePath(input)).buildFuture();
94         } else if (input.getOperation().getIntValue() == 2) {
95             LOG.info("Delete operation request received");
96             return RpcResultBuilder.success(deleteServicePath(input)).buildFuture();
97         }
98         return RpcResultBuilder.success(new ServicePathOutputBuilder().setResult("Invalid operation")).buildFuture();
99     }
100
101     /**
102      * This method set's wavelength path based on the following steps.
103      * For each node:
104      *
105      * <p>
106      * 1. Create Och interface on source termination point. 2. Create Och
107      * interface on destination termination point. 3. Create cross connect
108      * between source and destination tps created in step 1 and 2.
109      *
110      * <p>
111      * Naming convention used for OCH interfaces name : tp-wavenumber Naming
112      * convention used for cross connect name : src-dest-wavenumber
113      *
114      * @param input
115      *            Input parameter from the service-path yang model
116      *
117      * @return Result list of all nodes if request successful otherwise specific
118      *         reason of failure.
119      */
120     public ServicePathOutputBuilder setupServicePath(ServicePathInput input) {
121
122         String serviceName = input.getServiceName();
123         List<Nodes> nodes = input.getNodes();
124         ServicePathOutputBuilder setServBldr = new ServicePathOutputBuilder();
125         LOG.info(currentMountedDevice.toString());
126         int crossConnectFlag;
127         for (Nodes n : nodes) {
128             LOG.info("Starting provisioning for node : {}", n.getNodeId());
129             crossConnectFlag = 0;
130             String nodeId = n.getNodeId();
131             // if the node is currently mounted then proceed
132             if (currentMountedDevice.contains(n.getNodeId())) {
133                 String srcTp = n.getSrcTp();
134                 String destTp = n.getDestTp();
135
136                 Long waveNumber = input.getWaveNumber();
137                 String mf = input.getModulationFormat();
138                 if (destTp.contains("LINE")) {
139                     crossConnectFlag++;
140
141                     ModulationFormat modulationFormat = null;
142                     for (int i = 0; i < ModulationFormat.values().length; i++) {
143                         ModulationFormat smodulationFormat = ModulationFormat.forValue(i);
144                         if (smodulationFormat.getName().equals(mf)) {
145                             modulationFormat = smodulationFormat;
146                         }
147                     }
148                     try {
149                         LOG.info("Modulation Format {} configured exists.", modulationFormat.getName());
150                     } catch (NullPointerException e) {
151                         LOG.error("{} modulation format does not exist.",mf);
152                     }
153
154                     if (!new OpenRoadmXponderInterface(db, mps, nodeId, destTp, serviceName)
155                             .createLineInterfaces(waveNumber, R100G.class, modulationFormat)) {
156
157                         return setServBldr.setResult("Unable to LINE interface on " + nodeId + " at " + destTp);
158                     }
159                     if (!activateService(nodeId, destTp, mps, true)) {
160                         return setServBldr
161                             .setResult("Unable to activate Equipment State on " + nodeId + " for " + destTp);
162                     }
163                 }
164                 if (srcTp.contains("CLNT")) {
165                     crossConnectFlag++;
166                     if (!new OpenRoadmXponderInterface(db, mps, nodeId, srcTp, serviceName).createClientInterfaces()) {
167                         return setServBldr.setResult("Unable to Client interface on " + nodeId + " at " + srcTp);
168                     }
169                 }
170                 String srcIf;
171                 String dstIf;
172                 if (srcTp.contains("TTP") || srcTp.contains("PP")) {
173                     srcIf = new OpenRoadmOchInterface(db, mps, nodeId, srcTp, serviceName).createInterface(waveNumber);
174                     // if source interface creation was successful
175                     // then proceed otherwise return.
176                     if (srcIf == null) {
177                         LOG.warn("Unable to create OCH interface on {} at {}", nodeId, srcTp);
178                         return setServBldr.setResult("Unable to create OCH interface on " + nodeId + " at " + srcTp);
179                     }
180                 }
181                 if (destTp.contains("TTP") || destTp.contains("PP")) {
182                     dstIf = new OpenRoadmOchInterface(db, mps, nodeId, destTp, serviceName).createInterface(waveNumber);
183                     // if destination interface creation was successful
184                     // then proceed otherwise return.
185                     if (dstIf == null) {
186                         LOG.warn("Unable to create OCH interface on {} at {}", nodeId, destTp);
187                         return setServBldr.setResult("Unable to create OCH interface on " + nodeId + " at " + destTp);
188                     }
189                 }
190                 if (crossConnectFlag < 1) {
191                     LOG.info("Creating cross connect between source :{} destination {} for node {}", srcTp, destTp,
192                         n.getNodeId());
193                     DataBroker netconfNodeDataBroker = PortMapping.getDeviceDataBroker(nodeId, mps);
194                     String crossConnectName = srcTp + "-" + destTp + "-" + waveNumber;
195                     CrossConnect roadmConnections = new CrossConnect(netconfNodeDataBroker);
196                     if (roadmConnections.postCrossConnect(waveNumber, srcTp, destTp)) {
197                         nodesProvisioned.add(nodeId);
198                         roadmConnections.getConnectionPortTrail(nodeId, mps, waveNumber, srcTp, destTp);
199                     } else {
200                         return setServBldr.setResult("Unable to post Roadm-connection for node " + nodeId);
201                     }
202                 }
203             } else {
204                 LOG.warn("{} is not mounted on the controller", nodeId);
205                 return setServBldr.setResult(nodeId + " is not mounted on the controller");
206             }
207         }
208         return setServBldr.setResult("Roadm-connection successfully created for nodes " + nodesProvisioned.toString());
209     }
210
211     /**
212      * This method removes wavelength path based on following steps: For each
213      * node:
214      *
215      * <p>
216      * 1. Delete Cross connect between source and destination tps.
217      * 2. Delete Och interface on source termination point.
218      * 3. Delete Och interface on destination termination point.
219      *
220      * <p>
221      * Naming convention used for OCH interfaces name : tp-wavenumber Naming
222      * convention used for cross connect name : src-dest-wavenumber
223      *
224      * @param input
225      *            Input parameter from the service-path yang model
226      *
227      * @return Result result of the request.
228      */
229     public ServicePathOutputBuilder deleteServicePath(ServicePathInput input) {
230         List<Nodes> nodes = input.getNodes();
231         ServicePathOutputBuilder delServBldr = new ServicePathOutputBuilder();
232         LOG.info(currentMountedDevice.toString());
233         for (Nodes n : nodes) {
234
235             String nodeId = n.getNodeId();
236             LOG.info("Deleting service setup on node {}", nodeId);
237             String srcTp = n.getSrcTp();
238             String destTp = n.getDestTp();
239             Long waveNumber = input.getWaveNumber();
240
241             // if the node is currently mounted then proceed.
242             if (currentMountedDevice.contains(nodeId)) {
243
244                 if (destTp.contains("LINE")) {
245                     if (!activateService(nodeId, destTp, mps, false)) {
246                         LOG.error("Unable to desactivate Equipment State on {} for {}", nodeId, destTp);
247                     }
248                     if (new OpenRoadmInterfaces(db, mps, nodeId, destTp)
249                         .deleteInterface(destTp + "-ODU") == false) {
250                         LOG.error("Failed to delete interface {}-ODU on {}", destTp, nodeId);
251                     }
252                     if (new OpenRoadmInterfaces(db, mps, nodeId, destTp)
253                         .deleteInterface(destTp + "-OTU") == false) {
254                         LOG.error("Failed to delete interface {}-OTU on {}", destTp, nodeId);
255                     }
256                     if (new OpenRoadmInterfaces(db, mps, nodeId, destTp)
257                         .deleteInterface(destTp + "-" + waveNumber) == false) {
258                         LOG.error("Failed to delete interface {}-{} on {}", destTp, waveNumber, nodeId);
259                     }
260                 }
261                 if (srcTp.contains("CLNT")) {
262                     // Deleting interface on source termination point
263                     if (new OpenRoadmInterfaces(db, mps, nodeId, srcTp)
264                         .deleteInterface(srcTp + "-ETHERNET") == false) {
265                         LOG.error("Failed to delete Ethernet interface on {} on {}", srcTp, nodeId);
266                     }
267                     continue;
268                 }
269                 String connectionNumber = srcTp + "-" + destTp + "-" + waveNumber;
270                 CrossConnect roadmConnection = new CrossConnect(PortMapping.getDeviceDataBroker(nodeId, mps),
271                     connectionNumber);
272                 if (!roadmConnection.deleteCrossConnect()) {
273                     LOG.error("Failed to delete {} on {}", connectionNumber, nodeId);
274                 }
275                 // Deleting interface on source termination point
276                 if (!new OpenRoadmInterfaces(db, mps, nodeId, srcTp)
277                     .deleteInterface(srcTp + "-" + waveNumber.toString())) {
278                     LOG.error("Failed to delete interface {}-{} on {}", srcTp, waveNumber.toString(), nodeId);
279                 }
280
281                 // Deleting interface on destination termination point
282                 if (!new OpenRoadmInterfaces(db, mps, nodeId, destTp)
283                     .deleteInterface(destTp + "-" + waveNumber.toString())) {
284                     LOG.error("Failed to delete interface {}-{} on {}", destTp, waveNumber.toString(), nodeId);
285                 }
286             } else {
287                 LOG.warn("{} is not mounted on the controller", nodeId);
288                 return delServBldr.setResult(nodeId + " is not mounted on the controller");
289             }
290         }
291         return delServBldr.setResult("Request processed");
292     }
293
294     /**
295      * This method does a post(edit-config) on a given circuit-packs subtree to
296      * change its equipment-state.
297      *
298      * @param nodeId
299      *            Netconf device.
300      * @param logicalConnPoint
301      *            Logical Connection point resulting from PortMapping to
302      *            retrieve associated circuit-pack.
303      * @param mps
304      *            Mount point service.
305      * @param activate
306      *            true to configure the circuit-pack to "NotReservedInuse".
307      *            false to configure the circuit-pack to "NotReservedAvailable".
308      * @return true/false based on status of operation.
309      */
310     private boolean activateService(String nodeId, String logicalConnPoint, MountPointService mps, boolean activate) {
311         DataBroker deviceDb = PortMapping.getDeviceDataBroker(nodeId, mps);
312         String circuitPack = PortMapping.getMapping(nodeId, logicalConnPoint, db).getSupportingCircuitPackName();
313
314         InstanceIdentifier<CircuitPacks> circuitPackIID = InstanceIdentifier.create(OrgOpenroadmDevice.class)
315             .child(CircuitPacks.class, new CircuitPacksKey(circuitPack));
316         ReadOnlyTransaction readTx = deviceDb.newReadOnlyTransaction();
317         // retrieve relevent CircuitPack object
318         Optional<CircuitPacks> cpObject;
319         CircuitPacks cp = null;
320         try {
321             cpObject = readTx.read(LogicalDatastoreType.CONFIGURATION, circuitPackIID).get();
322             if (cpObject.isPresent()) {
323                 cp = cpObject.get();
324             } else {
325                 LOG.info("Could not find CircuitPack {} in equipment config datastore for nodeId {}", circuitPack,
326                     nodeId);
327                 return false;
328             }
329
330         } catch (InterruptedException | ExecutionException ex) {
331             LOG.error("Issue reading config datastore on node {}", nodeId, ex);
332         }
333         CircuitPacksBuilder cpBldr = new CircuitPacksBuilder(cp);
334         if (activate) {
335             cpBldr.setEquipmentState(States.NotReservedInuse);
336         } else {
337             cpBldr.setEquipmentState(States.NotReservedAvailable);
338         }
339         WriteTransaction wt = deviceDb.newWriteOnlyTransaction();
340         wt.put(LogicalDatastoreType.CONFIGURATION, circuitPackIID, cpBldr.build());
341         try {
342             wt.submit().get(15, TimeUnit.SECONDS);
343             LOG.info("Successfully posted Equipment State on circuit pack {} on node {}", circuitPack, nodeId);
344             return true;
345         } catch (InterruptedException | ExecutionException | TimeoutException e) {
346             LOG.warn("Failed to post {} on node {}", circuitPack, nodeId, e);
347             return false;
348         }
349     }
350 }