Allow specification of ODL's HELLO message 69/72669/2
authorRyan Goulding <ryandgoulding@gmail.com>
Mon, 9 Apr 2018 22:47:29 +0000 (18:47 -0400)
committerRyan Goulding <ryandgoulding@gmail.com>
Mon, 4 Jun 2018 16:32:22 +0000 (12:32 -0400)
Some devices are very particular about what they will accept
for a HELLO message.  This change allows specification of a custom
message per device mount.  If one is not specified, then the
existing default is utilized.

Additionally, certain tests were using very out of date versions of
netconf-node-topology.  This is due to the fact that the test
yang files are located in src/test/resources, and were out of date
with the netconf-node-topology used in src/main/yang.  These were
updated to the most up-to-date version as of this patch.

JIRA: NETCONF-543
Change-Id: I4049a87a7781655d8d396bb35eb43aab2eca0223
Signed-off-by: Ryan Goulding <ryandgoulding@gmail.com>
netconf/netconf-api/src/main/java/org/opendaylight/netconf/api/messages/NetconfHelloMessage.java
netconf/netconf-client/src/main/java/org/opendaylight/netconf/client/NetconfClientDispatcherImpl.java
netconf/netconf-client/src/main/java/org/opendaylight/netconf/client/conf/NetconfClientConfiguration.java
netconf/netconf-client/src/main/java/org/opendaylight/netconf/client/conf/NetconfClientConfigurationBuilder.java
netconf/netconf-client/src/main/java/org/opendaylight/netconf/client/conf/NetconfReconnectingClientConfiguration.java
netconf/netconf-client/src/main/java/org/opendaylight/netconf/client/conf/NetconfReconnectingClientConfigurationBuilder.java
netconf/netconf-console/src/test/resources/schemas/netconf-node-topology.yang
netconf/netconf-topology-singleton/src/main/java/org/opendaylight/netconf/topology/singleton/impl/RemoteDeviceConnectorImpl.java
netconf/sal-netconf-connector/src/main/yang/netconf-node-topology.yang
netconf/sal-netconf-connector/src/test/resources/schemas/netconf-node-topology.yang

index f3266968f0a27f10f02a8921ec35daa0a2cf68c2..6d9184b07642634a1f77306ac4449c87a1cdff74 100644 (file)
@@ -22,7 +22,8 @@ import org.w3c.dom.Element;
 
 /**
  * NetconfMessage that can carry additional header with session metadata.
- * See {@link NetconfHelloMessageAdditionalHeader}
+ *
+ * @see NetconfHelloMessageAdditionalHeader
  */
 public final class NetconfHelloMessage extends NetconfMessage {
 
index 6abce42b43239d0c0d645964d11450c8abcb2c7a..3b63d41a8cf93c53c80856611c3fca62a8d53afd 100644 (file)
@@ -12,9 +12,13 @@ import io.netty.channel.EventLoopGroup;
 import io.netty.util.Timer;
 import io.netty.util.concurrent.Future;
 import java.io.Closeable;
+import java.util.LinkedHashSet;
+import java.util.List;
+import java.util.Set;
 import org.opendaylight.netconf.client.conf.NetconfClientConfiguration;
 import org.opendaylight.netconf.client.conf.NetconfReconnectingClientConfiguration;
 import org.opendaylight.protocol.framework.AbstractDispatcher;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.Uri;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -99,7 +103,19 @@ public class NetconfClientDispatcherImpl extends AbstractDispatcher<NetconfClien
     }
 
     protected NetconfClientSessionNegotiatorFactory getNegotiatorFactory(final NetconfClientConfiguration cfg) {
-        return new NetconfClientSessionNegotiatorFactory(timer, cfg.getAdditionalHeader(),
-                cfg.getConnectionTimeoutMillis());
+        final List<Uri> odlHelloCapabilities = cfg.getOdlHelloCapabilities();
+        if (odlHelloCapabilities == null || odlHelloCapabilities.isEmpty()) {
+            return new NetconfClientSessionNegotiatorFactory(timer, cfg.getAdditionalHeader(),
+                    cfg.getConnectionTimeoutMillis());
+        } else {
+            // LinkedHashSet since perhaps the device cares about order of hello message capabilities.
+            // This allows user control of the order while complying with the existing interface.
+            final Set<String> stringCapabilities = new LinkedHashSet<>();
+            for (final Uri uri : odlHelloCapabilities) {
+                stringCapabilities.add(uri.getValue());
+            }
+            return new NetconfClientSessionNegotiatorFactory(timer, cfg.getAdditionalHeader(),
+                    cfg.getConnectionTimeoutMillis(), stringCapabilities);
+        }
     }
 }
index ae0d3330087c4db4f7d4f5a97c9f509284ae8c76..56c25ff34a8c6ef2a5b69e592288f0e2fa9e8a28 100644 (file)
@@ -12,10 +12,12 @@ import com.google.common.base.MoreObjects.ToStringHelper;
 import com.google.common.base.Optional;
 import com.google.common.base.Preconditions;
 import java.net.InetSocketAddress;
+import java.util.List;
 import org.opendaylight.netconf.api.messages.NetconfHelloMessageAdditionalHeader;
 import org.opendaylight.netconf.client.NetconfClientSessionListener;
 import org.opendaylight.netconf.nettyutil.handler.ssh.authentication.AuthenticationHandler;
 import org.opendaylight.protocol.framework.ReconnectStrategy;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.Uri;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -34,11 +36,15 @@ public class NetconfClientConfiguration {
 
     private final AuthenticationHandler authHandler;
 
+    private final List<Uri> odlHelloCapabilities;
+
     NetconfClientConfiguration(final NetconfClientProtocol protocol, final InetSocketAddress address,
                                final Long connectionTimeoutMillis,
                                final NetconfHelloMessageAdditionalHeader additionalHeader,
                                final NetconfClientSessionListener sessionListener,
-                               final ReconnectStrategy reconnectStrategy, final AuthenticationHandler authHandler) {
+
+                               final ReconnectStrategy reconnectStrategy, final AuthenticationHandler authHandler,
+                               final List<Uri> odlHelloCapabilities) {
         this.address = address;
         this.connectionTimeoutMillis = connectionTimeoutMillis;
         this.additionalHeader = additionalHeader;
@@ -46,6 +52,7 @@ public class NetconfClientConfiguration {
         this.clientProtocol = protocol;
         this.reconnectStrategy = reconnectStrategy;
         this.authHandler = authHandler;
+        this.odlHelloCapabilities = odlHelloCapabilities;
         validateConfiguration();
     }
 
@@ -77,6 +84,10 @@ public class NetconfClientConfiguration {
         return clientProtocol;
     }
 
+    public List<Uri> getOdlHelloCapabilities() {
+        return odlHelloCapabilities;
+    }
+
     @SuppressWarnings("checkstyle:FallThrough")
     private void validateConfiguration() {
         Preconditions.checkNotNull(clientProtocol, " ");
index 73f664cdceaa8dcc18e84affa840b37ca9ed614c..5b26f79c15067c13eb8ec107328de1543ca1d7ac 100644 (file)
@@ -8,10 +8,12 @@
 package org.opendaylight.netconf.client.conf;
 
 import java.net.InetSocketAddress;
+import java.util.List;
 import org.opendaylight.netconf.api.messages.NetconfHelloMessageAdditionalHeader;
 import org.opendaylight.netconf.client.NetconfClientSessionListener;
 import org.opendaylight.netconf.nettyutil.handler.ssh.authentication.AuthenticationHandler;
 import org.opendaylight.protocol.framework.ReconnectStrategy;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.Uri;
 
 public class NetconfClientConfigurationBuilder {
 
@@ -26,6 +28,7 @@ public class NetconfClientConfigurationBuilder {
     private ReconnectStrategy reconnectStrategy;
     private AuthenticationHandler authHandler;
     private NetconfClientConfiguration.NetconfClientProtocol clientProtocol = DEFAULT_CLIENT_PROTOCOL;
+    private List<Uri> odlHelloCapabilities;
 
     protected NetconfClientConfigurationBuilder() {
     }
@@ -78,6 +81,12 @@ public class NetconfClientConfigurationBuilder {
         return this;
     }
 
+    @SuppressWarnings("checkstyle:hiddenField")
+    public NetconfClientConfigurationBuilder withOdlHelloCapabilities(final List<Uri> odlHelloCapabilities) {
+        this.odlHelloCapabilities = odlHelloCapabilities;
+        return this;
+    }
+
     final InetSocketAddress getAddress() {
         return address;
     }
@@ -106,8 +115,12 @@ public class NetconfClientConfigurationBuilder {
         return clientProtocol;
     }
 
+    final List<Uri> getOdlHelloCapabilities() {
+        return odlHelloCapabilities;
+    }
+
     public NetconfClientConfiguration build() {
         return new NetconfClientConfiguration(clientProtocol, address, connectionTimeoutMillis, additionalHeader,
-                sessionListener, reconnectStrategy, authHandler);
+                sessionListener, reconnectStrategy, authHandler, odlHelloCapabilities);
     }
 }
index a2512687e4ad569a35adc5bfd5f91472edc62797..71a715061dc56c2f6439baca2834933f2dbde842 100644 (file)
@@ -10,11 +10,13 @@ package org.opendaylight.netconf.client.conf;
 import com.google.common.base.MoreObjects.ToStringHelper;
 import com.google.common.base.Preconditions;
 import java.net.InetSocketAddress;
+import java.util.List;
 import org.opendaylight.netconf.api.messages.NetconfHelloMessageAdditionalHeader;
 import org.opendaylight.netconf.client.NetconfClientSessionListener;
 import org.opendaylight.netconf.nettyutil.handler.ssh.authentication.AuthenticationHandler;
 import org.opendaylight.protocol.framework.ReconnectStrategy;
 import org.opendaylight.protocol.framework.ReconnectStrategyFactory;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.Uri;
 
 public final class NetconfReconnectingClientConfiguration extends NetconfClientConfiguration {
 
@@ -26,9 +28,10 @@ public final class NetconfReconnectingClientConfiguration extends NetconfClientC
                                            final NetconfClientSessionListener sessionListener,
                                            final ReconnectStrategy reconnectStrategy,
                                            final ReconnectStrategyFactory connectStrategyFactory,
-                                           final AuthenticationHandler authHandler) {
+                                           final AuthenticationHandler authHandler,
+                                           final List<Uri> odlHelloCapabilities) {
         super(clientProtocol, address, connectionTimeoutMillis, additionalHeader, sessionListener, reconnectStrategy,
-                authHandler);
+                authHandler, odlHelloCapabilities);
         this.connectStrategyFactory = connectStrategyFactory;
         validateReconnectConfiguration();
     }
index e705d3cca62e3fb8798f554d22ceca0f8b90a1c7..dd3d052b6aa999085ae16d59961c279feed9a516 100644 (file)
@@ -8,11 +8,13 @@
 package org.opendaylight.netconf.client.conf;
 
 import java.net.InetSocketAddress;
+import java.util.List;
 import org.opendaylight.netconf.api.messages.NetconfHelloMessageAdditionalHeader;
 import org.opendaylight.netconf.client.NetconfClientSessionListener;
 import org.opendaylight.netconf.nettyutil.handler.ssh.authentication.AuthenticationHandler;
 import org.opendaylight.protocol.framework.ReconnectStrategy;
 import org.opendaylight.protocol.framework.ReconnectStrategyFactory;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.Uri;
 
 public final class NetconfReconnectingClientConfigurationBuilder extends NetconfClientConfigurationBuilder {
 
@@ -36,7 +38,7 @@ public final class NetconfReconnectingClientConfigurationBuilder extends Netconf
     public NetconfReconnectingClientConfiguration build() {
         return new NetconfReconnectingClientConfiguration(getProtocol(), getAddress(), getConnectionTimeoutMillis(),
                 getAdditionalHeader(), getSessionListener(), getReconnectStrategy(), connectStrategyFactory,
-                getAuthHandler());
+                getAuthHandler(), getOdlHelloCapabilities());
     }
 
     // Override setter methods to return subtype
@@ -81,4 +83,9 @@ public final class NetconfReconnectingClientConfigurationBuilder extends Netconf
             NetconfClientConfiguration.NetconfClientProtocol clientProtocol) {
         return (NetconfReconnectingClientConfigurationBuilder) super.withProtocol(clientProtocol);
     }
+
+    @Override
+    public NetconfReconnectingClientConfigurationBuilder withOdlHelloCapabilities(List<Uri> odlHelloCapabilities) {
+        return (NetconfReconnectingClientConfigurationBuilder) super.withOdlHelloCapabilities(odlHelloCapabilities);
+    }
 }
index 3da84be98b845219b9a32b9aa31e868d21f05dde..ed20f6a81882dab668b0a1976aedbe5451bb2fcc 100644 (file)
@@ -185,6 +185,15 @@ module netconf-node-topology {
                     default 5;
                     description "Time that slave actor will wait for response from master.";
         }
+
+        container odl-hello-message-capabilities {
+            config true;
+            leaf-list capability {
+                type inet:uri;
+                description "Certain devices are non-accepting of ODL's hello message.  This allows specification of
+                             a custom ODL hello message based on a list of supported capabilities.";
+            }
+        }
     }
 
     grouping netconf-node-connection-status {
index 8c57957a65624042adeefef84c7250bc270d3a38..34a54c7fc419872b935cbebd85ec6abb2fafcfc8 100644 (file)
@@ -57,7 +57,9 @@ import org.opendaylight.protocol.framework.ReconnectStrategyFactory;
 import org.opendaylight.protocol.framework.TimedReconnectStrategy;
 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.Host;
 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.inet.types.rev130715.Uri;
 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.netconf.node.connection.parameters.OdlHelloMessageCapabilities;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.netconf.node.topology.rev150114.netconf.node.connection.status.available.capabilities.AvailableCapability.CapabilityOrigin;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.netconf.node.topology.rev150114.netconf.node.credentials.Credentials;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.netconf.node.topology.rev150114.netconf.node.credentials.credentials.KeyAuth;
@@ -281,17 +283,31 @@ public class RemoteDeviceConnectorImpl implements RemoteDeviceConnector {
 
         final AuthenticationHandler authHandler = getHandlerFromCredentials(node.getCredentials());
 
-        return NetconfReconnectingClientConfigurationBuilder.create()
-                .withAddress(socketAddress)
-                .withConnectionTimeoutMillis(clientConnectionTimeoutMillis)
-                .withReconnectStrategy(strategy)
-                .withAuthHandler(authHandler)
-                .withProtocol(node.isTcpOnly()
-                        ? NetconfClientConfiguration.NetconfClientProtocol.TCP
-                        : NetconfClientConfiguration.NetconfClientProtocol.SSH)
-                .withConnectStrategyFactory(sf)
-                .withSessionListener(listener)
-                .build();
+        final NetconfReconnectingClientConfigurationBuilder builder =
+                NetconfReconnectingClientConfigurationBuilder.create()
+                        .withAddress(socketAddress)
+                        .withConnectionTimeoutMillis(clientConnectionTimeoutMillis)
+                        .withReconnectStrategy(strategy)
+                        .withAuthHandler(authHandler)
+                        .withProtocol(node.isTcpOnly()
+                                ? NetconfClientConfiguration.NetconfClientProtocol.TCP
+                                : NetconfClientConfiguration.NetconfClientProtocol.SSH)
+                        .withConnectStrategyFactory(sf)
+                        .withSessionListener(listener);
+
+        final List<Uri> odlHelloCapabilities = getOdlHelloCapabilities(node);
+        if (odlHelloCapabilities != null) {
+            builder.withOdlHelloCapabilities(odlHelloCapabilities);
+        }
+        return builder.build();
+    }
+
+    private List<Uri> getOdlHelloCapabilities(final NetconfNode node) {
+        final OdlHelloMessageCapabilities helloCapabilities = node.getOdlHelloMessageCapabilities();
+        if (helloCapabilities != null) {
+            return helloCapabilities.getCapability();
+        }
+        return null;
     }
 
     private AuthenticationHandler getHandlerFromCredentials(final Credentials credentials) {
index 3da84be98b845219b9a32b9aa31e868d21f05dde..ed20f6a81882dab668b0a1976aedbe5451bb2fcc 100644 (file)
@@ -185,6 +185,15 @@ module netconf-node-topology {
                     default 5;
                     description "Time that slave actor will wait for response from master.";
         }
+
+        container odl-hello-message-capabilities {
+            config true;
+            leaf-list capability {
+                type inet:uri;
+                description "Certain devices are non-accepting of ODL's hello message.  This allows specification of
+                             a custom ODL hello message based on a list of supported capabilities.";
+            }
+        }
     }
 
     grouping netconf-node-connection-status {
index 7b872968ce52e339d144589ce4c2bf9b580c072a..ed20f6a81882dab668b0a1976aedbe5451bb2fcc 100644 (file)
@@ -15,17 +15,50 @@ module netconf-node-topology {
         }
     }
 
-    grouping netconf-node-credentials {
+    grouping username-password {
+        leaf username {
+            type string;
+        }
 
+        leaf password {
+            type string;
+        }
+    }
+
+    grouping netconf-node-credentials {
         choice credentials {
             config true;
             case login-password {
-                leaf username {
-                    type string;
+                description "Deprecated way of storing credentials, unencrypted.";
+
+                status deprecated;
+                uses username-password;
+            }
+            case login-pw {
+                description "login-password credentials, encrypted.";
+
+                container login-password {
+                    uses username-password;
                 }
+            }
+            case login-pw-unencrypted {
+                description "login-password credentials, not encrypted.";
 
-                leaf password {
-                    type string;
+                container login-password-unencrypted {
+                    uses username-password;
+                }
+            }
+            case key-auth {
+                description "key-based authentication, use the id for the pair thats stored in the keystore.";
+
+                container key-based {
+                    leaf key-id {
+                        type string;
+                    }
+
+                    leaf username {
+                        type string;
+                    }
                 }
             }
         }
@@ -143,6 +176,24 @@ module netconf-node-topology {
             description "Limit of concurrent messages that can be send before reply messages are received.
                          If value <1 is provided, no limit will be enforced";
         }
+
+        leaf actor-response-wait-time {
+                    config true;
+                    type uint16 {
+                      range "1..max";
+                    }
+                    default 5;
+                    description "Time that slave actor will wait for response from master.";
+        }
+
+        container odl-hello-message-capabilities {
+            config true;
+            leaf-list capability {
+                type inet:uri;
+                description "Certain devices are non-accepting of ODL's hello message.  This allows specification of
+                             a custom ODL hello message based on a list of supported capabilities.";
+            }
+        }
     }
 
     grouping netconf-node-connection-status {
@@ -170,6 +221,10 @@ module netconf-node-topology {
                     }
                 }
             }
+            leaf netconf-master-node {
+                config false;
+                type string;
+            }
         }
 
         leaf connected-message {
@@ -259,10 +314,28 @@ module netconf-node-topology {
 
     }
 
+    rpc create-device {
+        input {
+            uses netconf-node-fields;
+            leaf node-id {
+                type string;
+            }
+        }
+    }
+
+    rpc delete-device {
+        input {
+            leaf node-id {
+                type string;
+            }
+        }
+    }
+
     augment "/nt:network-topology/nt:topology/nt:node" {
         when "../../nt:topology-types/topology-netconf";
         ext:augment-identifier "netconf-node";
 
         uses netconf-node-fields;
     }
-}
\ No newline at end of file
+
+}