From: Shweta V Date: Wed, 20 Dec 2017 10:23:09 +0000 (+0100) Subject: add a common folder for mutualized functions X-Git-Tag: v0.2.0~71 X-Git-Url: https://git.opendaylight.org/gerrit/gitweb?p=transportpce.git;a=commitdiff_plain;h=f8f1b05b6eefd0f5c18e22c22b4d4e023f61faf6 add a common folder for mutualized functions Co-Authored-By: Dhruv Bhardwaj Co-Authored-By: Shweta Vachhani Co-Authored-By: Masha Dorfman <> Co-Authored-By: Archana Soundararajan Co-Authored-By: Juraj Veverka Co-Authored-By: Samuel Kontri Co-Authored-By: Andrej Zan Co-Authored-By: Milan Fratrik <> Co-authored-by: Martial COULIBALY Change-Id: I1b41bb54a2e5ba05797b67a629c72a38d31d1819 Signed-off-by: Shweta Signed-off-by: Martial COULIBALY --- diff --git a/common/pom.xml b/common/pom.xml new file mode 100644 index 000000000..f14ae5339 --- /dev/null +++ b/common/pom.xml @@ -0,0 +1,90 @@ + + + + + 4.0.0 + + + org.opendaylight.odlparent + bundle-parent + 3.1.0 + + + + org.opendaylight.transportpce + transportpce-common + 0.2.0-SNAPSHOT + bundle + + + + + org.opendaylight.controller + mdsal-artifacts + 1.7.3-SNAPSHOT + import + pom + + + org.opendaylight.netconf + netconf-artifacts + 1.4.3-SNAPSHOT + import + pom + + + org.opendaylight.mdsal.model + mdsal-model-artifacts + 0.12.3-SNAPSHOT + import + pom + + + + + + + ${project.groupId} + transportpce-api + ${project.version} + + + org.opendaylight.controller + sal-binding-api + + + org.opendaylight.controller.model + model-topology + + + org.opendaylight.mdsal.model + ietf-network-2015-06-08 + + + org.opendaylight.netconf + sal-netconf-connector + + + ${project.groupId}.ordmodels + transportpce-ordmodels-device + ${project.version} + + + + + junit + junit + test + + + + org.mockito + mockito-core + test + + + + diff --git a/common/src/main/java/org/opendaylight/transportpce/common/InstanceIdentifiers.java b/common/src/main/java/org/opendaylight/transportpce/common/InstanceIdentifiers.java new file mode 100644 index 000000000..e883923e5 --- /dev/null +++ b/common/src/main/java/org/opendaylight/transportpce/common/InstanceIdentifiers.java @@ -0,0 +1,40 @@ +/* + * 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.common; + +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.network.rev150608.Network; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.network.rev150608.NetworkId; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.network.rev150608.NetworkKey; +import org.opendaylight.yang.gen.v1.urn.opendaylight.netconf.node.topology.rev150114.network.topology.topology.topology.types.TopologyNetconf; +import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.NetworkTopology; +import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.TopologyId; +import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.Topology; +import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.TopologyKey; +import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; + +public class InstanceIdentifiers { + + public static final InstanceIdentifier NETCONF_TOPOLOGY_II = + InstanceIdentifier.create(NetworkTopology.class).child(Topology.class, new TopologyKey( + new TopologyId(TopologyNetconf.QNAME.getLocalName()))); + + public static final InstanceIdentifier UNDERLAY_NETWORK_II = InstanceIdentifier + .builder(Network.class, new NetworkKey(new NetworkId(NetworkUtils.UNDERLAY_NETWORK_ID))).build(); + + public static final InstanceIdentifier OVERLAY_NETWORK_II = InstanceIdentifier + .builder(Network.class, new NetworkKey(new NetworkId(NetworkUtils.OVERLAY_NETWORK_ID))).build(); + + public static final InstanceIdentifier CLLI_NETWORK_II = InstanceIdentifier + .builder(Network.class, new NetworkKey(new NetworkId(NetworkUtils.CLLI_NETWORK_ID))).build(); + + private InstanceIdentifiers() { + // Instance should be not created + } + +} diff --git a/common/src/main/java/org/opendaylight/transportpce/common/NetworkUtils.java b/common/src/main/java/org/opendaylight/transportpce/common/NetworkUtils.java new file mode 100644 index 000000000..ded1ce3f6 --- /dev/null +++ b/common/src/main/java/org/opendaylight/transportpce/common/NetworkUtils.java @@ -0,0 +1,19 @@ +/* + * Copyright © 2016 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.common; + +public final class NetworkUtils { + + private NetworkUtils() { + } + + public static final String CLLI_NETWORK_ID = "clli-network"; + public static final String UNDERLAY_NETWORK_ID = "openroadm-network"; + public static final String OVERLAY_NETWORK_ID = "openroadm-topology"; + +} diff --git a/common/src/main/java/org/opendaylight/transportpce/common/OperationResult.java b/common/src/main/java/org/opendaylight/transportpce/common/OperationResult.java new file mode 100644 index 000000000..2506d0675 --- /dev/null +++ b/common/src/main/java/org/opendaylight/transportpce/common/OperationResult.java @@ -0,0 +1,36 @@ +/* + * Copyright © 2017 Orange, Inc. 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.common; + +public class OperationResult { + + private final boolean success; + private final String resultMessage; + + protected OperationResult(boolean success, String resultMessage) { + this.success = success; + this.resultMessage = resultMessage; + } + + public boolean isSuccess() { + return success; + } + + public String getResultMessage() { + return resultMessage; + } + + public static OperationResult failed(String message) { + return new OperationResult(false, message); + } + + public static OperationResult ok(String message) { + return new OperationResult(true, message); + } + +} diff --git a/common/src/main/java/org/opendaylight/transportpce/common/ResponseCodes.java b/common/src/main/java/org/opendaylight/transportpce/common/ResponseCodes.java new file mode 100644 index 000000000..435afd374 --- /dev/null +++ b/common/src/main/java/org/opendaylight/transportpce/common/ResponseCodes.java @@ -0,0 +1,20 @@ +/* + * Copyright © 2016 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.common; + +public class ResponseCodes { + + public static final String RESPONSE_FAILED = "500"; + public static final String RESPONSE_OK = "200"; + public static final String FINAL_ACK_YES = "Yes"; + public static final String FINAL_ACK_NO = "No"; + + public static final String SUCCESS_RESULT = "Success"; + public static final String FAILED_RESULT = "Failed"; + +} diff --git a/common/src/main/java/org/opendaylight/transportpce/common/StringConstants.java b/common/src/main/java/org/opendaylight/transportpce/common/StringConstants.java new file mode 100644 index 000000000..e45d99335 --- /dev/null +++ b/common/src/main/java/org/opendaylight/transportpce/common/StringConstants.java @@ -0,0 +1,20 @@ +/* + * Copyright © 2016 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.common; + +public class StringConstants { + + public static final String OPENROADM_DEVICE_MODEL_NAME = "org-openroadm-device"; + public static final String DEFAULT_NETCONF_NODEID = "controller-config"; + + private StringConstants() { + // hiding the default constructor + } + +} diff --git a/common/src/main/java/org/opendaylight/transportpce/common/Timeouts.java b/common/src/main/java/org/opendaylight/transportpce/common/Timeouts.java new file mode 100644 index 000000000..c8051c6f1 --- /dev/null +++ b/common/src/main/java/org/opendaylight/transportpce/common/Timeouts.java @@ -0,0 +1,34 @@ +/* + * Copyright © 2017 Orange, Inc. 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.common; + +import java.util.concurrent.TimeUnit; + +public final class Timeouts { + public static final long DATASTORE_READ = 1000; + public static final long DATASTORE_WRITE = 1000; + public static final long DATASTORE_DELETE = 1000; + + // TODO remove '* 2' when renderer and olm is running in parallel + public static final long RENDERING_TIMEOUT = 240000 * 2; + public static final long OLM_TIMEOUT = 240000 * 2; + + public static final long SERVICE_ACTIVATION_TEST_RETRY_TIME = 20000; + + /** + * Device read timeout in seconds. + */ + public static final long DEVICE_READ_TIMEOUT = 240; + public static final TimeUnit DEVICE_READ_TIMEOUT_UNIT = TimeUnit.SECONDS; + + public static final long DEVICE_WRITE_TIMEOUT = 240; + public static final TimeUnit DEVICE_WRITE_TIMEOUT_UNIT = TimeUnit.SECONDS; + + //TODO add timeouts for device setup (olm power setup etc.) +} diff --git a/common/src/main/java/org/opendaylight/transportpce/common/crossconnect/CrossConnect.java b/common/src/main/java/org/opendaylight/transportpce/common/crossconnect/CrossConnect.java new file mode 100644 index 000000000..45a244043 --- /dev/null +++ b/common/src/main/java/org/opendaylight/transportpce/common/crossconnect/CrossConnect.java @@ -0,0 +1,81 @@ +/* + * 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.common.crossconnect; + +import java.util.List; +import java.util.Optional; + +import org.opendaylight.transportpce.common.openroadminterfaces.OpenRoadmInterfaceException; +import org.opendaylight.yang.gen.v1.http.org.openroadm.device.rev170206.get.connection.port.trail.output.Ports; +import org.opendaylight.yang.gen.v1.http.org.openroadm.device.rev170206.org.openroadm.device.container.org.openroadm.device.RoadmConnections; + +public interface CrossConnect { + + /** + * This method return the RoadmConnection subtree for a given connection + * number. + * + * @param deviceId + * Device id. + * @param connectionNumber + * Name of the cross connect. + * + * @return Roadm connection subtree from the device. + */ + Optional getCrossConnect(String deviceId, String connectionNumber); + + /** + * This method does a post(edit-config) on roadm connection subtree for a + * given connection number. + * + * @param deviceId + * Device id. + * @param waveNumber + * Wavelength number. + * @param srcTp + * Name of source termination point. + * @param destTp + * Name of destination termination point. + * @return optional of connection number + */ + Optional postCrossConnect(String deviceId, Long waveNumber, String srcTp, String destTp); + + /** + * This method does a delete(edit-config) on roadm connection subtree for a + * given connection number. + * + * @param deviceId + * Device id. + * @param connectionNumber + * Name of the cross connect. + * + * @return true/false based on status of operation. + */ + + boolean deleteCrossConnect(String deviceId, String connectionNumber); + + /** + * This public method returns the list of ports (port-trail) for a roadm's + * cross connect. It calls rpc get-port-trail on device. To be used store + * detailed path description. + * + * @param nodeId + * node-id of NE. + * @param waveNumber + * Wavelength number. + * @param srcTp + * Source logical connection point. + * @param destTp + * Destination logical connection point. + * + * @return list of Ports object type. + */ + List getConnectionPortTrail(String nodeId, Long waveNumber, String srcTp, String destTp) + throws OpenRoadmInterfaceException; +} diff --git a/common/src/main/java/org/opendaylight/transportpce/common/crossconnect/CrossConnectImpl.java b/common/src/main/java/org/opendaylight/transportpce/common/crossconnect/CrossConnectImpl.java new file mode 100644 index 000000000..b67f76c6f --- /dev/null +++ b/common/src/main/java/org/opendaylight/transportpce/common/crossconnect/CrossConnectImpl.java @@ -0,0 +1,188 @@ +/* + * 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.common.crossconnect; + +import com.google.common.util.concurrent.ListenableFuture; + +import java.util.Collections; +import java.util.List; +import java.util.Optional; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.Future; + +import org.opendaylight.controller.md.sal.binding.api.MountPoint; +import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType; +import org.opendaylight.controller.sal.binding.api.RpcConsumerRegistry; +import org.opendaylight.transportpce.common.Timeouts; +import org.opendaylight.transportpce.common.device.DeviceTransaction; +import org.opendaylight.transportpce.common.device.DeviceTransactionManager; +import org.opendaylight.transportpce.common.openroadminterfaces.OpenRoadmInterfaceException; +import org.opendaylight.yang.gen.v1.http.org.openroadm.common.types.rev161014.OpticalControlMode; +import org.opendaylight.yang.gen.v1.http.org.openroadm.device.rev170206.GetConnectionPortTrailInputBuilder; +import org.opendaylight.yang.gen.v1.http.org.openroadm.device.rev170206.GetConnectionPortTrailOutput; +import org.opendaylight.yang.gen.v1.http.org.openroadm.device.rev170206.OrgOpenroadmDeviceService; +import org.opendaylight.yang.gen.v1.http.org.openroadm.device.rev170206.connection.DestinationBuilder; +import org.opendaylight.yang.gen.v1.http.org.openroadm.device.rev170206.connection.SourceBuilder; +import org.opendaylight.yang.gen.v1.http.org.openroadm.device.rev170206.get.connection.port.trail.output.Ports; +import org.opendaylight.yang.gen.v1.http.org.openroadm.device.rev170206.org.openroadm.device.container.OrgOpenroadmDevice; +import org.opendaylight.yang.gen.v1.http.org.openroadm.device.rev170206.org.openroadm.device.container.org.openroadm.device.RoadmConnections; +import org.opendaylight.yang.gen.v1.http.org.openroadm.device.rev170206.org.openroadm.device.container.org.openroadm.device.RoadmConnectionsBuilder; +import org.opendaylight.yang.gen.v1.http.org.openroadm.device.rev170206.org.openroadm.device.container.org.openroadm.device.RoadmConnectionsKey; +import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; +import org.opendaylight.yangtools.yang.common.RpcResult; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class CrossConnectImpl implements CrossConnect { + + private static final Logger LOG = LoggerFactory.getLogger(CrossConnectImpl.class); + + private final DeviceTransactionManager deviceTransactionManager; + + public CrossConnectImpl(DeviceTransactionManager deviceTransactionManager) { + this.deviceTransactionManager = deviceTransactionManager; + } + + @Override + public Optional getCrossConnect(String deviceId, String connectionNumber) { + return deviceTransactionManager.getDataFromDevice(deviceId, LogicalDatastoreType.OPERATIONAL, + generateRdmConnectionIID(connectionNumber), Timeouts.DEVICE_READ_TIMEOUT, + Timeouts.DEVICE_READ_TIMEOUT_UNIT); + } + + @Override + public Optional postCrossConnect(String deviceId, Long waveNumber, String srcTp, String destTp) { + RoadmConnectionsBuilder rdmConnBldr = new RoadmConnectionsBuilder(); + String connectionNumber = generateConnectionNumber(srcTp, destTp, waveNumber); + rdmConnBldr.setConnectionNumber(connectionNumber); + rdmConnBldr.setWavelengthNumber(waveNumber); + rdmConnBldr.setOpticalControlMode(OpticalControlMode.Off); + rdmConnBldr.setSource(new SourceBuilder().setSrcIf(srcTp + "-" + waveNumber.toString()).build()); + rdmConnBldr.setDestination(new DestinationBuilder().setDstIf(destTp + "-" + waveNumber.toString()).build()); + InstanceIdentifier rdmConnectionIID = InstanceIdentifier.create(OrgOpenroadmDevice.class) + .child(RoadmConnections.class, new RoadmConnectionsKey(rdmConnBldr.getConnectionNumber())); + + Future> deviceTxFuture = deviceTransactionManager.getDeviceTransaction(deviceId); + DeviceTransaction deviceTx; + try { + Optional deviceTxOpt = deviceTxFuture.get(); + if (deviceTxOpt.isPresent()) { + deviceTx = deviceTxOpt.get(); + } else { + LOG.error("Device transaction for device {} was not found!", deviceId); + return Optional.empty(); + } + } catch (InterruptedException | ExecutionException e) { + LOG.error("Unable to obtain device transaction for device {}!", deviceId, e); + return Optional.empty(); + } + + // post the cross connect on the device + deviceTx.put(LogicalDatastoreType.CONFIGURATION, rdmConnectionIID, rdmConnBldr.build()); + ListenableFuture submit = + deviceTx.submit(Timeouts.DEVICE_WRITE_TIMEOUT, Timeouts.DEVICE_WRITE_TIMEOUT_UNIT); + try { + submit.get(); + LOG.info("Roadm-connection successfully created: {}-{}-{}", srcTp, destTp, waveNumber); + return Optional.of(connectionNumber); + } catch (InterruptedException | ExecutionException e) { + LOG.warn("Failed to post {}. Exception: {}", rdmConnBldr.build(), e); + } + return Optional.empty(); + } + + @Override + public boolean deleteCrossConnect(String deviceId, String connectionNumber) { + //Check if cross connect exists before delete + if (!getCrossConnect(deviceId, connectionNumber).isPresent()) { + LOG.warn("Cross connect does not exist, halting delete"); + return false; + } + Future> deviceTxFuture = deviceTransactionManager.getDeviceTransaction(deviceId); + DeviceTransaction deviceTx; + try { + Optional deviceTxOpt = deviceTxFuture.get(); + if (deviceTxOpt.isPresent()) { + deviceTx = deviceTxOpt.get(); + } else { + LOG.error("Device transaction for device {} was not found!", deviceId); + return false; + } + } catch (InterruptedException | ExecutionException e) { + LOG.error("Unable to obtain device transaction for device {}!", deviceId, e); + return false; + } + + // post the cross connect on the device + deviceTx.delete(LogicalDatastoreType.CONFIGURATION, generateRdmConnectionIID(connectionNumber)); + ListenableFuture submit = + deviceTx.submit(Timeouts.DEVICE_WRITE_TIMEOUT, Timeouts.DEVICE_WRITE_TIMEOUT_UNIT); + try { + submit.get(); + LOG.info("Roadm connection successfully deleted "); + return true; + } catch (InterruptedException | ExecutionException e) { + LOG.warn("Failed to delete {}", connectionNumber, e); + } + return false; + } + + @Override + public List getConnectionPortTrail(String nodeId, Long waveNumber, String srcTp, String destTp) + throws OpenRoadmInterfaceException { + String connectionName = generateConnectionNumber(srcTp, destTp, waveNumber); + Optional mountPointOpt = deviceTransactionManager.getDeviceMountPoint(nodeId); + List ports = null; + MountPoint mountPoint; + if (mountPointOpt.isPresent()) { + mountPoint = mountPointOpt.get(); + } else { + LOG.error("Failed to obtain mount point for device {}!", nodeId); + return Collections.emptyList(); + } + final Optional service = mountPoint.getService(RpcConsumerRegistry.class).toJavaUtil(); + if (!service.isPresent()) { + LOG.error("Failed to get RpcService for node {}", nodeId); + } + final OrgOpenroadmDeviceService rpcService = service.get().getRpcService(OrgOpenroadmDeviceService.class); + final GetConnectionPortTrailInputBuilder portTrainInputBuilder = new GetConnectionPortTrailInputBuilder(); + portTrainInputBuilder.setConnectionNumber(connectionName); + final Future> portTrailOutput = rpcService.getConnectionPortTrail( + portTrainInputBuilder.build()); + if (portTrailOutput != null) { + try { + RpcResult connectionPortTrailOutputRpcResult = portTrailOutput.get(); + GetConnectionPortTrailOutput connectionPortTrailOutput = connectionPortTrailOutputRpcResult.getResult(); + if (connectionPortTrailOutput == null) { + throw new OpenRoadmInterfaceException(String.format("RPC get connection port trail called on" + + " node %s returned null!", nodeId)); + } + LOG.info("Getting port trail for node {}'s connection number {}", nodeId, connectionName); + ports = connectionPortTrailOutput.getPorts(); + for (Ports port : ports) { + LOG.info("{} - Circuit pack {} - Port {}", nodeId, port.getCircuitPackName(), port.getPortName()); + } + } catch (InterruptedException | ExecutionException e) { + LOG.warn("Exception caught", e); + } + } else { + LOG.warn("Port trail is null in getConnectionPortTrail for nodeId {}", nodeId); + } + return ports != null ? ports : Collections.emptyList(); + } + + private InstanceIdentifier generateRdmConnectionIID(String connectionNumber) { + return InstanceIdentifier.create(OrgOpenroadmDevice.class) + .child(RoadmConnections.class, new RoadmConnectionsKey(connectionNumber)); + } + + private String generateConnectionNumber(String srcTp, String destTp, Long waveNumber) { + return srcTp + "-" + destTp + "-" + waveNumber; + } +} diff --git a/common/src/main/java/org/opendaylight/transportpce/common/device/DeviceTransaction.java b/common/src/main/java/org/opendaylight/transportpce/common/device/DeviceTransaction.java new file mode 100644 index 000000000..45c401dfe --- /dev/null +++ b/common/src/main/java/org/opendaylight/transportpce/common/device/DeviceTransaction.java @@ -0,0 +1,150 @@ +/* + * Copyright © 2017 Orange, Inc. 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.common.device; + +import com.google.common.base.Optional; +import com.google.common.util.concurrent.CheckedFuture; +import com.google.common.util.concurrent.FutureCallback; +import com.google.common.util.concurrent.Futures; +import com.google.common.util.concurrent.ListenableFuture; + +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.Executors; +import java.util.concurrent.ScheduledExecutorService; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.atomic.AtomicBoolean; +import javax.annotation.Nullable; + +import org.opendaylight.controller.md.sal.binding.api.ReadWriteTransaction; +import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType; +import org.opendaylight.controller.md.sal.common.api.data.ReadFailedException; +import org.opendaylight.yangtools.yang.binding.DataObject; +import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * Represents read-write transaction on netconf device. + * This transaction can be obtained by {@link DeviceTransactionManager}. + * + *

+ * WARNING: Only one transaction can be opened at the same time on device! + * It's important to close (cancel/submit) transaction when work is done with it + * (so others can access the device). + *

+ */ +public class DeviceTransaction { + + private static final Logger LOG = LoggerFactory.getLogger(DeviceTransaction.class); + + private final ReadWriteTransaction rwTx; + private final CountDownLatch deviceLock; + private final ScheduledExecutorService scheduledExecutorService; + private final AtomicBoolean wasSubmittedOrCancelled = new AtomicBoolean(false); + + DeviceTransaction(ReadWriteTransaction rwTx, CountDownLatch deviceLock) { + this.rwTx = rwTx; + this.deviceLock = deviceLock; + this.scheduledExecutorService = Executors.newSingleThreadScheduledExecutor(); + LOG.debug("Device transaction created. Lock: {}", deviceLock); + } + + public CheckedFuture, ReadFailedException> read(LogicalDatastoreType store, + InstanceIdentifier path) { + return rwTx.read(store, path); + } + + public void put(LogicalDatastoreType store, InstanceIdentifier path, T data) { + rwTx.put(store, path, data); + } + + public void put(LogicalDatastoreType store, InstanceIdentifier path, T data, + boolean createMissingParents) { + rwTx.put(store, path, data, createMissingParents); + } + + public void merge(LogicalDatastoreType store, InstanceIdentifier path, T data) { + rwTx.merge(store, path, data); + } + + public void merge(LogicalDatastoreType store, InstanceIdentifier path, T data, + boolean createMissingParents) { + rwTx.merge(store, path, data, createMissingParents); + } + + public void delete(LogicalDatastoreType store, InstanceIdentifier path) { + rwTx.delete(store, path); + } + + /** + * Cancels transaction and unlocks it. + * @return true if cancel was successful. + */ + public boolean cancel() { + if (wasSubmittedOrCancelled.get()) { + LOG.warn("Transaction was already submitted or canceled!"); + return false; + } + + LOG.debug("Transaction cancelled. Lock: {}", deviceLock); + wasSubmittedOrCancelled.set(true); + afterClose(); + return rwTx.cancel(); + } + + /** + * Submits data changed in transaction to device with defined timeout to submit. If time from timeout runs out then + * submit will be interrupted and device will be unlocked. + * + * @param timeout a timeout + * @param timeUnit a time unit + * @return ListenableFuture which indicates when is submit completed. + */ + public ListenableFuture submit(long timeout, TimeUnit timeUnit) { + if (wasSubmittedOrCancelled.get()) { + String msg = "Transaction was already submitted or canceled!"; + LOG.error(msg); + return Futures.immediateFailedFuture(new IllegalStateException(msg)); + } + + LOG.debug("Transaction submitted. Lock: {}", deviceLock); + wasSubmittedOrCancelled.set(true); + ListenableFuture future = + Futures.withTimeout(rwTx.submit(), timeout, timeUnit, scheduledExecutorService); + + Futures.addCallback(future, new FutureCallback() { + @Override + public void onSuccess(@Nullable Void result) { + LOG.debug("Transaction with lock {} successfully submitted.", deviceLock); + afterClose(); + } + + @Override + public void onFailure(Throwable t) { + LOG.error("Device transaction submit failed or submit took longer than {} {}!" + + " Unlocking device.", timeout, timeUnit, t); + afterClose(); + } + }, scheduledExecutorService); + return future; + } + + /** + * Returns state of transaction. + * @return true if transaction was closed; otherwise false + */ + public AtomicBoolean wasSubmittedOrCancelled() { + return wasSubmittedOrCancelled; + } + + private void afterClose() { + scheduledExecutorService.shutdown(); + deviceLock.countDown(); + } +} diff --git a/common/src/main/java/org/opendaylight/transportpce/common/device/DeviceTransactionManager.java b/common/src/main/java/org/opendaylight/transportpce/common/device/DeviceTransactionManager.java new file mode 100644 index 000000000..20371356f --- /dev/null +++ b/common/src/main/java/org/opendaylight/transportpce/common/device/DeviceTransactionManager.java @@ -0,0 +1,164 @@ +/* + * Copyright © 2017 Orange, Inc. 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.common.device; + +import java.util.Optional; +import java.util.concurrent.Future; +import java.util.concurrent.TimeUnit; + +import org.opendaylight.controller.md.sal.binding.api.MountPoint; +import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType; +import org.opendaylight.yangtools.yang.binding.DataObject; +import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; + +/** + *

+ * Device transaction manager manages access to netconf devices. Only one transaction can be opened per device so + * it IS IMPORTANT TO CLOSE TRANSACTION as soon as transactions is not needed. + *

+ * + *

+ * Most important method is {@link DeviceTransactionManager#getDeviceTransaction(String)}. This method let's you + * obtain {@link DeviceTransaction} on the device. {@link DeviceTransaction} provices methods to read/write data + * from/to device. + *

+ * + *

+ * Method + * {@link DeviceTransactionManager#getDataFromDevice(String, LogicalDatastoreType, InstanceIdentifier, long, TimeUnit)} + * is 'shortcut' to get data from device. It creates {@link DeviceTransaction}, gets data via it and then closes + * the transaction. + *

+ * + *

+ * Two timeouts are built in process to prevent locking device forever: + *

+ *
    + *
  • + * First is from creation of {@link DeviceTransaction} to calling method to close it (submit or cancel). When using + * {@link DeviceTransactionManager#getDeviceTransaction(String)} method then default timeout will be used. If there + * is need to specify this timeout manually use + * {@link DeviceTransactionManager#getDeviceTransaction(String, long, TimeUnit)} method. So if programmer will + * forgot to close transaction or it will take too much time transaction will be cancelled automatically and device + * will be unlocked. + *
  • + * + *
  • + * Second timeout is from calling {@link DeviceTransaction#submit(long, TimeUnit)} until submit is completed on + * device. Timeout can be specified directly using submit method. So in case submit will freeze somewhere on device + * or it will take too much time device will be unlocked. + *
  • + *
+ * + *

+ * If there is only need to read from device + * {@link DeviceTransactionManager#getDataFromDevice(String, LogicalDatastoreType, InstanceIdentifier, long, TimeUnit)} + * method can be used. It will automatically take care of {@link DeviceTransaction} and it will return data. + * This method SHOULD NOT BE USED TOGETHER WITH DEVICE TRANSACTION ON THE SAME DEVICE IN THE SAME TIME. + * In case that {@link DeviceTransaction} is created on device and before submitting it + * {@link DeviceTransactionManager#getDataFromDevice(String, LogicalDatastoreType, InstanceIdentifier, long, TimeUnit)} + * method is called then get method will wait (will be blocking current thread) until device will be unlocked. + * However device is locked by transaction previously created. So this will result in blocking current thread until + * timeout for submit transaction will run out and cancel transaction. This can lead to incorrect execution of code. + *

+ * + *

+ * Bellow is simple example how to get {@link DeviceTransaction}, put some data to it and then submit it. + *

+ * {@code
+ *     // get device transaction future from device transaction manager
+ *     Future> deviceTxFuture = deviceTransactionManager.getDeviceTransaction(deviceId);
+ *     DeviceTransaction deviceTx;
+ *     try {
+ *         // wait until device transaction is available
+ *         Optional deviceTxOpt = deviceTxFuture.get();
+ *
+ *         // check if device transaction is present
+ *         if (deviceTxOpt.isPresent()) {
+ *             deviceTx = deviceTxOpt.get();
+ *         } else {
+ *             throw new IllegalStateException("Device transaction for device " + deviceId + " was not found!");
+ *         }
+ *     } catch (InterruptedException | ExecutionException e) {
+ *         throw new IllegalStateException("Unable to obtain device transaction for device " + deviceId + "!", e);
+ *     }
+ *
+ *     // do some operations with transaction
+ *     deviceTx.put(LogicalDatastoreType.CONFIGURATION, someInstanceIdentifier, someData);
+ *     deviceTx.delete(LogicalDatastoreType.CONFIGURATION, someOtherInstanceIdentifier, someOtherData);
+ *
+ *     // submit transaction with 5 seconds timeout
+ *     ListenableFuture submit = deviceTx.submit(5, TimeUnit.SECONDS);
+ *     try {
+ *         // wait until transaction is submitted
+ *         submit.get();
+ *     } catch (InterruptedException | ExecutionException e) {
+ *         throw new IllegalStateException("Failed to post data to device " + deviceId + "!", e);
+ *     }
+ * }
+ * 
+ *

+ */ +public interface DeviceTransactionManager { + + /** + * Gets Future containing {@link DeviceTransaction}. Since only one transaction can be opened per device future will + * return transaction when all previously submitted transaction on device are closed. This method will use default + * timeout for submit transaction. + * + * @param deviceId device identifier on which will be transaction created. + * @return Future returning Optional of DeviceTransaction. Optional will be empty if device with specified ID + * does not exists or transaction will fail to obtain. + */ + Future> getDeviceTransaction(String deviceId); + + /** + * Works same as {@link DeviceTransactionManager#getDeviceTransaction(String)} but with option to set custom timeout. + * + * @param deviceId device id on which will be transaction created. + * @param timeoutToSubmit timeout will start running when transaction is created. If transaction will not be + * closed (submitted or cancelled) when times runs out it will be canceled (so device will + * be unlocked). + * @param timeUnit time units for timeout. + * @return Future returning Optional of DeviceTransaction. Optional will be empty if device with specified ID + * does not exists or transaction will fail to obtain. + */ + Future> getDeviceTransaction(String deviceId, long timeoutToSubmit, TimeUnit timeUnit); + + // TODO make private in impl + @Deprecated + Optional getDeviceMountPoint(String deviceId); + + /** + * Returns data from device from specified path. Creates new device transaction, gets data via it and closes + * transaction. + * + * This method is blocking - it's waiting until it receives {@link DeviceTransaction} and then the data from device. + * + * @param deviceId Device identifier from which will be data read. + * @param logicalDatastoreType Datastore type. + * @param path Path to data in device's datastore. + * @param timeout Timeout to automatically close transaction AND to get data from device (sets both timeouts to + * same value). + * @param timeUnit Time unit of timeout. + * @param Type of data to be returned. + * @return Optional of data obtained from device. If device does not contain data or device does not exists then + * empty Optional will be returned. + */ + Optional getDataFromDevice(String deviceId, LogicalDatastoreType logicalDatastoreType, + InstanceIdentifier path, long timeout, TimeUnit timeUnit); + + /** + * Checks if device with specified ID is mounted. + * + * @param deviceId Identifier of device to check. + * @return True if device is mounted. + */ + boolean isDeviceMounted(String deviceId); +} diff --git a/common/src/main/java/org/opendaylight/transportpce/common/device/DeviceTransactionManagerImpl.java b/common/src/main/java/org/opendaylight/transportpce/common/device/DeviceTransactionManagerImpl.java new file mode 100644 index 000000000..889b4795d --- /dev/null +++ b/common/src/main/java/org/opendaylight/transportpce/common/device/DeviceTransactionManagerImpl.java @@ -0,0 +1,187 @@ +/* + * Copyright © 2017 Orange, Inc. 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.common.device; + +import com.google.common.util.concurrent.FutureCallback; +import com.google.common.util.concurrent.Futures; +import com.google.common.util.concurrent.ListenableFuture; +import com.google.common.util.concurrent.ListeningExecutorService; +import com.google.common.util.concurrent.MoreExecutors; + +import java.util.Optional; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.ConcurrentMap; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.Executors; +import java.util.concurrent.Future; +import java.util.concurrent.ScheduledExecutorService; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.TimeoutException; + +import org.opendaylight.controller.md.sal.binding.api.DataBroker; +import org.opendaylight.controller.md.sal.binding.api.MountPoint; +import org.opendaylight.controller.md.sal.binding.api.MountPointService; +import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType; +import org.opendaylight.transportpce.common.InstanceIdentifiers; +import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.NodeId; +import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.Node; +import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.NodeKey; +import org.opendaylight.yangtools.yang.binding.DataObject; +import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + + +public class DeviceTransactionManagerImpl implements DeviceTransactionManager { + + // TODO cache device data brokers + // TODO remove disconnected devices from maps + + private static final Logger LOG = LoggerFactory.getLogger(DeviceTransactionManagerImpl.class); + private static final int NUMBER_OF_THREADS = 4; + private static final long GET_DATA_SUBMIT_TIMEOUT = 3000; + private static final TimeUnit GET_DATA_SUBMIT_TIME_UNIT = TimeUnit.MILLISECONDS; + + private final MountPointService mountPointService; + private final ScheduledExecutorService checkingExecutor; + private final ListeningExecutorService listeningExecutor; + private final ConcurrentMap deviceLocks; + private final long maxDurationToSubmitTransaction; // TODO set reasonable value in blueprint + private final TimeUnit maxDurationToSubmitTransactionTimeUnit = TimeUnit.MILLISECONDS; + + public DeviceTransactionManagerImpl(MountPointService mountPointService, long maxDurationToSubmitTransaction) { + this.mountPointService = mountPointService; + this.maxDurationToSubmitTransaction = maxDurationToSubmitTransaction; + this.deviceLocks = new ConcurrentHashMap<>(); + this.checkingExecutor = Executors.newScheduledThreadPool(NUMBER_OF_THREADS); + this.listeningExecutor = MoreExecutors.listeningDecorator(Executors.newFixedThreadPool(NUMBER_OF_THREADS)); + } + + @Override + public Future> getDeviceTransaction(String deviceId) { + return getDeviceTransaction(deviceId, maxDurationToSubmitTransaction, maxDurationToSubmitTransactionTimeUnit); + } + + @Override + public Future> getDeviceTransaction(String deviceId, long timeoutToSubmit, + TimeUnit timeUnit) { + CountDownLatch newLock = new CountDownLatch(1); + ListenableFuture> future = listeningExecutor.submit(() -> { + LOG.debug("Starting creation of transaction for device {}.", deviceId); + // get current lock from device and set new lock + CountDownLatch actualLock = swapActualLock(deviceId, newLock); + if (actualLock != null) { + // if lock was present on device wait until it unlocks + actualLock.await(); + } + + Optional deviceDataBrokerOpt = getDeviceDataBroker(deviceId); + DataBroker deviceDataBroker; + if (deviceDataBrokerOpt.isPresent()) { + deviceDataBroker = deviceDataBrokerOpt.get(); + } else { + newLock.countDown(); + return Optional.empty(); + } + LOG.debug("Created transaction for device {}.", deviceId); + return Optional.of(new DeviceTransaction(deviceDataBroker.newReadWriteTransaction(), newLock)); + }); + + Futures.addCallback(future, new FutureCallback>() { + @Override + public void onSuccess(Optional deviceTransactionOptional) { + // creates timeout for transaction to submit right after transaction is created + // if time will run out and transaction was not closed then it will be cancelled (and unlocked) + checkingExecutor.schedule(() -> { + if (deviceTransactionOptional.isPresent()) { + DeviceTransaction deviceTx = deviceTransactionOptional.get(); + LOG.debug("Timeout to submit transaction run out! Transaction was {} submitted or canceled.", + deviceTx.wasSubmittedOrCancelled().get() ? "" : "not"); + if (!deviceTx.wasSubmittedOrCancelled().get()) { + LOG.error(String.format("Transaction for node %s was not submitted or canceled after %s" + + " milliseconds! Cancelling transaction!", deviceId, + timeoutToSubmit)); + deviceTx.cancel(); + } + } + }, timeoutToSubmit, timeUnit); + } + + @Override + public void onFailure(Throwable t) { + LOG.error("Exception thrown while getting device transaction for device {}! Unlocking device.", + deviceId, t); + newLock.countDown(); + } + }, checkingExecutor); + + return future; + } + + private synchronized CountDownLatch swapActualLock(String deviceId, CountDownLatch newLock) { + return deviceLocks.put(deviceId, newLock); + } + + private Optional getDeviceDataBroker(String deviceId) { + Optional netconfNode = getDeviceMountPoint(deviceId); + if (netconfNode.isPresent()) { + return netconfNode.get().getService(DataBroker.class).toJavaUtil(); + } else { + LOG.error("Device mount point not found for : {}", deviceId); + return Optional.empty(); + } + } + + @Override + public Optional getDeviceMountPoint(String deviceId) { + InstanceIdentifier netconfNodeIID = InstanceIdentifiers.NETCONF_TOPOLOGY_II.child(Node.class, + new NodeKey(new NodeId(deviceId))); + return mountPointService.getMountPoint(netconfNodeIID).toJavaUtil(); + } + + @Override + public Optional getDataFromDevice(String deviceId, + LogicalDatastoreType logicalDatastoreType, InstanceIdentifier path, long timeout, TimeUnit timeUnit) { + Optional deviceTxOpt; + try { + deviceTxOpt = getDeviceTransaction(deviceId, timeout, timeUnit).get(); + } catch (InterruptedException | ExecutionException e) { + LOG.error("Exception thrown while getting transaction for device {}!", deviceId, e); + return Optional.empty(); + } + if (deviceTxOpt.isPresent()) { + DeviceTransaction deviceTx = deviceTxOpt.get(); + try { + return deviceTx.read(logicalDatastoreType, path).get(timeout, timeUnit).toJavaUtil(); + } catch (InterruptedException | ExecutionException | TimeoutException e) { + LOG.error("Exception thrown while reading data from device {}! IID: {}", deviceId, path, e); + } finally { + deviceTx.submit(GET_DATA_SUBMIT_TIMEOUT, GET_DATA_SUBMIT_TIME_UNIT); + } + } else { + LOG.error("Could not obtain transaction for device {}!", deviceId); + } + return Optional.empty(); + } + + @Override + public boolean isDeviceMounted(String deviceId) { + return getDeviceDataBroker(deviceId).isPresent(); + } + + public void preDestroy() { + checkingExecutor.shutdown(); + listeningExecutor.shutdown(); + } + + public long getMaxDurationToSubmitTransaction() { + return maxDurationToSubmitTransaction; + } +} diff --git a/common/src/main/java/org/opendaylight/transportpce/common/mapping/PortMapping.java b/common/src/main/java/org/opendaylight/transportpce/common/mapping/PortMapping.java new file mode 100644 index 000000000..5ddbe0109 --- /dev/null +++ b/common/src/main/java/org/opendaylight/transportpce/common/mapping/PortMapping.java @@ -0,0 +1,65 @@ +/* + * 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.common.mapping; + +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.portmapping.rev170228.network.nodes.Mapping; + +public interface PortMapping { + + /** + * This method creates logical to physical port mapping for a given device. + * Instead of parsing all the circuit packs/ports in the device this methods + * does a selective read operation on degree/srg subtree to get circuit + * packs/ports that map to : + * + *

+ * 1. DEGn-TTP-TX, DEGn-TTP-RX, DEGn-TTP-TXRX + * + *

+ * 2. SRGn-PPp-TX, SRGn-PPp-RX, SRGn-PPp-TXRX + * + *

+ * 3. LINEn + * + *

+ * 4. CLNTn. + * + *

+ * If the port is Mw it also store the OMS, OTS interface provisioned on the + * port. It skips the logical ports that are internal. If operation is + * successful the mapping gets stored in datastore corresponding to + * portmapping.yang data model. + * + * @return true/false based on status of operation + */ + boolean createMappingData(String nodeId); + + /** + * This method for a given node's termination point returns the Mapping object based on + * portmapping.yang model stored in the MD-SAL data store which is created when the node is + * connected for the first time. The mapping object basically contains the following attributes of + * interest: + * + *

+ * 1. Supporting circuit pack + * + *

+ * 2. Supporting port + * + *

+ * 3. Supporting OMS interface (if port on ROADM) 4. Supporting OTS interface (if port on ROADM) + * + * @param nodeId Unique Identifier for the node of interest. + * @param logicalConnPoint Name of the logical point + * + * @return Result Mapping object if success otherwise null. + */ + + Mapping getMapping(String nodeId, String logicalConnPoint); +} diff --git a/common/src/main/java/org/opendaylight/transportpce/common/mapping/PortMappingImpl.java b/common/src/main/java/org/opendaylight/transportpce/common/mapping/PortMappingImpl.java new file mode 100644 index 000000000..e8e9e10fa --- /dev/null +++ b/common/src/main/java/org/opendaylight/transportpce/common/mapping/PortMappingImpl.java @@ -0,0 +1,525 @@ +/* + * 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.common.mapping; + +import com.google.common.util.concurrent.CheckedFuture; + +import java.util.ArrayList; +import java.util.Comparator; +import java.util.List; +import java.util.Optional; +import java.util.concurrent.ExecutionException; +import java.util.stream.Collectors; + +import org.opendaylight.controller.md.sal.binding.api.DataBroker; +import org.opendaylight.controller.md.sal.binding.api.ReadOnlyTransaction; +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.common.Timeouts; +import org.opendaylight.transportpce.common.device.DeviceTransactionManager; +import org.opendaylight.transportpce.common.openroadminterfaces.OpenRoadmInterfaceException; +import org.opendaylight.transportpce.common.openroadminterfaces.OpenRoadmInterfaces; +import org.opendaylight.transportpce.common.openroadminterfaces.OpenRoadmInterfacesImpl; +import org.opendaylight.yang.gen.v1.http.org.openroadm.common.types.rev161014.NodeTypes; +import org.opendaylight.yang.gen.v1.http.org.openroadm.device.rev170206.CircuitPack; +import org.opendaylight.yang.gen.v1.http.org.openroadm.device.rev170206.Port; +import org.opendaylight.yang.gen.v1.http.org.openroadm.device.rev170206.circuit.pack.Ports; +import org.opendaylight.yang.gen.v1.http.org.openroadm.device.rev170206.circuit.pack.PortsKey; +import org.opendaylight.yang.gen.v1.http.org.openroadm.device.rev170206.circuit.packs.CircuitPacks; +import org.opendaylight.yang.gen.v1.http.org.openroadm.device.rev170206.circuit.packs.CircuitPacksKey; +import org.opendaylight.yang.gen.v1.http.org.openroadm.device.rev170206.degree.ConnectionPorts; +import org.opendaylight.yang.gen.v1.http.org.openroadm.device.rev170206.interfaces.grp.Interface; +import org.opendaylight.yang.gen.v1.http.org.openroadm.device.rev170206.org.openroadm.device.container.OrgOpenroadmDevice; +import org.opendaylight.yang.gen.v1.http.org.openroadm.device.rev170206.org.openroadm.device.container.org.openroadm.device.Degree; +import org.opendaylight.yang.gen.v1.http.org.openroadm.device.rev170206.org.openroadm.device.container.org.openroadm.device.DegreeKey; +import org.opendaylight.yang.gen.v1.http.org.openroadm.device.rev170206.org.openroadm.device.container.org.openroadm.device.Info; +import org.opendaylight.yang.gen.v1.http.org.openroadm.device.rev170206.org.openroadm.device.container.org.openroadm.device.SharedRiskGroup; +import org.opendaylight.yang.gen.v1.http.org.openroadm.device.rev170206.org.openroadm.device.container.org.openroadm.device.SharedRiskGroupKey; +import org.opendaylight.yang.gen.v1.http.org.openroadm.device.rev170206.port.Interfaces; +import org.opendaylight.yang.gen.v1.http.org.openroadm.interfaces.rev161014.InterfaceType; +import org.opendaylight.yang.gen.v1.http.org.openroadm.interfaces.rev161014.OpenROADMOpticalMultiplex; +import org.opendaylight.yang.gen.v1.http.org.openroadm.interfaces.rev161014.OpticalTransport; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.portmapping.rev170228.Network; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.portmapping.rev170228.NetworkBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.portmapping.rev170228.network.Nodes; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.portmapping.rev170228.network.NodesBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.portmapping.rev170228.network.NodesKey; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.portmapping.rev170228.network.nodes.CpToDegree; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.portmapping.rev170228.network.nodes.CpToDegreeBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.portmapping.rev170228.network.nodes.CpToDegreeKey; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.portmapping.rev170228.network.nodes.Mapping; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.portmapping.rev170228.network.nodes.MappingBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.portmapping.rev170228.network.nodes.MappingKey; +import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class PortMappingImpl implements PortMapping { + + private static final Logger LOG = LoggerFactory.getLogger(PortMappingImpl.class); + + private final DataBroker dataBroker; + private final DeviceTransactionManager deviceTransactionManager; + private final OpenRoadmInterfaces openRoadmInterfaces; + + public PortMappingImpl(DataBroker dataBroker, DeviceTransactionManager deviceTransactionManager, + OpenRoadmInterfaces openRoadmInterfaces) { + this.dataBroker = dataBroker; + this.deviceTransactionManager = deviceTransactionManager; + this.openRoadmInterfaces = openRoadmInterfaces; + } + + @Override + public boolean createMappingData(String nodeId) { + + LOG.info("Create Mapping Data for node {}", nodeId); + List portMapList = new ArrayList<>(); + InstanceIdentifier infoIID = InstanceIdentifier.create(OrgOpenroadmDevice.class).child(Info.class); + Optional deviceInfoOptional = + deviceTransactionManager.getDataFromDevice(nodeId, LogicalDatastoreType.OPERATIONAL, infoIID, + Timeouts.DEVICE_READ_TIMEOUT, Timeouts.DEVICE_READ_TIMEOUT_UNIT); + + Info deviceInfo; + if (deviceInfoOptional.isPresent()) { + deviceInfo = deviceInfoOptional.get(); + } else { + LOG.warn("Device info subtree is absent for {}", nodeId); + return false; + } + if (deviceInfo.getNodeType() == null) { + LOG.warn("Node type field is missing"); // TODO make mandatory in yang + return false; + } + switch (deviceInfo.getNodeType()) { + + case Rdm: + // Get TTP port mapping + if (!createTtpPortMapping(nodeId, deviceInfo, portMapList)) { + // return false if mapping creation for TTP's failed + LOG.warn("Unable to create mapping for TTP's on node {}", nodeId); + return false; + } + + // Get PP port mapping + if (!createPpPortMapping(nodeId, deviceInfo, portMapList)) { + // return false if mapping creation for PP's failed + LOG.warn("Unable to create mapping for PP's on node {}", nodeId); + return false; + } + break; + case Xpdr: + if (!createXpdrPortMapping(nodeId, portMapList)) { + LOG.warn("Unable to create mapping for Xponder on node {}", nodeId); + return false; + } + break; + default: + LOG.error("Unable to create mapping for node {} : unknown nodetype ", nodeId); + break; + + } + return postPortMapping(deviceInfo, portMapList, deviceInfo.getNodeType().getIntValue(), null); + } + + /** + * This private method gets the list of external ports on a degree. For each port in the degree, it + * does a get on port subtree with circuit-pack-name/port-name as key in order to get the logical + * connection point name corresponding to it. + * + * @param deviceInfo Info subtree read from the device + * @param portMapList Reference to the list containing the mapping to be pushed to MD-SAL + * + * @return true/false based on status of operation + */ + private boolean createTtpPortMapping(String nodeId, Info deviceInfo, List portMapList) { + // Creating mapping data for degree TTP's + + List degrees = getDegrees(nodeId, deviceInfo); + List degreeConPorts = getDegreePorts(degrees); + List cpToDegreeList = getCpToDegreeList(degrees); + + postPortMapping(deviceInfo, null, deviceInfo.getNodeType().getIntValue(), cpToDegreeList); + + // Getting circuit-pack-name/port-name corresponding to TTP's + for (ConnectionPorts cp : degreeConPorts) { + String circuitPackName = cp.getCircuitPackName(); + String portName = cp.getPortName().toString(); + InstanceIdentifier portIID = InstanceIdentifier.create(OrgOpenroadmDevice.class) + .child(CircuitPacks.class, new CircuitPacksKey(circuitPackName)) + .child(Ports.class, new PortsKey(portName)); + + LOG.info("Fetching logical Connection Point value for port {} at circuit pack {}", portName, + circuitPackName); + Optional portObject = + deviceTransactionManager.getDataFromDevice(nodeId, LogicalDatastoreType.OPERATIONAL, portIID, + Timeouts.DEVICE_READ_TIMEOUT, Timeouts.DEVICE_READ_TIMEOUT_UNIT); + if (portObject.isPresent()) { + Ports port = portObject.get(); + if (port.getLogicalConnectionPoint() != null) { + LOG.info("Logical Connection Point for {} {} is {}", circuitPackName, portName, + port.getLogicalConnectionPoint()); + portMapList.add(createMappingObject(nodeId, port, circuitPackName, + port.getLogicalConnectionPoint())); + } else { + LOG.warn("Logical Connection Point value is missing for {} {}", circuitPackName, + port.getPortName()); + } + } else { + LOG.warn("Port {} is not present in node {} in circuit pack {}!", portName, nodeId, circuitPackName); + continue; // TODO continue or return true? + } + } + return true; + } + + private List getDegrees(String deviceId, Info ordmInfo) { + List degrees = new ArrayList<>(); + Integer maxDegree; + + // Get value for max degree from info subtree, required for iteration + // if not present assume to be 20 (temporary) + if (ordmInfo.getMaxDegrees() != null) { + maxDegree = ordmInfo.getMaxDegrees(); + } else { + maxDegree = 20; + } + + for (int degreeCounter = 1; degreeCounter <= maxDegree; degreeCounter++) { + LOG.info("Getting Connection ports for Degree Number {}", degreeCounter); + InstanceIdentifier deviceIID = InstanceIdentifier.create(OrgOpenroadmDevice.class) + .child(Degree.class, new DegreeKey(degreeCounter)); + Optional ordmDegreeObject = + deviceTransactionManager.getDataFromDevice(deviceId, LogicalDatastoreType.CONFIGURATION, deviceIID, + Timeouts.DEVICE_READ_TIMEOUT, Timeouts.DEVICE_READ_TIMEOUT_UNIT); + if (ordmDegreeObject.isPresent()) { + degrees.add(ordmDegreeObject.get()); + } else { + LOG.info("Device has {} degree", degreeCounter - 1); + break; + } + } + return degrees; + } + + /** + * This private method gets the list of circuit packs on an Srg. For each circuit pack on an Srg, it + * does a get on circuit-pack subtree with circuit-pack-name as key in order to get the list of + * ports. It then iterates over the list of ports to get ports with port-qual as roadm-external. It + * appends a TX,RX,TXRX to the logical connection point name based on the direction of the port. + * + * @param nodeId Id of device + * @param deviceInfo Info subtree read from the device + * @param portMapList Reference to the list containing the mapping to be pushed to MD-SAL + * + * @return true/false based on status of operation + */ + + private boolean createPpPortMapping(String nodeId, Info deviceInfo, List portMapList) { + // Creating mapping data for degree PP's + List srgCps = + getSrgCps(nodeId, deviceInfo); + + for (org.opendaylight.yang.gen.v1.http.org.openroadm.device.rev170206.srg.CircuitPacks cps : srgCps) { + String circuitPackName = cps.getCircuitPackName(); + InstanceIdentifier cpIID = InstanceIdentifier.create(OrgOpenroadmDevice.class) + .child(CircuitPacks.class, new CircuitPacksKey(circuitPackName)); + Optional circuitPackObject = + deviceTransactionManager.getDataFromDevice(nodeId, LogicalDatastoreType.OPERATIONAL, cpIID, + Timeouts.DEVICE_READ_TIMEOUT, Timeouts.DEVICE_READ_TIMEOUT_UNIT); + + if (!circuitPackObject.isPresent() || circuitPackObject.get().getPorts() == null) { + LOG.warn("Circuit pack was not found or ports are mission for name: {}", circuitPackName); + continue; // TODO continue or return false? + } + CircuitPacks cp = circuitPackObject.get(); + for (Ports port : cp.getPorts()) { + if (port.getLogicalConnectionPoint() != null) { + String logicalConnectionPoint = getLogicalConnectionPort(port); + LOG.info("Logical Connection Point for {} {} is {}", circuitPackName, port.getPortName(), + logicalConnectionPoint); + portMapList.add(createMappingObject(nodeId, port, circuitPackName, logicalConnectionPoint)); + } else if (Port.PortQual.RoadmInternal.equals(port.getPortQual())) { + LOG.info("Port is internal, skipping Logical Connection Point missing for {} {}", circuitPackName, + port.getPortName()); + } else if (port.getLogicalConnectionPoint() == null) { + LOG.info("Value missing, Skipping Logical Connection Point missing for {} {}", circuitPackName, + port.getPortName()); + } + } + } + return true; + } + + /** + * This method does a get operation on shared risk group subtree of the + * netconf device's config datastore and returns a list of all circuit packs + * objects that are part of srgs. It is required to do a selective get on + * all the circuit packs that contain add/drop ports of interest. + * + * @param deviceId Device id + * @param ordmInfo Info subtree from the device + * @return List of circuit packs object belonging to- shared risk group subtree + */ + private List getSrgCps( + String deviceId, Info ordmInfo) { + + List srgCps = + new ArrayList<>(); + Integer maxSrg; + // Get value for max Srg from info subtree, required for iteration + // if not present assume to be 20 (temporary) + if (ordmInfo.getMaxSrgs() != null) { + maxSrg = ordmInfo.getMaxSrgs(); + } else { + maxSrg = 20; + } + + for (int srgCounter = 1; srgCounter <= maxSrg; srgCounter++) { + LOG.info("Getting Circuitpacks for Srg Number {}", srgCounter); + InstanceIdentifier srgIID = InstanceIdentifier.create(OrgOpenroadmDevice.class) + .child(SharedRiskGroup.class, new SharedRiskGroupKey(srgCounter)); + Optional ordmSrgObject = + deviceTransactionManager.getDataFromDevice(deviceId, LogicalDatastoreType.CONFIGURATION, srgIID, + Timeouts.DEVICE_READ_TIMEOUT, Timeouts.DEVICE_READ_TIMEOUT_UNIT); + + if (ordmSrgObject.isPresent()) { + srgCps.addAll(ordmSrgObject.get().getCircuitPacks()); + } else { + LOG.info("Device has {} Srg", srgCounter - 1); + break; + } + } + return srgCps; + } + + /** + * This private method gets the list of circuit packs on a xponder. For each circuit pack on a + * Xponder, it does a get on circuit-pack subtree with circuit-pack-name as key in order to get the + * list of ports. It then iterates over the list of ports to get ports with port-qual as + * xpdr-network/xpdr-client. The line and client ports are saved as: + * + *

+ * 1. LINEn + * + *

+ * 2. CLNTn + * + * @param nodeId Id of device + * @param portMapList Reference to the list containing the mapping to be pushed to MD-SAL + * + * @return true/false based on status of operation + */ + private boolean createXpdrPortMapping(String nodeId, List portMapList) { + // Creating for Xponder Line and Client Ports + InstanceIdentifier deviceIID = InstanceIdentifier.create(OrgOpenroadmDevice.class); + Optional deviceObject = + deviceTransactionManager.getDataFromDevice(nodeId, LogicalDatastoreType.OPERATIONAL, deviceIID, + Timeouts.DEVICE_READ_TIMEOUT, Timeouts.DEVICE_READ_TIMEOUT_UNIT); + + // Variable to keep track of number of line ports + int line = 1; + // Variable to keep track of number of client ports + int client = 1; + if (!deviceObject.isPresent() || deviceObject.get().getCircuitPacks() == null) { + LOG.warn("Circuit Packs are not present for {}", nodeId); + return false; // TODO return false or continue? + } + + List circuitPackList = deviceObject.get().getCircuitPacks(); + circuitPackList.sort(Comparator.comparing(CircuitPack::getCircuitPackName)); + + for (CircuitPacks cp : circuitPackList) { + String circuitPackName = cp.getCircuitPackName(); + if (cp.getPorts() == null) { + LOG.warn("Ports were not found for circuit pack: {}", circuitPackName); + continue; + } + for (Ports port : cp.getPorts()) { + if (Port.PortQual.XpdrNetwork.equals(port.getPortQual())) { + portMapList.add(createMappingObject(nodeId, port, circuitPackName, + OpenRoadmInterfacesImpl.NETWORK_TOKEN + line)); + line++; + } else if (Port.PortQual.XpdrClient.equals(port.getPortQual())) { + portMapList.add(createMappingObject(nodeId, port, circuitPackName, + OpenRoadmInterfacesImpl.CLIENT_TOKEN + client)); + client++; + } else { + LOG.warn("Not supported type of port! Port type: {}", port.getPortQual()); + } + } + } + return true; + } + + /** + * This private method builds the mapping object to be pushed in MD-SAL in order to save port + * mapping. In case of TTP ports, it also saves the OTS,OMS interfaces provisioned on the port. + * + * @param port Reference to device's port subtree object. + * @param circuitPackName Name of cp where port exists. + * @param logicalConnectionPoint logical name of the port. + * + * @return true/false based on status of operation + */ + + private Mapping createMappingObject(String nodeId, Ports port, String circuitPackName, + String logicalConnectionPoint) { + MappingBuilder mpBldr = new MappingBuilder(); + mpBldr.setKey(new MappingKey(logicalConnectionPoint)).setLogicalConnectionPoint(logicalConnectionPoint) + .setSupportingCircuitPackName(circuitPackName).setSupportingPort(port.getPortName()); + + // Get OMS and OTS interface provisioned on the TTP's + if (logicalConnectionPoint.contains(OpenRoadmInterfacesImpl.TTP_TOKEN) && port.getInterfaces() != null) { + for (Interfaces interfaces : port.getInterfaces()) { + try { + Optional openRoadmInterface = + openRoadmInterfaces.getInterface(nodeId, interfaces.getInterfaceName()); + if (openRoadmInterface.isPresent()) { + Class interfaceType = openRoadmInterface.get().getType(); + // Check if interface type is OMS or OTS + if (interfaceType.equals(OpenROADMOpticalMultiplex.class)) { + mpBldr.setSupportingOms(interfaces.getInterfaceName()); + } + if (interfaceType.equals(OpticalTransport.class)) { + mpBldr.setSupportingOts(interfaces.getInterfaceName()); + } + } else { + LOG.warn("Interface {} from node {} was null!", interfaces.getInterfaceName(), nodeId); + } + } catch (OpenRoadmInterfaceException ex) { + LOG.warn("Error while getting interface {} from node {}!", interfaces.getInterfaceName(), nodeId, + ex); + } + } + } + return mpBldr.build(); + } + + private static CpToDegree createCpToDegreeObject(String circuitPackName, String degreeNumber) { + return new CpToDegreeBuilder().setKey(new CpToDegreeKey(circuitPackName)).setCircuitPackName(circuitPackName) + .setDegreeNumber(new Long(degreeNumber)).build(); + } + + private static List getDegreePorts(List degrees) { + return degrees.stream().filter(degree -> degree.getConnectionPorts() != null) + .flatMap(degree -> degree.getConnectionPorts().stream()).collect(Collectors.toList()); + } + + private List getCpToDegreeList(List degrees) { + List cpToDegreeList = new ArrayList<>(); + for (Degree degree : degrees) { + if (degree.getCircuitPacks() != null) { + cpToDegreeList.addAll(degree.getCircuitPacks().stream() + .map(cp -> createCpToDegreeObject(cp.getCircuitPackName(), degree.getDegreeNumber().toString())) + .collect(Collectors.toList())); + } + } + return cpToDegreeList; + } + + /** + * This method for ports the portMapping corresponding to the portmapping.yang file to the MD-SAL + * datastore. + * + *

+ * 1. Supporting circuit pack 2. Supporting port 3. Supporting OMS interface (if port on ROADM) + * + * @param deviceInfo Info subtree from the device. + * @param portMapList Reference to the list containing the mapping to be pushed to MD-SAL. + * + * @return Result true/false based on status of operation. + */ + private boolean postPortMapping(Info deviceInfo, List portMapList, Integer nodeType, + List cp2DegreeList) { + NodesBuilder nodesBldr = new NodesBuilder(); + nodesBldr.setKey(new NodesKey(deviceInfo.getNodeId())).setNodeId(deviceInfo.getNodeId()); + nodesBldr.setNodeType(NodeTypes.forValue(nodeType)); + + if (portMapList != null) { + nodesBldr.setMapping(portMapList); + } + if (cp2DegreeList != null) { + nodesBldr.setCpToDegree(cp2DegreeList); + } + + List nodesList = new ArrayList<>(); + nodesList.add(nodesBldr.build()); + + NetworkBuilder nwBldr = new NetworkBuilder(); + nwBldr.setNodes(nodesList); + + final WriteTransaction writeTransaction = dataBroker.newWriteOnlyTransaction(); + InstanceIdentifier nodesIID = InstanceIdentifier.builder(Network.class).build(); + Network network = nwBldr.build(); + writeTransaction.merge(LogicalDatastoreType.CONFIGURATION, nodesIID, network); + CheckedFuture submit = writeTransaction.submit(); + try { + submit.checkedGet(); + return true; + + } catch (TransactionCommitFailedException e) { + LOG.warn("Failed to post {}", network, e); + return false; + } + } + + @Override + public Mapping getMapping(String nodeId, String logicalConnPoint) { + + /* + * Getting physical mapping corresponding to logical connection point + */ + InstanceIdentifier portMappingIID = InstanceIdentifier.builder(Network.class).child(Nodes.class, + new NodesKey(nodeId)).child(Mapping.class, new MappingKey(logicalConnPoint)).build(); + try (ReadOnlyTransaction readTx = dataBroker.newReadOnlyTransaction()) { + Optional mapObject = + readTx.read(LogicalDatastoreType.CONFIGURATION, portMappingIID).get().toJavaUtil(); + if (mapObject.isPresent()) { + Mapping mapping = mapObject.get(); + LOG.info("Found mapping for the logical port {}. Mapping: {}", logicalConnPoint, mapping.toString()); + return mapping; + } else { + LOG.warn("Could not find mapping for logical connection point {} for nodeId {}", logicalConnPoint, + nodeId); + } + } catch (InterruptedException | ExecutionException ex) { + LOG.error("Unable to read mapping for logical connection point : {} for nodeId {}", logicalConnPoint, + nodeId, ex); + } + return null; + } + + private static String getLogicalConnectionPort(Ports port) { + if (port.getLogicalConnectionPoint() != null) { + switch (port.getPortDirection()) { + case Tx: + // Port direction is transmit + return port.getLogicalConnectionPoint() + "-TX"; + case Rx: + // Port direction is receive + return port.getLogicalConnectionPoint() + "-RX"; + case Bidirectional: + // port is bi-directional + if (port.getLogicalConnectionPoint().endsWith("-TXRX")) { + return port.getLogicalConnectionPoint(); + } + return port.getLogicalConnectionPoint() + "-TXRX"; + default: + // Unsupported Port direction + LOG.error("Unsupported port direction for port {} - {}", port, port.getPortDirection()); + return ""; // TODO return false or continue? + } + } + LOG.warn("Unsupported port direction for port {} - {} - LogicalConnectionPoint is null", + port, port.getPortDirection()); + return ""; // TODO return false or continue? + } + +} diff --git a/common/src/main/java/org/opendaylight/transportpce/common/openroadminterfaces/OpenRoadmInterfaceException.java b/common/src/main/java/org/opendaylight/transportpce/common/openroadminterfaces/OpenRoadmInterfaceException.java new file mode 100644 index 000000000..200c27282 --- /dev/null +++ b/common/src/main/java/org/opendaylight/transportpce/common/openroadminterfaces/OpenRoadmInterfaceException.java @@ -0,0 +1,20 @@ +/* + * 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.common.openroadminterfaces; + +public class OpenRoadmInterfaceException extends Exception { + + public OpenRoadmInterfaceException(String message) { + super(message); + } + + public OpenRoadmInterfaceException(String message, Throwable cause) { + super(message, cause); + } +} diff --git a/common/src/main/java/org/opendaylight/transportpce/common/openroadminterfaces/OpenRoadmInterfaces.java b/common/src/main/java/org/opendaylight/transportpce/common/openroadminterfaces/OpenRoadmInterfaces.java new file mode 100644 index 000000000..b553a422f --- /dev/null +++ b/common/src/main/java/org/opendaylight/transportpce/common/openroadminterfaces/OpenRoadmInterfaces.java @@ -0,0 +1,60 @@ +/* + * 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.common.openroadminterfaces; + +import java.util.Optional; + +import org.opendaylight.yang.gen.v1.http.org.openroadm.device.rev170206.interfaces.grp.Interface; +import org.opendaylight.yang.gen.v1.http.org.openroadm.device.rev170206.interfaces.grp.InterfaceBuilder; + +public interface OpenRoadmInterfaces { + + /** + * This methods does an edit-config operation on the openROADM device in order + * to create the given interface. + * + *

+ * Before posting the interface it checks if: + * 1. Interface with same name does not exist + * 2. If exists then admin state of interface is outOfState/Maintenance + *

+ * + * @param ifBuilder Builder object containing the data to post. + * + */ + void postInterface(String nodeId, InterfaceBuilder ifBuilder) throws OpenRoadmInterfaceException; + + /** + * This private does a get on the interface subtree of the device with the + * interface name as the key and return the class corresponding to the interface + * type. + * + * @param interfaceName + * Name of the interface + * + * @return Optional of Interface from datastore + */ + Optional getInterface(String nodeId, String interfaceName) throws OpenRoadmInterfaceException; + + /** + * This methods does an edit-config operation on the openROADM device in order + * to delete the given interface. + * + *

+ * Before deleting the method: + * 1. Checks if interface exists + * 2. If exists then changes the state of interface to outOfService + *

+ * + * @param interfaceName + * Name of the interface to delete. + */ + void deleteInterface(String nodeId, String interfaceName) throws OpenRoadmInterfaceException; + +} diff --git a/common/src/main/java/org/opendaylight/transportpce/common/openroadminterfaces/OpenRoadmInterfacesImpl.java b/common/src/main/java/org/opendaylight/transportpce/common/openroadminterfaces/OpenRoadmInterfacesImpl.java new file mode 100644 index 000000000..e8bff8fb7 --- /dev/null +++ b/common/src/main/java/org/opendaylight/transportpce/common/openroadminterfaces/OpenRoadmInterfacesImpl.java @@ -0,0 +1,179 @@ +/* + * 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.common.openroadminterfaces; + +import com.google.common.util.concurrent.ListenableFuture; + +import java.util.Optional; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.Future; + +import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType; +import org.opendaylight.transportpce.common.Timeouts; +import org.opendaylight.transportpce.common.device.DeviceTransaction; +import org.opendaylight.transportpce.common.device.DeviceTransactionManager; +import org.opendaylight.yang.gen.v1.http.org.openroadm.device.rev170206.interfaces.grp.Interface; +import org.opendaylight.yang.gen.v1.http.org.openroadm.device.rev170206.interfaces.grp.InterfaceBuilder; +import org.opendaylight.yang.gen.v1.http.org.openroadm.device.rev170206.interfaces.grp.InterfaceKey; +import org.opendaylight.yang.gen.v1.http.org.openroadm.device.rev170206.org.openroadm.device.container.OrgOpenroadmDevice; +import org.opendaylight.yang.gen.v1.http.org.openroadm.equipment.states.types.rev161014.AdminStates; +import org.opendaylight.yang.gen.v1.http.org.openroadm.interfaces.rev161014.OtnOdu; +import org.opendaylight.yang.gen.v1.http.org.openroadm.interfaces.rev161014.OtnOtu; +import org.opendaylight.yang.gen.v1.http.org.openroadm.maintenance.loopback.rev161014.maint.loopback.MaintLoopbackBuilder; +import org.opendaylight.yang.gen.v1.http.org.openroadm.maintenance.testsignal.rev161014.maint.testsignal.MaintTestsignalBuilder; +import org.opendaylight.yang.gen.v1.http.org.openroadm.otn.odu.interfaces.rev161014.Interface1; +import org.opendaylight.yang.gen.v1.http.org.openroadm.otn.odu.interfaces.rev161014.Interface1Builder; +import org.opendaylight.yang.gen.v1.http.org.openroadm.otn.odu.interfaces.rev161014.odu.container.OduBuilder; +import org.opendaylight.yang.gen.v1.http.org.openroadm.otn.otu.interfaces.rev161014.otu.container.OtuBuilder; +import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class OpenRoadmInterfacesImpl implements OpenRoadmInterfaces { + + private static final Logger LOG = LoggerFactory.getLogger(OpenRoadmInterfacesImpl.class); + + // TODO move somewhere to constants + public static final String NETWORK_TOKEN = "XPDR1-NETWORK"; + public static final String TTP_TOKEN = "TTP"; + public static final String CLIENT_TOKEN = "XPDR1-CLIENT"; + public static final String PP_TOKEN = "PP"; + + private final DeviceTransactionManager deviceTransactionManager; + + public OpenRoadmInterfacesImpl(DeviceTransactionManager deviceTransactionManager) { + this.deviceTransactionManager = deviceTransactionManager; + } + + @Override + public void postInterface(String nodeId, InterfaceBuilder ifBuilder) throws OpenRoadmInterfaceException { + Future> deviceTxFuture = deviceTransactionManager.getDeviceTransaction(nodeId); + DeviceTransaction deviceTx; + try { + Optional deviceTxOpt = deviceTxFuture.get(); + if (deviceTxOpt.isPresent()) { + deviceTx = deviceTxOpt.get(); + } else { + throw new OpenRoadmInterfaceException(String.format("Device transaction was not found for node %s!", + nodeId)); + } + } catch (InterruptedException | ExecutionException e) { + throw new OpenRoadmInterfaceException(String.format("Failed to obtain device transaction for node %s!", + nodeId), e); + } + + InstanceIdentifier interfacesIID = InstanceIdentifier.create(OrgOpenroadmDevice.class) + .child(Interface.class, new InterfaceKey(ifBuilder.getName())); + deviceTx.put(LogicalDatastoreType.CONFIGURATION, interfacesIID, ifBuilder.build()); + ListenableFuture txSubmitFuture = deviceTx.submit(Timeouts.DEVICE_WRITE_TIMEOUT, + Timeouts.DEVICE_WRITE_TIMEOUT_UNIT); + try { + txSubmitFuture.get(); + LOG.info("Successfully posted interface {} on node {}", ifBuilder.getName(), nodeId); + } catch (InterruptedException | ExecutionException e) { + throw new OpenRoadmInterfaceException(String.format("Failed to post interface %s on node %s!", + ifBuilder.getName(), nodeId), e); + } + } + + @Override + public Optional getInterface(String nodeId, String interfaceName) throws OpenRoadmInterfaceException { + InstanceIdentifier interfacesIID = InstanceIdentifier.create(OrgOpenroadmDevice.class) + .child(Interface.class, new InterfaceKey(interfaceName)); + return deviceTransactionManager.getDataFromDevice(nodeId, LogicalDatastoreType.CONFIGURATION, interfacesIID, + Timeouts.DEVICE_READ_TIMEOUT, Timeouts.DEVICE_READ_TIMEOUT_UNIT); + } + + @Override + public void deleteInterface(String nodeId, String interfaceName) + throws OpenRoadmInterfaceException { + Optional intf2DeleteOpt; + try { + intf2DeleteOpt = getInterface(nodeId, interfaceName); + } catch (OpenRoadmInterfaceException e) { + throw new OpenRoadmInterfaceException(String.format("Failed to check if interface %s exists on node %s!", + interfaceName, nodeId), e); + } + if (intf2DeleteOpt.isPresent()) { + Interface intf2Delete = intf2DeleteOpt.get(); + // State admin state to out of service + InterfaceBuilder ifBuilder = new InterfaceBuilder(intf2Delete); + if (ifBuilder.getType() == OtnOdu.class) { + Interface1Builder oduBuilder = new Interface1Builder(intf2Delete.getAugmentation(Interface1.class)); + OduBuilder odu = new OduBuilder(oduBuilder.getOdu()); + if (odu.getMaintTestsignal() != null) { + MaintTestsignalBuilder maintSignalBuilder = + new MaintTestsignalBuilder(); + maintSignalBuilder.setEnabled(false); + odu.setMaintTestsignal(maintSignalBuilder.build()); + } + oduBuilder.setOdu(odu.build()); + ifBuilder.addAugmentation(Interface1.class, oduBuilder.build()); + } else if (ifBuilder.getType() == OtnOtu.class) { + org.opendaylight.yang.gen.v1.http.org.openroadm.otn.otu + .interfaces.rev161014.Interface1Builder otuBuilder = + new org.opendaylight.yang.gen.v1.http.org.openroadm.otn.otu + .interfaces.rev161014.Interface1Builder(intf2Delete + .getAugmentation(org.opendaylight.yang.gen.v1 + .http.org.openroadm.otn.otu.interfaces.rev161014.Interface1.class)); + OtuBuilder otu = new OtuBuilder(otuBuilder.getOtu()); + if (otu.getMaintLoopback() != null) { + MaintLoopbackBuilder maintLoopBackBuilder = + new MaintLoopbackBuilder(); + maintLoopBackBuilder.setEnabled(false); + otu.setMaintLoopback(maintLoopBackBuilder.build()); + } + otuBuilder.setOtu(otu.build()); + ifBuilder.addAugmentation(org.opendaylight.yang.gen + .v1.http.org.openroadm.otn.otu.interfaces.rev161014.Interface1.class, otuBuilder.build()); + } + ifBuilder.setAdministrativeState(AdminStates.OutOfService); + // post interface with updated admin state + try { + postInterface(nodeId, ifBuilder); + } catch (OpenRoadmInterfaceException ex) { + throw new OpenRoadmInterfaceException(String.format("Failed to set state of interface %s to %s while" + + " deleting it!", interfaceName, AdminStates.OutOfService), ex); + } + + InstanceIdentifier interfacesIID = InstanceIdentifier.create(OrgOpenroadmDevice.class) + .child(Interface.class, new InterfaceKey(interfaceName)); + Future> deviceTxFuture = deviceTransactionManager.getDeviceTransaction(nodeId); + DeviceTransaction deviceTx; + try { + Optional deviceTxOpt = deviceTxFuture.get(); + if (deviceTxOpt.isPresent()) { + deviceTx = deviceTxOpt.get(); + } else { + throw new OpenRoadmInterfaceException(String.format("Device transaction was not found for node %s!", + nodeId)); + } + } catch (InterruptedException | ExecutionException e) { + throw new OpenRoadmInterfaceException(String.format("Failed to obtain device transaction for node %s!", + nodeId), e); + } + + deviceTx.delete(LogicalDatastoreType.CONFIGURATION, interfacesIID); + ListenableFuture submit = deviceTx.submit( + Timeouts.DEVICE_WRITE_TIMEOUT, Timeouts.DEVICE_WRITE_TIMEOUT_UNIT); + + try { + submit.get(); + LOG.info("Successfully deleted {} on node {}", interfaceName, nodeId); + } catch (InterruptedException | ExecutionException e) { + throw new OpenRoadmInterfaceException(String.format("Failed to delete interface %s on " + + "node %s", interfaceName, nodeId), e); + } + } else { + LOG.info("Interface does not exist, cannot delete on node {}", nodeId); + } + } + + +} diff --git a/common/src/main/resources/org/opendaylight/blueprint/common-blueprint.xml b/common/src/main/resources/org/opendaylight/blueprint/common-blueprint.xml new file mode 100644 index 000000000..bf4bcc955 --- /dev/null +++ b/common/src/main/resources/org/opendaylight/blueprint/common-blueprint.xml @@ -0,0 +1,45 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/common/src/test/java/org/opendaylight/transportpce/common/device/DeviceTransactionManagerTest.java b/common/src/test/java/org/opendaylight/transportpce/common/device/DeviceTransactionManagerTest.java new file mode 100644 index 000000000..1815c184f --- /dev/null +++ b/common/src/test/java/org/opendaylight/transportpce/common/device/DeviceTransactionManagerTest.java @@ -0,0 +1,363 @@ +/* + * Copyright © 2017 Orange, Inc. 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.common.device; + +import static org.mockito.Matchers.any; + +import com.google.common.base.Optional; +import com.google.common.util.concurrent.Futures; +import com.google.common.util.concurrent.ListenableFuture; +import com.google.common.util.concurrent.ListeningExecutorService; +import com.google.common.util.concurrent.MoreExecutors; + +import java.util.LinkedList; +import java.util.List; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.Executors; +import java.util.concurrent.Future; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.TimeoutException; + +import org.junit.After; +import org.junit.Assert; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mock; +import org.mockito.Mockito; +import org.mockito.runners.MockitoJUnitRunner; +import org.opendaylight.controller.md.sal.binding.api.DataBroker; +import org.opendaylight.controller.md.sal.binding.api.MountPoint; +import org.opendaylight.controller.md.sal.binding.api.MountPointService; +import org.opendaylight.controller.md.sal.binding.api.ReadWriteTransaction; +import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.network.rev150608.Network; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.network.rev150608.NetworkBuilder; +import org.opendaylight.yangtools.yang.binding.DataObject; +import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; + + +@RunWith(MockitoJUnitRunner.class) +public class DeviceTransactionManagerTest { + + @Mock private MountPointService mountPointServiceMock; + @Mock private MountPoint mountPointMock; + @Mock private DataBroker dataBrokerMock; + @Mock private ReadWriteTransaction rwTransactionMock; + + private DeviceTransactionManagerImpl transactionManager; + private String defaultDeviceId = "device-id"; + private LogicalDatastoreType defaultDatastore = LogicalDatastoreType.OPERATIONAL; + private InstanceIdentifier defaultIid = InstanceIdentifier.create(Network.class); + private Network defaultData = new NetworkBuilder().build(); + private long defaultTimeout = 1000; + private TimeUnit defaultTimeUnit = TimeUnit.MILLISECONDS; + + @Before + public void before() { + Mockito.when(mountPointServiceMock.getMountPoint(any())).thenReturn(Optional.of(mountPointMock)); + Mockito.when(mountPointMock.getService(any())).thenReturn(Optional.of(dataBrokerMock)); + Mockito.when(dataBrokerMock.newReadWriteTransaction()).thenReturn(rwTransactionMock); + Mockito.when(rwTransactionMock.submit()).thenReturn(Futures.immediateCheckedFuture(null)); + + this.transactionManager = new DeviceTransactionManagerImpl(mountPointServiceMock, 3000); + } + + @After + public void after() { + transactionManager.preDestroy(); + } + + @Test + public void basicPositiveTransactionTest() { + try { + putAndSubmit(transactionManager, defaultDeviceId, defaultDatastore, defaultIid, defaultData); + } catch (InterruptedException | ExecutionException e) { + Assert.fail("Exception catched! " + e); + return; + } + + Mockito.verify(rwTransactionMock, Mockito.times(1)).put(defaultDatastore, defaultIid, defaultData); + Mockito.verify(rwTransactionMock, Mockito.times(1)).submit(); + } + + @Test + public void advancedPositiveTransactionTest() { + try { + Future> firstDeviceTxFuture = + transactionManager.getDeviceTransaction(defaultDeviceId); + DeviceTransaction firstDeviceTx = firstDeviceTxFuture.get().get(); + + Future> secondDeviceTxFuture = + transactionManager.getDeviceTransaction(defaultDeviceId); + Assert.assertFalse(secondDeviceTxFuture.isDone()); + + Future> thirdDeviceTxFuture = + transactionManager.getDeviceTransaction(defaultDeviceId); + Assert.assertFalse(thirdDeviceTxFuture.isDone()); + + Future> anotherDeviceTxFuture = + transactionManager.getDeviceTransaction("another-id"); + + firstDeviceTx.put(defaultDatastore, defaultIid, defaultData); + Assert.assertFalse(secondDeviceTxFuture.isDone()); + Assert.assertFalse(thirdDeviceTxFuture.isDone()); + Thread.sleep(200); + Assert.assertFalse(secondDeviceTxFuture.isDone()); + Assert.assertFalse(thirdDeviceTxFuture.isDone()); + + Assert.assertTrue(anotherDeviceTxFuture.isDone()); + anotherDeviceTxFuture.get().get().submit(defaultTimeout, defaultTimeUnit); + + firstDeviceTx.submit(defaultTimeout, defaultTimeUnit); + Thread.sleep(200); + Assert.assertTrue(secondDeviceTxFuture.isDone()); + Assert.assertFalse(thirdDeviceTxFuture.isDone()); + + DeviceTransaction secondDeviceTx = secondDeviceTxFuture.get().get(); + secondDeviceTx.put(defaultDatastore, defaultIid, defaultData); + Assert.assertFalse(thirdDeviceTxFuture.isDone()); + + secondDeviceTx.submit(defaultTimeout, defaultTimeUnit); + Thread.sleep(200); + Assert.assertTrue(thirdDeviceTxFuture.isDone()); + + DeviceTransaction thirdDeviceTx = thirdDeviceTxFuture.get().get(); + thirdDeviceTx.put(defaultDatastore, defaultIid, defaultData); + thirdDeviceTx.submit(defaultTimeout, defaultTimeUnit); + + Mockito.verify(rwTransactionMock, Mockito.times(3)).put(defaultDatastore, defaultIid, defaultData); + Mockito.verify(rwTransactionMock, Mockito.times(4)).submit(); + } catch (InterruptedException | ExecutionException e) { + Assert.fail("Exception catched! " + e); + } + } + + @Test + public void bigAmountOfTransactionsOnSameDeviceTest() { + int numberOfTxs = 100; + List>> deviceTransactionFutures = new LinkedList<>(); + List deviceTransactions = new LinkedList<>(); + + for (int i = 0; i < numberOfTxs; i++) { + deviceTransactionFutures.add(transactionManager.getDeviceTransaction(defaultDeviceId)); + } + + try { + for (Future> futureTx : deviceTransactionFutures) { + DeviceTransaction deviceTx = futureTx.get().get(); + deviceTx.submit(defaultTimeout, defaultTimeUnit); + deviceTransactions.add(deviceTx); + } + } catch (InterruptedException | ExecutionException e) { + Assert.fail("Exception catched! " + e); + } + + for (DeviceTransaction deviceTx : deviceTransactions) { + Assert.assertTrue(deviceTx.wasSubmittedOrCancelled().get()); + } + } + + @Test + public void bigAmountOfTransactionsOnDifferentDevicesTest() { + int numberOfTxs = 1000; + List deviceTransactions = new LinkedList<>(); + + try { + for (int i = 0; i < numberOfTxs; i++) { + deviceTransactions.add(transactionManager.getDeviceTransaction(defaultDeviceId + " " + i).get().get()); + } + } catch (InterruptedException | ExecutionException e) { + Assert.fail("Exception catched! " + e); + } + + deviceTransactions.parallelStream() + .forEach(deviceTransaction -> deviceTransaction.submit(defaultTimeout, defaultTimeUnit)); + + deviceTransactions.parallelStream() + .forEach(deviceTransaction -> Assert.assertTrue(deviceTransaction.wasSubmittedOrCancelled().get())); + } + + @Test + public void bigAmountOfTransactionsOnDifferentDevicesWithoutSubmitTest() { + int numberOfTxs = 1000; + List deviceTransactions = new LinkedList<>(); + + try { + for (int i = 0; i < numberOfTxs; i++) { + deviceTransactions.add(transactionManager.getDeviceTransaction(defaultDeviceId + " " + i).get().get()); + } + } catch (InterruptedException | ExecutionException e) { + Assert.fail("Exception catched! " + e); + } + + try { + Thread.sleep(transactionManager.getMaxDurationToSubmitTransaction() + 1000); + } catch (InterruptedException e) { + Assert.fail("Exception catched! " + e); + } + deviceTransactions.parallelStream() + .forEach(deviceTransaction -> Assert.assertTrue(deviceTransaction.wasSubmittedOrCancelled().get())); + } + + @Test + public void notSubmittedTransactionTest() { + Future> deviceTxFuture = + transactionManager.getDeviceTransaction(defaultDeviceId); + try { + deviceTxFuture.get(); + Thread.sleep(transactionManager.getMaxDurationToSubmitTransaction() + 1000); + } catch (InterruptedException | ExecutionException e) { + Assert.fail("Exception catched! " + e); + } + Mockito.verify(rwTransactionMock, Mockito.times(1)).cancel(); + + try { + putAndSubmit(transactionManager, defaultDeviceId, defaultDatastore, defaultIid, defaultData); + } catch (InterruptedException | ExecutionException e) { + Assert.fail("Exception catched! " + e); + return; + } + + Mockito.verify(rwTransactionMock, Mockito.times(1)).cancel(); + Mockito.verify(rwTransactionMock, Mockito.times(1)).put(defaultDatastore, defaultIid, defaultData); + Mockito.verify(rwTransactionMock, Mockito.times(1)).submit(); + } + + @Test + public void dataBrokerTimeoutTransactionTest() { + Mockito.when(dataBrokerMock.newReadWriteTransaction()).then(invocation -> { + Thread.sleep(transactionManager.getMaxDurationToSubmitTransaction() + 1000); + return rwTransactionMock; + }); + + try { + putAndSubmit(transactionManager, defaultDeviceId, defaultDatastore, defaultIid, defaultData); + } catch (InterruptedException | ExecutionException e) { + Assert.fail("Exception catched! " + e); + } + + Mockito.verify(rwTransactionMock, Mockito.times(1)).submit(); + + Mockito.when(dataBrokerMock.newReadWriteTransaction()).thenReturn(rwTransactionMock); // remove sleep + + try { + putAndSubmit(transactionManager, defaultDeviceId, defaultDatastore, defaultIid, defaultData); + } catch (InterruptedException | ExecutionException e) { + Assert.fail("Exception catched! " + e); + return; + } + + Mockito.verify(rwTransactionMock, Mockito.times(2)).put(defaultDatastore, defaultIid, defaultData); + Mockito.verify(rwTransactionMock, Mockito.times(2)).submit(); + } + + @Test + public void getFutureTimeoutTransactionTest() { + Mockito.when(dataBrokerMock.newReadWriteTransaction()).then(invocation -> { + Thread.sleep(3000); + return rwTransactionMock; + }); + + Exception throwedException = null; + + Future> deviceTxFuture = + transactionManager.getDeviceTransaction(defaultDeviceId); + try { + deviceTxFuture.get(1000, TimeUnit.MILLISECONDS); + } catch (InterruptedException | ExecutionException e) { + Assert.fail("Exception catched! " + e); + } catch (TimeoutException e) { + throwedException = e; + } + + if (throwedException == null) { + Assert.fail("TimeoutException should be thrown!"); + return; + } + + Mockito.when(dataBrokerMock.newReadWriteTransaction()).thenReturn(rwTransactionMock); // remove sleep + + try { + putAndSubmit(transactionManager, defaultDeviceId, defaultDatastore, defaultIid, defaultData); + } catch (InterruptedException | ExecutionException e) { + Assert.fail("Exception catched! " + e); + return; + } + + Mockito.verify(rwTransactionMock, Mockito.times(1)).put(defaultDatastore, defaultIid, defaultData); + Mockito.verify(rwTransactionMock, Mockito.times(1)).submit(); + } + + @Test + public void submitTxTimeoutTransactionTest() { + ListeningExecutorService executor = MoreExecutors.listeningDecorator(Executors.newSingleThreadExecutor()); + Mockito.when(rwTransactionMock.submit()).then(invocation -> Futures.makeChecked(executor.submit(() -> { + try { + Thread.sleep(3000); + } catch (InterruptedException e) { + Assert.fail("Exception catched in future! " + e); + } + return null; + }), input -> input)); + + Future> deviceTxFuture = + transactionManager.getDeviceTransaction(defaultDeviceId); + DeviceTransaction deviceTx; + try { + deviceTx = deviceTxFuture.get().get(); + } catch (InterruptedException | ExecutionException e) { + Assert.fail("Exception catched! " + e); + return; + } + + deviceTx.put(defaultDatastore, defaultIid, defaultData); + + Exception throwedException = null; + + ListenableFuture submitFuture = deviceTx.submit(200, defaultTimeUnit); + try { + submitFuture.get(); + } catch (InterruptedException e) { + Assert.fail("Exception catched! " + e); + } catch (ExecutionException e) { + throwedException = e; + } + + if (throwedException == null + || !throwedException.getMessage().contains(TimeoutException.class.getName())) { + Assert.fail("TimeoutException inside of should be thrown!"); + return; + } + + + Mockito.when(rwTransactionMock.submit()).thenReturn(Futures.immediateCheckedFuture(null)); + + try { + putAndSubmit(transactionManager, defaultDeviceId, defaultDatastore, defaultIid, defaultData); + } catch (InterruptedException | ExecutionException e) { + Assert.fail("Exception catched! " + e); + return; + } + + Mockito.verify(rwTransactionMock, Mockito.times(2)).put(defaultDatastore, defaultIid, defaultData); + Mockito.verify(rwTransactionMock, Mockito.times(2)).submit(); + + executor.shutdown(); + } + + private void putAndSubmit(DeviceTransactionManagerImpl deviceTxManager, String deviceId, + LogicalDatastoreType store, InstanceIdentifier path, T data) + throws ExecutionException, InterruptedException { + Future> deviceTxFuture = deviceTxManager.getDeviceTransaction(deviceId); + DeviceTransaction deviceTx = deviceTxFuture.get().get(); + deviceTx.put(store, path, data); + deviceTx.submit(defaultTimeout, defaultTimeUnit); + } +} diff --git a/common/src/test/java/org/opendaylight/transportpce/common/test/TransportPCETest.java b/common/src/test/java/org/opendaylight/transportpce/common/test/TransportPCETest.java new file mode 100644 index 000000000..ee2f9e7a8 --- /dev/null +++ b/common/src/test/java/org/opendaylight/transportpce/common/test/TransportPCETest.java @@ -0,0 +1,25 @@ +/* + * Copyright © 2016 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.common.test; + +import org.junit.Ignore; +import org.junit.Test; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class TransportPCETest { + + private static final Logger LOG = LoggerFactory.getLogger(TransportPCETest.class); + + @Ignore + @Test + public void test() { + LOG.info("test"); + } + +} diff --git a/common/src/test/resources/sample-config-ROADM.xml b/common/src/test/resources/sample-config-ROADM.xml new file mode 100644 index 000000000..349685b91 --- /dev/null +++ b/common/src/test/resources/sample-config-ROADM.xml @@ -0,0 +1,5430 @@ + + + + + ROADMA + 2 + rdm + NodeA + vendorA + 2 + 0002 + 127.0.0.11 + 28 + 127.0.0.20 + static + 127.0.0.11 + 28 + 127.0.0.20 + bb:bb:bb:bb:bb:bb + 1 + 2 + 9 + + + + openroadm + openroadm + sudo + + + + 1 + + + sdegE + pizza + XYZ + 2 + inService + vendorA + 1 + 00002 + xxxxx + degE + 01 + inService + not-reserved-available + 2016-10-25T09:00:00-00:00 + + 0 + + 2/0 + + + + sdegW + pizza + XYZ + 3 + inService + vendorA + 1 + 00003 + xxxxx + degW + 01 + inService + not-reserved-available + 2016-10-25T09:00:00-00:00 + + 0 + + 3/0 + + + + ssrg + pizza + XYZ + 4 + inService + vendorA + 1 + 00004 + xxxxx + srgW + 01 + inService + not-reserved-available + 2016-10-25T09:00:00-00:00 + + 0 + + 4/0 + + + + 2/0 + WSSDEG + inService + vendorA + WSS9 + 2017-08-08T10:47:04.698808+00:00 + wss1 + inService + not-reserved-available + NORMAL + 2 + 0 + 0 + + OSC-SLOT + + 2/0/OSC-PLUG + + + C1 + Client + roadm-internal + multi-wavelength + bidirectional + 1 + inService + inService + DEG1-CTP-TXRX + + + C2 + Client + roadm-internal + multi-wavelength + bidirectional + 1 + inService + inService + DEG1-CTP-TXRX + + + C3 + Client + roadm-internal + multi-wavelength + bidirectional + 1 + inService + inService + DEG1-CTP-TXRX + + + C4 + Client + roadm-internal + multi-wavelength + bidirectional + 1 + inService + inService + DEG1-CTP-TXRX + + + C5 + Client + roadm-internal + multi-wavelength + bidirectional + 1 + inService + inService + DEG1-CTP-TXRX + + + C6 + Client + roadm-internal + multi-wavelength + bidirectional + 1 + inService + inService + DEG1-CTP-TXRX + + + C7 + Client + roadm-internal + multi-wavelength + bidirectional + 1 + inService + inService + DEG1-CTP-TXRX + + + C8 + Client + roadm-internal + multi-wavelength + bidirectional + 1 + inService + inService + DEG1-CTP-TXRX + + + C9 + Client + roadm-internal + multi-wavelength + bidirectional + 1 + inService + inService + DEG1-CTP-TXRX + + + L1 + LINE + roadm-external + multi-wavelength + bidirectional + 1 + inService + inService + DEG1-TTP-TXRX + + -35.0 + -9.0 + 14.0 + 21.82 + + + + + LOG1 + Logical + roadm-internal + multi-wavelength + bidirectional + inService + inService + + + OSC-DEMUX + OSC + roadm-internal + multi-wavelength + bidirectional + inService + inService + + + + 2/0/OSC-PLUG + port + inService + vendorA + SFP/SFP+ + 00000163600843 + oooooo + 2017-08-08T10:47:04.698808+00:00 + oscplug + 01 + not-reserved-available + NORMAL + 2 + 0 + 0 + + 2/0 + OSC-SLOT + + + OSC-PORT + 1GEX + roadm-internal + multi-wavelength + bidirectional + inService + inService + + + + 3/0 + WSSDEG + inService + vendorA + WSS9 + 2017-08-08T10:47:04.698808+00:00 + wss2 + inService + not-reserved-available + NORMAL + 3 + 0 + 0 + + OSC-SLOT + + 3/0/OSC-PLUG + + + C1 + Client + roadm-internal + multi-wavelength + bidirectional + 1 + inService + inService + DEG2-CTP-TXRX + + + C2 + Client + roadm-internal + multi-wavelength + bidirectional + 1 + inService + inService + DEG2-CTP-TXRX + + + C3 + Client + roadm-internal + multi-wavelength + bidirectional + 1 + inService + inService + DEG2-CTP-TXRX + + + C4 + Client + roadm-internal + multi-wavelength + bidirectional + 1 + inService + inService + DEG2-CTP-TXRX + + + C5 + Client + roadm-internal + multi-wavelength + bidirectional + 1 + inService + inService + DEG2-CTP-TXRX + + + C6 + Client + roadm-internal + multi-wavelength + bidirectional + 1 + inService + inService + DEG2-CTP-TXRX + + + C7 + Client + roadm-internal + multi-wavelength + bidirectional + 1 + inService + inService + DEG2-CTP-TXRX + + + C8 + Client + roadm-internal + multi-wavelength + bidirectional + 1 + inService + inService + DEG2-CTP-TXRX + + + C9 + Client + roadm-internal + multi-wavelength + bidirectional + 1 + inService + inService + DEG2-CTP-TXRX + + + L1 + LINE + roadm-external + multi-wavelength + bidirectional + 1 + inService + inService + DEG2-TTP-TXRX + + -35.0 + -9.0 + 14.0 + 21.82 + + + + + LOG1 + Logical + roadm-internal + multi-wavelength + bidirectional + inService + inService + + + OSC-DEMUX + OSC + roadm-internal + multi-wavelength + bidirectional + inService + inService + + + + 3/0/OSC-PLUG + port + inService + vendorA + SFP/SFP+ + 00000163600843 + oooooo + 2017-08-08T10:47:04.698808+00:00 + oscplug + 01 + not-reserved-available + NORMAL + 3 + 0 + 0 + + 3/0 + OSC-SLOT + + + OSC-PORT + 1GEX + roadm-internal + multi-wavelength + bidirectional + inService + inService + + + + 4/0 + ADDDROP + inService + vendorA + 16CX4D + cccccccc + inService + not-reserved-available + NORMAL + 4 + 0 + 0 + + C1 + Client + roadm-external + wavelength + bidirectional + inService + inService + SRG1-PP1 + + -15.0 + -28.0 + 10.0 + 15.0 + + + + + C10 + Client + roadm-external + wavelength + bidirectional + inService + inService + SRG1-PP10 + + -15.0 + -28.0 + 10.0 + 15.0 + + + + + C11 + Client + roadm-external + wavelength + bidirectional + inService + inService + SRG1-PP11 + + -15.0 + -28.0 + 10.0 + 15.0 + + + + + C12 + Client + roadm-external + wavelength + bidirectional + inService + inService + SRG1-PP12 + + -15.0 + -28.0 + 10.0 + 15.0 + + + + + C13 + Client + roadm-external + wavelength + bidirectional + inService + inService + SRG1-PP13 + + -15.0 + -28.0 + 10.0 + 15.0 + + + + + C14 + Client + roadm-external + wavelength + bidirectional + inService + inService + SRG1-PP14 + + -15.0 + -28.0 + 10.0 + 15.0 + + + + + C15 + Client + roadm-external + wavelength + bidirectional + inService + inService + SRG1-PP15 + + -15.0 + -28.0 + 10.0 + 15.0 + + + + + C16 + Client + roadm-external + wavelength + bidirectional + inService + inService + SRG1-PP16 + + -15.0 + -28.0 + 10.0 + 15.0 + + + + + C2 + Client + roadm-external + wavelength + bidirectional + inService + inService + SRG1-PP2 + + -15.0 + -28.0 + 10.0 + 15.0 + + + + + C3 + Client + roadm-external + wavelength + bidirectional + inService + inService + SRG1-PP3 + + -15.0 + -28.0 + 10.0 + 15.0 + + + + + C4 + Client + roadm-external + wavelength + bidirectional + inService + inService + SRG1-PP4 + + -15.0 + -28.0 + 10.0 + 15.0 + + + + + C5 + Client + roadm-external + wavelength + bidirectional + inService + inService + SRG1-PP5 + + -15.0 + -28.0 + 10.0 + 15.0 + + + + + C6 + Client + roadm-external + wavelength + bidirectional + inService + inService + SRG1-PP6 + + -15.0 + -28.0 + 10.0 + 15.0 + + + + + C7 + Client + roadm-external + wavelength + bidirectional + inService + inService + SRG1-PP7 + + -15.0 + -28.0 + 10.0 + 15.0 + + + + + C8 + Client + roadm-external + wavelength + bidirectional + inService + inService + SRG1-PP8 + + -15.0 + -28.0 + 10.0 + 15.0 + + + + + C9 + Client + roadm-external + wavelength + bidirectional + inService + inService + SRG1-PP9 + + -15.0 + -28.0 + 10.0 + 15.0 + + + + + AD-DEG1 + Edge + roadm-internal + multi-wavelength + bidirectional + inService + inService + SRG1-CP-TXRX + + + AD-DEG2 + Edge + roadm-internal + multi-wavelength + bidirectional + inService + inService + SRG1-CP-TXRX + + + AD-DEG3 + Edge + roadm-internal + multi-wavelength + bidirectional + inService + inService + SRG1-CP-TXRX + + + AD-DEG4 + Edge + roadm-internal + multi-wavelength + bidirectional + inService + inService + SRG1-CP-TXRX + + + + oms-2/0/0/L1 + openROADM-if:openROADMOpticalMultiplex + inService + inService + ots-2/0/0/L1 + 2/0 + L1 + + + oms-3/0/0/L1 + openROADM-if:openROADMOpticalMultiplex + inService + inService + Link-1 + ots-3/0/0/L1 + 3/0 + L1 + + + ots-2/0/0/L1 + openROADM-if:opticalTransport + inService + inService + 2/0 + L1 + + smf + 15 + 15 + + + + ots-3/0/0/L1 + openROADM-if:opticalTransport + inService + inService + 3/0 + L1 + + smf + 10.0 + 10.0 + + + + + 1 + 196.1 + 1528.77 + + + 2 + 196.05 + 1529.16 + + + 3 + 196.0 + 1529.55 + + + 4 + 195.95 + 1529.94 + + + 5 + 195.9 + 1530.33 + + + 6 + 195.85 + 1530.72 + + + 7 + 195.8 + 1531.11 + + + 8 + 195.75 + 1531.5 + + + 9 + 195.7 + 1531.89 + + + 10 + 195.65 + 1532.28 + + + 11 + 195.6 + 1532.67 + + + 12 + 195.55 + 1533.06 + + + 13 + 195.5 + 1533.45 + + + 14 + 195.45 + 1533.84 + + + 15 + 195.4 + 1534.23 + + + 16 + 195.35 + 1534.62 + + + 17 + 195.3 + 1535.01 + + + 18 + 195.25 + 1535.4 + + + 19 + 195.2 + 1535.79 + + + 20 + 195.15 + 1536.18 + + + 21 + 195.1 + 1536.57 + + + 22 + 195.05 + 1536.96 + + + 23 + 195.0 + 1537.35 + + + 24 + 194.95 + 1537.74 + + + 25 + 194.9 + 1538.13 + + + 26 + 194.85 + 1538.52 + + + 27 + 194.8 + 1538.91 + + + 28 + 194.75 + 1539.3 + + + 29 + 194.7 + 1539.69 + + + 30 + 194.65 + 1540.08 + + + 31 + 194.6 + 1540.47 + + + 32 + 194.55 + 1540.86 + + + 33 + 194.5 + 1541.25 + + + 34 + 194.45 + 1541.64 + + + 35 + 194.4 + 1542.03 + + + 36 + 194.35 + 1542.42 + + + 37 + 194.3 + 1542.81 + + + 38 + 194.25 + 1543.2 + + + 39 + 194.2 + 1543.59 + + + 40 + 194.15 + 1543.98 + + + 41 + 194.1 + 1544.37 + + + 42 + 194.05 + 1544.76 + + + 43 + 194.0 + 1545.15 + + + 44 + 193.95 + 1545.54 + + + 45 + 193.9 + 1545.93 + + + 46 + 193.85 + 1546.32 + + + 47 + 193.8 + 1546.71 + + + 48 + 193.75 + 1547.1 + + + 49 + 193.7 + 1547.49 + + + 50 + 193.65 + 1547.88 + + + 51 + 193.6 + 1548.27 + + + 52 + 193.55 + 1548.66 + + + 53 + 193.5 + 1549.05 + + + 54 + 193.45 + 1549.44 + + + 55 + 193.4 + 1549.83 + + + 56 + 193.35 + 1550.22 + + + 57 + 193.3 + 1550.61 + + + 58 + 193.25 + 1551.0 + + + 59 + 193.2 + 1551.39 + + + 60 + 193.15 + 1551.78 + + + 61 + 193.1 + 1552.17 + + + 62 + 193.05 + 1552.56 + + + 63 + 193.0 + 1552.95 + + + 64 + 192.95 + 1553.34 + + + 65 + 192.9 + 1553.73 + + + 66 + 192.85 + 1554.12 + + + 67 + 192.8 + 1554.51 + + + 68 + 192.75 + 1554.9 + + + 69 + 192.7 + 1555.29 + + + 70 + 192.65 + 1555.68 + + + 71 + 192.6 + 1556.07 + + + 72 + 192.55 + 1556.46 + + + 73 + 192.5 + 1556.85 + + + 74 + 192.45 + 1557.24 + + + 75 + 192.4 + 1557.63 + + + 76 + 192.35 + 1558.02 + + + 77 + 192.3 + 1558.41 + + + 78 + 192.25 + 1558.8 + + + 79 + 192.2 + 1559.19 + + + 80 + 192.15 + 1559.58 + + + 81 + 192.1 + 1559.97 + + + 82 + 192.05 + 1560.36 + + + 83 + 192.0 + 1560.75 + + + 84 + 191.95 + 1561.14 + + + 85 + 191.9 + 1561.53 + + + 86 + 191.85 + 1561.92 + + + 87 + 191.8 + 1562.31 + + + 88 + 191.75 + 1562.7 + + + 89 + 191.7 + 1563.09 + + + 90 + 191.65 + 1563.48 + + + 91 + 191.6 + 1563.87 + + + 92 + 191.55 + 1564.26 + + + 93 + 191.5 + 1564.65 + + + 94 + 191.45 + 1565.04 + + + 95 + 191.4 + 1565.43 + + + 96 + 191.35 + 1565.82 + + + + 2/0/C1-to-2/0/L1 + + 2/0 + C1 + + + 2/0 + L1 + + + + 2/0/C2-to-2/0/L1 + + 2/0 + C2 + + + 2/0 + L1 + + + + 2/0/C3-to-2/0/L1 + + 2/0 + C3 + + + 2/0 + L1 + + + + 2/0/C4-to-2/0/L1 + + 2/0 + C4 + + + 2/0 + L1 + + + + 2/0/C5-to-2/0/L1 + + 2/0 + C5 + + + 2/0 + L1 + + + + 2/0/C6-to-2/0/L1 + + 2/0 + C6 + + + 2/0 + L1 + + + + 2/0/C7-to-2/0/L1 + + 2/0 + C7 + + + 2/0 + L1 + + + + 2/0/C8-to-2/0/L1 + + 2/0 + C8 + + + 2/0 + L1 + + + + 2/0/C9-to-2/0/L1 + + 2/0 + C9 + + + 2/0 + L1 + + + + 2/0/L1-to-2/0/C1 + + 2/0 + L1 + + + 2/0 + C1 + + + + 2/0/L1-to-2/0/C2 + + 2/0 + L1 + + + 2/0 + C2 + + + + 2/0/L1-to-2/0/C3 + + 2/0 + L1 + + + 2/0 + C3 + + + + 2/0/L1-to-2/0/C4 + + 2/0 + L1 + + + 2/0 + C4 + + + + 2/0/L1-to-2/0/C5 + + 2/0 + L1 + + + 2/0 + C5 + + + + 2/0/L1-to-2/0/C6 + + 2/0 + L1 + + + 2/0 + C6 + + + + 2/0/L1-to-2/0/C7 + + 2/0 + L1 + + + 2/0 + C7 + + + + 2/0/L1-to-2/0/C8 + + 2/0 + L1 + + + 2/0 + C8 + + + + 2/0/L1-to-2/0/C9 + + 2/0 + L1 + + + 2/0 + C9 + + + + 3/0/C1-to-3/0/L1 + + 3/0 + C1 + + + 3/0 + L1 + + + + 3/0/C2-to-3/0/L1 + + 3/0 + C2 + + + 3/0 + L1 + + + + 3/0/C3-to-3/0/L1 + + 3/0 + C3 + + + 3/0 + L1 + + + + 3/0/C4-to-3/0/L1 + + 3/0 + C4 + + + 3/0 + L1 + + + + 3/0/C5-to-3/0/L1 + + 3/0 + C5 + + + 3/0 + L1 + + + + 3/0/C6-to-3/0/L1 + + 3/0 + C6 + + + 3/0 + L1 + + + + 3/0/C7-to-3/0/L1 + + 3/0 + C7 + + + 3/0 + L1 + + + + 3/0/C8-to-3/0/L1 + + 3/0 + C8 + + + 3/0 + L1 + + + + 3/0/C9-to-3/0/L1 + + 3/0 + C9 + + + 3/0 + L1 + + + + 3/0/L1-to-3/0/C1 + + 3/0 + L1 + + + 3/0 + C1 + + + + 3/0/L1-to-3/0/C2 + + 3/0 + L1 + + + 3/0 + C2 + + + + 3/0/L1-to-3/0/C3 + + 3/0 + L1 + + + 3/0 + C3 + + + + 3/0/L1-to-3/0/C4 + + 3/0 + L1 + + + 3/0 + C4 + + + + 3/0/L1-to-3/0/C5 + + 3/0 + L1 + + + 3/0 + C5 + + + + 3/0/L1-to-3/0/C6 + + 3/0 + L1 + + + 3/0 + C6 + + + + 3/0/L1-to-3/0/C7 + + 3/0 + L1 + + + 3/0 + C7 + + + + 3/0/L1-to-3/0/C8 + + 3/0 + L1 + + + 3/0 + C8 + + + + 3/0/L1-to-3/0/C9 + + 3/0 + L1 + + + 3/0 + C9 + + + + 4/0/C1-to-4/0/ADD-DEG1 + + 4/0 + C1 + + + 4/0 + ADD-DEG1 + + + + 4/0/C1-to-4/0/ADD-DEG2 + + 4/0 + C1 + + + 4/0 + ADD-DEG2 + + + + 4/0/C1-to-4/0/ADD-DEG3 + + 4/0 + C1 + + + 4/0 + ADD-DEG3 + + + + 4/0/C1-to-4/0/ADD-DEG4 + + 4/0 + C1 + + + 4/0 + ADD-DEG4 + + + + 4/0/C2-to-4/0/ADD-DEG1 + + 4/0 + C2 + + + 4/0 + ADD-DEG1 + + + + 4/0/C2-to-4/0/ADD-DEG2 + + 4/0 + C2 + + + 4/0 + ADD-DEG2 + + + + 4/0/C2-to-4/0/ADD-DEG3 + + 4/0 + C2 + + + 4/0 + ADD-DEG3 + + + + 4/0/C2-to-4/0/ADD-DEG4 + + 4/0 + C2 + + + 4/0 + ADD-DEG4 + + + + 4/0/C3-to-4/0/ADD-DEG1 + + 4/0 + C3 + + + 4/0 + ADD-DEG1 + + + + 4/0/C3-to-4/0/ADD-DEG2 + + 4/0 + C3 + + + 4/0 + ADD-DEG2 + + + + 4/0/C3-to-4/0/ADD-DEG3 + + 4/0 + C3 + + + 4/0 + ADD-DEG3 + + + + 4/0/C3-to-4/0/ADD-DEG4 + + 4/0 + C3 + + + 4/0 + ADD-DEG4 + + + + 4/0/C4-to-4/0/ADD-DEG1 + + 4/0 + C4 + + + 4/0 + ADD-DEG1 + + + + 4/0/C4-to-4/0/ADD-DEG2 + + 4/0 + C4 + + + 4/0 + ADD-DEG2 + + + + 4/0/C4-to-4/0/ADD-DEG3 + + 4/0 + C4 + + + 4/0 + ADD-DEG3 + + + + 4/0/C4-to-4/0/ADD-DEG4 + + 4/0 + C4 + + + 4/0 + ADD-DEG4 + + + + 4/0/C5-to-4/0/ADD-DEG1 + + 4/0 + C5 + + + 4/0 + ADD-DEG1 + + + + 4/0/C5-to-4/0/ADD-DEG2 + + 4/0 + C5 + + + 4/0 + ADD-DEG2 + + + + 4/0/C5-to-4/0/ADD-DEG3 + + 4/0 + C5 + + + 4/0 + ADD-DEG3 + + + + 4/0/C5-to-4/0/ADD-DEG4 + + 4/0 + C5 + + + 4/0 + ADD-DEG4 + + + + 4/0/C6-to-4/0/ADD-DEG1 + + 4/0 + C6 + + + 4/0 + ADD-DEG1 + + + + 4/0/C6-to-4/0/ADD-DEG2 + + 4/0 + C6 + + + 4/0 + ADD-DEG2 + + + + 4/0/C6-to-4/0/ADD-DEG3 + + 4/0 + C6 + + + 4/0 + ADD-DEG3 + + + + 4/0/C6-to-4/0/ADD-DEG4 + + 4/0 + C6 + + + 4/0 + ADD-DEG4 + + + + 4/0/C7-to-4/0/ADD-DEG1 + + 4/0 + C7 + + + 4/0 + ADD-DEG1 + + + + 4/0/C7-to-4/0/ADD-DEG2 + + 4/0 + C7 + + + 4/0 + ADD-DEG2 + + + + 4/0/C7-to-4/0/ADD-DEG3 + + 4/0 + C7 + + + 4/0 + ADD-DEG3 + + + + 4/0/C7-to-4/0/ADD-DEG4 + + 4/0 + C7 + + + 4/0 + ADD-DEG4 + + + + 4/0/C8-to-4/0/ADD-DEG1 + + 4/0 + C8 + + + 4/0 + ADD-DEG1 + + + + 4/0/C8-to-4/0/ADD-DEG2 + + 4/0 + C8 + + + 4/0 + ADD-DEG2 + + + + 4/0/C8-to-4/0/ADD-DEG3 + + 4/0 + C8 + + + 4/0 + ADD-DEG3 + + + + 4/0/C8-to-4/0/ADD-DEG4 + + 4/0 + C8 + + + 4/0 + ADD-DEG4 + + + + 4/0/C9-to-4/0/ADD-DEG1 + + 4/0 + C9 + + + 4/0 + ADD-DEG1 + + + + 4/0/C9-to-4/0/ADD-DEG2 + + 4/0 + C9 + + + 4/0 + ADD-DEG2 + + + + 4/0/C9-to-4/0/ADD-DEG3 + + 4/0 + C9 + + + 4/0 + ADD-DEG3 + + + + 4/0/C9-to-4/0/ADD-DEG4 + + 4/0 + C9 + + + 4/0 + ADD-DEG4 + + + + 4/0/C10-to-4/0/ADD-DEG1 + + 4/0 + C10 + + + 4/0 + ADD-DEG1 + + + + 4/0/C10-to-4/0/ADD-DEG2 + + 4/0 + C10 + + + 4/0 + ADD-DEG2 + + + + 4/0/C10-to-4/0/ADD-DEG3 + + 4/0 + C10 + + + 4/0 + ADD-DEG3 + + + + 4/0/C10-to-4/0/ADD-DEG4 + + 4/0 + C10 + + + 4/0 + ADD-DEG4 + + + + 4/0/C11-to-4/0/ADD-DEG1 + + 4/0 + C11 + + + 4/0 + ADD-DEG1 + + + + 4/0/C11-to-4/0/ADD-DEG2 + + 4/0 + C11 + + + 4/0 + ADD-DEG2 + + + + 4/0/C11-to-4/0/ADD-DEG3 + + 4/0 + C11 + + + 4/0 + ADD-DEG3 + + + + 4/0/C11-to-4/0/ADD-DEG4 + + 4/0 + C11 + + + 4/0 + ADD-DEG4 + + + + 4/0/C12-to-4/0/ADD-DEG1 + + 4/0 + C12 + + + 4/0 + ADD-DEG1 + + + + 4/0/C12-to-4/0/ADD-DEG2 + + 4/0 + C12 + + + 4/0 + ADD-DEG2 + + + + 4/0/C12-to-4/0/ADD-DEG3 + + 4/0 + C12 + + + 4/0 + ADD-DEG3 + + + + 4/0/C12-to-4/0/ADD-DEG4 + + 4/0 + C12 + + + 4/0 + ADD-DEG4 + + + + 4/0/C13-to-4/0/ADD-DEG1 + + 4/0 + C13 + + + 4/0 + ADD-DEG1 + + + + 4/0/C13-to-4/0/ADD-DEG2 + + 4/0 + C13 + + + 4/0 + ADD-DEG2 + + + + 4/0/C13-to-4/0/ADD-DEG3 + + 4/0 + C13 + + + 4/0 + ADD-DEG3 + + + + 4/0/C13-to-4/0/ADD-DEG4 + + 4/0 + C13 + + + 4/0 + ADD-DEG4 + + + + 4/0/C14-to-4/0/ADD-DEG1 + + 4/0 + C14 + + + 4/0 + ADD-DEG1 + + + + 4/0/C14-to-4/0/ADD-DEG2 + + 4/0 + C14 + + + 4/0 + ADD-DEG2 + + + + 4/0/C14-to-4/0/ADD-DEG3 + + 4/0 + C14 + + + 4/0 + ADD-DEG3 + + + + 4/0/C14-to-4/0/ADD-DEG4 + + 4/0 + C14 + + + 4/0 + ADD-DEG4 + + + + 4/0/C15-to-4/0/ADD-DEG1 + + 4/0 + C15 + + + 4/0 + ADD-DEG1 + + + + 4/0/C15-to-4/0/ADD-DEG2 + + 4/0 + C15 + + + 4/0 + ADD-DEG2 + + + + 4/0/C15-to-4/0/ADD-DEG3 + + 4/0 + C15 + + + 4/0 + ADD-DEG3 + + + + 4/0/C15-to-4/0/ADD-DEG4 + + 4/0 + C15 + + + 4/0 + ADD-DEG4 + + + + 4/0/C16-to-4/0/ADD-DEG1 + + 4/0 + C16 + + + 4/0 + ADD-DEG1 + + + + 4/0/C16-to-4/0/ADD-DEG2 + + 4/0 + C16 + + + 4/0 + ADD-DEG2 + + + + 4/0/C16-to-4/0/ADD-DEG3 + + 4/0 + C16 + + + 4/0 + ADD-DEG3 + + + + 4/0/C16-to-4/0/ADD-DEG4 + + 4/0 + C16 + + + 4/0 + ADD-DEG4 + + + + 4/0/ADD-DEG1-to-4/0/C1 + + 4/0 + ADD-DEG1 + + + 4/0 + C1 + + + + 4/0/ADD-DEG1-to-4/0/C2 + + 4/0 + ADD-DEG1 + + + 4/0 + C2 + + + + 4/0/ADD-DEG1-to-4/0/C3 + + 4/0 + ADD-DEG1 + + + 4/0 + C3 + + + + 4/0/ADD-DEG1-to-4/0/C4 + + 4/0 + ADD-DEG1 + + + 4/0 + C4 + + + + 4/0/ADD-DEG1-to-4/0/C5 + + 4/0 + ADD-DEG1 + + + 4/0 + C5 + + + + 4/0/ADD-DEG1-to-4/0/C6 + + 4/0 + ADD-DEG1 + + + 4/0 + C6 + + + + 4/0/ADD-DEG1-to-4/0/C7 + + 4/0 + ADD-DEG1 + + + 4/0 + C7 + + + + 4/0/ADD-DEG1-to-4/0/C8 + + 4/0 + ADD-DEG1 + + + 4/0 + C8 + + + + 4/0/ADD-DEG1-to-4/0/C9 + + 4/0 + ADD-DEG1 + + + 4/0 + C9 + + + + 4/0/ADD-DEG1-to-4/0/C10 + + 4/0 + ADD-DEG1 + + + 4/0 + C10 + + + + 4/0/ADD-DEG1-to-4/0/C11 + + 4/0 + ADD-DEG1 + + + 4/0 + C11 + + + + 4/0/ADD-DEG1-to-4/0/C12 + + 4/0 + ADD-DEG1 + + + 4/0 + C12 + + + + 4/0/ADD-DEG1-to-4/0/C13 + + 4/0 + ADD-DEG1 + + + 4/0 + C13 + + + + 4/0/ADD-DEG1-to-4/0/C14 + + 4/0 + ADD-DEG1 + + + 4/0 + C14 + + + + 4/0/ADD-DEG1-to-4/0/C15 + + 4/0 + ADD-DEG1 + + + 4/0 + C15 + + + + 4/0/ADD-DEG1-to-4/0/C16 + + 4/0 + ADD-DEG1 + + + 4/0 + C16 + + + + 4/0/ADD-DEG2-to-4/0/C1 + + 4/0 + ADD-DEG2 + + + 4/0 + C1 + + + + 4/0/ADD-DEG2-to-4/0/C2 + + 4/0 + ADD-DEG2 + + + 4/0 + C2 + + + + 4/0/ADD-DEG2-to-4/0/C3 + + 4/0 + ADD-DEG2 + + + 4/0 + C3 + + + + 4/0/ADD-DEG2-to-4/0/C4 + + 4/0 + ADD-DEG2 + + + 4/0 + C4 + + + + 4/0/ADD-DEG2-to-4/0/C5 + + 4/0 + ADD-DEG2 + + + 4/0 + C5 + + + + 4/0/ADD-DEG2-to-4/0/C6 + + 4/0 + ADD-DEG2 + + + 4/0 + C6 + + + + 4/0/ADD-DEG2-to-4/0/C7 + + 4/0 + ADD-DEG2 + + + 4/0 + C7 + + + + 4/0/ADD-DEG2-to-4/0/C8 + + 4/0 + ADD-DEG2 + + + 4/0 + C8 + + + + 4/0/ADD-DEG2-to-4/0/C9 + + 4/0 + ADD-DEG2 + + + 4/0 + C9 + + + + 4/0/ADD-DEG2-to-4/0/C10 + + 4/0 + ADD-DEG2 + + + 4/0 + C10 + + + + 4/0/ADD-DEG2-to-4/0/C11 + + 4/0 + ADD-DEG2 + + + 4/0 + C11 + + + + 4/0/ADD-DEG2-to-4/0/C12 + + 4/0 + ADD-DEG2 + + + 4/0 + C12 + + + + 4/0/ADD-DEG2-to-4/0/C13 + + 4/0 + ADD-DEG2 + + + 4/0 + C13 + + + + 4/0/ADD-DEG2-to-4/0/C14 + + 4/0 + ADD-DEG2 + + + 4/0 + C14 + + + + 4/0/ADD-DEG2-to-4/0/C15 + + 4/0 + ADD-DEG2 + + + 4/0 + C15 + + + + 4/0/ADD-DEG2-to-4/0/C16 + + 4/0 + ADD-DEG2 + + + 4/0 + C16 + + + + 4/0/ADD-DEG3-to-4/0/C1 + + 4/0 + ADD-DEG3 + + + 4/0 + C1 + + + + 4/0/ADD-DEG3-to-4/0/C2 + + 4/0 + ADD-DEG3 + + + 4/0 + C2 + + + + 4/0/ADD-DEG3-to-4/0/C3 + + 4/0 + ADD-DEG3 + + + 4/0 + C3 + + + + 4/0/ADD-DEG3-to-4/0/C4 + + 4/0 + ADD-DEG3 + + + 4/0 + C4 + + + + 4/0/ADD-DEG3-to-4/0/C5 + + 4/0 + ADD-DEG3 + + + 4/0 + C5 + + + + 4/0/ADD-DEG3-to-4/0/C6 + + 4/0 + ADD-DEG3 + + + 4/0 + C6 + + + + 4/0/ADD-DEG3-to-4/0/C7 + + 4/0 + ADD-DEG3 + + + 4/0 + C7 + + + + 4/0/ADD-DEG3-to-4/0/C8 + + 4/0 + ADD-DEG3 + + + 4/0 + C8 + + + + 4/0/ADD-DEG3-to-4/0/C9 + + 4/0 + ADD-DEG3 + + + 4/0 + C9 + + + + 4/0/ADD-DEG3-to-4/0/C10 + + 4/0 + ADD-DEG3 + + + 4/0 + C10 + + + + 4/0/ADD-DEG3-to-4/0/C11 + + 4/0 + ADD-DEG3 + + + 4/0 + C11 + + + + 4/0/ADD-DEG3-to-4/0/C12 + + 4/0 + ADD-DEG3 + + + 4/0 + C12 + + + + 4/0/ADD-DEG3-to-4/0/C13 + + 4/0 + ADD-DEG3 + + + 4/0 + C13 + + + + 4/0/ADD-DEG3-to-4/0/C14 + + 4/0 + ADD-DEG3 + + + 4/0 + C14 + + + + 4/0/ADD-DEG3-to-4/0/C15 + + 4/0 + ADD-DEG3 + + + 4/0 + C15 + + + + 4/0/ADD-DEG3-to-4/0/C16 + + 4/0 + ADD-DEG3 + + + 4/0 + C16 + + + + 4/0/ADD-DEG4-to-4/0/C1 + + 4/0 + ADD-DEG4 + + + 4/0 + C1 + + + + 4/0/ADD-DEG4-to-4/0/C2 + + 4/0 + ADD-DEG4 + + + 4/0 + C2 + + + + 4/0/ADD-DEG4-to-4/0/C3 + + 4/0 + ADD-DEG4 + + + 4/0 + C3 + + + + 4/0/ADD-DEG4-to-4/0/C4 + + 4/0 + ADD-DEG4 + + + 4/0 + C4 + + + + 4/0/ADD-DEG4-to-4/0/C5 + + 4/0 + ADD-DEG4 + + + 4/0 + C5 + + + + 4/0/ADD-DEG4-to-4/0/C6 + + 4/0 + ADD-DEG4 + + + 4/0 + C6 + + + + 4/0/ADD-DEG4-to-4/0/C7 + + 4/0 + ADD-DEG4 + + + 4/0 + C7 + + + + 4/0/ADD-DEG4-to-4/0/C8 + + 4/0 + ADD-DEG4 + + + 4/0 + C8 + + + + 4/0/ADD-DEG4-to-4/0/C9 + + 4/0 + ADD-DEG4 + + + 4/0 + C9 + + + + 4/0/ADD-DEG4-to-4/0/C10 + + 4/0 + ADD-DEG4 + + + 4/0 + C10 + + + + 4/0/ADD-DEG4-to-4/0/C11 + + 4/0 + ADD-DEG4 + + + 4/0 + C11 + + + + 4/0/ADD-DEG4-to-4/0/C12 + + 4/0 + ADD-DEG4 + + + 4/0 + C12 + + + + 4/0/ADD-DEG4-to-4/0/C13 + + 4/0 + ADD-DEG4 + + + 4/0 + C13 + + + + 4/0/ADD-DEG4-to-4/0/C14 + + 4/0 + ADD-DEG4 + + + 4/0 + C14 + + + + 4/0/ADD-DEG4-to-4/0/C15 + + 4/0 + ADD-DEG4 + + + 4/0 + C15 + + + + 4/0/ADD-DEG4-to-4/0/C16 + + 4/0 + ADD-DEG4 + + + 4/0 + C16 + + + + phylink-1 + + 2/0 + C1 + + + 4/0 + ADD-DEG1 + + + + phylink-2 + + 4/0 + ADD-DEG1 + + + 2/0 + C1 + + + + phylink-3 + + 3/0 + C1 + + + 4/0 + ADD-DEG2 + + + + phylink-4 + + 4/0 + ADD-DEG2 + + + 3/0 + C1 + + + + phylink-5 + + 2/0 + C9 + + + 3/0 + C9 + + + + phylink-6 + + 3/0 + C9 + + + 2/0 + C9 + + + + 1 + 96 + + 1 + 2/0 + + + 1 + 2/0 + L1 + + + + 2 + 96 + + 1 + 3/0 + + + 1 + 3/0 + L1 + + + + 1 + 16 + onePerSRG + + 1 + 4/0 + + + + 1 + + 2/0 + L1 + + + 4/0 + C1 + + + 4/0 + C2 + + + 4/0 + C3 + + + 4/0 + C4 + + + 4/0 + C5 + + + 4/0 + C6 + + + 4/0 + C7 + + + 4/0 + C8 + + + 4/0 + C9 + + + 4/0 + C10 + + + 4/0 + C11 + + + 4/0 + C12 + + + 4/0 + C13 + + + 4/0 + C14 + + + 4/0 + C15 + + + 4/0 + C16 + + + + 2 + + 4/0 + C1 + + + 2/0 + E1 + + + + 3 + + 4/0 + C2 + + + 2/0 + E1 + + + + 4 + + 4/0 + C3 + + + 2/0 + E1 + + + + 5 + + 4/0 + C4 + + + 2/0 + E1 + + + + 6 + + 4/0 + C5 + + + 2/0 + E1 + + + + 7 + + 4/0 + C6 + + + 2/0 + E1 + + + + 8 + + 4/0 + C7 + + + 2/0 + E1 + + + + 9 + + 4/0 + C8 + + + 2/0 + E1 + + + + 10 + + 4/0 + C9 + + + 2/0 + E1 + + + + 11 + + 4/0 + C10 + + + 2/0 + E1 + + + + 12 + + 4/0 + C11 + + + 2/0 + E1 + + + + 13 + + 4/0 + C12 + + + 2/0 + E1 + + + + 14 + + 4/0 + C13 + + + 2/0 + E1 + + + + 15 + + 4/0 + C14 + + + 2/0 + E1 + + + + 16 + + 4/0 + C15 + + + 2/0 + E1 + + + + 17 + + 4/0 + C16 + + + 2/0 + E1 + + + + 18 + + 3/0 + L1 + + + 4/0 + C1 + + + 4/0 + C2 + + + 4/0 + C3 + + + 4/0 + C4 + + + 4/0 + C5 + + + 4/0 + C6 + + + 4/0 + C7 + + + 4/0 + C8 + + + 4/0 + C9 + + + 4/0 + C10 + + + 4/0 + C11 + + + 4/0 + C12 + + + 4/0 + C13 + + + 4/0 + C14 + + + 4/0 + C15 + + + 4/0 + C16 + + + + 19 + + 4/0 + C1 + + + 3/0 + E1 + + + + 20 + + 4/0 + C2 + + + 3/0 + E1 + + + + 21 + + 4/0 + C3 + + + 3/0 + E1 + + + + 22 + + 4/0 + C4 + + + 3/0 + E1 + + + + 23 + + 4/0 + C5 + + + 3/0 + E1 + + + + 24 + + 4/0 + C6 + + + 3/0 + E1 + + + + 25 + + 4/0 + C7 + + + 3/0 + E1 + + + + 26 + + 4/0 + C8 + + + 3/0 + E1 + + + + 27 + + 4/0 + C9 + + + 3/0 + E1 + + + + 28 + + 4/0 + C10 + + + 3/0 + E1 + + + + 29 + + 4/0 + C11 + + + 3/0 + E1 + + + + 30 + + 4/0 + C12 + + + 3/0 + E1 + + + + 31 + + 4/0 + C13 + + + 3/0 + E1 + + + + 32 + + 4/0 + C14 + + + 3/0 + E1 + + + + 33 + + 4/0 + C15 + + + 3/0 + E1 + + + + 34 + + 4/0 + C16 + + + 3/0 + E1 + + + + diff --git a/pom.xml b/pom.xml index 38e2d6293..2d40ce9cb 100644 --- a/pom.xml +++ b/pom.xml @@ -31,6 +31,7 @@ and is available at http://www.eclipse.org/legal/epl-v10.html INTERNAL artifacts api + common ordmodels renderer olm