NetconfSession refactoring
- Move netconf rpc envelope processing common across secure transport implementation
to AbstractNetconfSession
work by: Palash Kala <palash.kala@samsung.com>
Change-Id: I5f0d6adecf6224ae44f224291f645725b3c87739
diff --git a/apps/configsync-netconf/src/test/java/org/onosproject/d/config/sync/impl/netconf/NetconfDeviceConfigSynchronizerProviderTest.java b/apps/configsync-netconf/src/test/java/org/onosproject/d/config/sync/impl/netconf/NetconfDeviceConfigSynchronizerProviderTest.java
index 1aa3411..8851cf1 100644
--- a/apps/configsync-netconf/src/test/java/org/onosproject/d/config/sync/impl/netconf/NetconfDeviceConfigSynchronizerProviderTest.java
+++ b/apps/configsync-netconf/src/test/java/org/onosproject/d/config/sync/impl/netconf/NetconfDeviceConfigSynchronizerProviderTest.java
@@ -293,7 +293,7 @@
*/
private class TestEditNetconfSession extends NetconfSessionAdapter {
@Override
- public CompletableFuture<String> request(String request)
+ public CompletableFuture<String> rpc(String request)
throws NetconfException {
System.out.println("TestEditNetconfSession received:");
System.out.println(XmlString.prettifyXml(request));
diff --git a/drivers/microsemi/ea1000/src/test/java/org/onosproject/drivers/microsemi/yang/MockNetconfSessionEa1000.java b/drivers/microsemi/ea1000/src/test/java/org/onosproject/drivers/microsemi/yang/MockNetconfSessionEa1000.java
index 6bf67c0..6831fc3 100644
--- a/drivers/microsemi/ea1000/src/test/java/org/onosproject/drivers/microsemi/yang/MockNetconfSessionEa1000.java
+++ b/drivers/microsemi/ea1000/src/test/java/org/onosproject/drivers/microsemi/yang/MockNetconfSessionEa1000.java
@@ -1308,7 +1308,8 @@
}
- private boolean checkReply(String reply) throws NetconfException {
+ @Override
+ protected boolean checkReply(String reply) {
if (reply != null) {
if (!reply.contains("<rpc-error>")) {
log.debug("Device {} sent reply {}", deviceInfo, reply);
diff --git a/drivers/netconf/src/test/java/org/onosproject/drivers/netconf/MockNetconfSession.java b/drivers/netconf/src/test/java/org/onosproject/drivers/netconf/MockNetconfSession.java
index 155a5a0..ec1996c 100644
--- a/drivers/netconf/src/test/java/org/onosproject/drivers/netconf/MockNetconfSession.java
+++ b/drivers/netconf/src/test/java/org/onosproject/drivers/netconf/MockNetconfSession.java
@@ -332,7 +332,8 @@
}
- private boolean checkReply(String reply) throws NetconfException {
+ @Override
+ protected boolean checkReply(String reply) {
if (reply != null) {
if (!reply.contains("<rpc-error>")) {
log.debug("Device {} sent reply {}", deviceInfo, reply);
diff --git a/protocols/netconf/api/src/main/java/org/onosproject/netconf/AbstractNetconfSession.java b/protocols/netconf/api/src/main/java/org/onosproject/netconf/AbstractNetconfSession.java
new file mode 100644
index 0000000..07098f6
--- /dev/null
+++ b/protocols/netconf/api/src/main/java/org/onosproject/netconf/AbstractNetconfSession.java
@@ -0,0 +1,416 @@
+/*
+ * Copyright 2018-present Open Networking Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.onosproject.netconf;
+
+import java.util.Set;
+import java.util.concurrent.CompletableFuture;
+
+import org.slf4j.Logger;
+
+import com.google.common.annotations.Beta;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+import static org.slf4j.LoggerFactory.getLogger;
+
+
+/**
+ * Abstract netconf session implements methods common
+ * for different implementations of netconf session.
+ */
+public abstract class AbstractNetconfSession implements NetconfSession {
+
+ private static final Logger log = getLogger(AbstractNetconfSession.class);
+
+ private static final String ENDPATTERN = "]]>]]>";
+ private static final String MESSAGE_ID_STRING = "message-id";
+ private static final String NEW_LINE = "\n";
+ private static final String EQUAL = "=";
+ private static final String RPC_OPEN = "<rpc ";
+ private static final String RPC_CLOSE = "</rpc>";
+ private static final String GET_OPEN = "<get>";
+ private static final String GET_CLOSE = "</get>";
+ private static final String WITH_DEFAULT_OPEN = "<with-defaults ";
+ private static final String WITH_DEFAULT_CLOSE = "</with-defaults>";
+ private static final String DEFAULT_OPERATION_OPEN = "<default-operation>";
+ private static final String DEFAULT_OPERATION_CLOSE = "</default-operation>";
+ private static final String SUBTREE_FILTER_OPEN = "<filter type=\"subtree\">";
+ private static final String SUBTREE_FILTER_CLOSE = "</filter>";
+ private static final String EDIT_CONFIG_OPEN = "<edit-config>";
+ private static final String EDIT_CONFIG_CLOSE = "</edit-config>";
+ private static final String TARGET_OPEN = "<target>";
+ private static final String TARGET_CLOSE = "</target>";
+ // FIXME hard coded namespace nc
+ private static final String CONFIG_OPEN = "<config xmlns:nc=\"urn:ietf:params:xml:ns:netconf:base:1.0\">";
+ private static final String CONFIG_CLOSE = "</config>";
+ private static final String XML_HEADER = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>";
+ private static final String NETCONF_BASE_NAMESPACE =
+ "xmlns=\"urn:ietf:params:xml:ns:netconf:base:1.0\"";
+ private static final String NETCONF_WITH_DEFAULTS_NAMESPACE =
+ "xmlns=\"urn:ietf:params:xml:ns:yang:ietf-netconf-with-defaults\"";
+
+ @Override
+ public abstract CompletableFuture<String> request(String request) throws NetconfException;
+
+ @Override
+ public abstract CompletableFuture<String> rpc(String request) throws NetconfException;
+
+ @Override
+ public CompletableFuture<CharSequence> asyncGetConfig(DatastoreId datastore) throws NetconfException {
+ StringBuilder rpc = new StringBuilder();
+ rpc.append("<rpc xmlns=\"urn:ietf:params:xml:ns:netconf:base:1.0\">\n");
+ rpc.append("<get-config>\n");
+ rpc.append("<source>\n");
+ rpc.append('<').append(checkNotNull(datastore)).append("/>");
+ rpc.append("</source>");
+ // filter here
+ rpc.append("</get-config>\n");
+ rpc.append("</rpc>");
+
+ return rpc(rpc.toString())
+ .thenApply(msg -> {
+ // crude way of removing rpc-reply envelope
+ int begin = msg.indexOf("<data>");
+ int end = msg.lastIndexOf("</data>");
+ if (begin != -1 && end != -1) {
+ return msg.subSequence(begin, end + "</data>".length());
+ } else {
+ // FIXME probably should exceptionally fail here.
+ return msg;
+ }
+ });
+ }
+
+ @Override
+ public CompletableFuture<CharSequence> asyncGet() throws NetconfException {
+ StringBuilder rpc = new StringBuilder();
+ rpc.append("<rpc xmlns=\"urn:ietf:params:xml:ns:netconf:base:1.0\">\n");
+ rpc.append("<get>\n");
+ // filter here
+ rpc.append("</get>\n");
+ rpc.append("</rpc>");
+ return rpc(rpc.toString())
+ .thenApply(msg -> {
+ // crude way of removing rpc-reply envelope
+ int begin = msg.indexOf("<data>");
+ int end = msg.lastIndexOf("</data>");
+ if (begin != -1 && end != -1) {
+ return msg.subSequence(begin, end + "</data>".length());
+ } else {
+ // FIXME probably should exceptionally fail here.
+ return msg;
+ }
+ });
+
+ }
+
+ @Override
+ public String get(String request) throws NetconfException {
+ return requestSync(request);
+ }
+
+ @Override
+ public String get(String filterSchema, String withDefaultsMode) throws NetconfException {
+ StringBuilder rpc = new StringBuilder(XML_HEADER);
+ rpc.append(RPC_OPEN);
+ rpc.append(MESSAGE_ID_STRING);
+ rpc.append(EQUAL);
+ rpc.append("\"");
+ //Assign a random integer here, it will be replaced in formatting
+ rpc.append(1);
+ rpc.append("\" ");
+ rpc.append(NETCONF_BASE_NAMESPACE).append(">\n");
+ rpc.append(GET_OPEN).append(NEW_LINE);
+ if (filterSchema != null) {
+ rpc.append(SUBTREE_FILTER_OPEN).append(NEW_LINE);
+ rpc.append(filterSchema).append(NEW_LINE);
+ rpc.append(SUBTREE_FILTER_CLOSE).append(NEW_LINE);
+ }
+ if (withDefaultsMode != null) {
+ rpc.append(WITH_DEFAULT_OPEN).append(NETCONF_WITH_DEFAULTS_NAMESPACE).append(">");
+ rpc.append(withDefaultsMode).append(WITH_DEFAULT_CLOSE).append(NEW_LINE);
+ }
+ rpc.append(GET_CLOSE).append(NEW_LINE);
+ rpc.append(RPC_CLOSE).append(NEW_LINE);
+ rpc.append(ENDPATTERN);
+ return requestSync(rpc.toString());
+ }
+
+ @Override
+ public String doWrappedRpc(String request) throws NetconfException {
+ StringBuilder rpc = new StringBuilder(XML_HEADER);
+ rpc.append(RPC_OPEN);
+ rpc.append(MESSAGE_ID_STRING);
+ rpc.append(EQUAL);
+ rpc.append("\"");
+ //Assign a random integer here, it will be replaced in formatting
+ rpc.append(1);
+ rpc.append("\" ");
+ rpc.append(NETCONF_BASE_NAMESPACE).append(">\n");
+ rpc.append(request);
+ rpc.append(RPC_CLOSE).append(NEW_LINE);
+ rpc.append(ENDPATTERN);
+ return requestSync(rpc.toString());
+ }
+
+ @Override
+ public abstract String requestSync(String request) throws NetconfException;
+
+ @Override
+ public String getConfig(DatastoreId netconfTargetConfig) throws NetconfException {
+ return getConfig(netconfTargetConfig, null);
+ }
+
+ @Override
+ public String getConfig(DatastoreId netconfTargetConfig, String configurationFilterSchema) throws NetconfException {
+ StringBuilder rpc = new StringBuilder(XML_HEADER);
+ rpc.append("<rpc ");
+ rpc.append(MESSAGE_ID_STRING);
+ rpc.append(EQUAL);
+ rpc.append("\"");
+ //Assign a random integer here, it will be replaced in formatting
+ rpc.append(1);
+ rpc.append("\" ");
+ rpc.append("xmlns=\"urn:ietf:params:xml:ns:netconf:base:1.0\">\n");
+ rpc.append("<get-config>\n");
+ rpc.append("<source>\n");
+ rpc.append("<").append(netconfTargetConfig).append("/>");
+ rpc.append("</source>");
+ if (configurationFilterSchema != null) {
+ rpc.append("<filter type=\"subtree\">\n");
+ rpc.append(configurationFilterSchema).append("\n");
+ rpc.append("</filter>\n");
+ }
+ rpc.append("</get-config>\n");
+ rpc.append("</rpc>\n");
+ rpc.append(ENDPATTERN);
+ String reply = requestSync(rpc.toString());
+ return checkReply(reply) ? reply : "ERROR " + reply;
+ }
+
+ @Override
+ public boolean editConfig(String newConfiguration) throws NetconfException {
+ if (!newConfiguration.endsWith(ENDPATTERN)) {
+ newConfiguration = newConfiguration + ENDPATTERN;
+ }
+ return checkReply(requestSync(newConfiguration));
+ }
+
+ @Override
+ public boolean editConfig(DatastoreId netconfTargetConfig,
+ String mode,
+ String newConfiguration) throws NetconfException {
+ newConfiguration = newConfiguration.trim();
+ StringBuilder rpc = new StringBuilder(XML_HEADER);
+ rpc.append(RPC_OPEN);
+ rpc.append(MESSAGE_ID_STRING);
+ rpc.append(EQUAL);
+ rpc.append("\"");
+ //Assign a random integer here, it will be replaced in formatting
+ rpc.append(1);
+ rpc.append("\" ");
+ rpc.append(NETCONF_BASE_NAMESPACE).append(">\n");
+ rpc.append(EDIT_CONFIG_OPEN).append("\n");
+ rpc.append(TARGET_OPEN);
+ rpc.append("<").append(netconfTargetConfig).append("/>");
+ rpc.append(TARGET_CLOSE).append("\n");
+ if (mode != null) {
+ rpc.append(DEFAULT_OPERATION_OPEN);
+ rpc.append(mode);
+ rpc.append(DEFAULT_OPERATION_CLOSE).append("\n");
+ }
+ rpc.append(CONFIG_OPEN).append("\n");
+ rpc.append(newConfiguration);
+ rpc.append(CONFIG_CLOSE).append("\n");
+ rpc.append(EDIT_CONFIG_CLOSE).append("\n");
+ rpc.append(RPC_CLOSE);
+ rpc.append(ENDPATTERN);
+ String reply = requestSync(rpc.toString());
+ return checkReply(reply);
+ }
+
+ @Override
+ public boolean copyConfig(DatastoreId destination, DatastoreId source) throws NetconfException {
+ return checkReply(requestSync(bareCopyConfig(destination.asXml(), source.asXml())));
+ }
+
+ @Override
+ public boolean copyConfig(DatastoreId netconfTargetConfig, String newConfiguration) throws NetconfException {
+ return checkReply(requestSync(bareCopyConfig(netconfTargetConfig.asXml(),
+ normalizeCopyConfigParam(newConfiguration))));
+ }
+
+ @Override
+ public boolean copyConfig(String netconfTargetConfig, String newConfiguration) throws NetconfException {
+ return checkReply(requestSync(bareCopyConfig(normalizeCopyConfigParam(netconfTargetConfig),
+ normalizeCopyConfigParam(newConfiguration))));
+ }
+
+ @Override
+ public boolean deleteConfig(DatastoreId netconfTargetConfig) throws NetconfException {
+ if (netconfTargetConfig.equals(DatastoreId.RUNNING)) {
+ return false;
+ }
+ StringBuilder rpc = new StringBuilder(XML_HEADER);
+ rpc.append("<rpc>");
+ rpc.append("<delete-config>");
+ rpc.append("<target>");
+ rpc.append("<").append(netconfTargetConfig).append("/>");
+ rpc.append("</target>");
+ rpc.append("</delete-config>");
+ rpc.append("</rpc>");
+ rpc.append(ENDPATTERN);
+ return checkReply(requestSync(rpc.toString()));
+ }
+
+ @Override
+ public void startSubscription() throws NetconfException {
+ startSubscription(null);
+ }
+
+ @Override
+ public abstract void startSubscription(String filterSchema) throws NetconfException;
+
+ @Override
+ public abstract void endSubscription() throws NetconfException;
+
+ @Override
+ public boolean lock(DatastoreId datastore) throws NetconfException {
+ StringBuilder rpc = new StringBuilder(XML_HEADER);
+ rpc.append("<rpc xmlns=\"urn:ietf:params:xml:ns:netconf:base:1.0\">\n");
+ rpc.append("<lock>");
+ rpc.append("<target>");
+ rpc.append("<");
+ rpc.append(datastore.id());
+ rpc.append("/>");
+ rpc.append("</target>");
+ rpc.append("</lock>");
+ rpc.append("</rpc>");
+ rpc.append(ENDPATTERN);
+ String lockReply = requestSync(rpc.toString());
+ return checkReply(lockReply);
+ }
+
+ @Override
+ public boolean unlock(DatastoreId datastore) throws NetconfException {
+ StringBuilder rpc = new StringBuilder(XML_HEADER);
+ rpc.append("<rpc xmlns=\"urn:ietf:params:xml:ns:netconf:base:1.0\">\n");
+ rpc.append("<unlock>");
+ rpc.append("<target>");
+ rpc.append("<");
+ rpc.append(datastore.id());
+ rpc.append("/>");
+ rpc.append("</target>");
+ rpc.append("</unlock>");
+ rpc.append("</rpc>");
+ rpc.append(ENDPATTERN);
+ String unlockReply = requestSync(rpc.toString());
+ return checkReply(unlockReply);
+ }
+
+ @Override
+ public boolean close() throws NetconfException {
+ StringBuilder rpc = new StringBuilder();
+ rpc.append("<rpc xmlns=\"urn:ietf:params:xml:ns:netconf:base:1.0\">");
+ rpc.append("<close-session/>");
+ rpc.append("</rpc>");
+ rpc.append(ENDPATTERN);
+ boolean closed = checkReply(requestSync(rpc.toString()));
+ if (closed) {
+ return closed;
+ } else {
+ //forcefully kill session if not closed
+ rpc = new StringBuilder();
+ rpc.append("<rpc xmlns=\"urn:ietf:params:xml:ns:netconf:base:1.0\">");
+ rpc.append("<kill-session/>");
+ rpc.append("</rpc>");
+ rpc.append(ENDPATTERN);
+ return checkReply(requestSync(rpc.toString()));
+ }
+ }
+
+ @Override
+ public abstract String getSessionId();
+
+ @Override
+ public abstract Set<String> getDeviceCapabilitiesSet();
+
+ @Override
+ public abstract void addDeviceOutputListener(NetconfDeviceOutputEventListener listener);
+
+ @Override
+ public abstract void removeDeviceOutputListener(NetconfDeviceOutputEventListener listener);
+
+ /**
+ * Checks errors in reply from the session.
+ * @param reply reply string
+ * @return true if no error, else false
+ */
+ @Beta
+ protected boolean checkReply(String reply) {
+ if (reply != null) {
+ if (!reply.contains("<rpc-error>")) {
+ return true;
+ } else if (reply.contains("<ok/>")
+ || (reply.contains("<rpc-error>")
+ && reply.contains("warning"))) {
+ // FIXME rpc-error with a warning is considered same as Ok??
+ return true;
+ }
+ }
+ return false;
+ }
+
+ private String bareCopyConfig(CharSequence target,
+ CharSequence source)
+ throws NetconfException {
+ StringBuilder rpc = new StringBuilder(XML_HEADER);
+ rpc.append(RPC_OPEN);
+ rpc.append(NETCONF_BASE_NAMESPACE).append(">\n");
+ rpc.append("<copy-config>");
+ rpc.append("<target>");
+ rpc.append(target);
+ rpc.append("</target>");
+ rpc.append("<source>");
+ rpc.append(source);
+ rpc.append("</source>");
+ rpc.append("</copy-config>");
+ rpc.append("</rpc>");
+ rpc.append(ENDPATTERN);
+ return rpc.toString();
+ }
+
+ /**
+ * Normalize String parameter passed to copy-config API.
+ * <p>
+ * Provided for backward compatibility purpose
+ *
+ * @param input passed to copyConfig API
+ * @return XML likely to be suitable for copy-config source or target
+ */
+ private CharSequence normalizeCopyConfigParam(String input) {
+ input = input.trim();
+ if (input.startsWith("<url")) {
+ return input;
+ } else if (!input.startsWith("<")) {
+ // assume it is a datastore name
+ return DatastoreId.datastore(input).asXml();
+ } else if (!input.startsWith("<config>")) {
+ return "<config>" + input + "</config>";
+ }
+ return input;
+ }
+}
diff --git a/protocols/netconf/api/src/main/java/org/onosproject/netconf/NetconfSession.java b/protocols/netconf/api/src/main/java/org/onosproject/netconf/NetconfSession.java
index 0711137..bc04118 100644
--- a/protocols/netconf/api/src/main/java/org/onosproject/netconf/NetconfSession.java
+++ b/protocols/netconf/api/src/main/java/org/onosproject/netconf/NetconfSession.java
@@ -20,8 +20,6 @@
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
-import static com.google.common.base.Preconditions.checkNotNull;
-
import java.util.Set;
import java.util.concurrent.CompletableFuture;
@@ -57,9 +55,7 @@
* the underlying connection
* @throws NetconfTransportException on secure transport-layer error
*/
- default CompletableFuture<String> rpc(String request) throws NetconfException {
- return request(request);
- }
+ CompletableFuture<String> rpc(String request) throws NetconfException;
/**
* Retrieves the specified configuration.
@@ -70,30 +66,7 @@
* @throws NetconfException when there is a problem in the communication process on
* the underlying connection
*/
- default CompletableFuture<CharSequence> asyncGetConfig(DatastoreId datastore) throws NetconfException {
- StringBuilder rpc = new StringBuilder();
- rpc.append("<rpc xmlns=\"urn:ietf:params:xml:ns:netconf:base:1.0\">\n");
- rpc.append("<get-config>\n");
- rpc.append("<source>\n");
- rpc.append('<').append(checkNotNull(datastore)).append("/>");
- rpc.append("</source>");
- // filter here
- rpc.append("</get-config>\n");
- rpc.append("</rpc>");
-
- return rpc(rpc.toString())
- .thenApply(msg -> {
- // crude way of removing rpc-reply envelope
- int begin = msg.indexOf("<data>");
- int end = msg.lastIndexOf("</data>");
- if (begin != -1 && end != -1) {
- return msg.subSequence(begin, end + "</data>".length());
- } else {
- // FIXME probably should exceptionally fail here.
- return msg;
- }
- });
- }
+ CompletableFuture<CharSequence> asyncGetConfig(DatastoreId datastore) throws NetconfException;
/**
* Retrieves running configuration and device state.
@@ -103,27 +76,7 @@
* @throws NetconfException when there is a problem in the communication process on
* the underlying connection
*/
- default CompletableFuture<CharSequence> asyncGet() throws NetconfException {
- StringBuilder rpc = new StringBuilder();
- rpc.append("<rpc xmlns=\"urn:ietf:params:xml:ns:netconf:base:1.0\">\n");
- rpc.append("<get>\n");
- // filter here
- rpc.append("</get>\n");
- rpc.append("</rpc>");
- return rpc(rpc.toString())
- .thenApply(msg -> {
- // crude way of removing rpc-reply envelope
- int begin = msg.indexOf("<data>");
- int end = msg.lastIndexOf("</data>");
- if (begin != -1 && end != -1) {
- return msg.subSequence(begin, end + "</data>".length());
- } else {
- // FIXME probably should exceptionally fail here.
- return msg;
- }
- });
-
- }
+ CompletableFuture<CharSequence> asyncGet() throws NetconfException;
/**
@@ -357,7 +310,6 @@
* session.
*
* @return Network capabilities as strings in a Set.
- *
* @since 1.10.0
*/
Set<String> getDeviceCapabilitiesSet();
@@ -378,7 +330,6 @@
* Sets the ONOS side capabilities.
*
* @param capabilities list of capabilities ONOS has.
- *
* @since 1.10.0
*/
default void setOnosCapabilities(Iterable<String> capabilities) {
@@ -387,7 +338,7 @@
}
/**
- * Remove a listener from the underlying stream handler implementation.
+ * Add a listener to the underlying stream handler implementation.
*
* @param listener event listener.
*/
@@ -406,7 +357,7 @@
*/
default int timeoutConnectSec() {
return 0;
- };
+ }
/**
* Read the reply timeout that this session was created with.
@@ -414,7 +365,7 @@
*/
default int timeoutReplySec() {
return 0;
- };
+ }
/**
* Read the idle timeout that this session was created with.
@@ -422,6 +373,6 @@
*/
default int timeoutIdleSec() {
return 0;
- };
+ }
}
diff --git a/protocols/netconf/api/src/main/java/org/onosproject/netconf/NetconfSessionAdapter.java b/protocols/netconf/api/src/main/java/org/onosproject/netconf/NetconfSessionAdapter.java
index 6ca84c7..afb9015 100644
--- a/protocols/netconf/api/src/main/java/org/onosproject/netconf/NetconfSessionAdapter.java
+++ b/protocols/netconf/api/src/main/java/org/onosproject/netconf/NetconfSessionAdapter.java
@@ -24,7 +24,11 @@
/**
* Adapter mainly intended for usage in tests.
*/
-public class NetconfSessionAdapter implements NetconfSession {
+public class NetconfSessionAdapter
+ extends AbstractNetconfSession
+ implements NetconfSession {
+
+ // TODO remove methods defined in AbstractNetconfSession
@Override
public void startSubscription(String filterSchema) throws NetconfException {
@@ -46,6 +50,13 @@
}
@Override
+ public CompletableFuture<String> rpc(String request)
+ throws NetconfException {
+ return Tools.exceptionalFuture(new UnsupportedOperationException());
+ }
+
+
+ @Override
public void removeDeviceOutputListener(NetconfDeviceOutputEventListener listener) {
}
diff --git a/protocols/netconf/ctl/src/main/java/org/onosproject/netconf/ctl/impl/NetconfSessionMinaImpl.java b/protocols/netconf/ctl/src/main/java/org/onosproject/netconf/ctl/impl/NetconfSessionMinaImpl.java
index 846ec26..56818a3 100644
--- a/protocols/netconf/ctl/src/main/java/org/onosproject/netconf/ctl/impl/NetconfSessionMinaImpl.java
+++ b/protocols/netconf/ctl/src/main/java/org/onosproject/netconf/ctl/impl/NetconfSessionMinaImpl.java
@@ -33,7 +33,7 @@
import org.bouncycastle.openssl.PEMKeyPair;
import org.bouncycastle.openssl.jcajce.JcaPEMKeyConverter;
import org.onlab.util.SharedExecutors;
-import org.onosproject.netconf.DatastoreId;
+import org.onosproject.netconf.AbstractNetconfSession;
import org.onosproject.netconf.NetconfDeviceInfo;
import org.onosproject.netconf.NetconfDeviceOutputEvent;
import org.onosproject.netconf.NetconfDeviceOutputEvent.Type;
@@ -75,7 +75,7 @@
/**
* Implementation of a NETCONF session to talk to a device.
*/
-public class NetconfSessionMinaImpl implements NetconfSession {
+public class NetconfSessionMinaImpl extends AbstractNetconfSession {
private static final Logger log = getLogger(NetconfSessionMinaImpl.class);
@@ -89,29 +89,11 @@
private static final String END_OF_RPC_OPEN_TAG = "\">";
private static final String EQUAL = "=";
private static final String NUMBER_BETWEEN_QUOTES_MATCHER = "\"+([0-9]+)+\"";
- private static final String RPC_OPEN = "<rpc ";
- private static final String RPC_CLOSE = "</rpc>";
- private static final String GET_OPEN = "<get>";
- private static final String GET_CLOSE = "</get>";
- private static final String WITH_DEFAULT_OPEN = "<with-defaults ";
- private static final String WITH_DEFAULT_CLOSE = "</with-defaults>";
- private static final String DEFAULT_OPERATION_OPEN = "<default-operation>";
- private static final String DEFAULT_OPERATION_CLOSE = "</default-operation>";
- private static final String SUBTREE_FILTER_OPEN = "<filter type=\"subtree\">";
private static final String SUBTREE_FILTER_CLOSE = "</filter>";
- private static final String EDIT_CONFIG_OPEN = "<edit-config>";
- private static final String EDIT_CONFIG_CLOSE = "</edit-config>";
- private static final String TARGET_OPEN = "<target>";
- private static final String TARGET_CLOSE = "</target>";
// FIXME hard coded namespace nc
- private static final String CONFIG_OPEN = "<config xmlns:nc=\"urn:ietf:params:xml:ns:netconf:base:1.0\">";
- private static final String CONFIG_CLOSE = "</config>";
private static final String XML_HEADER =
"<?xml version=\"1.0\" encoding=\"UTF-8\"?>";
- private static final String NETCONF_BASE_NAMESPACE =
- "xmlns=\"urn:ietf:params:xml:ns:netconf:base:1.0\"";
- private static final String NETCONF_WITH_DEFAULTS_NAMESPACE =
- "xmlns=\"urn:ietf:params:xml:ns:yang:ietf-netconf-with-defaults\"";
+
// FIXME hard coded namespace base10
private static final String SUBSCRIPTION_SUBTREE_FILTER_OPEN =
"<filter xmlns:base10=\"urn:ietf:params:xml:ns:netconf:base:1.0\" base10:type=\"subtree\">";
@@ -212,6 +194,8 @@
startSession();
}
+ //TODO: Remove the default methods already implemented in NetconfSession
+
// FIXME blocking
@Deprecated
private void startSession() throws IOException {
@@ -316,14 +300,6 @@
subscriptionConnected = true;
}
- @Override
- public void startSubscription() throws NetconfException {
- if (!subscriptionConnected) {
- startSubscriptionStream(null);
- }
- streamHandler.setEnableNotifications(true);
- }
-
@Beta
@Override
public void startSubscription(String filterSchema) throws NetconfException {
@@ -642,266 +618,6 @@
}
@Override
- public String doWrappedRpc(String request) throws NetconfException {
- StringBuilder rpc = new StringBuilder(XML_HEADER);
- rpc.append(RPC_OPEN);
- rpc.append(MESSAGE_ID_STRING);
- rpc.append(EQUAL);
- rpc.append("\"");
- rpc.append(messageIdInteger.get());
- rpc.append("\" ");
- rpc.append(NETCONF_BASE_NAMESPACE).append(">\n");
- rpc.append(request);
- rpc.append(RPC_CLOSE).append(NEW_LINE);
- rpc.append(ENDPATTERN);
- String reply = sendRequest(rpc.toString());
- checkReply(reply);
- return reply;
- }
-
- @Override
- public String get(String request) throws NetconfException {
- return requestSync(request);
- }
-
- @Override
- public String get(String filterSchema, String withDefaultsMode) throws NetconfException {
- StringBuilder rpc = new StringBuilder(XML_HEADER);
- rpc.append(RPC_OPEN);
- rpc.append(MESSAGE_ID_STRING);
- rpc.append(EQUAL);
- rpc.append("\"");
- rpc.append(messageIdInteger.get());
- rpc.append("\" ");
- rpc.append(NETCONF_BASE_NAMESPACE).append(">\n");
- rpc.append(GET_OPEN).append(NEW_LINE);
- if (filterSchema != null) {
- rpc.append(SUBTREE_FILTER_OPEN).append(NEW_LINE);
- rpc.append(filterSchema).append(NEW_LINE);
- rpc.append(SUBTREE_FILTER_CLOSE).append(NEW_LINE);
- }
- if (withDefaultsMode != null) {
- rpc.append(WITH_DEFAULT_OPEN).append(NETCONF_WITH_DEFAULTS_NAMESPACE).append(">");
- rpc.append(withDefaultsMode).append(WITH_DEFAULT_CLOSE).append(NEW_LINE);
- }
- rpc.append(GET_CLOSE).append(NEW_LINE);
- rpc.append(RPC_CLOSE).append(NEW_LINE);
- rpc.append(ENDPATTERN);
- String reply = sendRequest(rpc.toString());
- checkReply(reply);
- return reply;
- }
-
- @Override
- public String getConfig(DatastoreId netconfTargetConfig) throws NetconfException {
- return getConfig(netconfTargetConfig, null);
- }
-
- @Override
- public String getConfig(DatastoreId netconfTargetConfig,
- String configurationSchema) throws NetconfException {
- StringBuilder rpc = new StringBuilder(XML_HEADER);
- rpc.append("<rpc ");
- rpc.append(MESSAGE_ID_STRING);
- rpc.append(EQUAL);
- rpc.append("\"");
- rpc.append(messageIdInteger.get());
- rpc.append("\" ");
- rpc.append("xmlns=\"urn:ietf:params:xml:ns:netconf:base:1.0\">\n");
- rpc.append("<get-config>\n");
- rpc.append("<source>\n");
- rpc.append("<").append(netconfTargetConfig).append("/>");
- rpc.append("</source>");
- if (configurationSchema != null) {
- rpc.append("<filter type=\"subtree\">\n");
- rpc.append(configurationSchema).append("\n");
- rpc.append("</filter>\n");
- }
- rpc.append("</get-config>\n");
- rpc.append("</rpc>\n");
- rpc.append(ENDPATTERN);
- String reply = sendRequest(rpc.toString());
- return checkReply(reply) ? reply : "ERROR " + reply;
- }
-
- @Override
- public boolean editConfig(String newConfiguration) throws NetconfException {
- if (!newConfiguration.endsWith(ENDPATTERN)) {
- newConfiguration = newConfiguration + ENDPATTERN;
- }
- return checkReply(sendRequest(newConfiguration));
- }
-
- @Override
- public boolean editConfig(DatastoreId netconfTargetConfig,
- String mode,
- String newConfiguration)
- throws NetconfException {
-
- newConfiguration = newConfiguration.trim();
- StringBuilder rpc = new StringBuilder(XML_HEADER);
- rpc.append(RPC_OPEN);
- rpc.append(MESSAGE_ID_STRING);
- rpc.append(EQUAL);
- rpc.append("\"");
- rpc.append(messageIdInteger.get());
- rpc.append("\" ");
- rpc.append(NETCONF_BASE_NAMESPACE).append(">\n");
- rpc.append(EDIT_CONFIG_OPEN).append("\n");
- rpc.append(TARGET_OPEN);
- rpc.append("<").append(netconfTargetConfig).append("/>");
- rpc.append(TARGET_CLOSE).append("\n");
- if (mode != null) {
- rpc.append(DEFAULT_OPERATION_OPEN);
- rpc.append(mode);
- rpc.append(DEFAULT_OPERATION_CLOSE).append("\n");
- }
- rpc.append(CONFIG_OPEN).append("\n");
- rpc.append(newConfiguration);
- rpc.append(CONFIG_CLOSE).append("\n");
- rpc.append(EDIT_CONFIG_CLOSE).append("\n");
- rpc.append(RPC_CLOSE);
- rpc.append(ENDPATTERN);
- log.debug("{}", rpc);
- String reply = sendRequest(rpc.toString());
- return checkReply(reply);
- }
-
- @Override
- public boolean copyConfig(DatastoreId destination,
- DatastoreId source)
- throws NetconfException {
- return bareCopyConfig(destination.asXml(), source.asXml());
- }
-
- @Override
- public boolean copyConfig(DatastoreId netconfTargetConfig,
- String newConfiguration)
- throws NetconfException {
- return bareCopyConfig(netconfTargetConfig.asXml(),
- normalizeCopyConfigParam(newConfiguration));
- }
-
- @Override
- public boolean copyConfig(String netconfTargetConfig,
- String newConfiguration) throws NetconfException {
- return bareCopyConfig(normalizeCopyConfigParam(netconfTargetConfig),
- normalizeCopyConfigParam(newConfiguration));
- }
-
- /**
- * Normalize String parameter passed to copy-config API.
- * <p>
- * Provided for backward compatibility purpose
- *
- * @param input passed to copyConfig API
- * @return XML likely to be suitable for copy-config source or target
- */
- private static CharSequence normalizeCopyConfigParam(String input) {
- input = input.trim();
- if (input.startsWith("<url")) {
- return input;
- } else if (!input.startsWith("<")) {
- // assume it is a datastore name
- return DatastoreId.datastore(input).asXml();
- } else if (!input.startsWith("<config>")) {
- return "<config>" + input + "</config>";
- }
- return input;
- }
-
- private boolean bareCopyConfig(CharSequence target,
- CharSequence source)
- throws NetconfException {
-
- StringBuilder rpc = new StringBuilder(XML_HEADER);
- rpc.append(RPC_OPEN);
- rpc.append(NETCONF_BASE_NAMESPACE).append(">\n");
- rpc.append("<copy-config>");
- rpc.append("<target>");
- rpc.append(target);
- rpc.append("</target>");
- rpc.append("<source>");
- rpc.append(source);
- rpc.append("</source>");
- rpc.append("</copy-config>");
- rpc.append("</rpc>");
- rpc.append(ENDPATTERN);
- return checkReply(sendRequest(rpc.toString()));
- }
-
- @Override
- public boolean deleteConfig(DatastoreId netconfTargetConfig) throws NetconfException {
- if (netconfTargetConfig.equals(DatastoreId.RUNNING)) {
- log.warn("Target configuration for delete operation can't be \"running\"",
- netconfTargetConfig);
- return false;
- }
- StringBuilder rpc = new StringBuilder(XML_HEADER);
- rpc.append("<rpc>");
- rpc.append("<delete-config>");
- rpc.append("<target>");
- rpc.append("<").append(netconfTargetConfig).append("/>");
- rpc.append("</target>");
- rpc.append("</delete-config>");
- rpc.append("</rpc>");
- rpc.append(ENDPATTERN);
- return checkReply(sendRequest(rpc.toString()));
- }
-
- @Override
- public boolean lock(DatastoreId configType) throws NetconfException {
- StringBuilder rpc = new StringBuilder(XML_HEADER);
- rpc.append("<rpc xmlns=\"urn:ietf:params:xml:ns:netconf:base:1.0\">\n");
- rpc.append("<lock>");
- rpc.append("<target>");
- rpc.append("<");
- rpc.append(configType.id());
- rpc.append("/>");
- rpc.append("</target>");
- rpc.append("</lock>");
- rpc.append("</rpc>");
- rpc.append(ENDPATTERN);
- String lockReply = sendRequest(rpc.toString());
- return checkReply(lockReply);
- }
-
- @Override
- public boolean unlock(DatastoreId configType) throws NetconfException {
- StringBuilder rpc = new StringBuilder(XML_HEADER);
- rpc.append("<rpc xmlns=\"urn:ietf:params:xml:ns:netconf:base:1.0\">\n");
- rpc.append("<unlock>");
- rpc.append("<target>");
- rpc.append("<");
- rpc.append(configType.id());
- rpc.append("/>");
- rpc.append("</target>");
- rpc.append("</unlock>");
- rpc.append("</rpc>");
- rpc.append(ENDPATTERN);
- String unlockReply = sendRequest(rpc.toString());
- return checkReply(unlockReply);
- }
-
- @Override
- public boolean close() throws NetconfException {
- return close(false);
- }
-
- private boolean close(boolean force) throws NetconfException {
- StringBuilder rpc = new StringBuilder();
- rpc.append("<rpc xmlns=\"urn:ietf:params:xml:ns:netconf:base:1.0\">");
- if (force) {
- rpc.append("<kill-session/>");
- } else {
- rpc.append("<close-session/>");
- }
- rpc.append("</rpc>");
- rpc.append(ENDPATTERN);
- return checkReply(sendRequest(rpc.toString())) || close(true);
- }
-
- @Override
public String getSessionId() {
return sessionID;
}
@@ -929,7 +645,9 @@
streamHandler.removeDeviceEventListener(listener);
}
- private boolean checkReply(String reply) {
+ @Override
+ protected boolean checkReply(String reply) {
+ // Overridden to record error logs
if (reply != null) {
if (!reply.contains("<rpc-error>")) {
log.debug("Device {} sent reply {}", deviceInfo, reply);