/* * Copyright © 2017 AT&T and others. All rights reserved. * * This program and the accompanying materials are made available under the * terms of the Eclipse Public License v1.0 which accompanies this distribution, * and is available at http://www.eclipse.org/legal/epl-v10.html */ package org.opendaylight.transportpce.renderer.provisiondevice; import com.google.common.util.concurrent.CheckedFuture; import java.util.HashSet; import java.util.List; import java.util.Set; import java.util.concurrent.Future; import org.opendaylight.controller.md.sal.binding.api.DataBroker; import org.opendaylight.controller.md.sal.binding.api.MountPointService; import org.opendaylight.controller.md.sal.binding.api.ReadWriteTransaction; import org.opendaylight.controller.md.sal.binding.api.WriteTransaction; import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType; import org.opendaylight.controller.md.sal.common.api.data.TransactionCommitFailedException; import org.opendaylight.transportpce.renderer.mapping.PortMapping; import org.opendaylight.yang.gen.v1.http.org.openroadm.common.types.rev161014.OpticalControlMode; import org.opendaylight.yang.gen.v1.http.org.openroadm.device.rev161014.connection.DestinationBuilder; import org.opendaylight.yang.gen.v1.http.org.openroadm.device.rev161014.connection.SourceBuilder; import org.opendaylight.yang.gen.v1.http.org.openroadm.device.rev161014.interfaces.grp.Interface; import org.opendaylight.yang.gen.v1.http.org.openroadm.device.rev161014.interfaces.grp.InterfaceKey; import org.opendaylight.yang.gen.v1.http.org.openroadm.device.rev161014.org.openroadm.device.container.OrgOpenroadmDevice; import org.opendaylight.yang.gen.v1.http.org.openroadm.device.rev161014.org.openroadm.device.container.org.openroadm.device.RoadmConnections; import org.opendaylight.yang.gen.v1.http.org.openroadm.device.rev161014.org.openroadm.device.container.org.openroadm.device.RoadmConnectionsBuilder; import org.opendaylight.yang.gen.v1.http.org.openroadm.device.rev161014.org.openroadm.device.container.org.openroadm.device.RoadmConnectionsKey; import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.renderer.rev170228.RendererService; import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.renderer.rev170228.ServicePathInput; import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.renderer.rev170228.ServicePathOutput; import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.renderer.rev170228.ServicePathOutputBuilder; import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.renderer.rev170228.service.path.input.Nodes; import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; import org.opendaylight.yangtools.yang.common.RpcResult; import org.opendaylight.yangtools.yang.common.RpcResultBuilder; import org.slf4j.Logger; import org.slf4j.LoggerFactory; public class DeviceRenderer implements RendererService { private final DataBroker db; private final MountPointService mps; private static final Logger LOG = LoggerFactory.getLogger(RendererService.class); private final Set currentMountedDevice; private final Set nodesProvisioned; public DeviceRenderer(DataBroker db, MountPointService mps, Set currentMountedDevice) { this.db = db; this.mps = mps; this.currentMountedDevice = currentMountedDevice; this.nodesProvisioned = new HashSet<>(); } /** * This method is the implementation of the 'service-path' RESTCONF service, * which is one of the external APIs into the renderer application. The * service provides two functions: * *

* 1. Create * This operation results in provisioning the device for a given wavelength and a * list of nodes with each node listing its termination points. * *

* 2. Delete * This operation results in de-provisioning the device for a given wavelength and a * list of nodes with each node listing its termination points. * *

* The signature for this method was generated by yang tools from the * renderer API model. * * @param input Input parameter from the service-path yang model * * @return Result of the request */ @Override public Future> servicePath(ServicePathInput input) { if (input.getOperation().getIntValue() == 1) { LOG.info("Create operation request received"); return RpcResultBuilder.success(setupServicePath(input)).buildFuture(); } else if (input.getOperation().getIntValue() == 2) { LOG.info("Delete operation request received"); return RpcResultBuilder.success(deleteServicePath(input)).buildFuture(); } return RpcResultBuilder.success(new ServicePathOutputBuilder().setResult("Invalid operation")).buildFuture(); } /** * This method set's wavelength path based on following steps: * For each node: * *

* 1. Create Och interface on source termination point. * 2. Create Och interface on destination termination point. * 3. Create cross connect between source and destination * tps created in step 1 and 2. * *

* Naming convention used for OCH interfaces name : tp-wavenumber * Naming convention used for cross connect name : src-dest-wavenumber * * @param input Input parameter from the service-path yang model * * @return Result list of all nodes if request successful * otherwise specific reason of failure. */ public ServicePathOutputBuilder setupServicePath(ServicePathInput input) { List nodes = input.getNodes(); ServicePathOutputBuilder setServBldr = new ServicePathOutputBuilder(); LOG.info(currentMountedDevice.toString()); for (Nodes n : nodes) { LOG.info("Starting provisioning for node : " + n.getNodeId()); //if the node is currently mounted then proceed if (currentMountedDevice.contains(n.getNodeId())) { String srcTp = n.getSrcTp(); String destTp = n.getDestTp(); Long waveNumber = input.getWaveNumber(); String srcIf = new OpenRoadmInterfaces(db, mps, n.getNodeId(), srcTp).createOchInterface(waveNumber); //if source interface creation was successful then proceed otherwise return. if (srcIf == null) { LOG.warn("Unable to create OCH interface on " + n.getNodeId() + " at " + srcTp); return setServBldr.setResult("Unable to create OCH interface on " + n.getNodeId() + " at " + srcTp); } //if destination interface creation was then proceed otherwise return. String dstIf = new OpenRoadmInterfaces(db, mps, n.getNodeId(), destTp).createOchInterface(waveNumber); if (dstIf == null) { LOG.warn("Unable to create OCH interface on " + n.getNodeId() + " at " + destTp); return setServBldr.setResult("Unable to create OCH interface on " + n.getNodeId() + " at " + destTp); } LOG.info("Creating cross connect between source :" + srcTp + " destination " + destTp + " for node " + n .getNodeId()); //Build cross connect object RoadmConnectionsBuilder rdmConnBldr = new RoadmConnectionsBuilder(); rdmConnBldr.setConnectionNumber(srcTp + "-" + destTp + "-" + waveNumber); rdmConnBldr.setWavelengthNumber(waveNumber); rdmConnBldr.setOpticalControlMode(OpticalControlMode.Off); rdmConnBldr.setSource(new SourceBuilder().setSrcIf(srcIf).build()); rdmConnBldr.setDestination(new DestinationBuilder().setDstIf(dstIf).build()); InstanceIdentifier rdmConnectionIID = InstanceIdentifier.create( OrgOpenroadmDevice.class).child(RoadmConnections.class, new RoadmConnectionsKey(rdmConnBldr .getConnectionNumber())); DataBroker netconfNodeDataBroker = PortMapping.getDeviceDataBroker(n.getNodeId(), mps); if (netconfNodeDataBroker != null) { final WriteTransaction writeTransaction = netconfNodeDataBroker.newWriteOnlyTransaction(); //post the cross connect on the device writeTransaction.put(LogicalDatastoreType.CONFIGURATION, rdmConnectionIID, rdmConnBldr.build()); final CheckedFuture submit = writeTransaction.submit(); try { submit.checkedGet(); nodesProvisioned.add(n.getNodeId()); LOG.info("Roadm-connection successfully created: " + srcTp + "-" + destTp); } catch (TransactionCommitFailedException ex) { LOG.warn("Failed to post {} ", rdmConnBldr.build(), ex); return setServBldr.setResult("Unable to post Roadm-connection for node " + n.getNodeId()); } } else { LOG.error("Unable to get device broker for node " + n.getNodeId()); return setServBldr.setResult("Unable to get device broker for node " + n.getNodeId()); } } else { LOG.warn(n.getNodeId() + " is not mounted on the controller"); return setServBldr.setResult(n.getNodeId() + " is not mounted on the controller"); } } return setServBldr.setResult("Roadm-connection successfully created for nodes " + nodesProvisioned.toString()); } /** * This method removes wavelength path based on following steps: * For each node: * *

* 1. Delete Cross connect between source and destination tps. * 2. Delete Och interface on source termination point. * 3. Delete Och interface on destination termination point. * *

* Naming convention used for OCH interfaces name : tp-wavenumber * Naming convention used for cross connect name : src-dest-wavenumber * * @param input Input parameter from the service-path yang model * * @return Result result of the request. */ public ServicePathOutputBuilder deleteServicePath(ServicePathInput input) { List nodes = input.getNodes(); ServicePathOutputBuilder delServBldr = new ServicePathOutputBuilder(); LOG.info(currentMountedDevice.toString()); for (Nodes n : nodes) { LOG.info("Deleting service setup on node " + n.getNodeId()); String srcTp = n.getSrcTp(); String destTp = n.getDestTp(); Long waveNumber = input.getWaveNumber(); //if the node is currently mounted then proceed. if (currentMountedDevice.contains(n.getNodeId())) { DataBroker netconfNodeDataBroker = PortMapping.getDeviceDataBroker(n.getNodeId(), mps); if (netconfNodeDataBroker != null) { // Deleting roadm connection InstanceIdentifier rdmConnectionIID = InstanceIdentifier.create( OrgOpenroadmDevice.class).child(RoadmConnections.class, new RoadmConnectionsKey(srcTp + "-" + destTp + "-" + waveNumber)); ReadWriteTransaction writeTx = netconfNodeDataBroker.newReadWriteTransaction(); writeTx.delete(LogicalDatastoreType.CONFIGURATION, rdmConnectionIID); final CheckedFuture submit = writeTx.submit(); try { submit.checkedGet(); LOG.info("Successfully deleted interface " + srcTp + "-" + destTp + "-" + waveNumber); } catch (TransactionCommitFailedException ex) { LOG.error("Failed to delete {} ", srcTp + "-" + destTp + "-" + waveNumber, ex); } // Deleting interface on source termination point writeTx = netconfNodeDataBroker.newReadWriteTransaction(); InstanceIdentifier srcInterfacesIID = InstanceIdentifier.create(OrgOpenroadmDevice.class) .child(Interface.class, new InterfaceKey(srcTp + "-" + waveNumber.toString())); writeTx.delete(LogicalDatastoreType.CONFIGURATION, srcInterfacesIID); final CheckedFuture submitSrcDel = writeTx.submit(); try { submitSrcDel.checkedGet(); LOG.info("Successfully deleted " + srcTp + "-" + waveNumber.toString()); } catch (TransactionCommitFailedException ex) { LOG.error("Failed to delete interface {} ", srcTp + "-" + waveNumber.toString(), ex); } // Deleting interface on destination termination point writeTx = netconfNodeDataBroker.newReadWriteTransaction(); InstanceIdentifier destInterfacesIID = InstanceIdentifier.create( OrgOpenroadmDevice.class).child(Interface.class, new InterfaceKey(destTp + "-" + waveNumber .toString())); writeTx.delete(LogicalDatastoreType.CONFIGURATION, destInterfacesIID); final CheckedFuture submitDestDel = writeTx.submit(); try { submitDestDel.checkedGet(); LOG.info("Successfully deleted " + destTp + "-" + waveNumber.toString()); } catch (TransactionCommitFailedException ex) { LOG.error("Failed to delete interface {} ", destTp + "-" + waveNumber.toString(), ex); } } } else { LOG.warn(n.getNodeId() + " is not mounted on the controller"); return delServBldr.setResult(n.getNodeId() + " is not mounted on the controller"); } } return delServBldr.setResult("Request processed"); } }