TE Topoplogy subsystem I2RS API changes
This submission contains the following:
1. Major changes in apps/tetopology. The changes are mainly introduced
to support new searching keys in TE Topology.
2. Add RESTCONF notification support in the TE Provider. i.e., for
south-bound RESTCONF communication with the domain controller.
Change-Id: I6786959deb66c98626edc65ff52694dcf08981a3
diff --git a/providers/ietfte/topology/features.xml b/providers/ietfte/topology/features.xml
index b6f1008..3207bac 100644
--- a/providers/ietfte/topology/features.xml
+++ b/providers/ietfte/topology/features.xml
@@ -21,8 +21,8 @@
<feature>onos-api</feature>
<feature>onos-app-tenbi-yangmodel</feature>
<bundle>mvn:${project.groupId}/${project.artifactId}/${project.version}</bundle>
- <bundle>mvn:${project.groupId}/onos-restsb-api/${project.version}</bundle>
- <bundle>mvn:${project.groupId}/onos-restsb-ctl/${project.version}</bundle>
+ <bundle>mvn:${project.groupId}/onos-restconf-client-api/${project.version}</bundle>
+ <bundle>mvn:${project.groupId}/onos-restconf-client-ctl/${project.version}</bundle>
<bundle>mvn:org.glassfish.jersey.core/jersey-client/2.22.2</bundle>
<bundle>mvn:commons-io/commons-io/2.4</bundle>
<bundle>mvn:org.apache.httpcomponents/httpclient-osgi/4.5.1</bundle>
diff --git a/providers/ietfte/topology/pom.xml b/providers/ietfte/topology/pom.xml
index d8621d1..04243e4 100644
--- a/providers/ietfte/topology/pom.xml
+++ b/providers/ietfte/topology/pom.xml
@@ -44,7 +44,7 @@
</dependency>
<dependency>
<groupId>org.onosproject</groupId>
- <artifactId>onos-app-tetopology</artifactId>
+ <artifactId>onos-app-tetopology-api</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
diff --git a/providers/ietfte/topology/src/main/java/org/onosproject/provider/te/topology/TeTopologyRestconfProvider.java b/providers/ietfte/topology/src/main/java/org/onosproject/provider/te/topology/TeTopologyRestconfProvider.java
index 06a8acf..442b65f 100644
--- a/providers/ietfte/topology/src/main/java/org/onosproject/provider/te/topology/TeTopologyRestconfProvider.java
+++ b/providers/ietfte/topology/src/main/java/org/onosproject/provider/te/topology/TeTopologyRestconfProvider.java
@@ -15,22 +15,7 @@
*/
package org.onosproject.provider.te.topology;
-import static org.onlab.util.Tools.groupedThreads;
-import static org.onosproject.net.config.NetworkConfigEvent.Type.CONFIG_ADDED;
-import static org.onosproject.net.config.NetworkConfigEvent.Type.CONFIG_UPDATED;
-import static org.onosproject.net.config.basics.SubjectFactories.APP_SUBJECT_FACTORY;
-import static org.slf4j.LoggerFactory.getLogger;
-
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.StringWriter;
-import java.nio.charset.StandardCharsets;
-import java.util.HashSet;
-import java.util.List;
-import java.util.Set;
-import java.util.concurrent.ExecutorService;
-import java.util.concurrent.Executors;
-
+import com.google.common.base.Preconditions;
import org.apache.commons.io.IOUtils;
import org.apache.felix.scr.annotations.Activate;
import org.apache.felix.scr.annotations.Component;
@@ -49,15 +34,25 @@
import org.onosproject.net.provider.AbstractProvider;
import org.onosproject.net.provider.ProviderId;
import org.onosproject.protocol.rest.RestSBDevice;
+import org.onosproject.protocol.restconf.RestConfNotificationEventListener;
import org.onosproject.protocol.restconf.RestConfSBController;
import org.onosproject.tetopology.management.api.TeTopologyProvider;
import org.onosproject.tetopology.management.api.TeTopologyProviderRegistry;
import org.onosproject.tetopology.management.api.TeTopologyProviderService;
+import org.onosproject.tetopology.management.api.TeTopologyService;
+import org.onosproject.tetopology.management.api.link.NetworkLink;
+import org.onosproject.tetopology.management.api.link.NetworkLinkKey;
+import org.onosproject.tetopology.management.api.node.NetworkNode;
+import org.onosproject.tetopology.management.api.node.NetworkNodeKey;
+import org.onosproject.teyang.utils.topology.LinkConverter;
import org.onosproject.teyang.utils.topology.NetworkConverter;
+import org.onosproject.teyang.utils.topology.NodeConverter;
import org.onosproject.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.network.rev20151208.IetfNetwork;
import org.onosproject.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.network.rev20151208.ietfnetwork.networks.Network;
import org.onosproject.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.network.topology.rev20151208.IetfNetworkTopology;
import org.onosproject.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.te.topology.rev20160708.IetfTeTopology;
+import org.onosproject.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.te.topology.rev20160708.ietftetopology.TeLinkEvent;
+import org.onosproject.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.te.topology.rev20160708.ietftetopology.TeNodeEvent;
import org.onosproject.yms.ych.YangCodecHandler;
import org.onosproject.yms.ych.YangProtocolEncodingFormat;
import org.onosproject.yms.ych.YangResourceIdentifierType;
@@ -65,7 +60,21 @@
import org.onosproject.yms.ymsm.YmsService;
import org.slf4j.Logger;
-import com.google.common.base.Preconditions;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.StringWriter;
+import java.nio.charset.StandardCharsets;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+
+import static org.onlab.util.Tools.groupedThreads;
+import static org.onosproject.net.config.NetworkConfigEvent.Type.CONFIG_ADDED;
+import static org.onosproject.net.config.NetworkConfigEvent.Type.CONFIG_UPDATED;
+import static org.onosproject.net.config.basics.SubjectFactories.APP_SUBJECT_FACTORY;
+import static org.slf4j.LoggerFactory.getLogger;
/**
* Provider for IETF TE Topology that use RESTCONF as means of communication.
@@ -75,10 +84,18 @@
implements TeTopologyProvider {
private static final String APP_NAME = "org.onosproject.teprovider.topology";
private static final String RESTCONF = "restconf";
- private static final String PROVIDER = "org.onosproject.teprovider.restconf.domain";
+ private static final String PROVIDER =
+ "org.onosproject.teprovider.restconf.domain";
private static final String IETF_NETWORK_URI = "ietf-network:networks";
- private static final String IETF_NETWORKS_PREFIX_TO_BE_REMOVED = "{\"networks\":";
- private static final String IETF_NOTIFICATION_URI = "/streams/NETCONF";
+ private static final String IETF_NETWORKS_PREFIX =
+ "{\"ietf-network:networks\":";
+ private static final String TE_NOTIFICATION_PREFIX =
+ "{\"ietf-te-topology:ietf-te-topology\":";
+ private static final String TE_LINK_EVENT_PREFIX =
+ "{\"ietf-te-topology:te-link-event\":";
+ private static final String TE_NODE_EVENT_PREFIX =
+ "{\"ietf-te-topology:te-node-event\":";
+ private static final String IETF_NOTIFICATION_URI = "netconf";
private static final String JSON = "json";
private static final String E_DEVICE_NULL = "Restconf device is null";
@@ -102,13 +119,16 @@
@Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
protected YmsService ymsService;
+ @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
+ protected TeTopologyService teTopologyService;
+
private YangCodecHandler codecHandler;
private TeTopologyProviderService topologyProviderService;
private final ExecutorService executor =
Executors.newFixedThreadPool(5, groupedThreads("onos/restconfsbprovider",
- "device-installer-%d", log));
+ "device-installer-%d", log));
private final ConfigFactory<ApplicationId, RestconfServerConfig> factory =
new ConfigFactory<ApplicationId, RestconfServerConfig>(APP_SUBJECT_FACTORY,
@@ -175,11 +195,13 @@
private void connectDevices() {
- RestconfServerConfig cfg = cfgService.getConfig(appId, RestconfServerConfig.class);
+ RestconfServerConfig cfg = cfgService.getConfig(appId,
+ RestconfServerConfig.class);
try {
if (cfg != null && cfg.getDevicesAddresses() != null) {
//Precomputing the devices to be removed
- Set<RestSBDevice> toBeRemoved = new HashSet<>(restconfClient.getDevices().values());
+ Set<RestSBDevice> toBeRemoved = new HashSet<>(restconfClient.
+ getDevices().values());
toBeRemoved.removeAll(cfg.getDevicesAddresses());
//Adding new devices
for (RestSBDevice device : cfg.getDevicesAddresses()) {
@@ -202,9 +224,12 @@
private void retrieveTopology(DeviceId deviceId) {
// Retrieve IETF Network at top level.
- InputStream jsonStream = restconfClient.get(deviceId, IETF_NETWORK_URI, JSON);
+ InputStream jsonStream = restconfClient.get(deviceId,
+ IETF_NETWORK_URI,
+ JSON);
if (jsonStream == null) {
- log.warn("Unable to retrieve network Topology from restconf server {}", deviceId);
+ log.warn("Unable to retrieve network Topology from restconf " +
+ "server {}", deviceId);
return;
}
@@ -213,16 +238,19 @@
try {
IOUtils.copy(jsonStream, writer, StandardCharsets.UTF_8);
} catch (IOException e) {
- log.warn("There is an exception {} for copy jsonStream to stringWriter for restconf {}",
+ log.warn("There is an exception {} for copy jsonStream to " +
+ "stringWriter for restconf {}",
e.getMessage(), deviceId);
return;
}
String jsonString = writer.toString();
- String networkLevelJsonString = getNetworkLevelJsonResponse(jsonString);
+ String networkLevelJsonString = removePrefixTagFromJson(jsonString,
+ IETF_NETWORKS_PREFIX);
- YangCompositeEncodingImpl yce = new YangCompositeEncodingImpl(YangResourceIdentifierType.URI,
- IETF_NETWORK_URI,
- networkLevelJsonString);
+ YangCompositeEncodingImpl yce =
+ new YangCompositeEncodingImpl(YangResourceIdentifierType.URI,
+ IETF_NETWORK_URI,
+ networkLevelJsonString);
Object yo = codecHandler.decode(yce,
YangProtocolEncodingFormat.JSON,
@@ -258,36 +286,20 @@
// topologyProviderService.networkUpdated(network);
// }
- //TODO: Uncomment when the RESTCONF server and the RESTCONF client
- // both fully support notifications in Ibis Release
-// RestConfNotificationEventListener callBackListener = new RestConfNotificationEventListenerImpl();
-// restconfClient.enableNotifications(deviceId, IETF_NOTIFICATION_URI, JSON, callBackListener);
+ RestConfNotificationEventListener<String> callBackListener =
+ new InternalRestconfNotificationEventListener();
+ restconfClient.enableNotifications(deviceId, IETF_NOTIFICATION_URI,
+ "application/json",
+ callBackListener);
}
- private String getNetworkLevelJsonResponse(String jsonString) {
- if (jsonString.startsWith(IETF_NETWORKS_PREFIX_TO_BE_REMOVED)) {
- log.debug("The retrieved JSON body from the RESTCONF server is in "
- + "networks level -- going to remove it from networks container");
- return jsonString.substring(IETF_NETWORKS_PREFIX_TO_BE_REMOVED.length(), jsonString.length() - 1);
+ private String removePrefixTagFromJson(String jsonString, String prefixTag) {
+ if (jsonString.startsWith(prefixTag)) {
+ return jsonString.substring(prefixTag.length(), jsonString.length() - 1);
}
- log.debug("The retrieved JSON body from the RESTCONF server is not in "
- + "networks level -- nothing to be removed");
return jsonString;
}
- //TODO: Uncomment when the RESTCONF server and the RESTCONF client
- // both fully support notifications in Ibis release
-// private class RestConfNotificationEventListenerImpl implements RestConfNotificationEventListener {
-//
-// @Override
-// public <T> void handleNotificationEvent(DeviceId deviceId,
-// T eventJsonString) {
-// // TODO: handle the event properly once the RESTCONF server fully supports
-// // notifications in Ibis release.
-// log.debug("a new notification: {} is received for device {}", eventJsonString, deviceId.toString());
-// }
-// }
-
private class InternalNetworkConfigListener implements NetworkConfigListener {
@Override
@@ -303,4 +315,75 @@
}
}
+ private class InternalRestconfNotificationEventListener implements
+ RestConfNotificationEventListener<String> {
+ @Override
+ public void handleNotificationEvent(DeviceId deviceId,
+ String eventJsonString) {
+ log.debug("New notification: {} for device: {}",
+ eventJsonString, deviceId.toString());
+
+ String teEventString = removePrefixTagFromJson(eventJsonString,
+ TE_NOTIFICATION_PREFIX);
+ if (teEventString.startsWith(TE_LINK_EVENT_PREFIX)) {
+ String linkString = removePrefixTagFromJson(teEventString,
+ TE_LINK_EVENT_PREFIX);
+ log.debug("link event={}", linkString);
+ handleRestconfLinkNotification(linkString);
+ } else if (teEventString.startsWith(TE_NODE_EVENT_PREFIX)) {
+ String nodeString = removePrefixTagFromJson(teEventString,
+ TE_NODE_EVENT_PREFIX);
+ log.debug("node event={}", nodeString);
+ handleRestconfNodeNotification(nodeString);
+ }
+ }
+
+ private void handleRestconfLinkNotification(String linkString) {
+ YangCompositeEncodingImpl yce =
+ new YangCompositeEncodingImpl(YangResourceIdentifierType.URI,
+ "ietf-te-topology:te-link-event",
+ linkString);
+ Object yo = codecHandler.decode(yce,
+ YangProtocolEncodingFormat.JSON,
+ YmsOperationType.NOTIFICATION);
+
+ if (yo == null) {
+ log.error("YMS decoder error");
+ return;
+ }
+
+ NetworkLinkKey linkKey = LinkConverter.yangLinkEvent2NetworkLinkKey(
+ (TeLinkEvent) yo);
+
+ NetworkLink networkLink = LinkConverter.yangLinkEvent2NetworkLink(
+ (TeLinkEvent) yo,
+ teTopologyService);
+
+ topologyProviderService.linkUpdated(linkKey, networkLink);
+ }
+
+ private void handleRestconfNodeNotification(String nodeString) {
+ YangCompositeEncodingImpl yce =
+ new YangCompositeEncodingImpl(YangResourceIdentifierType.URI,
+ "ietf-te-topology:te-node-event",
+ nodeString);
+ Object yo = codecHandler.decode(yce,
+ YangProtocolEncodingFormat.JSON,
+ YmsOperationType.NOTIFICATION);
+
+ if (yo == null) {
+ log.error("YMS decoder error");
+ return;
+ }
+
+ NetworkNodeKey nodeKey = NodeConverter.yangNodeEvent2NetworkNodeKey(
+ (TeNodeEvent) yo);
+
+ NetworkNode networkNode = NodeConverter.yangNodeEvent2NetworkNode(
+ (TeNodeEvent) yo,
+ teTopologyService);
+
+ topologyProviderService.nodeUpdated(nodeKey, networkNode);
+ }
+ }
}