From 0da8cea9fcd1c78753493ed6929f6e3241da06df Mon Sep 17 00:00:00 2001 From: Shweta V Date: Wed, 20 Dec 2017 12:12:12 +0100 Subject: [PATCH] Network topology and inventory init - Includes network topology creation when NE gets mounted including CLLI, Openroadm-Network and Openroadm-Topology - Abstracts network model for Roadm and Xponder nodes - Derives Roadm-to-Roadm links from LLDP config and notifications - Provides RPC to create Xponder-input and Xponder-output links - Includes functionality to update available and used pool based on service-create and service-delete request - Remove log error for LLDP subtree Differences with initial change from ATT-Sandbox branch - Fix code design issues pointed by Juraj (Patch Set 5) https://git.opendaylight.org/gerrit/#/c/68859/5 - fix inventory feature building 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: I440caf77157d2fa5a5b17ab048252c96833e7561 Signed-off-by: Shweta Signed-off-by: Martial COULIBALY --- features/features-transportpce/pom.xml | 7 + features/odl-transportpce-inventory/pom.xml | 103 +++ .../src/main/feature/feature.xml | 14 + .../org.opendaylight.transportpce.job.cfg | 6 + .../org.ops4j.datasource-transporpce.cfg | 6 + features/odl-transportpce/pom.xml | 5 + features/pom.xml | 1 + inventory/pom.xml | 82 ++ .../inventory/DeviceInventory.java | 109 +++ .../transportpce/inventory/INode.java | 254 ++++++ .../inventory/ListenerProvider.java | 87 ++ .../inventory/dto/InvDevInfo.java | 256 ++++++ .../job/PeriodicDeviceBackupJob.java | 249 ++++++ .../listener/ClliNetworkChangeListener.java | 26 + .../inventory/listener/DeviceListener.java | 146 +++ .../OverlayNetworkChangeListener.java | 26 + .../inventory/listener/ServiceListener.java | 160 ++++ .../UnderlayNetworkChangeListener.java | 26 + .../transportpce/inventory/query/Queries.java | 132 +++ .../inventory/query/QueryUtils.java | 205 +++++ .../inventory/query/StatementBuilder.java | 48 + .../inventory/utils/StringUtils.java | 80 ++ .../blueprint/inventory-blueprint.xml | 65 ++ networkmodel/pom.xml | 76 ++ .../networkmodel/NetConfTopologyListener.java | 228 +++++ .../networkmodel/NetworkModelProvider.java | 75 ++ .../networkmodel/NetworkUtilsImpl.java | 78 ++ .../transportpce/networkmodel/OrdLink.java | 89 ++ .../networkmodel/R2RLinkDiscovery.java | 320 +++++++ .../networkmodel/Rdm2XpdrLink.java | 116 +++ .../networkmodel/dto/NodeData.java | 29 + .../networkmodel/dto/NodeRegistration.java | 66 ++ .../networkmodel/dto/TopologyShard.java | 36 + .../listeners/AlarmNotificationListener.java | 216 +++++ .../listeners/DeOperationsListener.java | 3 +- .../listeners/DeviceListener.java | 5 +- .../networkmodel/listeners/LldpListener.java | 47 + .../networkmodel}/listeners/TcaListener.java | 6 +- .../service/NetworkModelService.java | 35 + .../service/NetworkModelServiceImpl.java | 143 +++ .../networkmodel/util/ClliNetwork.java | 119 +++ .../networkmodel/util/LinkIdUtil.java | 115 +++ .../networkmodel/util/OpenRoadmNetwork.java | 148 ++++ .../networkmodel/util/OpenRoadmTopology.java | 833 ++++++++++++++++++ .../blueprint/networkmodel-blueprint.xml | 59 ++ .../networkmodel/NetworkModelTest.java | 18 + pom.xml | 2 + .../renderer/RendererNotificationsImpl.java | 233 ----- .../renderer/RendererProvider.java | 28 +- .../listeners/AlarmNotificationListener.java | 29 - .../renderer/listeners/LldpListener.java | 30 - .../tasks/RollbackProcessor.java | 2 +- .../blueprint/renderer-blueprint.xml | 5 - 53 files changed, 4951 insertions(+), 331 deletions(-) create mode 100644 features/odl-transportpce-inventory/pom.xml create mode 100644 features/odl-transportpce-inventory/src/main/feature/feature.xml create mode 100644 features/odl-transportpce-inventory/src/main/resources/org.opendaylight.transportpce.job.cfg create mode 100644 features/odl-transportpce-inventory/src/main/resources/org.ops4j.datasource-transporpce.cfg create mode 100644 inventory/pom.xml create mode 100644 inventory/src/main/java/org/opendaylight/transportpce/inventory/DeviceInventory.java create mode 100644 inventory/src/main/java/org/opendaylight/transportpce/inventory/INode.java create mode 100644 inventory/src/main/java/org/opendaylight/transportpce/inventory/ListenerProvider.java create mode 100644 inventory/src/main/java/org/opendaylight/transportpce/inventory/dto/InvDevInfo.java create mode 100644 inventory/src/main/java/org/opendaylight/transportpce/inventory/job/PeriodicDeviceBackupJob.java create mode 100644 inventory/src/main/java/org/opendaylight/transportpce/inventory/listener/ClliNetworkChangeListener.java create mode 100644 inventory/src/main/java/org/opendaylight/transportpce/inventory/listener/DeviceListener.java create mode 100644 inventory/src/main/java/org/opendaylight/transportpce/inventory/listener/OverlayNetworkChangeListener.java create mode 100644 inventory/src/main/java/org/opendaylight/transportpce/inventory/listener/ServiceListener.java create mode 100644 inventory/src/main/java/org/opendaylight/transportpce/inventory/listener/UnderlayNetworkChangeListener.java create mode 100644 inventory/src/main/java/org/opendaylight/transportpce/inventory/query/Queries.java create mode 100644 inventory/src/main/java/org/opendaylight/transportpce/inventory/query/QueryUtils.java create mode 100644 inventory/src/main/java/org/opendaylight/transportpce/inventory/query/StatementBuilder.java create mode 100644 inventory/src/main/java/org/opendaylight/transportpce/inventory/utils/StringUtils.java create mode 100644 inventory/src/main/resources/org/opendaylight/blueprint/inventory-blueprint.xml create mode 100644 networkmodel/pom.xml create mode 100644 networkmodel/src/main/java/org/opendaylight/transportpce/networkmodel/NetConfTopologyListener.java create mode 100644 networkmodel/src/main/java/org/opendaylight/transportpce/networkmodel/NetworkModelProvider.java create mode 100644 networkmodel/src/main/java/org/opendaylight/transportpce/networkmodel/NetworkUtilsImpl.java create mode 100644 networkmodel/src/main/java/org/opendaylight/transportpce/networkmodel/OrdLink.java create mode 100644 networkmodel/src/main/java/org/opendaylight/transportpce/networkmodel/R2RLinkDiscovery.java create mode 100644 networkmodel/src/main/java/org/opendaylight/transportpce/networkmodel/Rdm2XpdrLink.java create mode 100644 networkmodel/src/main/java/org/opendaylight/transportpce/networkmodel/dto/NodeData.java create mode 100644 networkmodel/src/main/java/org/opendaylight/transportpce/networkmodel/dto/NodeRegistration.java create mode 100644 networkmodel/src/main/java/org/opendaylight/transportpce/networkmodel/dto/TopologyShard.java create mode 100644 networkmodel/src/main/java/org/opendaylight/transportpce/networkmodel/listeners/AlarmNotificationListener.java rename {renderer/src/main/java/org/opendaylight/transportpce/renderer => networkmodel/src/main/java/org/opendaylight/transportpce/networkmodel}/listeners/DeOperationsListener.java (94%) rename {renderer/src/main/java/org/opendaylight/transportpce/renderer => networkmodel/src/main/java/org/opendaylight/transportpce/networkmodel}/listeners/DeviceListener.java (89%) create mode 100644 networkmodel/src/main/java/org/opendaylight/transportpce/networkmodel/listeners/LldpListener.java rename {renderer/src/main/java/org/opendaylight/transportpce/renderer => networkmodel/src/main/java/org/opendaylight/transportpce/networkmodel}/listeners/TcaListener.java (84%) create mode 100644 networkmodel/src/main/java/org/opendaylight/transportpce/networkmodel/service/NetworkModelService.java create mode 100644 networkmodel/src/main/java/org/opendaylight/transportpce/networkmodel/service/NetworkModelServiceImpl.java create mode 100644 networkmodel/src/main/java/org/opendaylight/transportpce/networkmodel/util/ClliNetwork.java create mode 100644 networkmodel/src/main/java/org/opendaylight/transportpce/networkmodel/util/LinkIdUtil.java create mode 100644 networkmodel/src/main/java/org/opendaylight/transportpce/networkmodel/util/OpenRoadmNetwork.java create mode 100644 networkmodel/src/main/java/org/opendaylight/transportpce/networkmodel/util/OpenRoadmTopology.java create mode 100644 networkmodel/src/main/resources/org/opendaylight/blueprint/networkmodel-blueprint.xml create mode 100644 networkmodel/src/test/java/org/opendaylight/transportpce/networkmodel/NetworkModelTest.java delete mode 100644 renderer/src/main/java/org/opendaylight/transportpce/renderer/RendererNotificationsImpl.java delete mode 100644 renderer/src/main/java/org/opendaylight/transportpce/renderer/listeners/AlarmNotificationListener.java delete mode 100644 renderer/src/main/java/org/opendaylight/transportpce/renderer/listeners/LldpListener.java diff --git a/features/features-transportpce/pom.xml b/features/features-transportpce/pom.xml index 9ca8e011f..25e70765b 100644 --- a/features/features-transportpce/pom.xml +++ b/features/features-transportpce/pom.xml @@ -64,5 +64,12 @@ and is available at http://www.eclipse.org/legal/epl-v10.html INTERNAL features xml + + ${project.groupId} + odl-transportpce-inventory + ${project.version} + features + xml + diff --git a/features/odl-transportpce-inventory/pom.xml b/features/odl-transportpce-inventory/pom.xml new file mode 100644 index 000000000..d1f46e53d --- /dev/null +++ b/features/odl-transportpce-inventory/pom.xml @@ -0,0 +1,103 @@ + + + + 4.0.0 + + + org.opendaylight.odlparent + single-feature-parent + 3.1.0 + + + + org.opendaylight.transportpce + odl-transportpce-inventory + 0.2.0-SNAPSHOT + feature + + + localhost:3306 + tpce + root + root + data/transportpce/devicebackup + + 600 + + true + + + OpenDaylight :: transportpce :: Inventory + + + org.opendaylight.transportpce + transportpce-inventory + ${project.version} + + + org.opendaylight.transportpce + odl-transportpce-ui + ${project.version} + features + xml + + + + + + + maven-resources-plugin + + + copy-resources + validate + + copy-resources + + + ${basedir}/target/resources + + + + src/main/resources + + true + + + + + + + + org.codehaus.mojo + build-helper-maven-plugin + + + attach-db-artifact + package + + attach-artifact + + + + + target/resources/org.ops4j.datasource-transporpce.cfg + cfg + datasource + + + target/resources/org.opendaylight.transportpce.job.cfg + cfg + config + + + + + + + + + diff --git a/features/odl-transportpce-inventory/src/main/feature/feature.xml b/features/odl-transportpce-inventory/src/main/feature/feature.xml new file mode 100644 index 000000000..f95a75539 --- /dev/null +++ b/features/odl-transportpce-inventory/src/main/feature/feature.xml @@ -0,0 +1,14 @@ + + + + scheduler + pax-jdbc-mysql + pax-jdbc-pool-dbcp2 + + mvn:${project.groupId}/${project.artifactId}/${project.version}/cfg/datasource + + + mvn:${project.groupId}/${project.artifactId}/${project.version}/cfg/config + + + \ No newline at end of file diff --git a/features/odl-transportpce-inventory/src/main/resources/org.opendaylight.transportpce.job.cfg b/features/odl-transportpce-inventory/src/main/resources/org.opendaylight.transportpce.job.cfg new file mode 100644 index 000000000..c3505840d --- /dev/null +++ b/features/odl-transportpce-inventory/src/main/resources/org.opendaylight.transportpce.job.cfg @@ -0,0 +1,6 @@ +#folder where backup files are stored +deviceBackupFolder=${transporpce.device.backup.folder} +#prefix for the generated files +deviceBackupPrefix=${transporpce.device.backup.prefix} +#period of storing the device info is seconds +deviceBackupPeriod=${transporpce.device.backup.period} diff --git a/features/odl-transportpce-inventory/src/main/resources/org.ops4j.datasource-transporpce.cfg b/features/odl-transportpce-inventory/src/main/resources/org.ops4j.datasource-transporpce.cfg new file mode 100644 index 000000000..c10ae34fb --- /dev/null +++ b/features/odl-transportpce-inventory/src/main/resources/org.ops4j.datasource-transporpce.cfg @@ -0,0 +1,6 @@ +osgi.jdbc.driver.name=mysql +url=jdbc:mysql://${transportpce.db.host}/${transportpce.db.database}?useUnicode=true&characterEncoding=utf8 +pool=dbcp2 +user=${transportpce.db.username} +password=${transportpce.db.password} +dataSourceName=transportpce diff --git a/features/odl-transportpce/pom.xml b/features/odl-transportpce/pom.xml index 4c4d1f130..dd69778ee 100644 --- a/features/odl-transportpce/pom.xml +++ b/features/odl-transportpce/pom.xml @@ -94,6 +94,11 @@ and is available at http://www.eclipse.org/legal/epl-v10.html INTERNAL transportpce-common ${project.version} + + org.opendaylight.transportpce + transportpce-networkmodel + ${project.version} + org.opendaylight.transportpce transportpce-renderer diff --git a/features/pom.xml b/features/pom.xml index 174fcc479..d1b690d71 100644 --- a/features/pom.xml +++ b/features/pom.xml @@ -29,6 +29,7 @@ and is available at http://www.eclipse.org/legal/epl-v10.html INTERNAL odl-transportpce-stubmodels odl-transportpce odl-transportpce-ui + odl-transportpce-inventory odl-transportpce-rest diff --git a/inventory/pom.xml b/inventory/pom.xml new file mode 100644 index 000000000..ea11d15f9 --- /dev/null +++ b/inventory/pom.xml @@ -0,0 +1,82 @@ + + + + + 4.0.0 + + + org.opendaylight.controller + config-parent + 0.8.3-SNAPSHOT + + + + org.opendaylight.transportpce + transportpce-inventory + 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 + + + + + + + ${project.groupId} + transportpce-api + ${project.version} + + + ${project.groupId}.ordmodels + transportpce-ordmodels-device + ${project.version} + + + ${project.groupId} + transportpce-common + ${project.version} + + + ${project.groupId} + transportpce-renderer + ${project.version} + + + org.opendaylight.controller.model + model-topology + + + org.opendaylight.netconf + sal-netconf-connector + + + com.fasterxml.jackson.core + jackson-databind + + + org.apache.karaf.scheduler + org.apache.karaf.scheduler.core + 4.0.9 + provided + + + + diff --git a/inventory/src/main/java/org/opendaylight/transportpce/inventory/DeviceInventory.java b/inventory/src/main/java/org/opendaylight/transportpce/inventory/DeviceInventory.java new file mode 100644 index 000000000..63e0d41cb --- /dev/null +++ b/inventory/src/main/java/org/opendaylight/transportpce/inventory/DeviceInventory.java @@ -0,0 +1,109 @@ +/* + * 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.inventory; + +import java.sql.Connection; +import java.sql.PreparedStatement; +import java.sql.SQLException; +import java.text.SimpleDateFormat; +import java.util.Date; +import java.util.Optional; +import java.util.concurrent.ExecutionException; +import java.util.regex.Pattern; + +import javax.sql.DataSource; + +import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType; +import org.opendaylight.transportpce.common.Timeouts; +import org.opendaylight.transportpce.common.device.DeviceTransactionManager; +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.Info; +import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class DeviceInventory { + private static final String INSERT_ALARM_STRING = + "insert into inv_alarm_info(nodeid, probablecause, direction,extension,location," + + "notificationid,type,raisetime,severity,circuitid,circuitpack,connection,degree,iface," + + "internallink,physicallink,service,shelf,sharedriskgroup,port,portcircuitpack, create_date, update_date) " + + "values (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)"; + + private static final Logger LOG = LoggerFactory.getLogger(DeviceInventory.class); + + private final DataSource dataSource; + private final INode inode; + private final DeviceTransactionManager deviceTransactionManager; + + public DeviceInventory(DataSource dataSource, INode inode, + DeviceTransactionManager deviceTransactionManager) { + this.dataSource = dataSource; + this.inode = inode; + this.deviceTransactionManager = deviceTransactionManager; + } + + public void init() { + LOG.info("Initializing {}", DeviceInventory.class.getName()); + } + + public void initializeDevice(String deviceId) throws InterruptedException, ExecutionException { + InstanceIdentifier infoIID = InstanceIdentifier.create(OrgOpenroadmDevice.class).child(Info.class); + Optional infoOpt = + this.deviceTransactionManager.getDataFromDevice(deviceId, LogicalDatastoreType.OPERATIONAL, infoIID, + Timeouts.DEVICE_READ_TIMEOUT, Timeouts.DEVICE_READ_TIMEOUT_UNIT); + + Info deviceInfo; + if (infoOpt.isPresent()) { + deviceInfo = infoOpt.get(); + } else { + LOG.warn("Could not get device info from DataBrooker"); + return; + } + LOG.info("Creating Device Inventory {}", deviceInfo); + if (!this.inode.nodeExists(deviceId)) { + LOG.info("Adding node {} to inventory", deviceId); + this.inode.addNode(deviceInfo); + this.inode.getRoadmShelves(deviceId); + this.inode.getCircuitPacks(deviceId); + } + } + + /** + * Stores the alarm into DB using {@link PreparedStatement}. + * + * @param alarmString an alarm string + * @return number of rows inserted + */ + public int storeAlarm(String alarmString) { + String delimiter = "|"; + String[] splitAlarmString = alarmString.split(Pattern.quote(delimiter)); + int count = 0; + try (Connection connection = this.dataSource.getConnection(); + PreparedStatement statement = connection.prepareStatement(INSERT_ALARM_STRING)) { + LOG.debug("Inserting prepared stmt for {} query", INSERT_ALARM_STRING); + SimpleDateFormat simpleDate = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); + java.util.Date startTimetamp = new Date(); + String startTimetampStr = simpleDate.format(startTimetamp); + + for (int i = 0; i < 21; i++) { + String value = (splitAlarmString.length >= (i + 1)) ? splitAlarmString[i] : ""; + LOG.debug("Setting parameter {}, to {} in the insert alarm query", i + 1, value); + statement.setString(i + 1, value); + } + statement.setString(22, startTimetampStr); + statement.setString(23, startTimetampStr); + LOG.debug("Setting current time and edited time to {}", startTimetampStr); + count = statement.executeUpdate(); + LOG.debug("Statment {}, returned {}", INSERT_ALARM_STRING, count); + statement.clearParameters(); + } catch (SQLException e) { + LOG.error(e.getMessage(), e); + } + return count; + } +} diff --git a/inventory/src/main/java/org/opendaylight/transportpce/inventory/INode.java b/inventory/src/main/java/org/opendaylight/transportpce/inventory/INode.java new file mode 100644 index 000000000..37c9ce7e7 --- /dev/null +++ b/inventory/src/main/java/org/opendaylight/transportpce/inventory/INode.java @@ -0,0 +1,254 @@ +/* + * 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.inventory; + +import static org.opendaylight.transportpce.inventory.utils.StringUtils.getCurrentTimestamp; +import static org.opendaylight.transportpce.inventory.utils.StringUtils.prepareDashString; +import static org.opendaylight.transportpce.inventory.utils.StringUtils.prepareEmptyString; + +import com.google.common.base.Preconditions; + +import java.sql.Connection; +import java.sql.PreparedStatement; +import java.sql.ResultSet; +import java.sql.SQLException; +import java.util.concurrent.ExecutionException; +import javax.sql.DataSource; + +import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType; +import org.opendaylight.transportpce.common.Timeouts; +import org.opendaylight.transportpce.common.device.DeviceTransactionManager; +import org.opendaylight.transportpce.inventory.query.Queries; +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.org.openroadm.device.container.OrgOpenroadmDevice; +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.shelf.Slots; +import org.opendaylight.yang.gen.v1.http.org.openroadm.device.rev170206.shelves.Shelves; +import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class INode { + private static final Logger LOG = LoggerFactory.getLogger(INode.class); + + private final DataSource dataSource; + private final DeviceTransactionManager deviceTransactionManager; + + public INode(DataSource dataSource, DeviceTransactionManager deviceTransactionManager) { + this.dataSource = dataSource; + this.deviceTransactionManager = deviceTransactionManager; + } + + public boolean addNode(Info deviceInfo) { + boolean sqlResult = false; + String query = Queries.getQuery().deviceInfoInsert().get(); + LOG.debug("Running {} query ", query); + try (Connection connection = dataSource.getConnection(); + PreparedStatement preparedStatement = connection.prepareStatement(query)) { + String[] prepareParameters = prepareDeviceInfoParameters(deviceInfo); + for (int i = 0; i < prepareParameters.length; i++) { + LOG.debug("Parameter {} has value {}", i + 1, prepareParameters[i]); + preparedStatement.setString(i + 1, prepareParameters[i]); + } + int executeUpdate = preparedStatement.executeUpdate(); + LOG.info("#{} entries were added", executeUpdate); + sqlResult = true; + } catch (SQLException e) { + LOG.error(e.getMessage(), e); + } + return sqlResult; + } + + public boolean nodeExists(String nodeId) { + String selectTableSQL = "select count(*) node_exists from inv_dev_info where node_id = ?"; + int nodeExists = 0; + LOG.info("Checking if {} exists in DB", nodeId); + try (Connection connection = dataSource.getConnection(); + PreparedStatement preparedStmt = connection.prepareStatement(selectTableSQL)) { + preparedStmt.setString(1, nodeId); + try (ResultSet rs = preparedStmt.executeQuery()) { + while (rs.next()) { + nodeExists = rs.getInt("node_exists"); + LOG.debug("Found {} devices matching {}", nodeExists, nodeId); + } + } + } catch (SQLException e) { + LOG.error(e.getMessage(), e); + } + return nodeExists == 0 ? false : true; + } + + public void getRoadmShelves(String nodeId) throws InterruptedException, ExecutionException { + InstanceIdentifier deviceIID = InstanceIdentifier.create(OrgOpenroadmDevice.class); + java.util.Optional deviceObject = deviceTransactionManager.getDataFromDevice(nodeId, + LogicalDatastoreType.OPERATIONAL, deviceIID, Timeouts.DEVICE_READ_TIMEOUT, + Timeouts.DEVICE_READ_TIMEOUT_UNIT); + + LOG.info("Shelves size {}", deviceObject.get().getShelves().size()); + try (Connection connection = dataSource.getConnection()) { + Preconditions.checkNotNull(connection); + for (int i = 0; i < deviceObject.get().getShelves().size(); i++) { + Shelves shelve = deviceObject.get().getShelves().get(i); + String shelfName = shelve.getShelfName(); + + LOG.info("Getting Shelve Details of {}", shelfName); + LOG.info("Slot Size {} ", shelve.getSlots().size()); + + persistShelveSlots(nodeId, shelve, connection); + + persistShelves(nodeId, connection, shelve); + } + } catch (SQLException e1) { + LOG.error(e1.getMessage(), e1); + } + } + + public void getCircuitPacks(String nodeId) throws InterruptedException, ExecutionException { + InstanceIdentifier deviceIID = InstanceIdentifier.create(OrgOpenroadmDevice.class); + java.util.Optional deviceObject = + deviceTransactionManager.getDataFromDevice(nodeId, LogicalDatastoreType.OPERATIONAL, deviceIID, + Timeouts.DEVICE_READ_TIMEOUT, Timeouts.DEVICE_READ_TIMEOUT_UNIT); + if (!deviceObject.isPresent()) { + LOG.warn("Device object {} was not found", nodeId); + return; + } + LOG.info("Circuit pack size {}", deviceObject.get().getCircuitPacks().size()); + + try (Connection connection = dataSource.getConnection()) { + Preconditions.checkNotNull(connection); + for (int i = 0; i < deviceObject.get().getCircuitPacks().size(); i++) { + CircuitPacks cp = deviceObject.get().getCircuitPacks().get(i); + + if (cp.getCpSlots() != null) { + persistCircuitPacksSlots(nodeId, cp, connection); + } + LOG.info("Everything {}", cp); + LOG.info("CP is {}", cp); + + persistPorts(cp, connection); + + persistCircuitPacks(nodeId, connection, cp); + } + } catch (SQLException e1) { + LOG.error(e1.getMessage(), e1); + } + } + + private void persistCircuitPacks(String nodeId, Connection connection, CircuitPacks cp) { + String[] parameters = prepareCircuitPacksParameters(nodeId, cp); + String query = Queries.getQuery().deviceCircuitPackInsert().get(); + try (PreparedStatement stmt = connection.prepareStatement(query)) { + for (int j = 0; j < parameters.length; j++) { + stmt.setString(j + 1, parameters[j]); + } + stmt.execute(); + stmt.clearParameters(); + } catch (SQLException e) { + LOG.error(e.getMessage(), e); + } + } + + private void persistShelves(String nodeId, Connection connection, Shelves shelve) { + String[] shelvesParameter = prepareShelvesParameters(nodeId, shelve); + String query = Queries.getQuery().deviceShelfInsert().get(); + try (PreparedStatement preparedStmt = connection.prepareStatement(query)) { + for (int j = 0; j < shelvesParameter.length; j++) { + preparedStmt.setString(j + 1, shelvesParameter[j]); + } + preparedStmt.execute(); + preparedStmt.clearParameters(); + } catch (SQLException e) { + LOG.error(e.getMessage(), e); + } + } + + private void persistShelveSlots(String nodeId, Shelves shelves, Connection connection) { + String startTimetampStr = getCurrentTimestamp(); + for (int i = 0; i < shelves.getSlots().size(); i++) { + Slots slot = shelves.getSlots().get(i); + LOG.info("Getting Slot Details of {}", slot.getSlotName()); + String[] parameters = new String[] {nodeId, shelves.getShelfName(), slot.getSlotName(), slot.getLabel(), + slot.getProvisionedCircuitPack(), startTimetampStr, startTimetampStr}; + String query = Queries.getQuery().deviceShelfSlotInsert().get(); + try (PreparedStatement stmt = connection.prepareStatement(query)) { + for (int j = 0; j < parameters.length; j++) { + stmt.setString(j + 1, parameters[j]); + } + stmt.execute(); + stmt.clearParameters(); + } catch (SQLException e) { + LOG.error(e.getMessage(), e); + } + } + } + + private void persistCircuitPacksSlots(String nodeId, CircuitPacks circuitPacks, Connection connection) { + LOG.warn("CP slots are not persisted yet"); + } + + private void persistPorts(CircuitPacks circuitPacks, Connection connection) { + LOG.warn("Ports are not persisted yet"); + } + + + /** + * Prepares parameters for device insert query. + * + * @param deviceInfo the device Info + * @return String[] a string + */ + private static String[] prepareDeviceInfoParameters(Info deviceInfo) { + String startTimetampStr = getCurrentTimestamp(); + + return new String[] {prepareDashString(deviceInfo.getNodeId()), prepareDashString(deviceInfo.getNodeNumber()), + prepareDashString(deviceInfo.getNodeType().getName()), prepareDashString(deviceInfo.getClli()), + prepareDashString(deviceInfo.getVendor()), prepareDashString(deviceInfo.getModel()), + prepareDashString(deviceInfo.getSerialId()), prepareDashString(deviceInfo.getPrefixLength()), + prepareDashString(deviceInfo.getDefaultGateway()), prepareDashString(deviceInfo.getSource().getName()), + prepareDashString(deviceInfo.getCurrentIpAddress()), + prepareDashString(deviceInfo.getCurrentPrefixLength()), + prepareDashString(deviceInfo.getDefaultGateway()), + prepareDashString(deviceInfo.getMacAddress().getValue()), + prepareDashString(deviceInfo.getSoftwareVersion()), prepareDashString(deviceInfo.getTemplate()), + prepareDashString(deviceInfo.getCurrentDatetime()), + deviceInfo.getGeoLocation() != null ? prepareDashString(deviceInfo.getGeoLocation().getLatitude()) : "", + deviceInfo.getGeoLocation() != null ? prepareDashString(deviceInfo.getGeoLocation().getLongitude()) : "", + prepareDashString(deviceInfo.getMaxDegrees()), prepareDashString(deviceInfo.getMaxSrgs()), startTimetampStr, + startTimetampStr}; + } + + /** + * Prepares parameters for shelves. + * + * @param nodeId the node ID + * @param shelve the shelves + * @return String[] a string + */ + private static String[] prepareShelvesParameters(String nodeId, Shelves shelve) { + String startTimestamp = getCurrentTimestamp(); + + return new String[] {nodeId, shelve.getShelfName(), shelve.getShelfType(), shelve.getRack(), + shelve.getShelfPosition(), prepareEmptyString(shelve.getAdministrativeState()), shelve.getVendor(), + shelve.getModel(), shelve.getSerialId(), shelve.getType(), shelve.getProductCode(), + prepareEmptyString(shelve.getManufactureDate()), shelve.getClei(), shelve.getHardwareVersion(), + prepareEmptyString(shelve.getOperationalState()), prepareEmptyString(shelve.getEquipmentState()), + prepareEmptyString(shelve.getDueDate()), startTimestamp, startTimestamp}; + } + + private static String[] prepareCircuitPacksParameters(String nodeId, CircuitPacks cpack) { + return new String[] {nodeId, cpack.getCircuitPackName(), cpack.getCircuitPackType(), + cpack.getCircuitPackProductCode(), prepareEmptyString(cpack.getAdministrativeState()), + cpack.getVendor(), cpack.getModel(), cpack.getSerialId(), cpack.getType(), cpack.getProductCode(), + prepareEmptyString(cpack.getManufactureDate()), cpack.getClei(), cpack.getHardwareVersion(), + prepareEmptyString(cpack.getOperationalState()), prepareEmptyString(cpack.getEquipmentState()), + cpack.getCircuitPackMode(), cpack.getShelf(), cpack.getSlot(), cpack.getSubSlot(), + cpack.getCircuitPackCategory().getType().getName(), cpack.getCircuitPackCategory().getExtension(), + prepareEmptyString(cpack.getDueDate()), cpack.getParentCircuitPack().getCircuitPackName(), + cpack.getParentCircuitPack().getCpSlotName()}; + } +} diff --git a/inventory/src/main/java/org/opendaylight/transportpce/inventory/ListenerProvider.java b/inventory/src/main/java/org/opendaylight/transportpce/inventory/ListenerProvider.java new file mode 100644 index 000000000..0bfa50381 --- /dev/null +++ b/inventory/src/main/java/org/opendaylight/transportpce/inventory/ListenerProvider.java @@ -0,0 +1,87 @@ +/* + * 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.inventory; + +import org.opendaylight.controller.md.sal.binding.api.DataBroker; +import org.opendaylight.controller.md.sal.binding.api.DataTreeChangeListener; +import org.opendaylight.controller.md.sal.binding.api.DataTreeIdentifier; +import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType; +import org.opendaylight.transportpce.common.InstanceIdentifiers; +import org.opendaylight.transportpce.inventory.listener.ClliNetworkChangeListener; +import org.opendaylight.transportpce.inventory.listener.DeviceListener; +import org.opendaylight.transportpce.inventory.listener.OverlayNetworkChangeListener; +import org.opendaylight.transportpce.inventory.listener.ServiceListener; +import org.opendaylight.transportpce.inventory.listener.UnderlayNetworkChangeListener; +import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.Node; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * {@link ListenerProvider} registers {@link DataTreeChangeListener} for each + * network layer. + * + */ +public class ListenerProvider { + + private static final Logger LOG = LoggerFactory.getLogger(ListenerProvider.class); + + private final DataBroker dataBroker; + private final OverlayNetworkChangeListener overlayNetworkListener; + private final UnderlayNetworkChangeListener underlayNetworkListener; + private final ClliNetworkChangeListener clliNetworkChangeListener; + private final ServiceListener serviceListener; + private final DeviceListener deviceListener; + + /** + * Constructor invoked by blueprint injects all dependencies. + * + * @param dataBroker the databroker + * @param overlayNetworkListener the overlay network listener + * @param underlayNetworkListener the underlay network listener + * @param clliNetworkChangeListener the CLLI network changes listener + * @param serviceListener the service listener + * @param deviceListener the device listener + */ + public ListenerProvider(DataBroker dataBroker, OverlayNetworkChangeListener overlayNetworkListener, + UnderlayNetworkChangeListener underlayNetworkListener, ClliNetworkChangeListener clliNetworkChangeListener, + ServiceListener serviceListener, DeviceListener deviceListener) { + this.dataBroker = dataBroker; + this.overlayNetworkListener = overlayNetworkListener; + this.underlayNetworkListener = underlayNetworkListener; + this.clliNetworkChangeListener = clliNetworkChangeListener; + this.serviceListener = serviceListener; + this.deviceListener = deviceListener; + } + + /** + * Invoked by blueprint, registers the listeners. + */ + public void initialize() { + LOG.debug("Registering listeners..."); + dataBroker.registerDataTreeChangeListener( + new DataTreeIdentifier<>(LogicalDatastoreType.CONFIGURATION, InstanceIdentifiers.OVERLAY_NETWORK_II), + overlayNetworkListener); + LOG.info("Overlay network change listener was successfully registered"); + dataBroker.registerDataTreeChangeListener( + new DataTreeIdentifier<>(LogicalDatastoreType.CONFIGURATION, InstanceIdentifiers.UNDERLAY_NETWORK_II), + underlayNetworkListener); + LOG.info("Underlay network change listener was successfully registered"); + dataBroker.registerDataTreeChangeListener( + new DataTreeIdentifier<>(LogicalDatastoreType.CONFIGURATION, InstanceIdentifiers.CLLI_NETWORK_II), + clliNetworkChangeListener); + LOG.info("CLLI network change listener was successfully registered"); + dataBroker.registerDataTreeChangeListener( + new DataTreeIdentifier<>(LogicalDatastoreType.CONFIGURATION, ServiceListener.SERVICES_II), + serviceListener); + LOG.info("Service path listener was successfully registered"); + dataBroker.registerDataTreeChangeListener(new DataTreeIdentifier<>(LogicalDatastoreType.OPERATIONAL, + InstanceIdentifiers.NETCONF_TOPOLOGY_II.child(Node.class)), deviceListener); + LOG.info("Device change listener was successfully registered"); + } + +} diff --git a/inventory/src/main/java/org/opendaylight/transportpce/inventory/dto/InvDevInfo.java b/inventory/src/main/java/org/opendaylight/transportpce/inventory/dto/InvDevInfo.java new file mode 100644 index 000000000..c528f0e23 --- /dev/null +++ b/inventory/src/main/java/org/opendaylight/transportpce/inventory/dto/InvDevInfo.java @@ -0,0 +1,256 @@ +/* + * 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.inventory.dto; + +public class InvDevInfo { + private String nodeId; + private String nodeNumber; + private String nodeType; + private String clli; + private String vendor; + private String model; + private String serialId; + private String ipAddress; + private String prefixLength; + private String defaultGateway; + private String source; + private String currentIpAddress; + private String currentPrefixLength; + private String currentDefaultGateway; + private String macAddress; + private String softwareVersion; + private String template; + private String currentDatetime; + private String latitude; + private String longitude; + private String maxDegrees; + private String maxSrgs; + private String swVersion; + private String swValidationTimer; + private String activationDateTime; + private String createDate; + private String updateDate; + + + public String getNodeId() { + return this.nodeId; + } + + public void setNode_id(String nodeId) { + this.nodeId = nodeId; + } + + public String getNode_number() { + return this.nodeNumber; + } + + public void setNode_number(String nodeNumber) { + this.nodeNumber = nodeNumber; + } + + public String getNode_type() { + return this.nodeType; + } + + public void setNode_type(String nodeType) { + this.nodeType = nodeType; + } + + public String getClli() { + return this.clli; + } + + public void setClli(String clli) { + this.clli = clli; + } + + public String getVendor() { + return this.vendor; + } + + public void setVendor(String vendor) { + this.vendor = vendor; + } + + public String getModel() { + return this.model; + } + + public void setModel(String model) { + this.model = model; + } + + public String getSerial_id() { + return this.serialId; + } + + public void setSerial_id(String serialId) { + this.serialId = serialId; + } + + public String getIpAddress() { + return this.ipAddress; + } + + public void setIpAddress(String ipAddress) { + this.ipAddress = ipAddress; + } + + public String getPrefix_length() { + return this.prefixLength; + } + + public void setPrefix_length(String prefixLength) { + this.prefixLength = prefixLength; + } + + public String getDefault_gateway() { + return this.defaultGateway; + } + + public void setDefault_gateway(String defaultGateway) { + this.defaultGateway = defaultGateway; + } + + public String getSource() { + return this.source; + } + + public void setSource(String source) { + this.source = source; + } + + public String getCurrent_ipAddress() { + return this.currentIpAddress; + } + + public void setCurrent_ipAddress(String currentIpAddress) { + this.currentIpAddress = currentIpAddress; + } + + public String getCurrent_prefix_length() { + return this.currentPrefixLength; + } + + public void setCurrent_prefix_length(String currentPrefixLength) { + this.currentPrefixLength = currentPrefixLength; + } + + public String getCurrent_default_gateway() { + return this.currentDefaultGateway; + } + + public void setCurrent_default_gateway(String currentDefaultGateway) { + this.currentDefaultGateway = currentDefaultGateway; + } + + public String getMacAddress() { + return this.macAddress; + } + + public void setMacAddress(String macAddress) { + this.macAddress = macAddress; + } + + public String getSoftware_version() { + return this.softwareVersion; + } + + public void setSoftware_version(String softwareVersion) { + this.softwareVersion = softwareVersion; + } + + public String getTemplate() { + return this.template; + } + + public void setTemplate(String template) { + this.template = template; + } + + public String getCurrent_datetime() { + return this.currentDatetime; + } + + public void setCurrent_datetime(String currentDatetime) { + this.currentDatetime = currentDatetime; + } + + public String getLatitude() { + return this.latitude; + } + + public void setLatitude(String latitude) { + this.latitude = latitude; + } + + public String getLongitude() { + return this.longitude; + } + + public void setLongitude(String longitude) { + this.longitude = longitude; + } + + public String getMax_degrees() { + return this.maxDegrees; + } + + public void setMax_degrees(String maxDegrees) { + this.maxDegrees = maxDegrees; + } + + public String getMax_srgs() { + return this.maxSrgs; + } + + public void setMax_srgs(String maxSrgs) { + this.maxSrgs = maxSrgs; + } + + public String getSw_version() { + return this.swVersion; + } + + public void setSw_version(String swVersion) { + this.swVersion = swVersion; + } + + public String getSw_validation_timer() { + return this.swValidationTimer; + } + + public void setSw_validation_timer(String swValidationTimer) { + this.swValidationTimer = swValidationTimer; + } + + public String getActivation_date_time() { + return this.activationDateTime; + } + + public void setActivation_date_time(String activationDateTime) { + this.activationDateTime = activationDateTime; + } + + public String getCreate_date() { + return this.createDate; + } + + public void setCreate_date(String createDate) { + this.createDate = createDate; + } + + public String getUpdate_date() { + return this.updateDate; + } + + public void setUpdate_date(String updateDate) { + this.updateDate = updateDate; + } +} diff --git a/inventory/src/main/java/org/opendaylight/transportpce/inventory/job/PeriodicDeviceBackupJob.java b/inventory/src/main/java/org/opendaylight/transportpce/inventory/job/PeriodicDeviceBackupJob.java new file mode 100644 index 000000000..a431dd21b --- /dev/null +++ b/inventory/src/main/java/org/opendaylight/transportpce/inventory/job/PeriodicDeviceBackupJob.java @@ -0,0 +1,249 @@ +/* + * 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.inventory.job; + +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.google.common.base.Strings; +import com.google.common.io.Files; + +import java.io.File; +import java.io.IOException; +import java.nio.charset.StandardCharsets; +import java.text.SimpleDateFormat; +import java.util.Date; +import java.util.Optional; +import java.util.concurrent.ExecutionException; + +import org.apache.karaf.scheduler.Job; +import org.opendaylight.controller.md.sal.binding.api.DataBroker; +import org.opendaylight.controller.md.sal.binding.api.ReadOnlyTransaction; +import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType; +import org.opendaylight.mdsal.dom.api.DOMSchemaService; +import org.opendaylight.transportpce.common.InstanceIdentifiers; +import org.opendaylight.transportpce.common.Timeouts; +import org.opendaylight.transportpce.common.device.DeviceTransactionManager; +import org.opendaylight.yang.gen.v1.http.org.openroadm.device.rev170206.org.openroadm.device.container.OrgOpenroadmDevice; +import org.opendaylight.yang.gen.v1.urn.opendaylight.netconf.node.topology.rev150114.NetconfNode; +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.topology.Node; +import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; +import org.opendaylight.yangtools.yang.model.api.SchemaContext; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * Class which periodically backups the device into a file implements {@link Job} + * interface which is automatically registered via whitboard pattern into karaf + * environment. This job will persist an {@link OrgOpenroadmDevice} capable with + * the models provided in transportpce-models + */ +public class PeriodicDeviceBackupJob implements Runnable { + + private static final String TIMESTAMP_FORMAT = "yyyy-MM-dd_HH-mm-ss-SSS"; + private static final String ORG_OPENROADM_DEVICE = "org-openroadm-device"; + private static final Logger LOG = LoggerFactory.getLogger(PeriodicDeviceBackupJob.class); + + private final DataBroker dataBroker; + private final DeviceTransactionManager deviceTransactionManager; + + private final SchemaContext schemaContext; + private final SimpleDateFormat filenameFormatter; + + /** + * Folder property, where the file is placed. + */ + private String folder; + /** + * Prefix of device file. + */ + private String filePrefix; + + /** + * Constructor with injected fields. + * + * @param dataBroker the datatabroker + * @param domSchemaService the DOM schema service + * @param deviceTransactionManager the device transaction manager + */ + public PeriodicDeviceBackupJob(DataBroker dataBroker, DOMSchemaService domSchemaService, + DeviceTransactionManager deviceTransactionManager) { + this.dataBroker = dataBroker; + this.schemaContext = domSchemaService.getGlobalContext(); + this.deviceTransactionManager = deviceTransactionManager; + this.filenameFormatter = new SimpleDateFormat(TIMESTAMP_FORMAT); + } + + @Override + public void run() { + LOG.info("Running periodical device backup into {}", folder); + try { + backupAllDevices(); + } catch (InterruptedException | ExecutionException e) { + LOG.warn("Unable to read netconf topology from the operational datastore", e); + } + } + + /** + * Gets the folder. + * + * @return the folder + */ + public String getFolder() { + return folder; + } + + /** + * Sets the folder. + * + * @param folder the folder to set + */ + public void setFolder(String folder) { + this.folder = folder; + } + + /** + * Gets the filePrefix. + * + * @return the filePrefix + */ + public String getFilePrefix() { + return filePrefix; + } + + /** + * Sets the filePrefix. + * + * @param filePrefix the filePrefix to set + */ + public void setFilePrefix(String filePrefix) { + this.filePrefix = filePrefix; + } + + /** + * Stores all devices into files. + * + * @throws InterruptedException interrupted exception + * @throws ExecutionException execution exception + */ + private void backupAllDevices() throws InterruptedException, ExecutionException { + ReadOnlyTransaction newReadOnlyTransaction = dataBroker.newReadOnlyTransaction(); + Optional topology = newReadOnlyTransaction + .read(LogicalDatastoreType.OPERATIONAL, InstanceIdentifiers.NETCONF_TOPOLOGY_II).get().toJavaUtil(); + if (!topology.isPresent()) { + LOG.warn("Netconf topology was not found in datastore"); + return; + } + + for (Node node : topology.get().getNode()) { + String nodeId = getNodeId(node); + if (Strings.isNullOrEmpty(nodeId)) { + LOG.debug("{} node is not a roadm device"); + continue; + } + storeRoadmDevice(nodeId); + } + } + + /** + * Stores a single ROADM device into a file. + * + * @param nodeId the node ID + */ + private void storeRoadmDevice(String nodeId) { + InstanceIdentifier deviceIi = InstanceIdentifier.create(OrgOpenroadmDevice.class); + Optional deviceObject = + deviceTransactionManager.getDataFromDevice(nodeId, LogicalDatastoreType.OPERATIONAL, deviceIi, + Timeouts.DEVICE_READ_TIMEOUT, Timeouts.DEVICE_READ_TIMEOUT_UNIT); + if (!deviceObject.isPresent()) { + LOG.warn("Device object {} is not present.", nodeId); + return; + } + + // TODO: Serialization should be done via XMLDataObjectConverter when devices use the same model as + // this project + /* + * XMLDataObjectConverter createWithSchemaContext = + * XMLDataObjectConverter.createWithSchemaContext(schemaContext, nodeSerializer); Writer + * writerFromDataObject = createWithSchemaContext.writerFromDataObject(deviceObject.get(), + * OrgOpenroadmDevice.class, createWithSchemaContext.dataContainer()); + */ + StringBuilder serializedDevice = new StringBuilder(); + try { + serializedDevice.append(new ObjectMapper().writeValueAsString(deviceObject.get())); + } catch (JsonProcessingException e1) { + LOG.error(e1.getMessage(), e1); + } + + String prepareFileName = prepareFileName(nodeId); + File parent = new File(folder); + if (!parent.exists() && !parent.isDirectory() && !parent.mkdirs()) { + LOG.error("Could not create empty directory {}", folder); + throw new IllegalStateException(String.format("Could not create empty directory %s", folder)); + } + + File file = new File(parent, filePrefix.concat(prepareFileName)); + if (file.exists()) { + throw new IllegalStateException(String.format("The file %s already exists", file)); + } + try { + Files.asCharSink(file, StandardCharsets.UTF_8).write(serializedDevice.toString()); + } catch (IOException e) { + LOG.error("Could not write device backup into file {}", file); + } + } + + private String prepareFileName(String nodeId) { + String format = filenameFormatter.format(new Date()); + StringBuilder sb = new StringBuilder(format); + sb.append("__").append(nodeId).append("__").append(".xml"); + return sb.toString(); + } + + /** + * If the {@link Node} in the {@link Topology} is a {@link NetconfNode}, has + * capabilities of {@link PeriodicDeviceBackupJob#ORG_OPENROADM_DEVICE} and the + * key is not null returns the identifier of {@link OrgOpenroadmDevice} node. + * + * @param node inside the {@link Topology} + * @return node key + */ + private static String getNodeId(Node node) { + if (node == null) { + LOG.trace("The node is null"); + return ""; + } + NetconfNode netconfNode = node.getAugmentation(NetconfNode.class); + if (netconfNode == null) { + LOG.trace("The node {} has not properties of NetconfNode", node); + return ""; + } + if (netconfNode.getAvailableCapabilities() == null + || netconfNode.getAvailableCapabilities().getAvailableCapability() == null) { + LOG.trace("No available capabilities"); + return ""; + } + long count = netconfNode.getAvailableCapabilities().getAvailableCapability().stream() + .filter(cp -> cp.getCapability() != null && cp.getCapability().contains(ORG_OPENROADM_DEVICE)).count(); + if (count < 1) { + LOG.trace("The node {} has not capabilities of OpenROADMDevice", node); + return ""; + } + if (node.getKey() == null || node.getKey().getNodeId() == null) { + LOG.trace("Node {} has invalid key", node); + return ""; + } + if ("controller-config".equalsIgnoreCase(node.getKey().getNodeId().getValue())) { + LOG.info("Got controller-config instead of roadm-node"); + return ""; + } + return node.getKey().getNodeId().getValue(); + } + +} diff --git a/inventory/src/main/java/org/opendaylight/transportpce/inventory/listener/ClliNetworkChangeListener.java b/inventory/src/main/java/org/opendaylight/transportpce/inventory/listener/ClliNetworkChangeListener.java new file mode 100644 index 000000000..41a23ac8d --- /dev/null +++ b/inventory/src/main/java/org/opendaylight/transportpce/inventory/listener/ClliNetworkChangeListener.java @@ -0,0 +1,26 @@ +/* + * 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.inventory.listener; + +import java.util.Collection; +import org.opendaylight.controller.md.sal.binding.api.DataTreeChangeListener; +import org.opendaylight.controller.md.sal.binding.api.DataTreeModification; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.network.rev150608.Network; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class ClliNetworkChangeListener implements DataTreeChangeListener { + + private static final Logger LOG = LoggerFactory.getLogger(ClliNetworkChangeListener.class); + + @Override + public void onDataTreeChanged(Collection> changes) { + LOG.info("Clli network changed {}", changes); + } + +} diff --git a/inventory/src/main/java/org/opendaylight/transportpce/inventory/listener/DeviceListener.java b/inventory/src/main/java/org/opendaylight/transportpce/inventory/listener/DeviceListener.java new file mode 100644 index 000000000..2f8f8c673 --- /dev/null +++ b/inventory/src/main/java/org/opendaylight/transportpce/inventory/listener/DeviceListener.java @@ -0,0 +1,146 @@ +/* + * 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.inventory.listener; + +import java.util.Collection; +import java.util.List; +import java.util.concurrent.ExecutionException; +import java.util.stream.Collectors; +import org.opendaylight.controller.md.sal.binding.api.DataObjectModification.ModificationType; +import org.opendaylight.controller.md.sal.binding.api.DataTreeChangeListener; +import org.opendaylight.controller.md.sal.binding.api.DataTreeModification; +import org.opendaylight.transportpce.common.StringConstants; +import org.opendaylight.transportpce.inventory.DeviceInventory; +import org.opendaylight.yang.gen.v1.urn.opendaylight.netconf.node.topology.rev150114.NetconfNode; +import org.opendaylight.yang.gen.v1.urn.opendaylight.netconf.node.topology.rev150114.NetconfNodeConnectionStatus; +import org.opendaylight.yang.gen.v1.urn.opendaylight.netconf.node.topology.rev150114.NetconfNodeConnectionStatus.ConnectionStatus; +import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.Node; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * This class implements the {@link DataTreeChangeListener} on a {@link Node}. This listener should + * be registered on a netconf topology node. + * + */ +public class DeviceListener implements DataTreeChangeListener { + + private static final Logger LOG = LoggerFactory.getLogger(DeviceListener.class); + private final DeviceInventory deviceInventory; + + /** + * Default constructor invoked by blueprint injects {@link DeviceInventory} as a persistence layer. + * + * @param deviceInventory reference to the {@link DeviceInventory} + */ + public DeviceListener(DeviceInventory deviceInventory) { + this.deviceInventory = deviceInventory; + } + + @Override + public void onDataTreeChanged(Collection> changes) { + List> changesWithoutDefaultNetconfNode = getRealDevicesOnly(changes); + for (DataTreeModification device : changesWithoutDefaultNetconfNode) { + String nodeId = device.getRootNode().getDataAfter().getKey().getNodeId().getValue(); + NetconfNode netconfNode = device.getRootNode().getDataAfter().getAugmentation(NetconfNode.class); + if (isCreate(device) || isUpdate(device)) { + LOG.info("Node {} was modified", nodeId); + try { + processModifiedSubtree(nodeId, netconfNode); + } catch (InterruptedException | ExecutionException e) { + LOG.error(e.getMessage(), e); + } + } else if (isDelete(device)) { + LOG.info("Node {} was deleted", nodeId); + } + } + } + + /** + * Handles the {@link ModificationType#SUBTREE_MODIFIED} case. If the changed node has + * {@link StringConstants.OPENROADM_DEVICE_MODEL_NAME} capabilities it may be persisted. + * + * @param nodeId device id + * @param netconfNode netconf node + * @throws InterruptedException may be thrown if there is a problem getting the device from + * datastore + * @throws ExecutionException may be thrown if there is a problem getting the device from datastore + */ + private void processModifiedSubtree(String nodeId, NetconfNode netconfNode) + throws InterruptedException, ExecutionException { + NetconfNodeConnectionStatus.ConnectionStatus connectionStatus = netconfNode.getConnectionStatus(); + long count = netconfNode.getAvailableCapabilities().getAvailableCapability().stream() + .filter(cp -> cp.getCapability().contains(StringConstants.OPENROADM_DEVICE_MODEL_NAME)).count(); + if (count < 1) { + LOG.info("No {} capable device was found", StringConstants.OPENROADM_DEVICE_MODEL_NAME); + return; + } + if (ConnectionStatus.Connected.equals(connectionStatus)) { + deviceInventory.initializeDevice(nodeId); + } else if (ConnectionStatus.Connecting.equals(connectionStatus) + || ConnectionStatus.UnableToConnect.equals(connectionStatus)) { + LOG.info("The device is in {} state", connectionStatus); + } else { + LOG.warn("Invalid connection status {}", connectionStatus); + } + } + + /** + * Filters the {@link StringConstants#DEFAULT_NETCONF_NODEID} nodes from the provided + * {@link Collection}. + * + * @param changes a change + * @return {@code List>} a list of modifcations + */ + private static List> getRealDevicesOnly(Collection> changes) { + return changes.stream() + .filter(change -> (change.getRootNode().getDataAfter() != null + && !StringConstants.DEFAULT_NETCONF_NODEID + .equalsIgnoreCase(change.getRootNode().getDataAfter().getKey().getNodeId().getValue()) + && change.getRootNode().getDataAfter().getAugmentation(NetconfNode.class) != null) + || (change.getRootNode().getDataBefore() != null + && !StringConstants.DEFAULT_NETCONF_NODEID.equalsIgnoreCase( + change.getRootNode().getDataBefore().getKey().getNodeId().getValue()) + && change.getRootNode().getDataBefore().getAugmentation(NetconfNode.class) != null + + )).collect(Collectors.toList()); + } + + /** + * In the filtered collection checks if the change is a new write. + * + * @param change the change + * @return boolean true if the change is a new write + */ + private static boolean isCreate(DataTreeModification change) { + return change.getRootNode().getDataBefore() == null && change.getRootNode().getDataAfter() != null + && ModificationType.WRITE.equals(change.getRootNode().getModificationType()); + } + + /** + * In the filtered collection checks if the modification is update. + * + * @param change the change + * @return boolean true if the modification is update + */ + private static boolean isUpdate(DataTreeModification change) { + return ModificationType.SUBTREE_MODIFIED.equals(change.getRootNode().getModificationType()); + } + + /** + * In the filtered collection checks if the node was deleted. + * + * @param change the change + * @return boolean true if the node was deleted + */ + private static boolean isDelete(DataTreeModification change) { + return change.getRootNode().getDataBefore() != null && change.getRootNode().getDataAfter() == null + && ModificationType.DELETE.equals(change.getRootNode().getModificationType()); + } +} diff --git a/inventory/src/main/java/org/opendaylight/transportpce/inventory/listener/OverlayNetworkChangeListener.java b/inventory/src/main/java/org/opendaylight/transportpce/inventory/listener/OverlayNetworkChangeListener.java new file mode 100644 index 000000000..f5acd159e --- /dev/null +++ b/inventory/src/main/java/org/opendaylight/transportpce/inventory/listener/OverlayNetworkChangeListener.java @@ -0,0 +1,26 @@ +/* + * 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.inventory.listener; + +import java.util.Collection; +import org.opendaylight.controller.md.sal.binding.api.DataTreeChangeListener; +import org.opendaylight.controller.md.sal.binding.api.DataTreeModification; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.network.rev150608.Network; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class OverlayNetworkChangeListener implements DataTreeChangeListener { + + private static final Logger LOG = LoggerFactory.getLogger(OverlayNetworkChangeListener.class); + + @Override + public void onDataTreeChanged(Collection> changes) { + LOG.info("Overlay network changed {}", changes); + } + +} diff --git a/inventory/src/main/java/org/opendaylight/transportpce/inventory/listener/ServiceListener.java b/inventory/src/main/java/org/opendaylight/transportpce/inventory/listener/ServiceListener.java new file mode 100644 index 000000000..4c82b9899 --- /dev/null +++ b/inventory/src/main/java/org/opendaylight/transportpce/inventory/listener/ServiceListener.java @@ -0,0 +1,160 @@ +/* + * 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.inventory.listener; + +import java.sql.Connection; +import java.sql.PreparedStatement; +import java.sql.SQLException; +import java.util.Collection; +import java.util.List; +import java.util.stream.Collectors; +import javax.sql.DataSource; +import org.opendaylight.controller.md.sal.binding.api.DataObjectModification.ModificationType; +import org.opendaylight.controller.md.sal.binding.api.DataTreeChangeListener; +import org.opendaylight.controller.md.sal.binding.api.DataTreeModification; +import org.opendaylight.transportpce.inventory.query.Queries; +import org.opendaylight.transportpce.inventory.query.QueryUtils; +import org.opendaylight.yang.gen.v1.http.org.openroadm.service.rev161014.ServiceList; +import org.opendaylight.yang.gen.v1.http.org.openroadm.service.rev161014.service.list.Services; +import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * {@link ServiceListener} listens on {@link ServiceList} changes. + * + */ +public class ServiceListener implements DataTreeChangeListener { + + private static final Logger LOG = LoggerFactory.getLogger(ServiceListener.class); + public static final InstanceIdentifier SERVICES_II = + InstanceIdentifier.create(ServiceList.class); + /** + * Implementation for the {@link ChangeHandler} stores a newly added {@link Services}. + */ + private static final ChangeHandler CREATE_HANDLER = (services, connection) -> { + try (PreparedStatement stmt = connection.prepareStatement(Queries.getQuery().serviceCreate().get())) { + QueryUtils.setCreateServiceParameters(stmt, services); + stmt.executeUpdate(); + stmt.clearParameters(); + } catch (SQLException e) { + LOG.error("Could not insert service path {}", services); + } + }; + + /** + * Implementation for the {@link ChangeHandler} removes the deleted {@link Services}. + */ + private static final ChangeHandler DELETE_HANDLER = (services, connection) -> { + try (PreparedStatement stmt = connection.prepareStatement(Queries.getQuery().serviceDelete().get())) { + stmt.setString(1, services.getServiceName()); + stmt.executeUpdate(); + stmt.clearParameters(); + } catch (SQLException e) { + LOG.error("Could not delete service path {}", services); + LOG.error(e.getMessage(), e); + } + }; + + private final DataSource dataSource; + + /** + * Default constructor invoked by bluprint injects all required dependencies. + * + * @param dataSource reference for {@link DataSource} + */ + public ServiceListener(DataSource dataSource) { + this.dataSource = dataSource; + } + + @Override + public void onDataTreeChanged(Collection> changes) { + LOG.debug("Service path list changed ..."); + List> createItems = + changes.stream().filter(ServiceListener::writeFilter).collect(Collectors.toList()); + List> deleteItems = + changes.stream().filter(ServiceListener::deleteFilter).collect(Collectors.toList()); + try (Connection connection = dataSource.getConnection()) { + handleModification(createItems, CREATE_HANDLER, connection); + handleModification(deleteItems, DELETE_HANDLER, connection); + } catch (SQLException e) { + LOG.error(e.getMessage(), e); + } + } + + /** + * Handles the change with {@link ChangeHandler}. + * + * @param changeList list of modifications + * @param handleChange concrete implementation of {@link ChangeHandler} + * @param connection {@link DataSource} we don't want to create each time a new connection + */ + private void handleModification(List> changeList, ChangeHandler handleChange, + Connection connection) { + for (DataTreeModification change : changeList) { + ServiceList serviceList = change.getRootNode().getDataAfter(); + for (Services service : serviceList.getServices()) { + handleChange.handleChange(service, connection); + } + } + } + + /** + * Returns the filter for {@link ModificationType#WRITE} type change. + * + * @see #buildFilter(DataTreeModification, ModificationType) + * @param modification write modification object + * @return if the object was created + */ + private static boolean writeFilter(DataTreeModification modification) { + return buildFilter(modification, ModificationType.WRITE); + } + + /** + * Returns the filter for {@link ModificationType#DELETE} type change. + * + * @see #deleteFilter(DataTreeModification) + * @param modification delete modification + * @return if the object was deleted + */ + private static boolean deleteFilter(DataTreeModification modification) { + return buildFilter(modification, ModificationType.DELETE); + } + + /** + * Generalizes the creation of filter used in + * {@link #onDataTreeChanged(Collection)} method. + * + * @param modification a modification + * @param modificationType a modification type + * @return boolean modification status + */ + private static boolean buildFilter(DataTreeModification modification, + ModificationType modificationType) { + return (modification.getRootNode().getDataAfter() != null + && modificationType.equals(modification.getRootNode().getModificationType())); + } + + /** + * ChangeHandler interface is responsible for inserts or deletes in the DB based + * on the implementation. + * + */ + private interface ChangeHandler { + + /** + * Method will handle the changed {@link Services}. + * + * @param services changed object + * @param connection {@link Connection} should be created in the caller method and + * not closed in the implementation + */ + void handleChange(Services services, Connection connection); + } + +} diff --git a/inventory/src/main/java/org/opendaylight/transportpce/inventory/listener/UnderlayNetworkChangeListener.java b/inventory/src/main/java/org/opendaylight/transportpce/inventory/listener/UnderlayNetworkChangeListener.java new file mode 100644 index 000000000..c8937eee3 --- /dev/null +++ b/inventory/src/main/java/org/opendaylight/transportpce/inventory/listener/UnderlayNetworkChangeListener.java @@ -0,0 +1,26 @@ +/* + * 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.inventory.listener; + +import java.util.Collection; +import org.opendaylight.controller.md.sal.binding.api.DataTreeChangeListener; +import org.opendaylight.controller.md.sal.binding.api.DataTreeModification; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.network.rev150608.Network; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class UnderlayNetworkChangeListener implements DataTreeChangeListener { + + private static final Logger LOG = LoggerFactory.getLogger(UnderlayNetworkChangeListener.class); + + @Override + public void onDataTreeChanged(Collection> changes) { + LOG.info("Underlay network changed {}", changes); + } + +} diff --git a/inventory/src/main/java/org/opendaylight/transportpce/inventory/query/Queries.java b/inventory/src/main/java/org/opendaylight/transportpce/inventory/query/Queries.java new file mode 100644 index 000000000..d0381cec4 --- /dev/null +++ b/inventory/src/main/java/org/opendaylight/transportpce/inventory/query/Queries.java @@ -0,0 +1,132 @@ +/* + * 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.inventory.query; + +import com.google.common.base.Preconditions; +import com.google.common.base.Strings; + +public class Queries { + + private static final String DEVICE_INFO_INSERT = + "INSERT INTO %sinv_dev_info " + + "(node_id, node_number, node_type, clli, vendor, model, serial_id, ipAddress, prefix_length, " + + "default_gateway, source, current_ipAddress, current_prefix_length, current_default_gateway, macAddress, " + + "software_version, template, current_datetime, latitude, longitude, max_degrees, max_srgs, sw_version, " + + "sw_validation_timer, activation_date_time, create_date, update_date) " + + "VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)"; + + private static final String DEVICE_SHELF_INSERT = + "INSERT INTO %sinv_dev_shelf " + + "(node_id, shelf_name, shelf_type, rack, shelf_position, administrative_state, vendor, model, serial_id, " + + "type, product_code, manufacture_date, clei, hardware_version, operational_state, equipment_state, due_date, " + + "create_date, update_date) " + + "VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)"; + + private static final String DEVICE_SHELF_SLOT_INSERT = + "INSERT INTO %sinv_dev_shelf_slot " + + "(node_id, shelf_name, slot_name, label, provisioned_circuit_pack, create_date, update_date) " + + "VALUES (?, ?, ?, ?, ?, ?, ?)"; + + private static final String DEVICE_CP_INSERT = + "INSERT INTO %sinv_dev_circuit_pack " + + "(node_id, circuitPackName, circuitPackType, circuitPackProductCode, administrative_state, vendor, model, " + + "serial_id, type, product_code, manufacture_date, clei, hardware_version, operational_state, " + + "equipment_state, shelf, slot, subSlo, cpCatType, extension, due_date, parentCpName, parentCpSlotName) " + + "VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)"; + + private static final String SERVICE_INSERT = + "INSERT INTO %sinv_ser_main " + + "(service_name, common_id, sdnc_req_header_request_id, sdnc_req_header_rpc_action, " + + "sdnc_req_header_notification_url, sdnc_req_header_request_system_id, connection_type, lifecycle_state, " + + "administrative_state, operational_state, serv_condition, a_end_service_format, a_end_service_rate, " + + "a_end_clli, a_end_node_id, a_end_tx_port_device_name, a_end_tx_port_type, a_end_tx_port_name, " + + "a_end_tx_port_rack, a_end_tx_port_shelf, a_end_tx_port_slot, a_end_tx_port_sub_slot, " + + "a_end_tx_lgx_device_name, a_end_tx_lgx_port_name, a_end_tx_lgx_port_rack, a_end_tx_lgx_port_shelf, " + + "a_end_tx_tail_rnode_id, a_end_tx_xport_cp_name, a_end_tx_xport_port_name, a_end_tx_tail_roadm_port_aid, " + + "a_end_tx_tail_roadm_port_rack_loc, a_end_rx_port_device_name, a_end_rx_port_type, a_end_rx_port_name, " + + "a_end_rx_port_rack, a_end_rx_port_shelf, a_end_rx_port_slot, a_end_rx_port_sub_slot, " + + "a_end_rx_lgx_device_name, a_end_rx_lgx_port_name, a_end_rx_lgx_port_rack, a_end_rx_lgx_port_shelf, " + + "a_end_rx_tail_rnode_id, a_end_rx_xport_cp_name, a_end_rx_xport_port_name, a_end_rx_tail_roadm_port_aid, " + + "a_end_rx_tail_roadm_port_rack_loc, a_end_optic_type, a_end_router_node_id, a_end_router_ip_address, " + + "a_end_router_url, a_end_user_label, z_end_service_format, z_end_service_rate, z_end_clli, z_end_node_id, " + + "z_end_tx_port_device_name, z_end_tx_port_type, z_end_tx_port_name, z_end_tx_port_rack, z_end_tx_port_shelf, " + + "z_end_tx_port_slot, z_end_tx_port_sub_slot, z_end_tx_lgx_device_name, z_end_tx_lgx_port_name, " + + "z_end_tx_lgx_port_rack, z_end_tx_lgx_port_shelf, z_end_tx_tail_rnode_id, z_end_tx_xport_cp_name, " + + "z_end_tx_xport_port_name, z_end_tx_tail_roadm_port_aid, z_end_tx_tail_roadm_port_rack_loc, " + + "z_end_rx_port_device_name, z_end_rx_port_type, z_end_rx_port_name, z_end_rx_port_rack, z_end_rx_port_shelf, " + + "z_end_rx_port_slot, z_end_rx_port_sub_slot, z_end_rx_lgx_device_name, z_end_rx_lgx_port_name, " + + "z_end_rx_lgx_port_rack, z_end_rx_lgx_port_shelf, z_end_rx_tail_rnode_id, z_end_rx_xport_cp_name, " + + "z_end_rx_xport_port_name, z_end_rx_tail_roadm_port_aid, z_end_rx_tail_roadm_port_rack_loc, " + + "z_end_optic_type, z_end_router_node_id, z_end_router_ip_address, z_end_router_url, z_end_user_label, " + + "due_date, end_date, nc_code, nci_code, secondary_nci_code, customer, customer_contact, operator_contact, " + + "latency, fiber_span_srlgs, supp_serv_name, create_date, update_date) " + + "VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, " + + "?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, " + + "?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)"; + + private static final String SERVICE_DELETE = + "DELETE FROM %sinv_ser_main WHERE service_name = ?"; + + private Queries() { + // util class + } + + public static Query getQuery() { + return new Query(); + } + + public static class Query { + private String sql; + private String schema; + + private Query() { + this.schema = ""; + } + + public Query withSchema(String schema) { + this.schema = schema; + return this; + } + + public Query deviceInfoInsert() { + this.sql = DEVICE_INFO_INSERT; + return this; + } + + public Query deviceShelfInsert() { + this.sql = DEVICE_SHELF_INSERT; + return this; + } + + public Query deviceShelfSlotInsert() { + this.sql = DEVICE_SHELF_SLOT_INSERT; + return this; + } + + public Query deviceCircuitPackInsert() { + this.sql = DEVICE_CP_INSERT; + return this; + } + + public Query serviceCreate() { + this.sql = SERVICE_INSERT; + return this; + } + + public Query serviceDelete() { + this.sql = SERVICE_DELETE; + return this; + } + + public String get() { + Preconditions.checkArgument(!Strings.isNullOrEmpty(this.sql), "No query selected"); + return String.format(this.sql, this.schema.concat(".")); + } + } +} diff --git a/inventory/src/main/java/org/opendaylight/transportpce/inventory/query/QueryUtils.java b/inventory/src/main/java/org/opendaylight/transportpce/inventory/query/QueryUtils.java new file mode 100644 index 000000000..6e031f0d2 --- /dev/null +++ b/inventory/src/main/java/org/opendaylight/transportpce/inventory/query/QueryUtils.java @@ -0,0 +1,205 @@ +/* + * 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.inventory.query; + +import static org.opendaylight.transportpce.inventory.utils.StringUtils.getCurrentTimestamp; + +import com.google.common.base.Strings; + +import java.sql.PreparedStatement; +import java.sql.SQLException; + +import org.opendaylight.yang.gen.v1.http.org.openroadm.common.service.types.rev161014.service.ServiceAEnd; +import org.opendaylight.yang.gen.v1.http.org.openroadm.common.service.types.rev161014.service.ServiceZEnd; +import org.opendaylight.yang.gen.v1.http.org.openroadm.common.service.types.rev161014.service.endpoint.Router; +import org.opendaylight.yang.gen.v1.http.org.openroadm.common.service.types.rev161014.service.endpoint.RxDirection; +import org.opendaylight.yang.gen.v1.http.org.openroadm.common.service.types.rev161014.service.endpoint.TxDirection; +import org.opendaylight.yang.gen.v1.http.org.openroadm.common.service.types.rev161014.service.port.Port; +import org.opendaylight.yang.gen.v1.http.org.openroadm.service.rev161014.service.list.Services; + +/** + * Query manipulation class. + */ +public class QueryUtils { + + private QueryUtils() { + // no instance, just static access + } + + /** + * This method modifies the prepared statement for {@link Queries}. + * + * @param stmt the prepared statement + * @param servicePath the service path + * @throws SQLException a SQL exception + */ + public static void setCreateServiceParameters(PreparedStatement stmt, Services servicePath) throws SQLException { + StatementBuilder builder = StatementBuilder.builder(stmt); + builder.setParameter(servicePath.getServiceName()); + builder.setParameter(servicePath.getCommonId()); + + String requestId = ""; + String rpcAction = ""; + String notificationUrl = ""; + String requestSystemId = ""; + + if (servicePath.getSdncRequestHeader() != null) { + requestId = getStringOf(servicePath.getSdncRequestHeader().getRequestId()); + rpcAction = servicePath.getSdncRequestHeader().getRpcAction().getName(); + notificationUrl = servicePath.getSdncRequestHeader().getNotificationUrl(); + requestSystemId = servicePath.getSdncRequestHeader().getRequestSystemId(); + } + builder.setParameter(requestId).setParameter(rpcAction).setParameter(notificationUrl) + .setParameter(requestSystemId); + + String connectionType = ""; + String lifecycleState = ""; + String administrativeState = ""; + String condition = ""; + if (servicePath.getConnectionType() != null) { + connectionType = servicePath.getConnectionType().getName(); + } + if (servicePath.getLifecycleState() != null) { + lifecycleState = servicePath.getLifecycleState().getName(); + } + if (servicePath.getAdministrativeState() != null) { + administrativeState = servicePath.getAdministrativeState().getName(); + } + if (servicePath.getCondition() != null) { + condition = servicePath.getCondition().getName(); + } + // status stuff + builder.setParameter(connectionType); + builder.setParameter(lifecycleState); + builder.setParameter(administrativeState); + builder.setParameter(condition); + + // status stuff + ServiceAEnd serviceAEnd = servicePath.getServiceAEnd(); + builder.setParameter(serviceAEnd.getServiceFormat().getName()).setParameter(serviceAEnd.getServiceRate()) + .setParameter(serviceAEnd.getClli()).setParameter(serviceAEnd.getNodeId()); + + // tx port stuff + Port aendTxDirection = servicePath.getServiceAEnd().getTxDirection().getPort(); + builder.setParameter(aendTxDirection.getPortDeviceName()).setParameter(aendTxDirection.getPortName()) + .setParameter(aendTxDirection.getPortRack()).setParameter(aendTxDirection.getPortShelf()) + .setParameter(aendTxDirection.getPortSlot()).setParameter(aendTxDirection.getPortSubSlot()); + + // tx lgx stuff + TxDirection txDirectionA = servicePath.getServiceAEnd().getTxDirection(); + builder.setParameter(txDirectionA.getLgx().getLgxDeviceName()) + .setParameter(txDirectionA.getLgx().getLgxPortName()) + .setParameter(txDirectionA.getLgx().getLgxPortRack()) + .setParameter(txDirectionA.getLgx().getLgxPortShelf()); + builder.setParameter(txDirectionA.getTail().getTailRoadm().getNodeId()); + builder.setParameter(txDirectionA.getTail().getXponderPort().getCircuitPackName()); + builder.setParameter(txDirectionA.getTail().getXponderPort().getPortName()); + builder.setParameter(txDirectionA.getTail().getTailRoadmPortAid()); + builder.setParameter(txDirectionA.getTail().getTailRoadmPortRackLocation()); + + // rx lgx stuff + RxDirection rxDirectionA = servicePath.getServiceAEnd().getRxDirection(); + builder.setParameter(rxDirectionA.getLgx().getLgxDeviceName()) + .setParameter(rxDirectionA.getLgx().getLgxPortName()) + .setParameter(rxDirectionA.getLgx().getLgxPortRack()) + .setParameter(rxDirectionA.getLgx().getLgxPortShelf()); + builder.setParameter(rxDirectionA.getTail().getTailRoadm().getNodeId()); + builder.setParameter(rxDirectionA.getTail().getXponderPort().getCircuitPackName()); + builder.setParameter(rxDirectionA.getTail().getXponderPort().getPortName()); + builder.setParameter(rxDirectionA.getTail().getTailRoadmPortAid()); + builder.setParameter(rxDirectionA.getTail().getTailRoadmPortRackLocation()); + + builder.setParameter(servicePath.getServiceAEnd().getOpticType().getName()); + + Router routerA = servicePath.getServiceAEnd().getRouter(); + builder.setParameter(routerA.getNodeId()).setParameter(routerA.getIpAddress().toString()) + .setParameter(routerA.getUrl()); + builder.setParameter(servicePath.getServiceAEnd().getUserLabel()); + + ServiceZEnd serviceZEnd = servicePath.getServiceZEnd(); + builder.setParameter(serviceZEnd.getServiceFormat().getName()).setParameter(serviceZEnd.getServiceRate()) + .setParameter(serviceZEnd.getClli()).setParameter(serviceZEnd.getNodeId()); + + // tx port stuff + Port zendTxDirection = serviceZEnd.getTxDirection().getPort(); + builder.setParameter(zendTxDirection.getPortDeviceName()).setParameter(zendTxDirection.getPortName()) + .setParameter(zendTxDirection.getPortRack()).setParameter(zendTxDirection.getPortShelf()) + .setParameter(zendTxDirection.getPortSlot()).setParameter(zendTxDirection.getPortSubSlot()); + + // tx lgx stuff + TxDirection txDirectionZ = serviceZEnd.getTxDirection(); + builder.setParameter(txDirectionZ.getLgx().getLgxDeviceName()) + .setParameter(txDirectionZ.getLgx().getLgxPortName()) + .setParameter(txDirectionZ.getLgx().getLgxPortRack()) + .setParameter(txDirectionZ.getLgx().getLgxPortShelf()); + builder.setParameter(txDirectionZ.getTail().getTailRoadm().getNodeId()); + builder.setParameter(txDirectionZ.getTail().getXponderPort().getCircuitPackName()); + builder.setParameter(txDirectionZ.getTail().getXponderPort().getPortName()); + builder.setParameter(txDirectionZ.getTail().getTailRoadmPortAid()); + builder.setParameter(txDirectionZ.getTail().getTailRoadmPortRackLocation()); + + // rx lgx stuff + RxDirection rxDirectionZ = servicePath.getServiceAEnd().getRxDirection(); + builder.setParameter(rxDirectionZ.getLgx().getLgxDeviceName()) + .setParameter(rxDirectionZ.getLgx().getLgxPortName()) + .setParameter(rxDirectionZ.getLgx().getLgxPortRack()) + .setParameter(rxDirectionZ.getLgx().getLgxPortShelf()); + builder.setParameter(rxDirectionZ.getTail().getTailRoadm().getNodeId()); + builder.setParameter(rxDirectionZ.getTail().getXponderPort().getCircuitPackName()); + builder.setParameter(rxDirectionZ.getTail().getXponderPort().getPortName()); + builder.setParameter(rxDirectionZ.getTail().getTailRoadmPortAid()); + builder.setParameter(rxDirectionZ.getTail().getTailRoadmPortRackLocation()); + + builder.setParameter(servicePath.getServiceAEnd().getOpticType().getName()); + + Router routerZ = servicePath.getServiceZEnd().getRouter(); + builder.setParameter(routerZ.getNodeId()).setParameter(routerZ.getIpAddress().toString()) + .setParameter(routerZ.getUrl()); + builder.setParameter(servicePath.getServiceZEnd().getUserLabel()); + + String customerCode = ""; + if ((servicePath.getHardConstraints().getCustomerCode() == null) + || servicePath.getHardConstraints().getCustomerCode().isEmpty()) { + customerCode = servicePath.getHardConstraints().getCustomerCode().iterator().next(); + } + builder.setParameter(customerCode); + builder.setParameter(servicePath.getDueDate().getValue()); + builder.setParameter(servicePath.getEndDate().getValue()); + builder.setParameter(servicePath.getNcCode()); + builder.setParameter(servicePath.getNciCode()); + builder.setParameter(servicePath.getSecondaryNciCode()); + builder.setParameter(servicePath.getCustomer()); + builder.setParameter(servicePath.getCustomerContact()); + builder.setParameter(servicePath.getOperatorContact()); + builder.setParameter(servicePath.getLatency()); + String fiberSpanSrlgs = ""; + if ((servicePath.getFiberSpanSrlgs() == null) || servicePath.getFiberSpanSrlgs().isEmpty()) { + fiberSpanSrlgs = servicePath.getFiberSpanSrlgs().iterator().next(); + } + String supportingServiceName = ""; + if ((servicePath.getSupportingServiceName() == null) || servicePath.getSupportingServiceName().isEmpty()) { + supportingServiceName = servicePath.getSupportingServiceName().iterator().next(); + } + // TODO: hard constraints and soft constraints are missing + builder.setParameter(fiberSpanSrlgs); + builder.setParameter(supportingServiceName); + builder.setParameter(getCurrentTimestamp()); + builder.setParameter(getCurrentTimestamp()); + } + + /** + * If the input value is null or empty string returns an empty string otherwise + * its value. + * + * @param value a value potentially NULL + * @return String the string value potentially empty if value is NULL + */ + private static String getStringOf(String value) { + return Strings.isNullOrEmpty(value) ? "" : value; + } +} diff --git a/inventory/src/main/java/org/opendaylight/transportpce/inventory/query/StatementBuilder.java b/inventory/src/main/java/org/opendaylight/transportpce/inventory/query/StatementBuilder.java new file mode 100644 index 000000000..1990bb951 --- /dev/null +++ b/inventory/src/main/java/org/opendaylight/transportpce/inventory/query/StatementBuilder.java @@ -0,0 +1,48 @@ +/* + * 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.inventory.query; + +import java.sql.PreparedStatement; +import java.sql.SQLException; + +public class StatementBuilder { + + private final PreparedStatement statement; + private int index; + + private StatementBuilder(PreparedStatement statement) { + this.statement = statement; + this.index = 1; + } + + public StatementBuilder setParameter(String value) throws SQLException { + this.statement.setString(this.index++, value); + return this; + } + + public StatementBuilder setParameter(Long value) throws SQLException { + this.statement.setLong(this.index++, value); + return this; + } + + public StatementBuilder setParameters(String... strings) throws SQLException { + for (int i = 0; i < strings.length; i++) { + statement.setString(i + 1, strings[i]); + } + return this; + } + + public StatementBuilder reset() { + this.index = 1; + return this; + } + + public static StatementBuilder builder(PreparedStatement statement) { + return new StatementBuilder(statement); + } +} diff --git a/inventory/src/main/java/org/opendaylight/transportpce/inventory/utils/StringUtils.java b/inventory/src/main/java/org/opendaylight/transportpce/inventory/utils/StringUtils.java new file mode 100644 index 000000000..1ae663157 --- /dev/null +++ b/inventory/src/main/java/org/opendaylight/transportpce/inventory/utils/StringUtils.java @@ -0,0 +1,80 @@ +/* + * 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.inventory.utils; + +import java.text.SimpleDateFormat; +import java.util.Date; + +/** + * Utility class which handles strings in inventory project. + * + */ +public class StringUtils { + public static final String DEFAULT_SQL_DATE = "yyyy-MM-dd HH:mm:ss"; + + private StringUtils() { + // hiding the constructor + } + + /** + * Returns the current timestamp formatted with + * {@link StringUtils#DEFAULT_SQL_DATE}. + * + * @see StringUtils#getTimestamp(Date) + * @return String the current timestamp formatted + */ + public static String getCurrentTimestamp() { + return getTimestamp(new Date()); + } + + /** + * This method will format the provided {@link Date} with the + * {@link StringUtils#DEFAULT_SQL_DATE} format. + * + * @param date a date + * @return string represenation of the given date + */ + public static String getTimestamp(Date date) { + SimpleDateFormat simpleDate = new SimpleDateFormat(DEFAULT_SQL_DATE); + return simpleDate.format(date); + } + + /** + * Checks the input object for null and if it's null returns a dash instead. + * + * @param object an input object + * @return if object is null a dash is returned, + * otherwise {@link Object#toString()} + */ + public static String prepareDashString(Object object) { + return prepareString(object, "-"); + } + + /** + * Checks the input object for null and if's null returns an empty string instead. + * + * @param object an input object + * @return if object is null an empty string is returned, + * otherwise {@link Object#toString()} + */ + public static String prepareEmptyString(Object object) { + return prepareString(object, ""); + } + + /** + * Checks if the given object is null and returns its representation given by + * replacement. + * + * @param objectString a string object + * @param replacement a replacement + * @return String the representation of the object given by replacement + */ + public static String prepareString(Object objectString, String replacement) { + return objectString == null ? replacement : objectString.toString(); + } +} diff --git a/inventory/src/main/resources/org/opendaylight/blueprint/inventory-blueprint.xml b/inventory/src/main/resources/org/opendaylight/blueprint/inventory-blueprint.xml new file mode 100644 index 000000000..072664d4c --- /dev/null +++ b/inventory/src/main/resources/org/opendaylight/blueprint/inventory-blueprint.xml @@ -0,0 +1,65 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + ${deviceBackupPeriod} + + + org-openroadmdevice-backup-job + + + + diff --git a/networkmodel/pom.xml b/networkmodel/pom.xml new file mode 100644 index 000000000..e7805e31d --- /dev/null +++ b/networkmodel/pom.xml @@ -0,0 +1,76 @@ + + + + + 4.0.0 + + + org.opendaylight.controller + config-parent + 0.8.3-SNAPSHOT + + + + org.opendaylight.transportpce + transportpce-networkmodel + 0.2.0-SNAPSHOT + bundle + + + + + org.opendaylight.netconf + netconf-artifacts + 1.4.3-SNAPSHOT + import + pom + + + + + + + ${project.groupId} + transportpce-api + ${project.version} + + + ${project.groupId} + transportpce-common + ${project.version} + + + ${project.groupId}.ordmodels + transportpce-ordmodels-network + ${project.version} + + + ${project.groupId} + transportpce-renderer + ${project.version} + + + org.opendaylight.netconf + sal-netconf-connector + + + + + junit + junit + test + + + + org.mockito + mockito-core + test + + + diff --git a/networkmodel/src/main/java/org/opendaylight/transportpce/networkmodel/NetConfTopologyListener.java b/networkmodel/src/main/java/org/opendaylight/transportpce/networkmodel/NetConfTopologyListener.java new file mode 100644 index 000000000..0fc982ec5 --- /dev/null +++ b/networkmodel/src/main/java/org/opendaylight/transportpce/networkmodel/NetConfTopologyListener.java @@ -0,0 +1,228 @@ +/* + * Copyright © 2016 Orange 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.networkmodel; + +import java.util.Collection; +import java.util.Map; +import java.util.Optional; +import java.util.concurrent.ConcurrentHashMap; + +import javax.annotation.Nonnull; + +import org.opendaylight.controller.md.sal.binding.api.DataBroker; +import org.opendaylight.controller.md.sal.binding.api.DataObjectModification; +import org.opendaylight.controller.md.sal.binding.api.DataTreeChangeListener; +import org.opendaylight.controller.md.sal.binding.api.DataTreeModification; +import org.opendaylight.controller.md.sal.binding.api.MountPoint; +import org.opendaylight.controller.md.sal.binding.api.NotificationService; +import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType; +import org.opendaylight.controller.sal.binding.api.RpcConsumerRegistry; +import org.opendaylight.transportpce.common.StringConstants; +import org.opendaylight.transportpce.common.Timeouts; +import org.opendaylight.transportpce.common.device.DeviceTransactionManager; +import org.opendaylight.transportpce.networkmodel.dto.NodeRegistration; +import org.opendaylight.transportpce.networkmodel.listeners.AlarmNotificationListener; +import org.opendaylight.transportpce.networkmodel.listeners.DeOperationsListener; +import org.opendaylight.transportpce.networkmodel.listeners.DeviceListener; +import org.opendaylight.transportpce.networkmodel.listeners.LldpListener; +import org.opendaylight.transportpce.networkmodel.listeners.TcaListener; +import org.opendaylight.transportpce.networkmodel.service.NetworkModelService; +import org.opendaylight.yang.gen.v1.http.org.openroadm.alarm.rev161014.OrgOpenroadmAlarmListener; +import org.opendaylight.yang.gen.v1.http.org.openroadm.de.operations.rev161014.OrgOpenroadmDeOperationsListener; +import org.opendaylight.yang.gen.v1.http.org.openroadm.device.rev170206.OrgOpenroadmDeviceListener; +import org.opendaylight.yang.gen.v1.http.org.openroadm.lldp.rev161014.OrgOpenroadmLldpListener; +import org.opendaylight.yang.gen.v1.http.org.openroadm.tca.rev161014.OrgOpenroadmTcaListener; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.netconf.notification._1._0.rev080714.CreateSubscriptionInputBuilder; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.netconf.notification._1._0.rev080714.NotificationsService; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.netconf.notification._1._0.rev080714.StreamNameType; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.netmod.notification.rev080714.Netconf; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.netmod.notification.rev080714.netconf.Streams; +import org.opendaylight.yang.gen.v1.urn.opendaylight.netconf.node.topology.rev150114.NetconfNode; +import org.opendaylight.yang.gen.v1.urn.opendaylight.netconf.node.topology.rev150114.NetconfNodeConnectionStatus; +import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.Node; +import org.opendaylight.yangtools.concepts.ListenerRegistration; +import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class NetConfTopologyListener implements DataTreeChangeListener { + + private static final Logger LOG = LoggerFactory.getLogger(NetConfTopologyListener.class); + + private final NetworkModelService networkModelService; + private final R2RLinkDiscovery linkDiscovery; + private final DataBroker dataBroker; + private final DeviceTransactionManager deviceTransactionManager; + private final Map registrations; + + public NetConfTopologyListener(final NetworkModelService networkModelService, final DataBroker dataBroker, + final R2RLinkDiscovery linkDiscovery, DeviceTransactionManager deviceTransactionManager) { + this.networkModelService = networkModelService; + this.linkDiscovery = linkDiscovery; + this.dataBroker = dataBroker; + this.deviceTransactionManager = deviceTransactionManager; + this.registrations = new ConcurrentHashMap<>(); + } + + private void onDeviceConnected(final String nodeId) { + LOG.info("onDeviceConnected: {}", nodeId); + Optional mountPointOpt = this.deviceTransactionManager.getDeviceMountPoint(nodeId); + MountPoint mountPoint; + if (mountPointOpt.isPresent()) { + mountPoint = mountPointOpt.get(); + } else { + LOG.error("Failed to get mount point for node {}", nodeId); + return; + } + + final Optional notificationService = + mountPoint.getService(NotificationService.class).toJavaUtil(); + if (!notificationService.isPresent()) { + LOG.error("Failed to get RpcService for node {}", nodeId); + return; + } + + final OrgOpenroadmAlarmListener alarmListener = new AlarmNotificationListener(this.dataBroker); + LOG.info("Registering notification listener on OrgOpenroadmAlarmListener for node: {}", nodeId); + final ListenerRegistration accessAlarmNotificationListenerRegistration = + notificationService.get().registerNotificationListener(alarmListener); + + final OrgOpenroadmDeOperationsListener deOperationsListener = new DeOperationsListener(); + LOG.info("Registering notification listener on OrgOpenroadmDeOperationsListener for node: {}", nodeId); + final ListenerRegistration + accessDeOperationasNotificationListenerRegistration = + notificationService.get().registerNotificationListener(deOperationsListener); + + final OrgOpenroadmDeviceListener deviceListener = new DeviceListener(); + LOG.info("Registering notification listener on OrgOpenroadmDeviceListener for node: {}", nodeId); + final ListenerRegistration accessDeviceNotificationListenerRegistration = + notificationService.get().registerNotificationListener(deviceListener); + + final OrgOpenroadmLldpListener lldpListener = new LldpListener(this.linkDiscovery, nodeId); + LOG.info("Registering notification listener on OrgOpenroadmLldpListener for node: {}", nodeId); + final ListenerRegistration accessLldpNotificationListenerRegistration = + notificationService.get().registerNotificationListener(lldpListener); + + final OrgOpenroadmTcaListener tcaListener = new TcaListener(); + LOG.info("Registering notification listener on OrgOpenroadmTcaListener for node: {}", nodeId); + final ListenerRegistration accessTcaNotificationListenerRegistration = + notificationService.get().registerNotificationListener(tcaListener); + + + + String streamName = getSupportedStream(nodeId); + if (streamName == null) { + streamName = "OPENROADM"; + } + final Optional service = mountPoint.getService(RpcConsumerRegistry.class).toJavaUtil(); + if (service.isPresent()) { + final NotificationsService rpcService = service.get().getRpcService(NotificationsService.class); + if (rpcService == null) { + LOG.error("Failed to get RpcService for node {}", nodeId); + } else { + final CreateSubscriptionInputBuilder createSubscriptionInputBuilder = + new CreateSubscriptionInputBuilder(); + createSubscriptionInputBuilder.setStream(new StreamNameType(streamName)); + LOG.info("Triggering notification stream {} for node {}", streamName, nodeId); + rpcService.createSubscription(createSubscriptionInputBuilder.build()); + } + } else { + LOG.error("Failed to get RpcService for node {}", nodeId); + } + NodeRegistration nodeRegistration = new NodeRegistration(nodeId, accessAlarmNotificationListenerRegistration, + accessDeOperationasNotificationListenerRegistration, accessDeviceNotificationListenerRegistration, + accessLldpNotificationListenerRegistration, accessTcaNotificationListenerRegistration); + this.registrations.put(nodeId, nodeRegistration); + } + + private void onDeviceDisConnected(final String nodeId) { + LOG.info("onDeviceDisConnected: {}", nodeId); + NodeRegistration nodeRegistration = this.registrations.remove(nodeId); + if (nodeRegistration != null) { + nodeRegistration.getAccessAlarmNotificationListenerRegistration().close(); + nodeRegistration.getAccessDeOperationasNotificationListenerRegistration().close(); + nodeRegistration.getAccessDeviceNotificationListenerRegistration().close(); + nodeRegistration.getAccessLldpNotificationListenerRegistration().close(); + nodeRegistration.getAccessTcaNotificationListenerRegistration().close(); + } + } + + @Override + public void onDataTreeChanged(@Nonnull Collection> changes) { + LOG.info("onDataTreeChanged"); + for (DataTreeModification change : changes) { + DataObjectModification rootNode = change.getRootNode(); + if (rootNode.getDataAfter() == null) { + continue; + } + String nodeId = rootNode.getDataAfter().getKey().getNodeId().getValue(); + NetconfNode netconfNode = rootNode.getDataAfter().getAugmentation(NetconfNode.class); + if ((netconfNode != null) && !StringConstants.DEFAULT_NETCONF_NODEID.equals(nodeId)) { + switch (rootNode.getModificationType()) { + case WRITE: + LOG.info("Node added: {}", nodeId); + break; + case SUBTREE_MODIFIED: + NetconfNodeConnectionStatus.ConnectionStatus connectionStatus = + netconfNode.getConnectionStatus(); + long count = netconfNode.getAvailableCapabilities().getAvailableCapability().stream() + .filter(cp -> cp.getCapability().contains(StringConstants.OPENROADM_DEVICE_MODEL_NAME)) + .count(); + if (count > 0) { + LOG.info("OpenROADM node detected: {} {}", nodeId, connectionStatus.name()); + switch (connectionStatus) { + case Connected: + this.networkModelService.createOpenROADMnode(nodeId); + onDeviceConnected(nodeId); + break; + case Connecting: + case UnableToConnect: + this.networkModelService.setOpenROADMnodeStatus(nodeId, connectionStatus); + onDeviceDisConnected(nodeId); + break; + default: + LOG.warn("Unsupported device state {}", connectionStatus.getName()); + break; + } + } + break; + case DELETE: + LOG.info("Node deleted: {}", nodeId); + break; + default: + break; + } + } + } + } + + + private String getSupportedStream(String nodeId) { + InstanceIdentifier streamsIID = InstanceIdentifier.create(Netconf.class).child(Streams.class); + try { + Optional ordmInfoObject = + this.deviceTransactionManager.getDataFromDevice(nodeId, LogicalDatastoreType.OPERATIONAL, + streamsIID, Timeouts.DEVICE_READ_TIMEOUT, Timeouts.DEVICE_READ_TIMEOUT_UNIT); + if (!ordmInfoObject.isPresent()) { + LOG.error("Info subtree is not present"); + return null; + } + for (org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.netmod.notification.rev080714.netconf + .streams.Stream strm : ordmInfoObject.get().getStream()) { + + if ("OPENROADM".equalsIgnoreCase(strm.getName().getValue())) { + return strm.getName().getValue().toUpperCase(); + } + } + return "NETCONF"; + } catch (NullPointerException ex) { + LOG.error("NullPointerException thrown while getting Info from a non Open ROADM device {}", nodeId); + return null; + } + } +} diff --git a/networkmodel/src/main/java/org/opendaylight/transportpce/networkmodel/NetworkModelProvider.java b/networkmodel/src/main/java/org/opendaylight/transportpce/networkmodel/NetworkModelProvider.java new file mode 100644 index 000000000..e485367a3 --- /dev/null +++ b/networkmodel/src/main/java/org/opendaylight/transportpce/networkmodel/NetworkModelProvider.java @@ -0,0 +1,75 @@ +/* + * Copyright © 2016 Orange 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.networkmodel; + +import org.opendaylight.controller.md.sal.binding.api.DataBroker; +import org.opendaylight.controller.md.sal.binding.api.DataTreeIdentifier; +import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType; +import org.opendaylight.controller.sal.binding.api.BindingAwareBroker; +import org.opendaylight.controller.sal.binding.api.RpcProviderRegistry; +import org.opendaylight.transportpce.common.InstanceIdentifiers; +import org.opendaylight.transportpce.networkmodel.util.ClliNetwork; +import org.opendaylight.transportpce.networkmodel.util.OpenRoadmNetwork; +import org.opendaylight.transportpce.networkmodel.util.OpenRoadmTopology; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.networkutils.rev170818.NetworkutilsService; +import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.Node; +import org.opendaylight.yangtools.concepts.ListenerRegistration; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class NetworkModelProvider { + + private static final Logger LOG = LoggerFactory.getLogger(NetworkModelProvider.class); + + private final DataBroker dataBroker; + private final RpcProviderRegistry rpcProviderRegistry; + private final NetworkutilsService networkutilsService; + private final NetConfTopologyListener topologyListener; + private final OpenRoadmTopology openRoadmTopology; + private ListenerRegistration dataTreeChangeListenerRegistration; + private BindingAwareBroker.RpcRegistration networkutilsServiceRpcRegistration; + + public NetworkModelProvider(final DataBroker dataBroker, final RpcProviderRegistry rpcProviderRegistry, + final NetworkutilsService networkutilsService, final NetConfTopologyListener topologyListener, + OpenRoadmTopology openRoadmTopology) { + this.dataBroker = dataBroker; + this.rpcProviderRegistry = rpcProviderRegistry; + this.networkutilsService = networkutilsService; + this.topologyListener = topologyListener; + this.openRoadmTopology = openRoadmTopology; + } + + /** + * Method called when the blueprint container is created. + */ + public void init() { + LOG.info("NetworkModelProvider Session Initiated"); + ClliNetwork.createClliLayer(dataBroker); + OpenRoadmNetwork.createOpenRoadmNetworkLayer(dataBroker); + openRoadmTopology.createTopoLayer(dataBroker); + dataTreeChangeListenerRegistration = + dataBroker.registerDataTreeChangeListener(new DataTreeIdentifier<>(LogicalDatastoreType.OPERATIONAL, + InstanceIdentifiers.NETCONF_TOPOLOGY_II.child(Node.class)), topologyListener); + networkutilsServiceRpcRegistration = + rpcProviderRegistry.addRpcImplementation(NetworkutilsService.class, networkutilsService); + } + + /** + * Method called when the blueprint container is destroyed. + */ + public void close() { + LOG.info("NetworkModelProvider Closed"); + if (dataTreeChangeListenerRegistration != null) { + dataTreeChangeListenerRegistration.close(); + } + if (networkutilsServiceRpcRegistration != null) { + networkutilsServiceRpcRegistration.close(); + } + } + +} diff --git a/networkmodel/src/main/java/org/opendaylight/transportpce/networkmodel/NetworkUtilsImpl.java b/networkmodel/src/main/java/org/opendaylight/transportpce/networkmodel/NetworkUtilsImpl.java new file mode 100644 index 000000000..e42520f0f --- /dev/null +++ b/networkmodel/src/main/java/org/opendaylight/transportpce/networkmodel/NetworkUtilsImpl.java @@ -0,0 +1,78 @@ +/* + * 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.networkmodel; + +import java.util.concurrent.Future; + +import org.opendaylight.controller.md.sal.binding.api.DataBroker; +import org.opendaylight.transportpce.networkmodel.util.OpenRoadmTopology; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.networkutils.rev170818.InitRdmXpdrLinksInput; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.networkutils.rev170818.InitRdmXpdrLinksOutput; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.networkutils.rev170818.InitRdmXpdrLinksOutputBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.networkutils.rev170818.InitRoadmNodesInput; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.networkutils.rev170818.InitRoadmNodesOutput; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.networkutils.rev170818.InitRoadmNodesOutputBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.networkutils.rev170818.InitXpdrRdmLinksInput; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.networkutils.rev170818.InitXpdrRdmLinksOutput; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.networkutils.rev170818.InitXpdrRdmLinksOutputBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.networkutils.rev170818.NetworkutilsService; +import org.opendaylight.yangtools.yang.common.RpcResult; +import org.opendaylight.yangtools.yang.common.RpcResultBuilder; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class NetworkUtilsImpl implements NetworkutilsService { + + private static final Logger LOG = LoggerFactory.getLogger(NetworkUtilsImpl.class); + private final DataBroker dataBroker; + private final OpenRoadmTopology openRoadmTopology; + + public NetworkUtilsImpl(DataBroker dataBroker, OpenRoadmTopology openRoadmTopology) { + this.dataBroker = dataBroker; + this.openRoadmTopology = openRoadmTopology; + } + + public Future> initRoadmNodes(InitRoadmNodesInput input) { + boolean createRdmLinks = OrdLink.createRdm2RdmLinks(input, + openRoadmTopology,dataBroker); + if (createRdmLinks) { + return RpcResultBuilder + .success(new InitRoadmNodesOutputBuilder().setResult( + "Unidirectional Roadm-to-Roadm Link created successfully")) + .buildFuture(); + } else { + return RpcResultBuilder.failed().buildFuture(); + } + } + + @Override + public Future> initXpdrRdmLinks(InitXpdrRdmLinksInput input) { + // Assigns user provided input in init-network-view RPC to nodeId + boolean createXpdrRdmLinks = Rdm2XpdrLink.createXpdrRdmLinks(input.getLinksInput(), + openRoadmTopology,dataBroker); + if (createXpdrRdmLinks) { + return RpcResultBuilder + .success(new InitXpdrRdmLinksOutputBuilder().setResult("Xponder Roadm Link created successfully")) + .buildFuture(); + } else { + return RpcResultBuilder.failed().buildFuture(); + } + } + + public Future> initRdmXpdrLinks(InitRdmXpdrLinksInput input) { + boolean createRdmXpdrLinks = Rdm2XpdrLink.createRdmXpdrLinks(input.getLinksInput(), + openRoadmTopology,dataBroker); + if (createRdmXpdrLinks) { + return RpcResultBuilder + .success(new InitRdmXpdrLinksOutputBuilder().setResult("Roadm Xponder links created successfully")) + .buildFuture(); + } else { + return RpcResultBuilder.failed().buildFuture(); + } + } +} diff --git a/networkmodel/src/main/java/org/opendaylight/transportpce/networkmodel/OrdLink.java b/networkmodel/src/main/java/org/opendaylight/transportpce/networkmodel/OrdLink.java new file mode 100644 index 000000000..1915c5e64 --- /dev/null +++ b/networkmodel/src/main/java/org/opendaylight/transportpce/networkmodel/OrdLink.java @@ -0,0 +1,89 @@ +/* + * 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.networkmodel; + +import java.util.concurrent.ExecutionException; + +import org.opendaylight.controller.md.sal.binding.api.DataBroker; +import org.opendaylight.controller.md.sal.binding.api.WriteTransaction; +import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType; +import org.opendaylight.transportpce.common.NetworkUtils; +import org.opendaylight.transportpce.networkmodel.util.LinkIdUtil; +import org.opendaylight.transportpce.networkmodel.util.OpenRoadmTopology; +import org.opendaylight.yang.gen.v1.http.org.openroadm.network.topology.rev170929.Link1; +import org.opendaylight.yang.gen.v1.http.org.openroadm.network.topology.rev170929.Link1Builder; +import org.opendaylight.yang.gen.v1.http.org.openroadm.network.topology.rev170929.network.link.OMSAttributesBuilder; +import org.opendaylight.yang.gen.v1.http.org.openroadm.network.types.rev170929.OpenroadmLinkType; +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.ietf.params.xml.ns.yang.ietf.network.topology.rev150608.LinkId; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.network.topology.rev150608.Network1; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.network.topology.rev150608.network.Link; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.network.topology.rev150608.network.LinkBuilder; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.network.topology.rev150608.network.LinkKey; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.networkutils.rev170818.InitRoadmNodesInput; +import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public final class OrdLink { + + private static final Logger LOG = LoggerFactory.getLogger(OrdLink.class); + + /**Method to create OMS links if not discovered by LLDP. This is helpful + to create test topologies using simulators**/ + public static boolean createRdm2RdmLinks(InitRoadmNodesInput input, + OpenRoadmTopology openRoadmTopology, DataBroker dataBroker) { + + LinkId oppositeLinkId = LinkIdUtil.getRdm2RdmOppositeLinkId(input); + + //For setting up attributes for openRoadm augment + Link1Builder link1Builder = new Link1Builder(); + link1Builder.setLinkType(OpenroadmLinkType.ROADMTOROADM); + OMSAttributesBuilder omsAttributesBuilder = new OMSAttributesBuilder(); + omsAttributesBuilder.setOppositeLink(oppositeLinkId); + link1Builder.setOMSAttributes(omsAttributesBuilder.build()); + + //For opposite link augment + org.opendaylight.yang.gen.v1.http.org.openroadm.opposite.links.rev170929.Link1Builder oppsiteLinkBuilder = + new org.opendaylight.yang.gen.v1.http.org.openroadm.opposite.links.rev170929.Link1Builder(); + oppsiteLinkBuilder.setOppositeLink(oppositeLinkId); + + String srcNode = new StringBuilder(input.getRdmANode()).append("-DEG").append(input.getDegANum()).toString(); + String srcTp = input.getTerminationPointA(); + String destNode = new StringBuilder(input.getRdmZNode()).append("-DEG").append(input.getDegZNum()).toString(); + String destTp = input.getTerminationPointZ(); + + //IETF link builder + LinkBuilder linkBuilder = openRoadmTopology.createLink(srcNode, destNode, srcTp, destTp); + + linkBuilder.addAugmentation(Link1.class,link1Builder.build()); + linkBuilder.addAugmentation(org.opendaylight.yang.gen.v1.http + .org.openroadm.opposite.links.rev170929.Link1.class,oppsiteLinkBuilder.build()); + LinkId linkId = LinkIdUtil.buildLinkId(srcNode, srcTp, destNode, destTp); + + // Building link instance identifier + InstanceIdentifier.InstanceIdentifierBuilder linkIID = + InstanceIdentifier.builder(Network.class, new NetworkKey(new NetworkId(NetworkUtils.OVERLAY_NETWORK_ID))) + .augmentation(Network1.class).child(Link.class, new LinkKey(linkId)); + + WriteTransaction writeTransaction = dataBroker.newWriteOnlyTransaction(); + writeTransaction.merge(LogicalDatastoreType.CONFIGURATION, linkIID.build(), linkBuilder.build()); + try { + writeTransaction.submit().get(); + LOG.info("A new link with linkId: {} added into {} layer.", + linkId.getValue(), NetworkUtils.OVERLAY_NETWORK_ID); + return true; + } catch (InterruptedException | ExecutionException e) { + LOG.warn("Failed to create Roadm 2 Roadm Link for topo layer "); + return false; + } + } +} diff --git a/networkmodel/src/main/java/org/opendaylight/transportpce/networkmodel/R2RLinkDiscovery.java b/networkmodel/src/main/java/org/opendaylight/transportpce/networkmodel/R2RLinkDiscovery.java new file mode 100644 index 000000000..5bc386548 --- /dev/null +++ b/networkmodel/src/main/java/org/opendaylight/transportpce/networkmodel/R2RLinkDiscovery.java @@ -0,0 +1,320 @@ +/* + * 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.networkmodel; + +import java.util.Optional; +import java.util.concurrent.ExecutionException; + +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.ReadOnlyTransaction; +import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType; +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.networkmodel.util.OpenRoadmTopology; +import org.opendaylight.yang.gen.v1.http.org.openroadm.common.types.rev170929.Direction; +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.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.Protocols; +import org.opendaylight.yang.gen.v1.http.org.openroadm.lldp.rev161014.Protocols1; +import org.opendaylight.yang.gen.v1.http.org.openroadm.lldp.rev161014.lldp.container.lldp.NbrList; +import org.opendaylight.yang.gen.v1.http.org.openroadm.lldp.rev161014.lldp.container.lldp.nbr.list.IfName; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.network.rev150608.NodeId; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.networkutils.rev170818.InitRoadmNodesInputBuilder; +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.network.Nodes; +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.CpToDegreeKey; +import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class R2RLinkDiscovery { + + private static final Logger LOG = LoggerFactory.getLogger(R2RLinkDiscovery.class); + + private final DataBroker dataBroker; + private final DeviceTransactionManager deviceTransactionManager; + private final OpenRoadmTopology openRoadmTopology; + private final OpenRoadmInterfaces openRoadmInterfaces; + + public R2RLinkDiscovery(final DataBroker dataBroker, + DeviceTransactionManager deviceTransactionManager, OpenRoadmTopology openRoadmTopology, + OpenRoadmInterfaces openRoadmInterfaces) { + this.dataBroker = dataBroker; + this.deviceTransactionManager = deviceTransactionManager; + this.openRoadmTopology = openRoadmTopology; + this.openRoadmInterfaces = openRoadmInterfaces; + } + + public boolean readLLDP(NodeId nodeId) { + InstanceIdentifier protocolsIID = + InstanceIdentifier.create(OrgOpenroadmDevice.class).child(Protocols.class); + Optional protocolObject = + this.deviceTransactionManager.getDataFromDevice(nodeId.getValue(), LogicalDatastoreType.OPERATIONAL, + protocolsIID, Timeouts.DEVICE_READ_TIMEOUT, Timeouts.DEVICE_READ_TIMEOUT_UNIT); + if (!protocolObject.isPresent() || (protocolObject.get().getAugmentation(Protocols1.class) == null)) { + LOG.warn("LLDP subtree is missing : isolated openroadm device"); + return false; + } + NbrList nbrList = protocolObject.get().getAugmentation(Protocols1.class).getLldp().getNbrList(); + LOG.info("LLDP subtree is present. Device has {} neighbours", nbrList.getIfName().size()); + for (IfName ifName : nbrList.getIfName()) { + if (ifName.getRemoteSysName() == null) { + LOG.error("LLDP subtree is empty in the device for nodeId: {}", + nodeId.getValue()); + return false; + } + Optional mps = this.deviceTransactionManager.getDeviceMountPoint(ifName.getRemoteSysName()); + if (!mps.isPresent()) { + LOG.warn("Neighbouring nodeId: {} is not mounted yet", ifName.getRemoteSysName()); + return false; + } else { + if (!createR2RLink(nodeId, ifName.getIfName(), ifName.getRemoteSysName(), + ifName.getRemotePortId())) { + LOG.warn("Link Creation failed between {} and {} nodes.", nodeId, ifName.getRemoteSysName()); + return false; + } + } + } + return true; + } + + public Direction getDegreeDirection(Integer degreeCounter, NodeId nodeId) { + InstanceIdentifier deviceIID = + InstanceIdentifier.create(OrgOpenroadmDevice.class).child(Degree.class, new DegreeKey(degreeCounter)); + Optional degreeObject = + this.deviceTransactionManager.getDataFromDevice(nodeId.getValue(), LogicalDatastoreType.OPERATIONAL, + deviceIID, Timeouts.DEVICE_READ_TIMEOUT, Timeouts.DEVICE_READ_TIMEOUT_UNIT); + if (degreeObject.isPresent()) { + Integer connectionPortCount = degreeObject.get().getConnectionPorts().size(); + if (connectionPortCount == 1) { + return Direction.Bidirectional; + } else if (connectionPortCount > 1) { + return Direction.Tx; + } else { + return Direction.NotApplicable; + } + } else { + LOG.error("Couldnt retrieve Degree object for nodeId: {} and DegreeNumbner: {}", + nodeId.getValue(),degreeCounter); + return Direction.NotApplicable; + } + } + + public boolean createR2RLink(NodeId nodeId, String interfaceName, String remoteSystemName, + String remoteInterfaceName) { + String srcTpTx = null; + String srcTpRx = null; + String destTpTx = null; + String destTpRx = null; + //Find which degree is associated with ethernet interface + //portmapping.getDegFromCP(nodeId,interfaceName); + Integer srcDegId = getDegFromCP(nodeId, interfaceName); + if (srcDegId == null) { + LOG.error("Couldnt find degree connected to Ethernet interface for nodeId: {}", nodeId); + return false; + } + // Check whether degree is Unidirectional or Bidirectional by counting number of + // circuit-packs under degree subtree + Direction sourceDirection = getDegreeDirection(srcDegId, nodeId); + if (Direction.NotApplicable == sourceDirection) { + LOG.error("Couldnt find degree direction for nodeId: {} and degree: {}", nodeId, srcDegId); + return false; + } else if (Direction.Bidirectional == sourceDirection) { + srcTpTx = "DEG" + srcDegId + "-TTP-TXRX"; + srcTpRx = "DEG" + srcDegId + "-TTP-TXRX"; + } else { + srcTpTx = "DEG" + srcDegId + "-TTP-TX"; + srcTpRx = "DEG" + srcDegId + "-TTP-RX"; + } + // Find degree for which Ethernet interface is created on other end + NodeId destNodeId = new NodeId(remoteSystemName); + Integer destDegId = getDegFromCP(destNodeId, remoteInterfaceName); + //portmapping.getDegFromCP(nodeId,interfaceName); + if (destDegId == null) { + LOG.error("Couldnt find degree connected to Ethernet interface for nodeId: {}", nodeId); + return false; + } + // Check whether degree is Unidirectional or Bidirectional by counting number of + // circuit-packs under degree subtree + Direction destinationDirection = getDegreeDirection(destDegId, destNodeId); + if (Direction.NotApplicable == destinationDirection) { + LOG.error("Couldnt find degree direction for nodeId: {} and degree: {}", destNodeId, destDegId); + return false; + } else if (Direction.Bidirectional == destinationDirection) { + destTpTx = "DEG" + destDegId + "-TTP-TXRX"; + destTpRx = "DEG" + destDegId + "-TTP-TXRX"; + } else { + destTpTx = "DEG" + destDegId + "-TTP-TX"; + destTpRx = "DEG" + destDegId + "-TTP-RX"; + } + //A->Z + LOG.debug( + "Found a neighbor SrcNodeId: {} , SrcDegId: {} , SrcTPId: {}, DestNodeId:{} , DestDegId: {}, DestTPId: {}", + nodeId.getValue(), srcDegId, srcTpTx, destNodeId, destDegId, destTpRx); + InitRoadmNodesInputBuilder r2rlinkBuilderAToZ = new InitRoadmNodesInputBuilder(); + r2rlinkBuilderAToZ.setRdmANode(nodeId.getValue()) + .setDegANum(srcDegId.shortValue()).setTerminationPointA(srcTpTx) + .setRdmZNode(destNodeId.getValue()) + .setDegZNum(destDegId.shortValue()).setTerminationPointZ(destTpRx); + if (!OrdLink.createRdm2RdmLinks(r2rlinkBuilderAToZ.build(),openRoadmTopology, + dataBroker)) { + LOG.error("OMS Link creation failed between node: {} and nodeId: {} in A->Z direction", + nodeId.getValue(),destNodeId.getValue()); + return false; + } + //Z->A + LOG.debug( + "Found a neighbor SrcNodeId: {} , SrcDegId: {}" + + ", SrcTPId: {}, DestNodeId:{} , DestDegId: {}, DestTPId: {}", + destNodeId, destDegId, destTpTx, nodeId.getValue(), srcDegId, srcTpRx); + + InitRoadmNodesInputBuilder r2rlinkBuilderZToA = new InitRoadmNodesInputBuilder(); + r2rlinkBuilderZToA.setRdmANode(destNodeId.getValue()) + .setDegANum(destDegId.shortValue()).setTerminationPointA(destTpTx) + .setRdmZNode(nodeId.getValue()) + .setDegZNum(srcDegId.shortValue()).setTerminationPointZ(srcTpRx); + if (!OrdLink.createRdm2RdmLinks(r2rlinkBuilderZToA.build(),openRoadmTopology, + dataBroker)) { + LOG.error("OMS Link creation failed between node: {} and nodeId: {} in Z->A direction", + destNodeId.getValue(),nodeId.getValue()); + return false; + } + return true; + } + + public boolean deleteR2RLink(NodeId nodeId, String interfaceName, String remoteSystemName, + String remoteInterfaceName) { + String srcTpTx = null; + String srcTpRx = null; + String destTpTx = null; + String destTpRx = null; + //Find which degree is associated with ethernet interface + //portmapping.getDegFromCP(nodeId,interfaceName); + Integer srcDegId = getDegFromCP(nodeId, interfaceName); + if (srcDegId == null) { + LOG.error("Couldnt find degree connected to Ethernet interface for nodeId: {}", nodeId); + return false; + } + // Check whether degree is Unidirectional or Bidirectional by counting number of + // circuit-packs under degree subtree + Direction sourceDirection = getDegreeDirection(srcDegId, nodeId); + if (Direction.NotApplicable == sourceDirection) { + LOG.error("Couldnt find degree direction for nodeId: {} and degree: {}", nodeId, srcDegId); + return false; + } else if (Direction.Bidirectional == sourceDirection) { + srcTpTx = "DEG" + srcDegId + "-TTP-TXRX"; + srcTpRx = "DEG" + srcDegId + "-TTP-TXRX"; + } else { + srcTpTx = "DEG" + srcDegId + "-TTP-TX"; + srcTpRx = "DEG" + srcDegId + "-TTP-RX"; + } + // Find degree for which Ethernet interface is created on other end + NodeId destNodeId = new NodeId(remoteSystemName); + //portmapping.getDegFromCP(nodeId,interfaceName); + Integer destDegId = getDegFromCP(destNodeId, remoteInterfaceName); + if (destDegId == null) { + LOG.error("Couldnt find degree connected to Ethernet interface for nodeId: {}", nodeId); + return false; + } + // Check whether degree is Unidirectional or Bidirectional by counting number of + // circuit-packs under degree subtree + Direction destinationDirection = getDegreeDirection(destDegId, destNodeId); + if (Direction.NotApplicable == destinationDirection) { + LOG.error("Couldnt find degree direction for nodeId: {} and degree: {}", destNodeId, destDegId); + return false; + } else if (Direction.Bidirectional == destinationDirection) { + destTpTx = "DEG" + destDegId + "-TTP-TXRX"; + destTpRx = "DEG" + destDegId + "-TTP-TXRX"; + } else { + destTpTx = "DEG" + destDegId + "-TTP-TX"; + destTpRx = "DEG" + destDegId + "-TTP-RX"; + } + return this.openRoadmTopology.deleteLink(nodeId.getValue(), destNodeId.getValue(), srcTpTx, destTpRx) + && this.openRoadmTopology.deleteLink(destNodeId.getValue(), nodeId.getValue(), destTpTx, srcTpRx); + } + + private CpToDegree getCPtoDegreeMapping(NodeId nodeId, String circuitPackName) { + InstanceIdentifier cptoDegMappingIID = + InstanceIdentifier.builder(Network.class).child(Nodes.class, + new NodesKey(nodeId.getValue())) + .child(CpToDegree.class, new CpToDegreeKey(circuitPackName)).build(); + LOG.debug("Input parameters are {},{}", nodeId.getValue(), circuitPackName); + try (ReadOnlyTransaction readTx = this.dataBroker.newReadOnlyTransaction()) { + Optional cptpDegObject = + readTx.read(LogicalDatastoreType.CONFIGURATION, cptoDegMappingIID).get().toJavaUtil(); + if (cptpDegObject.isPresent()) { + CpToDegree cpToDeg = cptpDegObject.get(); + LOG.debug("Found mapping for the Circuit Pack {}. Degree: {}", circuitPackName, cpToDeg); + return cpToDeg; + } else { + LOG.warn("Could not find mapping for Circuit Pack {} for nodeId {}", circuitPackName, + nodeId.getValue()); + } + } catch (InterruptedException | ExecutionException ex) { + LOG.error("Unable to read mapping for circuit pack : {} for nodeId {}", circuitPackName, nodeId, ex); + } + return null; + } + + private Integer getDegFromParentCP(NodeId nodeId, String interfaceName, String supportingCircuitPack) { + InstanceIdentifier circuitPackIID = InstanceIdentifier.create(OrgOpenroadmDevice.class) + .child(CircuitPacks.class, new CircuitPacksKey(supportingCircuitPack)); + Optional circuitPackObject = + this.deviceTransactionManager.getDataFromDevice(nodeId.getValue(), LogicalDatastoreType.OPERATIONAL, + circuitPackIID, Timeouts.DEVICE_READ_TIMEOUT, Timeouts.DEVICE_READ_TIMEOUT_UNIT); + if (!circuitPackObject.isPresent() + || (circuitPackObject.get().getParentCircuitPack().getCircuitPackName() == null)) { + LOG.warn("Parent circuitpack not found for NodeId: {} and Interface: {}", nodeId, interfaceName); + return null; + } + String parentCP = circuitPackObject.get().getParentCircuitPack().getCircuitPackName(); + CpToDegree cpToDegree = getCPtoDegreeMapping(nodeId, parentCP); + if (cpToDegree == null) { + LOG.error("CP to Degree mapping not found even with parent circuitpack for NodeID: {}" + "and Interface {}", + nodeId, interfaceName); + return null; + } else { + LOG.debug("CP to degree is {}", cpToDegree.getDegreeNumber()); + return cpToDegree.getDegreeNumber().intValue(); + } + } + + private Integer getDegFromCP(NodeId nodeId, String interfaceName) { + try { + java.util.Optional interfaceOpt = this.openRoadmInterfaces.getInterface(nodeId.getValue(), + interfaceName); + if (!interfaceOpt.isPresent()) { + LOG.warn("Interface with {} on node {} was not found!", interfaceName, nodeId.getValue()); + return null; + } + String supportingCircuitPack = interfaceOpt.get().getSupportingCircuitPackName(); + LOG.debug("Supporting circuitpack name is :{}", + interfaceOpt.get().getSupportingCircuitPackName()); + CpToDegree cpToDegree = getCPtoDegreeMapping(nodeId, supportingCircuitPack); + // Currently devices have different ways to represent connection to Ethernet port and degree port + // If Circuit pack is not present under degree tree then read parent CP of given CP(Circuit pack) + if (cpToDegree != null) { + return cpToDegree.getDegreeNumber().intValue(); + } else { + return getDegFromParentCP(nodeId, interfaceName, supportingCircuitPack); + } + } catch (OpenRoadmInterfaceException ex) { + LOG.error("Failed to get source interface {} from node {}!", interfaceName, nodeId, ex); + return null; + } + } +} diff --git a/networkmodel/src/main/java/org/opendaylight/transportpce/networkmodel/Rdm2XpdrLink.java b/networkmodel/src/main/java/org/opendaylight/transportpce/networkmodel/Rdm2XpdrLink.java new file mode 100644 index 000000000..b757a7ba5 --- /dev/null +++ b/networkmodel/src/main/java/org/opendaylight/transportpce/networkmodel/Rdm2XpdrLink.java @@ -0,0 +1,116 @@ +/* + * 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.networkmodel; + +import com.google.common.collect.ImmutableList; +import com.google.common.util.concurrent.CheckedFuture; + +import org.opendaylight.controller.md.sal.binding.api.DataBroker; +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.NetworkUtils; +import org.opendaylight.transportpce.networkmodel.util.OpenRoadmTopology; +import org.opendaylight.yang.gen.v1.http.org.openroadm.network.topology.rev170929.Link1; +import org.opendaylight.yang.gen.v1.http.org.openroadm.network.topology.rev170929.Link1Builder; +import org.opendaylight.yang.gen.v1.http.org.openroadm.network.types.rev170929.OpenroadmLinkType; +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.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.ietf.params.xml.ns.yang.ietf.network.topology.rev150608.Network1; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.network.topology.rev150608.Network1Builder; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.network.topology.rev150608.network.LinkBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.networkutils.rev170818.links.input.grouping.LinksInput; +import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public final class Rdm2XpdrLink { + + private static final Logger LOG = LoggerFactory.getLogger(Rdm2XpdrLink.class); + + public static boolean createXpdrRdmLinks(LinksInput linksInput, OpenRoadmTopology openRoadmTopology, + DataBroker dataBroker) { + String srcNode = + new StringBuilder(linksInput.getXpdrNode()).append("-XPDR").append(linksInput.getXpdrNum()).toString(); + String srcTp = new StringBuilder("XPDR").append(linksInput.getXpdrNum()).append("-NETWORK") + .append(linksInput.getNetworkNum()).toString(); + String destNode = + new StringBuilder(linksInput.getRdmNode()).append("-SRG").append(linksInput.getSrgNum()).toString(); + String destTp = linksInput.getTerminationPointNum(); + + Network topoNetowkLayer = createNetworkBuilder(srcNode, srcTp, destNode, destTp, false, + openRoadmTopology).build(); + InstanceIdentifier.InstanceIdentifierBuilder nwIID = InstanceIdentifier.builder(Network.class, + new NetworkKey(new NetworkId(NetworkUtils.OVERLAY_NETWORK_ID))); + WriteTransaction wrtx = dataBroker.newWriteOnlyTransaction(); + wrtx.merge(LogicalDatastoreType.CONFIGURATION, nwIID.build(), topoNetowkLayer); + + CheckedFuture submit = wrtx.submit(); + + try { + submit.checkedGet(); + LOG.info("Post successful"); + return true; + + } catch (TransactionCommitFailedException e) { + LOG.warn("Failed to create Xponder to Roadm link in the Topo layer "); + return false; + + } + } + + public static boolean createRdmXpdrLinks(LinksInput linksInput, + OpenRoadmTopology openRoadmTopology, DataBroker dataBroker) { + String srcNode = + new StringBuilder(linksInput.getRdmNode()).append("-SRG").append(linksInput.getSrgNum()).toString(); + String srcTp = linksInput.getTerminationPointNum(); + String destNode = + new StringBuilder(linksInput.getXpdrNode()).append("-XPDR").append(linksInput.getXpdrNum()).toString(); + String destTp = new StringBuilder("XPDR").append(linksInput.getXpdrNum()).append("-NETWORK") + .append(linksInput.getNetworkNum()).toString(); + + Network topoNetowkLayer = createNetworkBuilder(srcNode, srcTp, destNode, destTp, true, + openRoadmTopology).build(); + InstanceIdentifier.InstanceIdentifierBuilder nwIID = InstanceIdentifier.builder(Network.class, + new NetworkKey(new NetworkId(NetworkUtils.OVERLAY_NETWORK_ID))); + WriteTransaction wrtx = dataBroker.newWriteOnlyTransaction(); + wrtx.merge(LogicalDatastoreType.CONFIGURATION, nwIID.build(), topoNetowkLayer); + CheckedFuture submit = wrtx.submit(); + try { + submit.checkedGet(); + LOG.info("Post successful"); + return true; + + } catch (TransactionCommitFailedException e) { + LOG.warn("Failed to create Xponder to Roadm link in the Topo layer "); + return false; + } + } + + private static NetworkBuilder createNetworkBuilder(String srcNode, String srcTp, String destNode, String destTp, + boolean isXponderInput, OpenRoadmTopology openRoadmTopology) { + NetworkId nwId = new NetworkId(NetworkUtils.OVERLAY_NETWORK_ID); + NetworkBuilder nwBuilder = new NetworkBuilder(); + nwBuilder.setNetworkId(nwId); + nwBuilder.setKey(new NetworkKey(nwId)); + Link1Builder lnk1bldr = new Link1Builder(); + LinkBuilder linkBuilder = openRoadmTopology.createLink(srcNode, destNode, srcTp, destTp); + lnk1bldr.setLinkType(isXponderInput ? OpenroadmLinkType.XPONDERINPUT : OpenroadmLinkType.XPONDEROUTPUT); + linkBuilder.addAugmentation(Link1.class, lnk1bldr.build()); + LOG.info("Link id in the linkbldr {}", linkBuilder.getLinkId()); + LOG.info("Link with oppo link {}", linkBuilder.getAugmentation(Link1.class)); + Network1Builder nwBldr1 = new Network1Builder(); + nwBldr1.setLink(ImmutableList.of(linkBuilder.build())); + nwBuilder.addAugmentation(Network1.class, nwBldr1.build()); + return nwBuilder; + } +} + diff --git a/networkmodel/src/main/java/org/opendaylight/transportpce/networkmodel/dto/NodeData.java b/networkmodel/src/main/java/org/opendaylight/transportpce/networkmodel/dto/NodeData.java new file mode 100644 index 000000000..c5eae8210 --- /dev/null +++ b/networkmodel/src/main/java/org/opendaylight/transportpce/networkmodel/dto/NodeData.java @@ -0,0 +1,29 @@ +/* + * 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.networkmodel.dto; + +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.network.rev150608.network.NodeBuilder; + +public class NodeData { + + private final NodeBuilder nodeBuilder; + private final int portDirectionEnum; + + public NodeData(NodeBuilder nodeBuilder, int portDirectionEnum) { + this.nodeBuilder = nodeBuilder; + this.portDirectionEnum = portDirectionEnum; + } + + public NodeBuilder getNodeBuilder() { + return nodeBuilder; + } + + public int getPortDirectionEnum() { + return portDirectionEnum; + } +} diff --git a/networkmodel/src/main/java/org/opendaylight/transportpce/networkmodel/dto/NodeRegistration.java b/networkmodel/src/main/java/org/opendaylight/transportpce/networkmodel/dto/NodeRegistration.java new file mode 100644 index 000000000..e802091b5 --- /dev/null +++ b/networkmodel/src/main/java/org/opendaylight/transportpce/networkmodel/dto/NodeRegistration.java @@ -0,0 +1,66 @@ +/* + * 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.networkmodel.dto; + +import org.opendaylight.yang.gen.v1.http.org.openroadm.alarm.rev161014.OrgOpenroadmAlarmListener; +import org.opendaylight.yang.gen.v1.http.org.openroadm.de.operations.rev161014.OrgOpenroadmDeOperationsListener; +import org.opendaylight.yang.gen.v1.http.org.openroadm.device.rev170206.OrgOpenroadmDeviceListener; +import org.opendaylight.yang.gen.v1.http.org.openroadm.lldp.rev161014.OrgOpenroadmLldpListener; +import org.opendaylight.yang.gen.v1.http.org.openroadm.tca.rev161014.OrgOpenroadmTcaListener; +import org.opendaylight.yangtools.concepts.ListenerRegistration; + +public class NodeRegistration { + + private final String nodeId; + private final ListenerRegistration accessAlarmNotificationListenerRegistration; + private final ListenerRegistration + accessDeOperationasNotificationListenerRegistration; + private final ListenerRegistration accessDeviceNotificationListenerRegistration; + private final ListenerRegistration accessLldpNotificationListenerRegistration; + private final ListenerRegistration accessTcaNotificationListenerRegistration; + + public NodeRegistration(String nodeId, + ListenerRegistration accessAlarmNotificationListenerRegistration, + ListenerRegistration accessDeOperationasNotificationListenerRegistration, + ListenerRegistration accessDeviceNotificationListenerRegistration, + ListenerRegistration accessLldpNotificationListenerRegistration, + ListenerRegistration accessTcaNotificationListenerRegistration) { + this.nodeId = nodeId; + this.accessAlarmNotificationListenerRegistration = accessAlarmNotificationListenerRegistration; + this.accessDeOperationasNotificationListenerRegistration = accessDeOperationasNotificationListenerRegistration; + this.accessDeviceNotificationListenerRegistration = accessDeviceNotificationListenerRegistration; + this.accessLldpNotificationListenerRegistration = accessLldpNotificationListenerRegistration; + this.accessTcaNotificationListenerRegistration = accessTcaNotificationListenerRegistration; + } + + public String getNodeId() { + return nodeId; + } + + public ListenerRegistration getAccessAlarmNotificationListenerRegistration() { + return accessAlarmNotificationListenerRegistration; + } + + public ListenerRegistration + getAccessDeOperationasNotificationListenerRegistration() { + return accessDeOperationasNotificationListenerRegistration; + } + + public ListenerRegistration getAccessDeviceNotificationListenerRegistration() { + return accessDeviceNotificationListenerRegistration; + } + + public ListenerRegistration getAccessLldpNotificationListenerRegistration() { + return accessLldpNotificationListenerRegistration; + } + + public ListenerRegistration getAccessTcaNotificationListenerRegistration() { + return accessTcaNotificationListenerRegistration; + } + +} diff --git a/networkmodel/src/main/java/org/opendaylight/transportpce/networkmodel/dto/TopologyShard.java b/networkmodel/src/main/java/org/opendaylight/transportpce/networkmodel/dto/TopologyShard.java new file mode 100644 index 000000000..d7508934c --- /dev/null +++ b/networkmodel/src/main/java/org/opendaylight/transportpce/networkmodel/dto/TopologyShard.java @@ -0,0 +1,36 @@ +/* + * 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.networkmodel.dto; + +import java.util.List; + +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.network.rev150608.network.Node; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.network.topology.rev150608.network.Link; + +/** + * Data holder for topology fragment. + */ +public class TopologyShard { + + private final List nodes; + private final List links; + + public TopologyShard(List nodes, List links) { + this.nodes = nodes; + this.links = links; + } + + public List getNodes() { + return nodes; + } + + public List getLinks() { + return links; + } + +} diff --git a/networkmodel/src/main/java/org/opendaylight/transportpce/networkmodel/listeners/AlarmNotificationListener.java b/networkmodel/src/main/java/org/opendaylight/transportpce/networkmodel/listeners/AlarmNotificationListener.java new file mode 100644 index 000000000..80e89c888 --- /dev/null +++ b/networkmodel/src/main/java/org/opendaylight/transportpce/networkmodel/listeners/AlarmNotificationListener.java @@ -0,0 +1,216 @@ +/* + * 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.networkmodel.listeners; + +import java.util.ArrayList; +import java.util.List; +import java.util.Optional; +import java.util.concurrent.ExecutionException; +import org.opendaylight.controller.md.sal.binding.api.DataBroker; +import org.opendaylight.controller.md.sal.binding.api.ReadOnlyTransaction; +import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType; +import org.opendaylight.yang.gen.v1.http.org.openroadm.alarm.rev161014.AlarmNotification; +import org.opendaylight.yang.gen.v1.http.org.openroadm.alarm.rev161014.OrgOpenroadmAlarmListener; +import org.opendaylight.yang.gen.v1.http.org.openroadm.alarm.rev161014.alarm.ProbableCause; +import org.opendaylight.yang.gen.v1.http.org.openroadm.resource.rev161014.resource.ResourceType; +import org.opendaylight.yang.gen.v1.http.org.openroadm.resource.rev161014.resource.resource.Resource; +import org.opendaylight.yang.gen.v1.http.org.openroadm.resource.rev161014.resource.resource.resource.CircuitPack; +import org.opendaylight.yang.gen.v1.http.org.openroadm.resource.rev161014.resource.resource.resource.Connection; +import org.opendaylight.yang.gen.v1.http.org.openroadm.resource.rev161014.resource.resource.resource.Degree; +import org.opendaylight.yang.gen.v1.http.org.openroadm.resource.rev161014.resource.resource.resource.Interface; +import org.opendaylight.yang.gen.v1.http.org.openroadm.resource.rev161014.resource.resource.resource.InternalLink; +import org.opendaylight.yang.gen.v1.http.org.openroadm.resource.rev161014.resource.resource.resource.PhysicalLink; +import org.opendaylight.yang.gen.v1.http.org.openroadm.resource.rev161014.resource.resource.resource.Port; +import org.opendaylight.yang.gen.v1.http.org.openroadm.resource.rev161014.resource.resource.resource.Service; +import org.opendaylight.yang.gen.v1.http.org.openroadm.resource.rev161014.resource.resource.resource.Shelf; +import org.opendaylight.yang.gen.v1.http.org.openroadm.resource.rev161014.resource.resource.resource.Srg; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.alarmsuppression.rev171102.ServiceNodelist; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.alarmsuppression.rev171102.service.nodelist.Nodelist; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.alarmsuppression.rev171102.service.nodelist.nodelist.Nodes; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.alarmsuppression.rev171102.service.nodelist.nodelist.NodesBuilder; +import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class AlarmNotificationListener implements OrgOpenroadmAlarmListener { + + private static final Logger LOG = LoggerFactory.getLogger(AlarmNotificationListener.class); + private static final String PIPE = "|"; + private final DataBroker dataBroker; + + public AlarmNotificationListener(DataBroker dataBroker) { + this.dataBroker = dataBroker; + } + + + /** + * Callback for alarm-notification. + * + * @param notification AlarmNotification object + */ + @Override + public void onAlarmNotification(AlarmNotification notification) { + List allNodeList = new ArrayList<>(); + InstanceIdentifier serviceNodeListIID = InstanceIdentifier.create(ServiceNodelist.class); + try { + ReadOnlyTransaction rtx = dataBroker.newReadOnlyTransaction(); + com.google.common.base.Optional serviceListObject = + rtx.read(LogicalDatastoreType.OPERATIONAL, serviceNodeListIID).get(); + if (serviceListObject.isPresent()) { + for (Nodelist nodelist : serviceListObject.get().getNodelist()) { + allNodeList.addAll(nodelist.getNodes()); + } + } + } catch (InterruptedException | ExecutionException ex) { + LOG.warn("Exception thrown while reading Logical Connection Point value from {} {}", ex); + } + StringBuilder sb = new StringBuilder(notification.getResource().getDevice().getNodeId()).append(PIPE); + sb.append(buildCause(notification.getProbableCause())); + sb.append(notification.getId() != null ? notification.getId() : "").append(PIPE) + .append(notification.getType() != null ? notification.getType().toString() : "").append(PIPE) + .append(notification.getRaiseTime() != null ? notification.getRaiseTime().toString() : "").append(PIPE) + .append(notification.getSeverity() != null ? notification.getSeverity().getName() : "").append(PIPE) + .append(notification.getCircuitId() != null ? notification.getCircuitId() : "").append(PIPE); + + sb.append(buildType(notification)); + + String message = sb.toString(); + Nodes build = new NodesBuilder().setNodeId(notification.getResource().getDevice().getNodeId()).build(); + if (allNodeList.contains(build)) { + LOG.info(message); + } else { + LOG.warn(message); + } + } + + private String buildCause(ProbableCause probableCause) { + StringBuilder sb = new StringBuilder(); + if (probableCause == null) { + return "||||"; + } + sb.append((probableCause.getCause() != null) ? probableCause.getCause().getName() : "").append(PIPE) + .append((probableCause.getDirection() != null) ? probableCause.getDirection().getName() : "") + .append(PIPE).append((probableCause.getExtension() != null) ? probableCause.getExtension() : "") + .append(PIPE).append((probableCause.getLocation() != null) ? probableCause.getLocation().getName() : "") + .append(PIPE); + return sb.toString(); + } + + @SuppressWarnings("unchecked") + private static Optional tryCastToParticularResource(Class resourceClass, + Resource resource) { + if (resource == null) { + LOG.error("Resource is null."); + } else if (!resourceClass.isInstance(resource)) { + LOG.error("Resource implement different type than expected. Expected {}, actual {}.", + resourceClass.getSimpleName(), resource.getClass().getSimpleName()); + } else { + return Optional.of((T) resource); + } + return Optional.empty(); + } + + private static String buildType(AlarmNotification notification) { + String circuitPack = ""; + String connection = ""; + String degree = ""; + String iface = ""; + String internalLink = ""; + String physicalLink = ""; + String service = ""; + String shelf = ""; + String sharedRiskGroup = ""; + String port = ""; + String portCircuitPack = ""; + + Resource resource = notification.getResource().getResource().getResource(); + ResourceType wantedResourceType = notification.getResource().getResourceType(); + + switch (wantedResourceType.getType()) { + case CircuitPack: + Optional circuitPackOptional = tryCastToParticularResource(CircuitPack.class, resource); + if (circuitPackOptional.isPresent()) { + circuitPack = circuitPackOptional.get().getCircuitPackName(); + } + break; + + case Connection: + Optional connectionOptional = tryCastToParticularResource(Connection.class, resource); + if (connectionOptional.isPresent()) { + connection = connectionOptional.get().getConnectionNumber(); + } + break; + + case Degree: + Optional degreeOptional = tryCastToParticularResource(Degree.class, resource); + if (degreeOptional.isPresent()) { + degree = degreeOptional.get().getDegreeNumber().toString(); + } + break; + + case Interface: + Optional interfaceOptional = tryCastToParticularResource(Interface.class, resource); + if (interfaceOptional.isPresent()) { + iface = interfaceOptional.get().getInterfaceName(); + } + break; + + case InternalLink: + Optional internalLinkOptional = tryCastToParticularResource(InternalLink.class, resource); + if (internalLinkOptional.isPresent()) { + internalLink = internalLinkOptional.get().getInternalLinkName(); + } + break; + + case PhysicalLink: + Optional physicalLinkOptional = tryCastToParticularResource(PhysicalLink.class, resource); + if (physicalLinkOptional.isPresent()) { + physicalLink = physicalLinkOptional.get().getPhysicalLinkName(); + } + break; + + case Service: + Optional serviceOptional = tryCastToParticularResource(Service.class, resource); + if (serviceOptional.isPresent()) { + service = serviceOptional.get().getServiceName(); + } + break; + + case Shelf: + Optional shelfOptional = tryCastToParticularResource(Shelf.class, resource); + if (shelfOptional.isPresent()) { + shelf = shelfOptional.get().getShelfName(); + } + break; + + case SharedRiskGroup: + Optional sharedRiskGroupOptional = tryCastToParticularResource(Srg.class, resource); + if (sharedRiskGroupOptional.isPresent()) { + sharedRiskGroup = sharedRiskGroupOptional.get().getSrgNumber().toString(); + } + break; + + case Port: + Optional portContainerOptional = tryCastToParticularResource(Port.class, resource); + if (portContainerOptional.isPresent()) { + port = portContainerOptional.get().getPort().getPortName(); + portCircuitPack = portContainerOptional.get().getPort().getCircuitPackName(); + } + break; + + default: + LOG.warn("Unknown resource type {}", wantedResourceType); + } + StringBuilder sb = new StringBuilder(circuitPack); + sb.append(PIPE).append(connection).append(PIPE).append(degree).append(PIPE).append(iface); + sb.append(PIPE).append(internalLink).append(PIPE).append(physicalLink).append(PIPE).append(service); + sb.append(PIPE).append(shelf).append(PIPE).append(sharedRiskGroup).append(PIPE).append(port); + sb.append(PIPE).append(portCircuitPack); + return sb.toString(); + } +} diff --git a/renderer/src/main/java/org/opendaylight/transportpce/renderer/listeners/DeOperationsListener.java b/networkmodel/src/main/java/org/opendaylight/transportpce/networkmodel/listeners/DeOperationsListener.java similarity index 94% rename from renderer/src/main/java/org/opendaylight/transportpce/renderer/listeners/DeOperationsListener.java rename to networkmodel/src/main/java/org/opendaylight/transportpce/networkmodel/listeners/DeOperationsListener.java index 2292b2fd9..c861c2f8e 100644 --- a/renderer/src/main/java/org/opendaylight/transportpce/renderer/listeners/DeOperationsListener.java +++ b/networkmodel/src/main/java/org/opendaylight/transportpce/networkmodel/listeners/DeOperationsListener.java @@ -6,7 +6,7 @@ * and is available at http://www.eclipse.org/legal/epl-v10.html */ -package org.opendaylight.transportpce.renderer.listeners; +package org.opendaylight.transportpce.networkmodel.listeners; import org.opendaylight.yang.gen.v1.http.org.openroadm.de.operations.rev161014.OrgOpenroadmDeOperationsListener; import org.opendaylight.yang.gen.v1.http.org.openroadm.de.operations.rev161014.RestartNotification; @@ -26,4 +26,5 @@ public class DeOperationsListener implements OrgOpenroadmDeOperationsListener { public void onRestartNotification(RestartNotification notification) { LOG.info("Notification {} received {}", RestartNotification.QNAME, notification); } + } \ No newline at end of file diff --git a/renderer/src/main/java/org/opendaylight/transportpce/renderer/listeners/DeviceListener.java b/networkmodel/src/main/java/org/opendaylight/transportpce/networkmodel/listeners/DeviceListener.java similarity index 89% rename from renderer/src/main/java/org/opendaylight/transportpce/renderer/listeners/DeviceListener.java rename to networkmodel/src/main/java/org/opendaylight/transportpce/networkmodel/listeners/DeviceListener.java index 2f57b3108..ab9d4e036 100644 --- a/renderer/src/main/java/org/opendaylight/transportpce/renderer/listeners/DeviceListener.java +++ b/networkmodel/src/main/java/org/opendaylight/transportpce/networkmodel/listeners/DeviceListener.java @@ -6,7 +6,7 @@ * and is available at http://www.eclipse.org/legal/epl-v10.html */ -package org.opendaylight.transportpce.renderer.listeners; +package org.opendaylight.transportpce.networkmodel.listeners; import org.opendaylight.yang.gen.v1.http.org.openroadm.device.rev170206.ChangeNotification; import org.opendaylight.yang.gen.v1.http.org.openroadm.device.rev170206.OrgOpenroadmDeviceListener; @@ -16,7 +16,7 @@ import org.slf4j.LoggerFactory; public class DeviceListener implements OrgOpenroadmDeviceListener { - private static final Logger LOG = LoggerFactory.getLogger(OrgOpenroadmDeviceListener.class); + private static final Logger LOG = LoggerFactory.getLogger(DeviceListener.class); /** * Callback for change-notification. @@ -39,4 +39,5 @@ public class DeviceListener implements OrgOpenroadmDeviceListener { LOG.info("Notification {} received {}", OtdrScanResult.QNAME, notification); } + } \ No newline at end of file diff --git a/networkmodel/src/main/java/org/opendaylight/transportpce/networkmodel/listeners/LldpListener.java b/networkmodel/src/main/java/org/opendaylight/transportpce/networkmodel/listeners/LldpListener.java new file mode 100644 index 000000000..276ca0e72 --- /dev/null +++ b/networkmodel/src/main/java/org/opendaylight/transportpce/networkmodel/listeners/LldpListener.java @@ -0,0 +1,47 @@ +/* + * 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.networkmodel.listeners; + +import org.opendaylight.transportpce.networkmodel.R2RLinkDiscovery; +import org.opendaylight.yang.gen.v1.http.org.openroadm.lldp.rev161014.LldpNbrInfoChange; +import org.opendaylight.yang.gen.v1.http.org.openroadm.lldp.rev161014.OrgOpenroadmLldpListener; +import org.opendaylight.yang.gen.v1.http.org.openroadm.resource.types.rev161014.ResourceNotificationType; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.network.rev150608.NodeId; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class LldpListener implements OrgOpenroadmLldpListener { + + private static final Logger LOG = LoggerFactory.getLogger(LldpListener.class); + private final R2RLinkDiscovery linkDiscovery; + private final NodeId nodeId; + + public LldpListener(final R2RLinkDiscovery linkDiscovery, final String nodeId) { + this.linkDiscovery = linkDiscovery; + this.nodeId = new NodeId(nodeId); + } + + /** + * Callback for lldp-nbr-info-change. + * @param notification LldpNbrInfoChange object + */ + @Override + public void onLldpNbrInfoChange(LldpNbrInfoChange notification) { + LOG.info("Notification {} received {}", LldpNbrInfoChange.QNAME, notification); + if (notification.getNotificationType().equals(ResourceNotificationType.ResourceCreation)) { + linkDiscovery.createR2RLink(nodeId,notification.getResource(), + notification.getNbrInfo().getRemoteSysName(), + notification.getNbrInfo().getRemotePortId()); + } else if (notification.getNotificationType().equals(ResourceNotificationType.ResourceDeletion)) { + linkDiscovery.deleteR2RLink(nodeId,notification.getResource(), + notification.getNbrInfo().getRemoteSysName(), + notification.getNbrInfo().getRemotePortId()); + } + } +} diff --git a/renderer/src/main/java/org/opendaylight/transportpce/renderer/listeners/TcaListener.java b/networkmodel/src/main/java/org/opendaylight/transportpce/networkmodel/listeners/TcaListener.java similarity index 84% rename from renderer/src/main/java/org/opendaylight/transportpce/renderer/listeners/TcaListener.java rename to networkmodel/src/main/java/org/opendaylight/transportpce/networkmodel/listeners/TcaListener.java index b9b92c757..ecfa36584 100644 --- a/renderer/src/main/java/org/opendaylight/transportpce/renderer/listeners/TcaListener.java +++ b/networkmodel/src/main/java/org/opendaylight/transportpce/networkmodel/listeners/TcaListener.java @@ -6,7 +6,7 @@ * and is available at http://www.eclipse.org/legal/epl-v10.html */ -package org.opendaylight.transportpce.renderer.listeners; +package org.opendaylight.transportpce.networkmodel.listeners; import org.opendaylight.yang.gen.v1.http.org.openroadm.tca.rev161014.OrgOpenroadmTcaListener; import org.opendaylight.yang.gen.v1.http.org.openroadm.tca.rev161014.TcaNotification; @@ -15,15 +15,15 @@ import org.slf4j.LoggerFactory; public class TcaListener implements OrgOpenroadmTcaListener { - private static final Logger LOG = LoggerFactory.getLogger(OrgOpenroadmTcaListener.class); + private static final Logger LOG = LoggerFactory.getLogger(TcaListener.class); /** * Callback for tca-notification. - * * @param notification TcaNotification object */ @Override public void onTcaNotification(TcaNotification notification) { LOG.info("Notification {} received {}", TcaNotification.QNAME, notification); } + } \ No newline at end of file diff --git a/networkmodel/src/main/java/org/opendaylight/transportpce/networkmodel/service/NetworkModelService.java b/networkmodel/src/main/java/org/opendaylight/transportpce/networkmodel/service/NetworkModelService.java new file mode 100644 index 000000000..3a5e54d41 --- /dev/null +++ b/networkmodel/src/main/java/org/opendaylight/transportpce/networkmodel/service/NetworkModelService.java @@ -0,0 +1,35 @@ +/* + * 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.networkmodel.service; + +import org.opendaylight.yang.gen.v1.urn.opendaylight.netconf.node.topology.rev150114.NetconfNodeConnectionStatus; + +/** + * Service for data manipulation on OpenROADM topology models. + */ +public interface NetworkModelService { + + /** + * Create new OpenROADM node in all OpenROADM topologies. + * + * @param nodeId + * unique node ID of new OpenROADM node + */ + void createOpenROADMnode(String nodeId); + + /** + * Set/update connection status of OpenROADM node. + * + * @param nodeId + * unique node ID of new OpenROADM node + * @param connectionStatus + * connection status of the node + */ + void setOpenROADMnodeStatus(String nodeId, NetconfNodeConnectionStatus.ConnectionStatus connectionStatus); + +} diff --git a/networkmodel/src/main/java/org/opendaylight/transportpce/networkmodel/service/NetworkModelServiceImpl.java b/networkmodel/src/main/java/org/opendaylight/transportpce/networkmodel/service/NetworkModelServiceImpl.java new file mode 100644 index 000000000..daf085245 --- /dev/null +++ b/networkmodel/src/main/java/org/opendaylight/transportpce/networkmodel/service/NetworkModelServiceImpl.java @@ -0,0 +1,143 @@ +/* + * 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.networkmodel.service; + +import java.util.concurrent.ExecutionException; + +import org.opendaylight.controller.md.sal.binding.api.DataBroker; +import org.opendaylight.controller.md.sal.binding.api.WriteTransaction; +import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType; +import org.opendaylight.transportpce.common.NetworkUtils; +import org.opendaylight.transportpce.common.device.DeviceTransactionManager; +import org.opendaylight.transportpce.common.mapping.PortMapping; +import org.opendaylight.transportpce.networkmodel.R2RLinkDiscovery; +import org.opendaylight.transportpce.networkmodel.dto.TopologyShard; +import org.opendaylight.transportpce.networkmodel.util.ClliNetwork; +import org.opendaylight.transportpce.networkmodel.util.OpenRoadmNetwork; +import org.opendaylight.transportpce.networkmodel.util.OpenRoadmTopology; +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.ietf.params.xml.ns.yang.ietf.network.rev150608.NodeId; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.network.rev150608.network.Node; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.network.topology.rev150608.Network1; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.network.topology.rev150608.network.Link; +import org.opendaylight.yang.gen.v1.urn.opendaylight.netconf.node.topology.rev150114.NetconfNodeConnectionStatus; +import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class NetworkModelServiceImpl implements NetworkModelService { + + private static final Logger LOG = LoggerFactory.getLogger(NetworkModelServiceImpl.class); + private static final boolean CREATE_MISSING_PARENTS = true; + + private final DataBroker dataBroker; + private final R2RLinkDiscovery linkDiscovery; + private final DeviceTransactionManager deviceTransactionManager; + private final OpenRoadmTopology openRoadmTopology; + private final PortMapping portMapping; + + public NetworkModelServiceImpl(final DataBroker dataBroker, final R2RLinkDiscovery linkDiscovery, + DeviceTransactionManager deviceTransactionManager, + OpenRoadmTopology openRoadmTopology, PortMapping portMapping) { + this.dataBroker = dataBroker; + this.linkDiscovery = linkDiscovery; + this.deviceTransactionManager = deviceTransactionManager; + this.openRoadmTopology = openRoadmTopology; + this.portMapping = portMapping; + } + + public void init() { + LOG.info("init ..."); + } + + public void close() { + } + + @Override + public void createOpenROADMnode(String nodeId) { + try { + LOG.info("createOpenROADMNode: {} ", nodeId); + + this.portMapping.createMappingData(nodeId); + this.linkDiscovery.readLLDP(new NodeId(nodeId)); + + Node clliNode = ClliNetwork.createNode(this.deviceTransactionManager, nodeId); + if (clliNode == null) { + LOG.error("Unable to create clli node! Node id: {}", nodeId); + return; + } + + Node openRoadmNode = OpenRoadmNetwork.createNode(nodeId, this.deviceTransactionManager); + if (openRoadmNode == null) { + LOG.error("Unable to create OpenRoadm node! Node id: {}", nodeId); + return; + } + + TopologyShard topologyShard = this.openRoadmTopology.createTopologyShard(nodeId); + if (topologyShard == null) { + LOG.error("Unable to create topology shard for node {}!", nodeId); + return; + } + + WriteTransaction writeTransaction = this.dataBroker.newWriteOnlyTransaction(); + LOG.info("creating node in {}", NetworkUtils.CLLI_NETWORK_ID); + InstanceIdentifier iiClliNode = InstanceIdentifier + .builder(Network.class, new NetworkKey(new NetworkId(NetworkUtils.CLLI_NETWORK_ID))) + .child(Node.class, clliNode.getKey()) + .build(); + writeTransaction.merge(LogicalDatastoreType.CONFIGURATION, iiClliNode, clliNode, + CREATE_MISSING_PARENTS); + LOG.info("creating node in {}", NetworkUtils.UNDERLAY_NETWORK_ID); + InstanceIdentifier iiOpenRoadmNode = InstanceIdentifier + .builder(Network.class, new NetworkKey(new NetworkId(NetworkUtils.UNDERLAY_NETWORK_ID))) + .child(Node.class, openRoadmNode.getKey()) + .build(); + writeTransaction.merge(LogicalDatastoreType.CONFIGURATION, iiOpenRoadmNode, openRoadmNode, + CREATE_MISSING_PARENTS); + for (Node openRoadmTopologyNode: topologyShard.getNodes()) { + LOG.info("creating node {} in {}", openRoadmTopologyNode.getNodeId().getValue(), + NetworkUtils.OVERLAY_NETWORK_ID); + InstanceIdentifier iiOpenRoadmTopologyNode = InstanceIdentifier + .builder(Network.class, new NetworkKey(new NetworkId(NetworkUtils.OVERLAY_NETWORK_ID))) + .child(Node.class, openRoadmTopologyNode.getKey()) + .build(); + writeTransaction.merge(LogicalDatastoreType.CONFIGURATION, iiOpenRoadmTopologyNode, + openRoadmTopologyNode, CREATE_MISSING_PARENTS); + } + for (Link openRoadmTopologyLink: topologyShard.getLinks()) { + LOG.info("creating link {} in {}", openRoadmTopologyLink.getLinkId().getValue(), + NetworkUtils.OVERLAY_NETWORK_ID); + InstanceIdentifier iiOpenRoadmTopologyLink = InstanceIdentifier + .builder(Network.class, new NetworkKey(new NetworkId(NetworkUtils.OVERLAY_NETWORK_ID))) + .augmentation(Network1.class) + .child(Link.class, openRoadmTopologyLink.getKey()) + .build(); + writeTransaction.merge(LogicalDatastoreType.CONFIGURATION, iiOpenRoadmTopologyLink, + openRoadmTopologyLink, CREATE_MISSING_PARENTS); + } + writeTransaction.submit().get(); + LOG.info("all nodes and links created"); + } catch (InterruptedException | ExecutionException e) { + LOG.error("ERROR: ", e); + } + } + + @Override + public void setOpenROADMnodeStatus(String nodeId, NetconfNodeConnectionStatus.ConnectionStatus connectionStatus) { + LOG.info("setOpenROADMNodeStatus: {} {}", nodeId, connectionStatus.name()); + /* + TODO: set connection status of the device in model, + TODO: so we don't need to keep it in memory (Set currentMountedDevice) + TODO: unfortunately there is no connection status OpenROADM in network models + TODO: waiting for new model version + */ + } + +} diff --git a/networkmodel/src/main/java/org/opendaylight/transportpce/networkmodel/util/ClliNetwork.java b/networkmodel/src/main/java/org/opendaylight/transportpce/networkmodel/util/ClliNetwork.java new file mode 100644 index 000000000..9c251823c --- /dev/null +++ b/networkmodel/src/main/java/org/opendaylight/transportpce/networkmodel/util/ClliNetwork.java @@ -0,0 +1,119 @@ +/* + * 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.networkmodel.util; + +import java.util.Optional; +import java.util.concurrent.ExecutionException; +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.WriteTransaction; +import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType; +import org.opendaylight.transportpce.common.NetworkUtils; +import org.opendaylight.transportpce.common.Timeouts; +import org.opendaylight.transportpce.common.device.DeviceTransactionManager; +import org.opendaylight.yang.gen.v1.http.org.openroadm.clli.network.rev170626.NetworkTypes1; +import org.opendaylight.yang.gen.v1.http.org.openroadm.clli.network.rev170626.NetworkTypes1Builder; +import org.opendaylight.yang.gen.v1.http.org.openroadm.clli.network.rev170626.Node1; +import org.opendaylight.yang.gen.v1.http.org.openroadm.clli.network.rev170626.Node1Builder; +import org.opendaylight.yang.gen.v1.http.org.openroadm.clli.network.rev170626.network.network.types.ClliNetworkBuilder; +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.Info; +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.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.ietf.params.xml.ns.yang.ietf.network.rev150608.NodeId; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.network.rev150608.network.NetworkTypesBuilder; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.network.rev150608.network.Node; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.network.rev150608.network.NodeBuilder; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.network.rev150608.network.NodeKey; +import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; +import org.opendaylight.yangtools.yang.binding.InstanceIdentifier.InstanceIdentifierBuilder; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class ClliNetwork { + + private static final Logger LOG = LoggerFactory.getLogger(ClliNetwork.class); + + private ClliNetwork() { + // utility class + } + + /** + * This public method creates the CLLI Layer and posts it to the controller. + */ + public static void createClliLayer(DataBroker controllerdb) { + try { + Network clliNetwork = createNetwork(); + InstanceIdentifierBuilder nwIID = InstanceIdentifier.builder( + Network.class,new NetworkKey(new NetworkId(NetworkUtils.CLLI_NETWORK_ID))); + WriteTransaction wrtx = controllerdb.newWriteOnlyTransaction(); + wrtx.put(LogicalDatastoreType.CONFIGURATION, nwIID.build(), clliNetwork); + wrtx.submit().get(1, TimeUnit.SECONDS); + LOG.info("CLLI-Network created successfully."); + } catch (ExecutionException | TimeoutException | InterruptedException e) { + LOG.warn("Failed to create CLLI-Network", e); + } + } + + /** + * Create single node entry for CLLI topology. + * + */ + public static Node createNode(DeviceTransactionManager deviceTransactionManager, String deviceId) { + //Read clli from the device + InstanceIdentifier infoIID = InstanceIdentifier.create(OrgOpenroadmDevice.class).child(Info.class); + Optional deviceInfo = deviceTransactionManager.getDataFromDevice(deviceId, + LogicalDatastoreType.OPERATIONAL, infoIID, Timeouts.DEVICE_READ_TIMEOUT, + Timeouts.DEVICE_READ_TIMEOUT_UNIT); + String clli; + if (deviceInfo.isPresent()) { + clli = deviceInfo.get().getClli(); + } else { + return null; + } + /* + * Create node in the CLLI layer of the network model + * with nodeId equal to the clli attribute in the device + * model's info subtree + */ + NodeBuilder nodeBldr = new NodeBuilder(); + NodeId nwNodeId = new NodeId(clli); + nodeBldr.setNodeId(nwNodeId); + nodeBldr.setKey(new NodeKey(nwNodeId)); + /* + * create clli node augmentation + * defined in openroadm-clli-network.yang + */ + Node1Builder clliAugmentationBldr = new Node1Builder(); + clliAugmentationBldr.setClli(clli); + nodeBldr.addAugmentation(Node1.class, clliAugmentationBldr.build()); + return nodeBldr.build(); + } + + /** + * Create empty CLLI network. + */ + private static Network createNetwork() { + NetworkBuilder nwBuilder = new NetworkBuilder(); + NetworkId nwId = new NetworkId(NetworkUtils.CLLI_NETWORK_ID); + nwBuilder.setNetworkId(nwId); + nwBuilder.setKey(new NetworkKey(nwId)); + //set network type to clli + NetworkTypes1Builder clliNetworkTypesBldr = new NetworkTypes1Builder(); + clliNetworkTypesBldr.setClliNetwork(new ClliNetworkBuilder().build()); + NetworkTypesBuilder nwTypeBuilder = new NetworkTypesBuilder(); + nwTypeBuilder.addAugmentation(NetworkTypes1.class, clliNetworkTypesBldr.build()); + nwBuilder.setNetworkTypes(nwTypeBuilder.build()); + return nwBuilder.build(); + } +} diff --git a/networkmodel/src/main/java/org/opendaylight/transportpce/networkmodel/util/LinkIdUtil.java b/networkmodel/src/main/java/org/opendaylight/transportpce/networkmodel/util/LinkIdUtil.java new file mode 100644 index 000000000..cf6eed3be --- /dev/null +++ b/networkmodel/src/main/java/org/opendaylight/transportpce/networkmodel/util/LinkIdUtil.java @@ -0,0 +1,115 @@ +/* + * 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.networkmodel.util; + +import java.text.MessageFormat; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.network.topology.rev150608.LinkId; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.networkutils.rev170818.InitRoadmNodesInput; + +public final class LinkIdUtil { + + private static final String NETWORK = "-NETWORK"; + private static final String TRANSMIT = "-TX"; + private static final String RECEIVE = "-RX"; + private static final String BIDIRECTIONAL = "-TXRX"; + private static final MessageFormat LINK_ID_FORMAT = new MessageFormat("{0}-{1}to{2}-{3}"); + + private LinkIdUtil() { + // utility class + } + + /** + * Builds the Link id in format {@link LinkIdUtil#LINK_ID_FORMAT}. + * + * @param srcNode source node id string + * @param srcTp source termination point + * @param destNode destination node id + * @param destTp destination termination point + * @return {@link LinkId} + */ + public static LinkId buildLinkId(String srcNode, String srcTp, String destNode, String destTp) { + return new LinkId(LINK_ID_FORMAT + .format(new Object[] {srcNode, srcTp, destNode, destTp}, new StringBuffer(), null).toString()); + } + + /** + * Builds the opposite {@link LinkId} from the {@link InitRoadmNodesInput}. + * + * @param input an init link for ROADM nodes + * @return opposite {@link LinkId} + */ + public static LinkId getRdm2RdmOppositeLinkId(InitRoadmNodesInput input) { + String srcNode = new StringBuilder(input.getRdmANode()).append("-DEG").append(input.getDegANum()).toString(); + String srcTp = input.getTerminationPointA(); + String destNode = new StringBuilder(input.getRdmZNode()).append("-DEG").append(input.getDegZNum()).toString(); + String destTp = input.getTerminationPointZ(); + + Object[] params = buildParams(srcNode, srcTp, destNode, destTp, false); + + return new LinkId(LINK_ID_FORMAT.format(params, new StringBuffer(), null).toString()); + } + + /** + * Builds the opposite {@link LinkId} from string descriptors. + * + * @param srcNode a source node + * @param srcTp a source termination point + * @param destNode a destination node + * @param destTp a destination termination point + * @return LinkId a link identifier + */ + public static LinkId getOppositeLinkId(String srcNode, String srcTp, String destNode, String destTp) { + return getOppositeLinkId(srcNode, srcTp, destNode, destTp, true); + } + + /** + * Builds the opposite {@link LinkId} from string descriptors. + * + * @param srcNode a source node + * @param srcTp a source termination point + * @param destNode a destination node + * @param destTp a destination termination point + * @return LinkId a link identifier + */ + public static LinkId getOppositeLinkId(String srcNode, String srcTp, String destNode, String destTp, + boolean checkNode) { + Object[] params = buildParams(srcNode, srcTp, destNode, destTp, checkNode); + return new LinkId(LINK_ID_FORMAT.format(params, new StringBuffer(), null).toString()); + } + + private static Object[] buildParams(String srcNode, String srcTp, String destNode, String destTp, + boolean checkForNetwork) { + Object[] params = null; + if (checkBidirectional(checkForNetwork, srcTp)) { + if (checkBidirectional(checkForNetwork, destTp)) { + params = new Object[] {destNode, destTp, srcNode, srcTp}; + } else if (destTp.contains(RECEIVE)) { + params = new Object[] {destNode, destTp.replace("RX", "TX"), srcNode, srcTp}; + } else { + throw new IllegalArgumentException("Dest Termination Point is either RX/TX_RX ! Check TP"); + } + } else if (srcTp.contains(TRANSMIT)) { + String replacedSrcTp = srcTp.replace("TX", "RX"); + if (checkBidirectional(checkForNetwork, destTp)) { + params = new Object[] {destNode, destTp, srcNode, replacedSrcTp}; + } else if (destTp.contains(RECEIVE)) { + params = new Object[] {destNode, destTp.replace("RX", "TX"), srcNode, replacedSrcTp}; + } else { + throw new IllegalArgumentException("Dest Termination Point is either RX/TX_RX ! Check TP"); + } + } else { + throw new IllegalArgumentException("SRC Termination Point is either TX/TXRX ! Check TP"); + } + return params; + } + + private static boolean checkBidirectional(boolean check, String tp) { + return tp.contains(BIDIRECTIONAL) || (check && tp.contains(NETWORK)); + } +} diff --git a/networkmodel/src/main/java/org/opendaylight/transportpce/networkmodel/util/OpenRoadmNetwork.java b/networkmodel/src/main/java/org/opendaylight/transportpce/networkmodel/util/OpenRoadmNetwork.java new file mode 100644 index 000000000..2292cf192 --- /dev/null +++ b/networkmodel/src/main/java/org/opendaylight/transportpce/networkmodel/util/OpenRoadmNetwork.java @@ -0,0 +1,148 @@ +/* + * 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.networkmodel.util; + +import com.google.common.collect.ImmutableList; + +import java.util.Optional; +import java.util.concurrent.ExecutionException; +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.WriteTransaction; +import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType; +import org.opendaylight.transportpce.common.NetworkUtils; +import org.opendaylight.transportpce.common.Timeouts; +import org.opendaylight.transportpce.common.device.DeviceTransactionManager; +import org.opendaylight.yang.gen.v1.http.org.openroadm.common.types.rev161014.NodeTypes; +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.Info; +import org.opendaylight.yang.gen.v1.http.org.openroadm.network.rev170929.NetworkTypes1; +import org.opendaylight.yang.gen.v1.http.org.openroadm.network.rev170929.NetworkTypes1Builder; +import org.opendaylight.yang.gen.v1.http.org.openroadm.network.rev170929.Node1; +import org.opendaylight.yang.gen.v1.http.org.openroadm.network.rev170929.Node1Builder; +import org.opendaylight.yang.gen.v1.http.org.openroadm.network.rev170929.network.network.types.OpenroadmNetworkBuilder; +import org.opendaylight.yang.gen.v1.http.org.openroadm.network.types.rev170929.OpenroadmNodeType; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.IpAddress; +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.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.ietf.params.xml.ns.yang.ietf.network.rev150608.NodeId; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.network.rev150608.network.NetworkTypesBuilder; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.network.rev150608.network.Node; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.network.rev150608.network.NodeBuilder; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.network.rev150608.network.NodeKey; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.network.rev150608.network.node.SupportingNodeBuilder; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.network.rev150608.network.node.SupportingNodeKey; +import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; +import org.opendaylight.yangtools.yang.binding.InstanceIdentifier.InstanceIdentifierBuilder; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + + +public class OpenRoadmNetwork { + + private static final Logger LOG = LoggerFactory.getLogger(OpenRoadmNetwork.class); + + private OpenRoadmNetwork() { + // utility class + } + + /** + * This public method creates the OpenRoadmNetwork Layer and posts it to the controller. + */ + public static void createOpenRoadmNetworkLayer(DataBroker controllerdb) { + try { + Network openRoadmNetwork = createOpenRoadmNetwork(); + InstanceIdentifierBuilder nwIID = InstanceIdentifier.builder(Network.class, + new NetworkKey(new NetworkId(NetworkUtils.UNDERLAY_NETWORK_ID))); + WriteTransaction wrtx = controllerdb.newWriteOnlyTransaction(); + wrtx.put(LogicalDatastoreType.CONFIGURATION, nwIID.build(), openRoadmNetwork); + wrtx.submit().get(1, TimeUnit.SECONDS); + LOG.info("OpenRoadm-Network created successfully."); + } catch (ExecutionException | TimeoutException | InterruptedException e) { + LOG.warn("Failed to create OpenRoadm-Network", e); + } + } + + /** + * Create single node entry for OpenRoadmNetwork. + * + */ + public static Node createNode(String nodeId, DeviceTransactionManager deviceTransactionManager) { + // Fetches the info from the deviceInfo + InstanceIdentifier infoIID = InstanceIdentifier.create(OrgOpenroadmDevice.class).child(Info.class); + Optional deviceInfoOpt = + deviceTransactionManager.getDataFromDevice(nodeId, LogicalDatastoreType.OPERATIONAL, infoIID, + Timeouts.DEVICE_READ_TIMEOUT, Timeouts.DEVICE_READ_TIMEOUT_UNIT); + Info deviceInfo; + if (deviceInfoOpt.isPresent()) { + deviceInfo = deviceInfoOpt.get(); + } else { + LOG.error("Unable to get device info from device {}!", nodeId); + return null; + } + NodeTypes nodeType = deviceInfo.getNodeType(); + + // Uses the Node Builder to set the nodeId and Key + NodeBuilder nodeBldr = new NodeBuilder(); + NodeId nwNodeId = new NodeId(nodeId); + nodeBldr.setNodeId(nwNodeId); + nodeBldr.setKey(new NodeKey(nwNodeId)); + Node1Builder node1bldr = new Node1Builder(); + + /* + * If the type of the Node is ROADM, Node type is set to ROADM Else, XPONDER + */ + if (nodeType.getIntValue() == 1) { + node1bldr.setNodeType(OpenroadmNodeType.ROADM); + } else if (nodeType.getIntValue() == 3) { + node1bldr.setNodeType(OpenroadmNodeType.XPONDER); + } + + String vendor = deviceInfo.getVendor(); + String model = deviceInfo.getModel(); + IpAddress ipAddress = deviceInfo.getIpAddress(); + // Sets IP, Model and Vendor information fetched from the deviceInfo + node1bldr.setIp(ipAddress); + node1bldr.setModel(model); + node1bldr.setVendor(vendor); + + // Sets the value of Network-ref and Node-ref as a part of the supporting node attribute + String clli = deviceInfo.getClli(); + SupportingNodeBuilder supportbldr = new SupportingNodeBuilder(); + supportbldr.setKey(new SupportingNodeKey(new NetworkId(NetworkUtils.CLLI_NETWORK_ID), new NodeId(clli))); + supportbldr.setNetworkRef(new NetworkId(NetworkUtils.CLLI_NETWORK_ID)); + supportbldr.setNodeRef(new NodeId(clli)); + nodeBldr.setSupportingNode(ImmutableList.of(supportbldr.build())); + + // Augment to the main node builder + nodeBldr.addAugmentation(Node1.class, node1bldr.build()); + return nodeBldr.build(); + } + + /** + * Create empty OpenROADM network. + */ + private static Network createOpenRoadmNetwork() { + NetworkBuilder openrdmnwBuilder = new NetworkBuilder(); + NetworkId nwId = new NetworkId(NetworkUtils.UNDERLAY_NETWORK_ID); + openrdmnwBuilder.setNetworkId(nwId); + openrdmnwBuilder.setKey(new NetworkKey(nwId)); + //sets network type to OpenRoadmNetwork + NetworkTypes1Builder openRoadmNetworkTypesBldr = new NetworkTypes1Builder(); + openRoadmNetworkTypesBldr.setOpenroadmNetwork(new OpenroadmNetworkBuilder().build()); + NetworkTypesBuilder openrdmnwTypeBuilder = new NetworkTypesBuilder(); + openrdmnwTypeBuilder.addAugmentation(NetworkTypes1.class, openRoadmNetworkTypesBldr.build()); + openrdmnwBuilder.setNetworkTypes(openrdmnwTypeBuilder.build()); + return openrdmnwBuilder.build(); + } +} diff --git a/networkmodel/src/main/java/org/opendaylight/transportpce/networkmodel/util/OpenRoadmTopology.java b/networkmodel/src/main/java/org/opendaylight/transportpce/networkmodel/util/OpenRoadmTopology.java new file mode 100644 index 000000000..3a23f7cf1 --- /dev/null +++ b/networkmodel/src/main/java/org/opendaylight/transportpce/networkmodel/util/OpenRoadmTopology.java @@ -0,0 +1,833 @@ +/* + * 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.networkmodel.util; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import java.util.Optional; +import java.util.concurrent.ExecutionException; +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.WriteTransaction; +import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType; +import org.opendaylight.transportpce.common.NetworkUtils; +import org.opendaylight.transportpce.common.Timeouts; +import org.opendaylight.transportpce.common.device.DeviceTransactionManager; +import org.opendaylight.transportpce.networkmodel.dto.NodeData; +import org.opendaylight.transportpce.networkmodel.dto.TopologyShard; +import org.opendaylight.yang.gen.v1.http.org.openroadm.common.types.rev161014.NodeTypes; +import org.opendaylight.yang.gen.v1.http.org.openroadm.degree.rev170929.degree.node.attributes.AvailableWavelengths; +import org.opendaylight.yang.gen.v1.http.org.openroadm.degree.rev170929.degree.node.attributes.AvailableWavelengthsBuilder; +import org.opendaylight.yang.gen.v1.http.org.openroadm.degree.rev170929.degree.node.attributes.AvailableWavelengthsKey; +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.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.network.topology.rev170929.Link1; +import org.opendaylight.yang.gen.v1.http.org.openroadm.network.topology.rev170929.Link1Builder; +import org.opendaylight.yang.gen.v1.http.org.openroadm.network.topology.rev170929.NetworkTypes1; +import org.opendaylight.yang.gen.v1.http.org.openroadm.network.topology.rev170929.NetworkTypes1Builder; +import org.opendaylight.yang.gen.v1.http.org.openroadm.network.topology.rev170929.Node1; +import org.opendaylight.yang.gen.v1.http.org.openroadm.network.topology.rev170929.Node1Builder; +import org.opendaylight.yang.gen.v1.http.org.openroadm.network.topology.rev170929.TerminationPoint1; +import org.opendaylight.yang.gen.v1.http.org.openroadm.network.topology.rev170929.TerminationPoint1Builder; +import org.opendaylight.yang.gen.v1.http.org.openroadm.network.topology.rev170929.network.network.types.OpenroadmTopologyBuilder; +import org.opendaylight.yang.gen.v1.http.org.openroadm.network.topology.rev170929.network.node.DegreeAttributesBuilder; +import org.opendaylight.yang.gen.v1.http.org.openroadm.network.topology.rev170929.network.node.SrgAttributesBuilder; +import org.opendaylight.yang.gen.v1.http.org.openroadm.network.topology.rev170929.network.node.termination.point.XpdrClientAttributesBuilder; +import org.opendaylight.yang.gen.v1.http.org.openroadm.network.topology.rev170929.network.node.termination.point.XpdrNetworkAttributesBuilder; +import org.opendaylight.yang.gen.v1.http.org.openroadm.network.types.rev170929.OpenroadmLinkType; +import org.opendaylight.yang.gen.v1.http.org.openroadm.network.types.rev170929.OpenroadmNodeType; +import org.opendaylight.yang.gen.v1.http.org.openroadm.network.types.rev170929.OpenroadmTpType; +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.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.ietf.params.xml.ns.yang.ietf.network.rev150608.NodeId; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.network.rev150608.network.NetworkTypesBuilder; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.network.rev150608.network.Node; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.network.rev150608.network.NodeBuilder; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.network.rev150608.network.NodeKey; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.network.rev150608.network.node.SupportingNode; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.network.rev150608.network.node.SupportingNodeBuilder; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.network.rev150608.network.node.SupportingNodeKey; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.network.topology.rev150608.LinkId; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.network.topology.rev150608.Network1; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.network.topology.rev150608.Network1Builder; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.network.topology.rev150608.TpId; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.network.topology.rev150608.network.Link; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.network.topology.rev150608.network.LinkBuilder; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.network.topology.rev150608.network.LinkKey; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.network.topology.rev150608.network.link.DestinationBuilder; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.network.topology.rev150608.network.link.SourceBuilder; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.network.topology.rev150608.network.node.TerminationPoint; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.network.topology.rev150608.network.node.TerminationPointBuilder; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.network.topology.rev150608.network.node.TerminationPointKey; +import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; +import org.opendaylight.yangtools.yang.binding.InstanceIdentifier.InstanceIdentifierBuilder; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class OpenRoadmTopology { + + private static final Logger LOG = LoggerFactory.getLogger(OpenRoadmTopology.class); + private static final int DEFAULT_PORT_DIRECTION = -1; + private static final int MAX_DEGREE = 20; + private static final int MAX_SRG = 20; + + private final DataBroker dataBroker; + private final DeviceTransactionManager deviceTransactionManager; + + public OpenRoadmTopology(DataBroker dataBroker, DeviceTransactionManager deviceTransactionManager) { + this.dataBroker = dataBroker; + this.deviceTransactionManager = deviceTransactionManager; + } + + /** + * This public method creates the OpenROADM Topology Layer and posts it to the controller. + */ + public void createTopoLayer(DataBroker controllerdb) { + try { + Network openRoadmTopology = createOpenRoadmTopology(); + InstanceIdentifierBuilder nwIID = InstanceIdentifier.builder(Network.class, + new NetworkKey(new NetworkId(NetworkUtils.OVERLAY_NETWORK_ID))); + WriteTransaction wrtx = controllerdb.newWriteOnlyTransaction(); + wrtx.put(LogicalDatastoreType.CONFIGURATION, nwIID.build(), openRoadmTopology); + wrtx.submit().get(1, TimeUnit.SECONDS); + LOG.info("OpenRoadm-Topology created successfully."); + } catch (ExecutionException | TimeoutException | InterruptedException e) { + LOG.warn("Failed to create OpenRoadm-Topology", e); + } + } + + /** + * Create empty OpenROADM topology. + */ + private Network createOpenRoadmTopology() { + NetworkBuilder nwBuilder = new NetworkBuilder(); + NetworkId nwId = new NetworkId(NetworkUtils.OVERLAY_NETWORK_ID); + nwBuilder.setNetworkId(nwId); + nwBuilder.setKey(new NetworkKey(nwId)); + // set network type to Transport Underlay + NetworkTypes1Builder topoNetworkTypesBldr = new NetworkTypes1Builder(); + topoNetworkTypesBldr.setOpenroadmTopology(new OpenroadmTopologyBuilder().build()); + NetworkTypesBuilder nwTypeBuilder = new NetworkTypesBuilder(); + nwTypeBuilder.addAugmentation(NetworkTypes1.class, topoNetworkTypesBldr.build()); + nwBuilder.setNetworkTypes(nwTypeBuilder.build()); + // Array to store nodes in the topolayer of a roadm/Xponder + Network1Builder nwBldr1 = new Network1Builder(); + // adding expressLinks + nwBldr1.setLink(Collections.emptyList()); + nwBuilder.addAugmentation(Network1.class, nwBldr1.build()); + nwBuilder.setNode(Collections.emptyList()); + return nwBuilder.build(); + } + + public TopologyShard createTopologyShard(String nodeId) { + int numOfDegrees; + int numOfSrgs; + int portDirectionEnum = DEFAULT_PORT_DIRECTION; + + InstanceIdentifier infoIID = InstanceIdentifier.create(OrgOpenroadmDevice.class).child(Info.class); + java.util.Optional deviceInfoOpt = + this.deviceTransactionManager.getDataFromDevice(nodeId, LogicalDatastoreType.OPERATIONAL, infoIID, + Timeouts.DEVICE_READ_TIMEOUT, Timeouts.DEVICE_READ_TIMEOUT_UNIT); + Info deviceInfo; + if (deviceInfoOpt.isPresent()) { + deviceInfo = deviceInfoOpt.get(); + } else { + LOG.error("Unable to get device info for device {}!", nodeId); + return null; + } + List nodes = new ArrayList<>(); + + // Check if node is ROADM + if (NodeTypes.Rdm.equals(deviceInfo.getNodeType())) { + + /* + * Adding Degree Node Get Degree Number -> x then get connection ports then find the port directions + * to decide whether TX/RX/TXRX Get value for max degree from info subtree, required for iteration + * if not present assume to be 20 (temporary) + */ + + Integer maxDegree; + if (deviceInfo.getMaxDegrees() != null) { + maxDegree = deviceInfo.getMaxDegrees(); + } else { + maxDegree = MAX_DEGREE; + } + + // Starting with degree Number = 1 + Integer degreeCounter = 1; + + while (degreeCounter <= maxDegree) { + LOG.info("creating degree node {}/{}", degreeCounter, maxDegree); + NodeData nodeData = createDegreeNode(nodeId, degreeCounter); + if (nodeData != null) { + NodeBuilder tempNode = nodeData.getNodeBuilder(); + portDirectionEnum = nodeData.getPortDirectionEnum(); + nodes.add(tempNode.build()); + degreeCounter++; + } else { + // null returned if Degree number= degreeCounter not present in the device + break; + } + } + numOfDegrees = degreeCounter - 1; + + Integer maxSrg; + if (deviceInfo.getMaxSrgs() != null) { + maxSrg = deviceInfo.getMaxSrgs(); + } else { + maxSrg = MAX_SRG; + } + + // Starting with degree Number = 1 + Integer srgCounter = 1; + + while (srgCounter <= maxSrg) { + LOG.info("creating SRG node {}/{}", srgCounter, maxSrg); + NodeBuilder tempNode = createSrgNode(nodeId, srgCounter, portDirectionEnum); + + if (tempNode != null) { + nodes.add(tempNode.build()); + srgCounter++; + } else { + // null returned if Degree number= degreeCounter not present in the device + break; + } + } + numOfSrgs = srgCounter - 1; + + + LOG.info("adding links numOfDegrees={} numOfSrgs={}", numOfDegrees, numOfSrgs); + List links = new ArrayList<>(); + links.addAll(createExpressLinks(nodeId, numOfDegrees, portDirectionEnum)); + links.addAll(createAddDropLinks(nodeId, numOfDegrees, numOfSrgs, portDirectionEnum)); + LOG.info("created nodes/links: {}/{}", nodes.size(), links.size()); + return new TopologyShard(nodes, links); + } else if (NodeTypes.Xpdr.equals(deviceInfo.getNodeType())) { + // Check if node is XPONDER + Integer clientport = getNoOfClientPorts(nodeId); + List links = new ArrayList<>(); + Integer clientCounter = 1; + Integer lineCounter = 1; + while (clientCounter <= clientport) { + NodeBuilder tempNode = createXpdr(clientCounter, lineCounter, nodeId); + if (tempNode == null) { + break; + } + nodes.add(tempNode.build()); + clientCounter++; + lineCounter++; + LOG.info("Entered this loop"); + } + return new TopologyShard(nodes, links); + } + + return null; + } + + /** + * 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 + */ + private int getNoOfClientPorts(String deviceId) { + // Creating for Xponder Line and Client Ports + InstanceIdentifier deviceIID = InstanceIdentifier.create(OrgOpenroadmDevice.class); + Optional deviceObject = + this.deviceTransactionManager.getDataFromDevice(deviceId, LogicalDatastoreType.OPERATIONAL, deviceIID, + Timeouts.DEVICE_READ_TIMEOUT, Timeouts.DEVICE_READ_TIMEOUT_UNIT); + + // Variable to keep track of number of client ports + int client = 1; + if (deviceObject.isPresent()) { + for (CircuitPacks cp : deviceObject.get().getCircuitPacks()) { + if (cp.getPorts() != null) { + for (Ports port : cp.getPorts()) { + if (port.getPortQual() != null) { + if (port.getPortQual().getIntValue() == 4) { + client++; + } + } + } + } + } + } else { + return 0; + } + return client; + } + + private NodeBuilder createXpdr(Integer clientCounter, Integer lineCounter, String nodeId) { + // Create a generic Topo Layer node + NodeBuilder nodebldr = createTopoLayerNode(nodeId); + // Create augmentation node to inorder to add degree + Node1Builder node1bldr = new Node1Builder(); + TerminationPoint1Builder tp1Bldr = new TerminationPoint1Builder(); + TerminationPointBuilder tempTpBldr; + + // set node type to Xponder + node1bldr.setNodeType(OpenroadmNodeType.XPONDER); + List tpList = new ArrayList<>(); + String nodeIdtopo = new StringBuilder().append(nodeId).append("-XPDR1").toString(); + // Ad degree node specific augmentation + nodebldr.setNodeId(new NodeId(nodeIdtopo)); + nodebldr.setKey(new NodeKey(new NodeId(nodeIdtopo))); + nodebldr.addAugmentation(Node1.class, node1bldr.build()); + while (clientCounter != 0) { + // Create CLNT-TX termination + tempTpBldr = createTpBldr("XPDR1-CLIENT" + clientCounter); + tp1Bldr.setTpType(OpenroadmTpType.XPONDERCLIENT); + XpdrClientAttributesBuilder xpdrClntBldr = new XpdrClientAttributesBuilder(); + xpdrClntBldr.setTailEquipmentId("XPDR1-NETWORK" + clientCounter); + tp1Bldr.setXpdrClientAttributes(xpdrClntBldr.build()); + tempTpBldr.addAugmentation(TerminationPoint1.class, tp1Bldr.build()); + tpList.add(tempTpBldr.build()); + clientCounter--; + } + while (lineCounter != 0) { + // Create LINE-TX termination + tempTpBldr = (createTpBldr("XPDR1-NETWORK" + lineCounter)); + tp1Bldr.setTpType(OpenroadmTpType.XPONDERNETWORK); + XpdrNetworkAttributesBuilder xpdrNwAttrBldr = new XpdrNetworkAttributesBuilder(); + xpdrNwAttrBldr.setTailEquipmentId("XPDR1-CLIENT" + lineCounter); + tp1Bldr.setXpdrNetworkAttributes(xpdrNwAttrBldr.build()); + tempTpBldr.addAugmentation(TerminationPoint1.class, tp1Bldr.build()); + tpList.add(tempTpBldr.build()); + lineCounter--; + } + LOG.info("printing tpList {}",tpList); + org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.network.topology.rev150608.Node1Builder tpNode1 = + new org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.network.topology.rev150608.Node1Builder(); + tpNode1.setTerminationPoint(tpList); + nodebldr.addAugmentation( + org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.network.topology.rev150608.Node1.class, + tpNode1.build()); + LOG.info("The nodebldr {}",nodebldr); + return nodebldr; + } + + + private NodeData createDegreeNode(String nodeId, int degreeCounter) { + // Create augmentation node to inorder to add degree + Node1Builder node1bldr = new Node1Builder(); + // set node type to degree + node1bldr.setNodeType(OpenroadmNodeType.DEGREE); + + // Get connection ports on degree number = degreeCounter in order to get port + // direction + List degreeConPorts = getDegreePorts(nodeId, degreeCounter); + if ((degreeConPorts == null) || degreeConPorts.isEmpty()) { + return null; + } + + DegreeAttributesBuilder degAttBldr = new DegreeAttributesBuilder(); + degAttBldr.setDegreeNumber(degreeCounter); + degAttBldr.setAvailableWavelengths(create96AvalWaveDegree()); + node1bldr.setDegreeAttributes(degAttBldr.build()); + + String nodeIdtopo = new StringBuilder(nodeId).append("-DEG").append(degreeCounter).toString(); + // Create a generic Topo Layer node + NodeBuilder nodebldr = createTopoLayerNode(nodeId); + nodebldr.setNodeId(new NodeId(nodeIdtopo)); + // Ad degree node specific augmentation + nodebldr.addAugmentation(Node1.class, node1bldr.build()); + // Get Port direction + int portDirectionEnum = getPortDirection(nodeId, degreeConPorts.get(0).getCircuitPackName(), + degreeConPorts.get(0).getPortName().toString()); + + /* + * if bi-directional then create 2 tp's : + * + * --> TTP-TXRX --> CTP-TXRX + * + * if uni-directional : + * + * --> TTP-TX + * --> TTP-RX + * --> CTP-TX + * --> CTP-RX + */ + TerminationPoint1Builder tp1Bldr = new TerminationPoint1Builder(); + TerminationPointBuilder tempTpBldr; + + List tpList = new ArrayList<>(); + if ((portDirectionEnum == 1) || (portDirectionEnum == 2)) { + // ports are uni Directional on a degree, therefore 4 termination points + // Create TTP-TX termination + + tempTpBldr = createTpBldr("DEG" + degreeCounter + "-TTP-TX"); + tp1Bldr.setTpType(OpenroadmTpType.DEGREETXTTP); + tempTpBldr.addAugmentation(TerminationPoint1.class, tp1Bldr.build()); + tpList.add(tempTpBldr.build()); + + // Create TTP-RX termination + tp1Bldr = new TerminationPoint1Builder(); + tempTpBldr = createTpBldr("DEG" + degreeCounter + "-TTP-RX"); + tp1Bldr.setTpType(OpenroadmTpType.DEGREERXTTP); + + tempTpBldr.addAugmentation(TerminationPoint1.class,tp1Bldr.build()); + tpList.add(tempTpBldr.build()); + + // Create CTP-TX termination + tp1Bldr = new TerminationPoint1Builder(); + tempTpBldr = createTpBldr("DEG" + degreeCounter + "-CTP-TX"); + tp1Bldr.setTpType(OpenroadmTpType.DEGREETXCTP); + tempTpBldr.addAugmentation(TerminationPoint1.class,tp1Bldr.build()); + tpList.add(tempTpBldr.build()); + + // Create CTP-RX termination + tp1Bldr = new TerminationPoint1Builder(); + tempTpBldr = createTpBldr("DEG" + degreeCounter + "-CTP-RX"); + tp1Bldr.setTpType(OpenroadmTpType.DEGREERXCTP); + tempTpBldr.addAugmentation(TerminationPoint1.class,tp1Bldr.build()); + tpList.add(tempTpBldr.build()); + + } else if (portDirectionEnum == 3) { + // Ports are bi directional therefore 2 termination points + // Create TTP-TXRX termination + tp1Bldr = new TerminationPoint1Builder(); + tempTpBldr = createTpBldr("DEG" + degreeCounter + "-TTP-TXRX"); + tp1Bldr.setTpType(OpenroadmTpType.DEGREETXRXTTP); + tempTpBldr.addAugmentation(TerminationPoint1.class,tp1Bldr.build()); + tpList.add(tempTpBldr.build()); + + // Create CTP-TXRX termination + tp1Bldr = new TerminationPoint1Builder(); + tempTpBldr = createTpBldr("DEG" + degreeCounter + "-CTP-TXRX"); + tp1Bldr.setTpType(OpenroadmTpType.DEGREETXRXCTP); + tempTpBldr.addAugmentation(TerminationPoint1.class,tp1Bldr.build()); + tpList.add(tempTpBldr.build()); + + } + + org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.network.topology.rev150608.Node1Builder tpNode1 = + new org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.network.topology.rev150608.Node1Builder(); + + tpNode1.setTerminationPoint(tpList); + + nodebldr.addAugmentation( + org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.network.topology.rev150608.Node1.class, + tpNode1.build()); + return new NodeData(nodebldr, portDirectionEnum); + } + + + private NodeBuilder createSrgNode(String nodeId, int srgCounter, int portDirectionEnum) { + // Create augmentation node to inorder to add degree + Node1Builder node1bldr = new Node1Builder(); + // set node type to degree + node1bldr.setNodeType(OpenroadmNodeType.SRG); + + node1bldr.setNodeType(OpenroadmNodeType.SRG); + + SrgAttributesBuilder srgAttrBldr = new SrgAttributesBuilder(); + srgAttrBldr.setAvailableWavelengths(create96AvalWaveSrg()); + node1bldr.setSrgAttributes(srgAttrBldr.build()); + + // Create a generic Topo Layer node + NodeBuilder nodebldr = createTopoLayerNode(nodeId); + nodebldr.addAugmentation(Node1.class, node1bldr.build()); + + // Get connection ports on degree number = degreeCounter in order to get port + // direction + int maxPpPorts = getMaxPp(nodeId, srgCounter); + if (maxPpPorts == -1) { + return null; + } + + + String nodeIdtopo = new StringBuilder().append(nodeId).append("-SRG").append(srgCounter).toString(); + nodebldr.setNodeId(new NodeId(nodeIdtopo)); + List tpList = new ArrayList<>(); + + TerminationPoint1Builder tp1Bldr; + TerminationPointBuilder tempTpBldr; + + for (int i = 1; i <= maxPpPorts; i++) { + if ((portDirectionEnum == 1) || (portDirectionEnum == 2)) { + if (i >= (maxPpPorts / 2)) { + break; + } + // ports are uni Directional on a degree, therefore 4 termination points + // Create TTP-TX termination + tempTpBldr = createTpBldr("SRG" + srgCounter + "-PP" + i + "-TX"); + tp1Bldr = new TerminationPoint1Builder(); + tp1Bldr.setTpType(OpenroadmTpType.SRGTXPP); + tempTpBldr.addAugmentation(TerminationPoint1.class, tp1Bldr.build()); + tpList.add(tempTpBldr.build()); + + // Create TTP-RX termination + tempTpBldr = createTpBldr("SRG" + srgCounter + "-PP" + i + "-RX"); + tp1Bldr = new TerminationPoint1Builder(); + tp1Bldr.setTpType(OpenroadmTpType.SRGRXPP); + tempTpBldr.addAugmentation(TerminationPoint1.class, tp1Bldr.build()); + tpList.add(tempTpBldr.build()); + + } else if (portDirectionEnum == 3) { + // Ports are bi directional therefore 2 termination points + // Create TTP-TXRX termination + tempTpBldr = createTpBldr("SRG" + srgCounter + "-PP" + i + "-TXRX"); + tp1Bldr = new TerminationPoint1Builder(); + tp1Bldr.setTpType(OpenroadmTpType.SRGTXRXPP); + tempTpBldr.addAugmentation(TerminationPoint1.class, tp1Bldr.build()); + tpList.add(tempTpBldr.build()); + } + } + + org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.network.topology.rev150608.Node1Builder tpNode1 = + new org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.network.topology.rev150608.Node1Builder(); + + tpNode1.setTerminationPoint(tpList); + + nodebldr.addAugmentation( + org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.network.topology.rev150608.Node1.class, + tpNode1.build()); + + return nodebldr; + } + + /* + * This method will return the TTP ports in the device for a given degree number to be used by the + * node to create TTP and CTP termination point on the device + */ + private List getDegreePorts(String deviceId, Integer degreeCounter) { + List degreeConPorts = new ArrayList<>(); + LOG.info("Getting Connection ports for Degree Number {}", degreeCounter); + InstanceIdentifier deviceIID = + InstanceIdentifier.create(OrgOpenroadmDevice.class).child(Degree.class, new DegreeKey(degreeCounter)); + + Optional ordmDegreeObject = + this.deviceTransactionManager.getDataFromDevice(deviceId, LogicalDatastoreType.CONFIGURATION, deviceIID, + Timeouts.DEVICE_READ_TIMEOUT, Timeouts.DEVICE_READ_TIMEOUT_UNIT); + + if (ordmDegreeObject.isPresent()) { + degreeConPorts.addAll(new ArrayList<>(ordmDegreeObject.get().getConnectionPorts())); + } else { + LOG.info("Device has {} degree", (degreeCounter - 1)); + return Collections.emptyList(); + } + return degreeConPorts; + } + + private int getMaxPp(String deviceId, Integer srgCounter) { + int maxPpPorts; + LOG.info("Getting max pp ports for Srg Number {}", srgCounter); + InstanceIdentifier deviceIID = InstanceIdentifier.create(OrgOpenroadmDevice.class) + .child(SharedRiskGroup.class, new SharedRiskGroupKey(srgCounter)); + Optional ordmSrgObject = + this.deviceTransactionManager.getDataFromDevice(deviceId, LogicalDatastoreType.OPERATIONAL, deviceIID, + Timeouts.DEVICE_READ_TIMEOUT, Timeouts.DEVICE_READ_TIMEOUT_UNIT); + if (ordmSrgObject.isPresent()) { + if (ordmSrgObject.get().getMaxAddDropPorts() != null) { + maxPpPorts = ordmSrgObject.get().getMaxAddDropPorts(); + } else { + LOG.info("Max add drop ports absent"); + return -1; + } + } else { + LOG.info("SRG absent"); + return -1; + } + return maxPpPorts; + } + + private NodeBuilder createTopoLayerNode(String nodeId) { + // Sets the value of Network-ref and Node-ref as a part of the supporting node + // attribute + SupportingNodeBuilder supportbldr = new SupportingNodeBuilder(); + supportbldr.setKey(new SupportingNodeKey(new NetworkId(NetworkUtils.UNDERLAY_NETWORK_ID), new NodeId(nodeId))); + supportbldr.setNetworkRef(new NetworkId(NetworkUtils.UNDERLAY_NETWORK_ID)); + supportbldr.setNodeRef(new NodeId(nodeId)); + ArrayList supportlist = new ArrayList<>(); + supportlist.add(supportbldr.build()); + NodeBuilder nodebldr = new NodeBuilder(); + nodebldr.setSupportingNode(supportlist); + return nodebldr; + } + + // Return 0 for null/error values + // Return 1 for tx + // Return 2 for rx + // Return 3 for bi-directional + + private int getPortDirection(String deviceId, String circuitPackName, String portName) { + InstanceIdentifier portIID = InstanceIdentifier.create(OrgOpenroadmDevice.class) + .child(CircuitPacks.class, new CircuitPacksKey(circuitPackName)) + .child(Ports.class, new PortsKey(portName)); + LOG.info("Fetching Port Direction for port {} at circuit pack {}", portName, circuitPackName); + Optional portObject = + this.deviceTransactionManager.getDataFromDevice(deviceId, LogicalDatastoreType.OPERATIONAL, portIID, + Timeouts.DEVICE_READ_TIMEOUT, Timeouts.DEVICE_READ_TIMEOUT_UNIT); + if (portObject.isPresent()) { + Ports port = portObject.get(); + if (port.getPortDirection() != null) { + return port.getPortDirection().getIntValue(); + } else { + LOG.warn("Port direction value missing for {} {}", circuitPackName, port.getPortName()); + return 0; + } + } + return 0; + } + + // This method returns a generic termination point builder for a given tpid + private TerminationPointBuilder createTpBldr(String tpId) { + TerminationPointBuilder tpBldr = new TerminationPointBuilder(); + TpId tp = new TpId(tpId); + TerminationPointKey tpKey = new TerminationPointKey(tp); + tpBldr.setKey(tpKey); + tpBldr.setTpId(tp); + return tpBldr; + } + + // This method returns the linkBuilder object for given source and destination + public LinkBuilder createLink(String srcNode, String dstNode, String srcTp, String destTp) { + LOG.info("creating link for {}-{}", srcNode, dstNode); + // Create Destination for link + DestinationBuilder dstNodeBldr = new DestinationBuilder(); + dstNodeBldr.setDestTp(destTp); + dstNodeBldr.setDestNode(new NodeId(dstNode)); + // Create Source for the link + SourceBuilder srcNodeBldr = new SourceBuilder(); + srcNodeBldr.setSourceNode(new NodeId(srcNode)); + srcNodeBldr.setSourceTp(srcTp); + LinkBuilder lnkBldr = new LinkBuilder(); + // set link builder attribute + lnkBldr.setDestination(dstNodeBldr.build()); + lnkBldr.setSource(srcNodeBldr.build()); + lnkBldr.setLinkId(LinkIdUtil.buildLinkId(srcNode, srcTp, dstNode, destTp)); + lnkBldr.setKey(new LinkKey(lnkBldr.getLinkId())); + org.opendaylight.yang.gen.v1.http.org.openroadm.opposite.links.rev170929.Link1Builder lnk1Bldr = + new org.opendaylight.yang.gen.v1.http.org.openroadm.opposite.links.rev170929.Link1Builder(); + LinkId oppositeLinkId = LinkIdUtil.getOppositeLinkId(srcNode, srcTp, dstNode, destTp); + lnk1Bldr.setOppositeLink(oppositeLinkId); + lnkBldr.addAugmentation(org.opendaylight.yang.gen.v1.http.org.openroadm.opposite.links.rev170929.Link1.class, + lnk1Bldr.build()); + return lnkBldr; + } + + private List createExpressLinks(String nodeId, int numOfDegrees, int portDirectionEnum) { + LOG.info("creating express links {} {} {}", nodeId, numOfDegrees, portDirectionEnum); + List links = new ArrayList<>(); + + String srcNode; + String destNode; + + String srcTp; + String destTp; + + // ports are uni-directional + if ((portDirectionEnum == 1) || (portDirectionEnum == 2)) { + LOG.info("creating uni-directional express links"); + for (int i = 1; i <= numOfDegrees; i++) { + for (int j = i + 1; j <= numOfDegrees; j++) { + + srcNode = nodeId + "-DEG" + i; + destNode = nodeId + "-DEG" + j; + + // AtoZ direction + srcTp = "DEG" + i + "-CTP-TX"; + destTp = "DEG" + j + "-CTP-RX"; + + LinkBuilder expLinkBldr = createLink(srcNode, destNode, srcTp, destTp); + + Link1Builder lnk1Bldr = new Link1Builder(); + lnk1Bldr.setLinkType(OpenroadmLinkType.EXPRESSLINK); + expLinkBldr.addAugmentation(Link1.class, lnk1Bldr.build()); + + links.add(expLinkBldr.build()); + + // ZtoA direction + srcTp = "DEG" + i + "-CTP-RX"; + destTp = "DEG" + j + "-CTP-TX"; + + expLinkBldr = createLink(destNode, srcNode, destTp, srcTp); + expLinkBldr.addAugmentation(Link1.class, lnk1Bldr.build()); + + links.add(expLinkBldr.build()); + + } + } + } + + // ports are bi-directional + if (portDirectionEnum == 3) { + LOG.info("creating bi-directional express links"); + for (int i = 1; i <= numOfDegrees; i++) { + for (int j = i + 1; j <= numOfDegrees; j++) { + + srcNode = nodeId + "-DEG" + i; + destNode = nodeId + "-DEG" + j; + + // AtoZ direction + srcTp = "DEG" + i + "-CTP-TXRX"; + destTp = "DEG" + j + "-CTP-TXRX"; + + Link1Builder lnk1Bldr = new Link1Builder(); + lnk1Bldr.setLinkType(OpenroadmLinkType.EXPRESSLINK); + + + LinkBuilder expLinkBldr = createLink(srcNode, destNode, srcTp, destTp); + expLinkBldr.addAugmentation(Link1.class, lnk1Bldr.build()); + links.add(expLinkBldr.build()); + + // ZtoA direction + expLinkBldr = createLink(destNode, srcNode, destTp, srcTp); + expLinkBldr.addAugmentation(Link1.class, lnk1Bldr.build()); + links.add(expLinkBldr.build()); + } + } + } + return links; + } + + private List createAddDropLinks(String nodeId, int numOfDegrees, int numOfSrgs, + int portDirectionEnum) { + LOG.info("creating add-drop links {} {} {} {}", nodeId, numOfDegrees, numOfSrgs, portDirectionEnum); + List links = new ArrayList<>(); + + String srcNode; + String destNode; + + String srcTp; + String destTp; + + // ports are uni-directional + if ((portDirectionEnum == 1) || (portDirectionEnum == 2)) { + LOG.info("creating uni-directional add-drop links"); + for (int i = 1; i <= numOfDegrees; i++) { + for (int j = 1; j <= numOfSrgs; j++) { + + srcNode = nodeId + "-DEG" + i; + destNode = nodeId + "-SRG" + j; + + // drop links + srcTp = "DEG" + i + "-CTP-TX"; + destTp = "SRG" + j + "-CP-RX"; + + LinkBuilder addDropLinkBldr = createLink(srcNode, destNode, srcTp, destTp); + Link1Builder lnk1Bldr = new Link1Builder(); + lnk1Bldr.setLinkType(OpenroadmLinkType.DROPLINK); + addDropLinkBldr.addAugmentation(Link1.class, lnk1Bldr.build()); + links.add(addDropLinkBldr.build()); + + // add links direction + srcTp = "DEG" + i + "-CTP-RX"; + destTp = "SRG" + j + "-CP-TX"; + + addDropLinkBldr = createLink(destNode, srcNode, destTp, srcTp); + lnk1Bldr.setLinkType(OpenroadmLinkType.ADDLINK); + addDropLinkBldr.addAugmentation(Link1.class, lnk1Bldr.build()); + links.add(addDropLinkBldr.build()); + + } + } + } + // ports are bi-directional + if (portDirectionEnum == 3) { + LOG.info("creating bi-directional add-drop links"); + for (int i = 1; i <= numOfDegrees; i++) { + for (int j = 1; j <= numOfSrgs; j++) { + + srcNode = nodeId + "-DEG" + i; + destNode = nodeId + "-SRG" + j; + + // drop links + srcTp = "DEG" + i + "-CTP-TXRX"; + destTp = "SRG" + j + "-CP-TXRX"; + + LinkBuilder addDropLinkBldr = createLink(srcNode, destNode, srcTp, destTp); + Link1Builder lnk1Bldr = new Link1Builder(); + lnk1Bldr.setLinkType(OpenroadmLinkType.DROPLINK); + addDropLinkBldr.addAugmentation(Link1.class, lnk1Bldr.build()); + links.add(addDropLinkBldr.build()); + + // add link + addDropLinkBldr = createLink(destNode, srcNode, destTp, srcTp); + lnk1Bldr.setLinkType(OpenroadmLinkType.ADDLINK); + addDropLinkBldr.addAugmentation(Link1.class, lnk1Bldr.build()); + links.add(addDropLinkBldr.build()); + } + } + } + return links; + } + + // This method returns the linkBuilder object for given source and destination + public boolean deleteLink(String srcNode, String dstNode, String srcTp, String destTp) { + LOG.info("deleting link for {}-{}", srcNode, dstNode); + try { + InstanceIdentifierBuilder linkIID = InstanceIdentifier + .builder(Network.class, new NetworkKey(new NetworkId(NetworkUtils.OVERLAY_NETWORK_ID))) + .augmentation(Network1.class) + .child(Link.class, new LinkKey(LinkIdUtil.buildLinkId(srcNode, srcTp, dstNode, destTp))); + WriteTransaction wrtx = this.dataBroker.newWriteOnlyTransaction(); + wrtx.delete(LogicalDatastoreType.CONFIGURATION, linkIID.build()); + wrtx.submit().get(1, TimeUnit.SECONDS); + } catch (InterruptedException | ExecutionException | TimeoutException e) { + LOG.error(e.getMessage(), e); + return false; + } + return true; + } + + private List create96AvalWaveDegree() { + List waveList = new ArrayList<>(); + + for (int i = 1; i < 97; i++) { + AvailableWavelengthsBuilder avalBldr = new AvailableWavelengthsBuilder(); + avalBldr.setIndex((long) i); + avalBldr.setKey(new AvailableWavelengthsKey((long) i)); + waveList.add(avalBldr.build()); + } + + return waveList; + } + + private List + create96AvalWaveSrg() { + + List + waveList = new ArrayList<>(); + + for (int i = 1; i < 97; i++) { + org.opendaylight.yang.gen.v1.http.org.openroadm.srg.rev170929.srg.node.attributes + .AvailableWavelengthsBuilder avalBldr = + new org.opendaylight.yang.gen.v1.http.org.openroadm.srg.rev170929.srg.node.attributes + .AvailableWavelengthsBuilder(); + avalBldr.setIndex((long) i); + avalBldr.setKey( + new org.opendaylight.yang.gen.v1.http.org.openroadm.srg.rev170929.srg.node.attributes + .AvailableWavelengthsKey((long) i)); + waveList.add(avalBldr.build()); + } + + return waveList; + } +} diff --git a/networkmodel/src/main/resources/org/opendaylight/blueprint/networkmodel-blueprint.xml b/networkmodel/src/main/resources/org/opendaylight/blueprint/networkmodel-blueprint.xml new file mode 100644 index 000000000..0264ab255 --- /dev/null +++ b/networkmodel/src/main/resources/org/opendaylight/blueprint/networkmodel-blueprint.xml @@ -0,0 +1,59 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/networkmodel/src/test/java/org/opendaylight/transportpce/networkmodel/NetworkModelTest.java b/networkmodel/src/test/java/org/opendaylight/transportpce/networkmodel/NetworkModelTest.java new file mode 100644 index 000000000..5002d5749 --- /dev/null +++ b/networkmodel/src/test/java/org/opendaylight/transportpce/networkmodel/NetworkModelTest.java @@ -0,0 +1,18 @@ +/* + * 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.networkmodel; + +import org.junit.Test; + +public class NetworkModelTest { + @Test + public void init() throws Exception { + //TODO implement test + } + +} diff --git a/pom.xml b/pom.xml index 67eb9b846..747bdde89 100644 --- a/pom.xml +++ b/pom.xml @@ -34,6 +34,8 @@ and is available at http://www.eclipse.org/legal/epl-v10.html INTERNAL api common renderer + inventory + networkmodel olm tests servicehandler diff --git a/renderer/src/main/java/org/opendaylight/transportpce/renderer/RendererNotificationsImpl.java b/renderer/src/main/java/org/opendaylight/transportpce/renderer/RendererNotificationsImpl.java deleted file mode 100644 index c0dd38ebd..000000000 --- a/renderer/src/main/java/org/opendaylight/transportpce/renderer/RendererNotificationsImpl.java +++ /dev/null @@ -1,233 +0,0 @@ -/* - * Copyright © 2017 AT&T and others. All rights reserved. - * - * This program and the accompanying materials are made available under the - * terms of the Eclipse Public License v1.0 which accompanies this distribution, - * and is available at http://www.eclipse.org/legal/epl-v10.html - */ -package org.opendaylight.transportpce.renderer; - -import com.google.common.base.Preconditions; -import com.google.common.cache.CacheBuilder; -import com.google.common.cache.CacheLoader; -import com.google.common.cache.LoadingCache; - -import java.util.Collection; -import java.util.List; -import java.util.Optional; -import java.util.Set; -import java.util.stream.Collectors; - -import org.opendaylight.controller.md.sal.binding.api.DataBroker; -import org.opendaylight.controller.md.sal.binding.api.DataObjectModification; -import org.opendaylight.controller.md.sal.binding.api.DataObjectModification.ModificationType; -import org.opendaylight.controller.md.sal.binding.api.DataTreeChangeListener; -import org.opendaylight.controller.md.sal.binding.api.DataTreeIdentifier; -import org.opendaylight.controller.md.sal.binding.api.DataTreeModification; -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.NotificationService; -import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType; -import org.opendaylight.controller.sal.binding.api.RpcConsumerRegistry; -import org.opendaylight.transportpce.common.device.DeviceTransactionManager; -import org.opendaylight.transportpce.common.mapping.PortMapping; -import org.opendaylight.transportpce.renderer.listeners.AlarmNotificationListener; -import org.opendaylight.transportpce.renderer.listeners.DeOperationsListener; -import org.opendaylight.transportpce.renderer.listeners.DeviceListener; -import org.opendaylight.transportpce.renderer.listeners.LldpListener; -import org.opendaylight.transportpce.renderer.listeners.TcaListener; -import org.opendaylight.yang.gen.v1.http.org.openroadm.alarm.rev161014.AlarmNotification; -import org.opendaylight.yang.gen.v1.http.org.openroadm.alarm.rev161014.OrgOpenroadmAlarmListener; -import org.opendaylight.yang.gen.v1.http.org.openroadm.de.operations.rev161014.OrgOpenroadmDeOperationsListener; -import org.opendaylight.yang.gen.v1.http.org.openroadm.device.rev170206.OrgOpenroadmDeviceListener; -import org.opendaylight.yang.gen.v1.http.org.openroadm.lldp.rev161014.OrgOpenroadmLldpListener; -import org.opendaylight.yang.gen.v1.http.org.openroadm.tca.rev161014.OrgOpenroadmTcaListener; -import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.netconf.notification._1._0.rev080714.CreateSubscriptionInputBuilder; -import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.netconf.notification._1._0.rev080714.NotificationsService; -import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.netconf.notification._1._0.rev080714.StreamNameType; -import org.opendaylight.yang.gen.v1.urn.opendaylight.netconf.node.topology.rev150114.NetconfNode; -import org.opendaylight.yang.gen.v1.urn.opendaylight.netconf.node.topology.rev150114.NetconfNodeConnectionStatus.ConnectionStatus; -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.NodeId; -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.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.concepts.ListenerRegistration; -import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; -import org.opendaylight.yangtools.yang.binding.KeyedInstanceIdentifier; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -public class RendererNotificationsImpl implements DataTreeChangeListener { - private final DataBroker dataBroker; - private final MountPointService mountService; - private static final Logger LOG = LoggerFactory.getLogger(RendererNotificationsImpl.class); - private ListenerRegistration dataTreeChangeListenerRegistration; - private final PortMapping portMapping; - private final DeviceTransactionManager deviceTransactionManager; - private final Set currentMountedDevice; - public static final InstanceIdentifier NETCONF_TOPO_IID = InstanceIdentifier.create(NetworkTopology.class) - .child(Topology.class, new TopologyKey(new TopologyId(TopologyNetconf.QNAME.getLocalName()))); - - LoadingCache> mountIds = CacheBuilder.newBuilder().maximumSize(20) - .build(new CacheLoader>() { - @Override - public KeyedInstanceIdentifier load(final String key) { - return NETCONF_TOPO_IID.child(Node.class, new NodeKey(new NodeId(key))); - } - }); - - public RendererNotificationsImpl(final DataBroker dataBroker, final MountPointService mountService, - Set currentMountedDevice, PortMapping portMapping,DeviceTransactionManager deviceTransactionManager) { - this.dataBroker = dataBroker; - this.mountService = mountService; - this.currentMountedDevice = currentMountedDevice; - this.portMapping = portMapping; - this.deviceTransactionManager = deviceTransactionManager; - if (portMapping == null) { - LOG.error("Portmapping is null !"); - } - if (deviceTransactionManager == null) { - LOG.error("deviceTransactionManager is null"); - } - if (mountService == null) { - LOG.error("Mount service is null"); - } - if (dataBroker != null) { - this.dataTreeChangeListenerRegistration = dataBroker.registerDataTreeChangeListener( - new DataTreeIdentifier<>(LogicalDatastoreType.OPERATIONAL, NETCONF_TOPO_IID.child(Node.class)), this); - } - } - - private void registerNotificationListener(final String nodeId) { - - LOG.info("onDeviceConnected: {}", nodeId); - Optional mountPointOpt = this.deviceTransactionManager.getDeviceMountPoint(nodeId); - MountPoint mountPoint; - if (mountPointOpt.isPresent()) { - mountPoint = mountPointOpt.get(); - } else { - LOG.error("Failed to get mount point for node {}", nodeId); - return; - } - - final Optional notificationService = - mountPoint.getService(NotificationService.class).toJavaUtil(); - if (!notificationService.isPresent()) { - LOG.error("Failed to get RpcService for node {}", nodeId); - return; - } - - final OrgOpenroadmAlarmListener alarmListener; - alarmListener = new AlarmNotificationListener(); - LOG.info("Registering notification listener on {} for node: {}", AlarmNotification.QNAME, nodeId); - // Register notification listener - - final OrgOpenroadmDeOperationsListener deOperationsListener; - deOperationsListener = new DeOperationsListener(); - LOG.info("Registering notification listener on OrgOpenroadmDeOperationsListener for node: {}", nodeId); - // Register notification listener - - final OrgOpenroadmDeviceListener deviceListener; - deviceListener = new DeviceListener(); - LOG.info("Registering notification listener on OrgOpenroadmDeviceListener for node: {}", nodeId); - // Register notification listener - - final OrgOpenroadmLldpListener lldpListener; - lldpListener = new LldpListener(); - LOG.info("Registering notification listener on OrgOpenroadmLldpListener for node: {}", nodeId); - // Register notification listener - - final OrgOpenroadmTcaListener tcaListener; - tcaListener = new TcaListener(); - LOG.info("Registering notification listener on OrgOpenroadmTcaListener for node: {}", nodeId); - // Register notification listener - - // Listening to NETCONF datastream - final String streamName = "NETCONF"; - final Optional service = mountPoint.getService(RpcConsumerRegistry.class).toJavaUtil(); - if (!service.isPresent()) { - LOG.error("Failed to get RpcService for node {}", nodeId); - } - - final NotificationsService rpcService = service.get().getRpcService(NotificationsService.class); - final CreateSubscriptionInputBuilder createSubscriptionInputBuilder = new CreateSubscriptionInputBuilder(); - createSubscriptionInputBuilder.setStream(new StreamNameType(streamName)); - LOG.info("Triggering notification stream {} for node {}", streamName, nodeId); - - } - - public void close() { - LOG.info("RenderernotificationsImpl Closed"); - // Clean up the Data Change Listener registration - if (this.dataTreeChangeListenerRegistration != null) { - this.dataTreeChangeListenerRegistration.close(); - } - } - - @Override - public void onDataTreeChanged(Collection> changes) { - - for (DataTreeModification change : changes) { - - DataObjectModification rootNode = change.getRootNode(); - NetconfNode nnode = null; - String nodeId = new String(); - if (rootNode.getDataAfter() != null) { - nnode = Preconditions.checkNotNull(rootNode.getDataAfter().getAugmentation(NetconfNode.class), - "Node not connected via Netconf protocol"); - nodeId = rootNode.getDataAfter().getKey().getNodeId().getValue(); - } - - if (rootNode.getModificationType() == ModificationType.DELETE) { - String nodeid = rootNode.getDataBefore().getKey().getNodeId().getValue(); - LOG.info("Node {} removed...", nodeid); - this.portMapping.deleteMappingData(nodeid); - } - - if (nnode != null) { - if (nodeId.equals("controller-config")) { - // We shouldn't process controller-config as an OpenROAM device - LOG.info("{} ignored: org-openroadm-device advertised but not a real ROADM device", nodeId); - return; - } - if ((rootNode.getModificationType() == ModificationType.WRITE) || - (rootNode.getModificationType() == ModificationType.SUBTREE_MODIFIED)) { - LOG.info("Node added or modified {}", nodeId); - ConnectionStatus csts = nnode.getConnectionStatus(); - - switch (csts) { - case Connected: { - LOG.info("NETCONF Node: {} is fully connected", nodeId); - List capabilities = nnode.getAvailableCapabilities().getAvailableCapability() - .stream().map(cp -> cp.getCapability()).collect(Collectors.toList()); - LOG.info("Capabilities: {}", capabilities); - /* - * TODO: check for required capabilities to listen - * for notifications - */ - registerNotificationListener(nodeId); - this.currentMountedDevice.add(nodeId); - this.portMapping.createMappingData(nodeId); - break; - } - case Connecting: { - LOG.info("NETCONF Node: {} is (dis)connecting", nodeId); - break; - } - case UnableToConnect: { - LOG.info("NETCONF Node: {} connection failed", nodeId); - break; - } - default: - LOG.warn("Unexpected connection status {}", csts.getName()); - } - } - } - } - LOG.info("Netconf devices currently mounted are : {}", this.currentMountedDevice.toString()); - } -} diff --git a/renderer/src/main/java/org/opendaylight/transportpce/renderer/RendererProvider.java b/renderer/src/main/java/org/opendaylight/transportpce/renderer/RendererProvider.java index 472951453..69dad3864 100644 --- a/renderer/src/main/java/org/opendaylight/transportpce/renderer/RendererProvider.java +++ b/renderer/src/main/java/org/opendaylight/transportpce/renderer/RendererProvider.java @@ -7,15 +7,8 @@ */ package org.opendaylight.transportpce.renderer; -import java.util.HashSet; -import java.util.Set; - -import org.opendaylight.controller.md.sal.binding.api.DataBroker; -import org.opendaylight.controller.md.sal.binding.api.MountPointService; import org.opendaylight.controller.sal.binding.api.BindingAwareBroker.RpcRegistration; import org.opendaylight.controller.sal.binding.api.RpcProviderRegistry; -import org.opendaylight.transportpce.common.device.DeviceTransactionManager; -import org.opendaylight.transportpce.common.mapping.PortMapping; import org.opendaylight.transportpce.renderer.provisiondevice.RendererServiceOperations; import org.opendaylight.transportpce.renderer.rpcs.DeviceRendererRPCImpl; import org.opendaylight.transportpce.renderer.rpcs.TransportPCEServicePathRPCImpl; @@ -27,30 +20,17 @@ import org.slf4j.LoggerFactory; public class RendererProvider { private static final Logger LOG = LoggerFactory.getLogger(RendererProvider.class); - private final DataBroker dataBroker; - private final MountPointService mountPointService; private final RpcProviderRegistry rpcProviderRegistry; - private final PortMapping portMapping; - private final DeviceTransactionManager deviceTransactionManager; private RpcRegistration deviceRendererRegistration; private DeviceRendererRPCImpl deviceRendererRPCImpl; private RpcRegistration tpceServiceRegistry; private RendererServiceOperations rendererServiceOperations; - private RendererNotificationsImpl rendererNotificationsImpl; - private final Set currentMountedDevice; public RendererProvider(RpcProviderRegistry rpcProviderRegistry, DeviceRendererRPCImpl deviceRendererRPCImpl, - RendererServiceOperations rendererServiceOperations,DataBroker dataBroker, - MountPointService mountPointService, PortMapping portMapping, - DeviceTransactionManager deviceTransactionManager) { + RendererServiceOperations rendererServiceOperations) { this.rpcProviderRegistry = rpcProviderRegistry; this.deviceRendererRPCImpl = deviceRendererRPCImpl; this.rendererServiceOperations = rendererServiceOperations; - this.dataBroker = dataBroker; - this.mountPointService = mountPointService; - this.currentMountedDevice = new HashSet<>(); - this.portMapping = portMapping; - this.deviceTransactionManager = deviceTransactionManager; } /** @@ -64,8 +44,6 @@ public class RendererProvider { .addRpcImplementation(RendererService.class, this.deviceRendererRPCImpl); this.tpceServiceRegistry = this.rpcProviderRegistry .addRpcImplementation(TransportpceServicepathService.class, transportPCEServicePathRPCImpl); - this.rendererNotificationsImpl = new RendererNotificationsImpl(this.dataBroker, this.mountPointService, - this.currentMountedDevice,this.portMapping,this.deviceTransactionManager); } /** @@ -79,10 +57,6 @@ public class RendererProvider { if (this.tpceServiceRegistry != null) { this.tpceServiceRegistry.close(); } - // Clean up the RendererNotificationsImpl - if (this.rendererNotificationsImpl != null) { - this.rendererNotificationsImpl.close(); - } } } diff --git a/renderer/src/main/java/org/opendaylight/transportpce/renderer/listeners/AlarmNotificationListener.java b/renderer/src/main/java/org/opendaylight/transportpce/renderer/listeners/AlarmNotificationListener.java deleted file mode 100644 index 8102abeeb..000000000 --- a/renderer/src/main/java/org/opendaylight/transportpce/renderer/listeners/AlarmNotificationListener.java +++ /dev/null @@ -1,29 +0,0 @@ -/* - * Copyright © 2017 AT&T and others. All rights reserved. - * - * This program and the accompanying materials are made available under the - * terms of the Eclipse Public License v1.0 which accompanies this distribution, - * and is available at http://www.eclipse.org/legal/epl-v10.html - */ - -package org.opendaylight.transportpce.renderer.listeners; - -import org.opendaylight.yang.gen.v1.http.org.openroadm.alarm.rev161014.AlarmNotification; -import org.opendaylight.yang.gen.v1.http.org.openroadm.alarm.rev161014.OrgOpenroadmAlarmListener; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -public class AlarmNotificationListener implements OrgOpenroadmAlarmListener { - - private static final Logger LOG = LoggerFactory.getLogger(AlarmNotificationListener.class); - - /** - * Callback for alarm-notification. - * - * @param notification AlarmNotification object - */ - @Override - public void onAlarmNotification(AlarmNotification notification) { - LOG.info("Notification {} received {}", AlarmNotification.QNAME, notification); - } -} \ No newline at end of file diff --git a/renderer/src/main/java/org/opendaylight/transportpce/renderer/listeners/LldpListener.java b/renderer/src/main/java/org/opendaylight/transportpce/renderer/listeners/LldpListener.java deleted file mode 100644 index 7b18f09a9..000000000 --- a/renderer/src/main/java/org/opendaylight/transportpce/renderer/listeners/LldpListener.java +++ /dev/null @@ -1,30 +0,0 @@ -/* - * Copyright © 2017 AT&T and others. All rights reserved. - * - * This program and the accompanying materials are made available under the - * terms of the Eclipse Public License v1.0 which accompanies this distribution, - * and is available at http://www.eclipse.org/legal/epl-v10.html - */ - -package org.opendaylight.transportpce.renderer.listeners; - -import org.opendaylight.yang.gen.v1.http.org.openroadm.lldp.rev161014.LldpNbrInfoChange; -import org.opendaylight.yang.gen.v1.http.org.openroadm.lldp.rev161014.OrgOpenroadmLldpListener; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -public class LldpListener implements OrgOpenroadmLldpListener { - private static final Logger LOG = LoggerFactory.getLogger(OrgOpenroadmLldpListener.class); - - /** - * Callback for lldp-nbr-info-change. - * - * @param notification LldpNbrInfoChange object - */ - @Override - public void onLldpNbrInfoChange(LldpNbrInfoChange notification) { - - LOG.info("Notification {} received {}", LldpNbrInfoChange.QNAME, notification); - - } -} \ No newline at end of file diff --git a/renderer/src/main/java/org/opendaylight/transportpce/renderer/provisiondevice/tasks/RollbackProcessor.java b/renderer/src/main/java/org/opendaylight/transportpce/renderer/provisiondevice/tasks/RollbackProcessor.java index 2531a4260..0405432a3 100644 --- a/renderer/src/main/java/org/opendaylight/transportpce/renderer/provisiondevice/tasks/RollbackProcessor.java +++ b/renderer/src/main/java/org/opendaylight/transportpce/renderer/provisiondevice/tasks/RollbackProcessor.java @@ -69,7 +69,7 @@ public class RollbackProcessor { try { LOG.info("rolling back: {}", task.getId()); task.call(); - //this methode prototype only use the generic Exception and no specific and useable subclasse + //this method prototype only uses the generic Exception but no specific and useable subclass } catch (Exception e) { LOG.error("ERROR: Rollback task {} has failed", task.getId(), e); } diff --git a/renderer/src/main/resources/org/opendaylight/blueprint/renderer-blueprint.xml b/renderer/src/main/resources/org/opendaylight/blueprint/renderer-blueprint.xml index f5d667642..fe04922d8 100644 --- a/renderer/src/main/resources/org/opendaylight/blueprint/renderer-blueprint.xml +++ b/renderer/src/main/resources/org/opendaylight/blueprint/renderer-blueprint.xml @@ -13,7 +13,6 @@ and is available at http://www.eclipse.org/legal/epl-v10.html - @@ -54,13 +53,9 @@ and is available at http://www.eclipse.org/legal/epl-v10.html - - - -