2 * Copyright © 2017 AT&T and others. All rights reserved.
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
9 package org.opendaylight.transportpce.renderer.provisiondevice;
11 import com.google.common.base.Optional;
13 import java.util.HashSet;
14 import java.util.List;
16 import java.util.concurrent.ExecutionException;
17 import java.util.concurrent.Future;
18 import java.util.concurrent.TimeUnit;
19 import java.util.concurrent.TimeoutException;
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;
46 import org.slf4j.Logger;
47 import org.slf4j.LoggerFactory;
49 public class DeviceRenderer implements RendererService {
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;
57 public DeviceRenderer(DataBroker db, MountPointService mps, Set<String> currentMountedDevice) {
60 this.currentMountedDevice = currentMountedDevice;
61 this.nodesProvisioned = new HashSet<>();
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:
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
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
80 * The signature for this method was generated by yang tools from the
84 * Input parameter from the service-path yang model
86 * @return Result of the request
89 public Future<RpcResult<ServicePathOutput>> servicePath(ServicePathInput input) {
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();
98 return RpcResultBuilder.success(new ServicePathOutputBuilder().setResult("Invalid operation")).buildFuture();
102 * This method set's wavelength path based on the following steps.
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.
111 * Naming convention used for OCH interfaces name : tp-wavenumber Naming
112 * convention used for cross connect name : src-dest-wavenumber
115 * Input parameter from the service-path yang model
117 * @return Result list of all nodes if request successful otherwise specific
120 public ServicePathOutputBuilder setupServicePath(ServicePathInput input) {
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();
136 Long waveNumber = input.getWaveNumber();
137 String mf = input.getModulationFormat();
138 if (destTp.contains("LINE")) {
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;
149 LOG.info("Modulation Format {} configured exists.", modulationFormat.getName());
150 } catch (NullPointerException e) {
151 LOG.error("{} modulation format does not exist.",mf);
154 if (!new OpenRoadmXponderInterface(db, mps, nodeId, destTp, serviceName)
155 .createLineInterfaces(waveNumber, R100G.class, modulationFormat)) {
157 return setServBldr.setResult("Unable to LINE interface on " + nodeId + " at " + destTp);
159 if (!activateService(nodeId, destTp, mps, true)) {
161 .setResult("Unable to activate Equipment State on " + nodeId + " for " + destTp);
164 if (srcTp.contains("CLNT")) {
166 if (!new OpenRoadmXponderInterface(db, mps, nodeId, srcTp, serviceName).createClientInterfaces()) {
167 return setServBldr.setResult("Unable to Client interface on " + nodeId + " at " + srcTp);
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.
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);
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.
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);
190 if (crossConnectFlag < 1) {
191 LOG.info("Creating cross connect between source :{} destination {} for node {}", srcTp, destTp,
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);
200 return setServBldr.setResult("Unable to post Roadm-connection for node " + nodeId);
204 LOG.warn("{} is not mounted on the controller", nodeId);
205 return setServBldr.setResult(nodeId + " is not mounted on the controller");
208 return setServBldr.setResult("Roadm-connection successfully created for nodes " + nodesProvisioned.toString());
212 * This method removes wavelength path based on following steps: For each
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.
221 * Naming convention used for OCH interfaces name : tp-wavenumber Naming
222 * convention used for cross connect name : src-dest-wavenumber
225 * Input parameter from the service-path yang model
227 * @return Result result of the request.
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) {
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();
241 // if the node is currently mounted then proceed.
242 if (currentMountedDevice.contains(nodeId)) {
244 if (destTp.contains("LINE")) {
245 if (!activateService(nodeId, destTp, mps, false)) {
246 LOG.error("Unable to desactivate Equipment State on {} for {}", nodeId, destTp);
248 if (new OpenRoadmInterfaces(db, mps, nodeId, destTp)
249 .deleteInterface(destTp + "-ODU") == false) {
250 LOG.error("Failed to delete interface {}-ODU on {}", destTp, nodeId);
252 if (new OpenRoadmInterfaces(db, mps, nodeId, destTp)
253 .deleteInterface(destTp + "-OTU") == false) {
254 LOG.error("Failed to delete interface {}-OTU on {}", destTp, nodeId);
256 if (new OpenRoadmInterfaces(db, mps, nodeId, destTp)
257 .deleteInterface(destTp + "-" + waveNumber) == false) {
258 LOG.error("Failed to delete interface {}-{} on {}", destTp, waveNumber, nodeId);
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);
269 String connectionNumber = srcTp + "-" + destTp + "-" + waveNumber;
270 CrossConnect roadmConnection = new CrossConnect(PortMapping.getDeviceDataBroker(nodeId, mps),
272 if (!roadmConnection.deleteCrossConnect()) {
273 LOG.error("Failed to delete {} on {}", connectionNumber, nodeId);
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);
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);
287 LOG.warn("{} is not mounted on the controller", nodeId);
288 return delServBldr.setResult(nodeId + " is not mounted on the controller");
291 return delServBldr.setResult("Request processed");
295 * This method does a post(edit-config) on a given circuit-packs subtree to
296 * change its equipment-state.
300 * @param logicalConnPoint
301 * Logical Connection point resulting from PortMapping to
302 * retrieve associated circuit-pack.
304 * Mount point service.
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.
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();
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;
321 cpObject = readTx.read(LogicalDatastoreType.CONFIGURATION, circuitPackIID).get();
322 if (cpObject.isPresent()) {
325 LOG.info("Could not find CircuitPack {} in equipment config datastore for nodeId {}", circuitPack,
330 } catch (InterruptedException | ExecutionException ex) {
331 LOG.error("Issue reading config datastore on node {}", nodeId, ex);
333 CircuitPacksBuilder cpBldr = new CircuitPacksBuilder(cp);
335 cpBldr.setEquipmentState(States.NotReservedInuse);
337 cpBldr.setEquipmentState(States.NotReservedAvailable);
339 WriteTransaction wt = deviceDb.newWriteOnlyTransaction();
340 wt.put(LogicalDatastoreType.CONFIGURATION, circuitPackIID, cpBldr.build());
342 wt.submit().get(15, TimeUnit.SECONDS);
343 LOG.info("Successfully posted Equipment State on circuit pack {} on node {}", circuitPack, nodeId);
345 } catch (InterruptedException | ExecutionException | TimeoutException e) {
346 LOG.warn("Failed to post {} on node {}", circuitPack, nodeId, e);