Allow specification of ODL's HELLO message 82/70682/4
authorRyan Goulding <ryandgoulding@gmail.com>
Mon, 9 Apr 2018 22:47:29 +0000 (18:47 -0400)
committerRyan Goulding <ryandgoulding@gmail.com>
Tue, 15 May 2018 15:39:39 +0000 (11:39 -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 d450672638c2aaa55d4d6ba23e3ada9907519fcd..52ec7e1078ea74c84023100cf9e17688f74aa30c 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 780ce7ff59f4103810ba99462b89dbd1ff9f1e30..b8fdee2054e2aa53024a3df07d18bfa7a9a26f15 100644 (file)
@@ -11,9 +11,13 @@ package org.opendaylight.netconf.client;
 import io.netty.channel.EventLoopGroup;
 import io.netty.util.Timer;
 import io.netty.util.concurrent.Future;
+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;
 
@@ -122,7 +126,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 ee41da8a8d165387d4da477d161c2830ac4e4445..b14d152e2561c1ad131c2567f76f8793fab4a4de 100644 (file)
@@ -12,11 +12,13 @@ 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.client.SslHandlerFactory;
 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;
 
@@ -36,12 +38,15 @@ public class NetconfClientConfiguration {
     private final AuthenticationHandler authHandler;
     private final SslHandlerFactory sslHandlerFactory;
 
+    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 SslHandlerFactory sslHandlerFactory) {
+                               final SslHandlerFactory sslHandlerFactory,
+                               final List<Uri> odlHelloCapabilities) {
         this.address = address;
         this.connectionTimeoutMillis = connectionTimeoutMillis;
         this.additionalHeader = additionalHeader;
@@ -50,6 +55,7 @@ public class NetconfClientConfiguration {
         this.reconnectStrategy = reconnectStrategy;
         this.authHandler = authHandler;
         this.sslHandlerFactory = sslHandlerFactory;
+        this.odlHelloCapabilities = odlHelloCapabilities;
         validateConfiguration();
     }
 
@@ -85,6 +91,10 @@ public class NetconfClientConfiguration {
         return sslHandlerFactory;
     }
 
+    public List<Uri> getOdlHelloCapabilities() {
+        return odlHelloCapabilities;
+    }
+
     private void validateConfiguration() {
         Preconditions.checkNotNull(clientProtocol, " ");
         switch (clientProtocol) {
index fd1d6276e40ae0e0364c66f2a2d8d0a56ef0c8b9..9e86c9c4b27756642c12ac515cb9245729f69fd2 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.client.SslHandlerFactory;
 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 {
 
@@ -28,6 +30,8 @@ public class NetconfClientConfigurationBuilder {
     private AuthenticationHandler authHandler;
     private NetconfClientConfiguration.NetconfClientProtocol clientProtocol = DEFAULT_CLIENT_PROTOCOL;
     private SslHandlerFactory sslHandlerFactory;
+    private List<Uri> odlHelloCapabilities;
+
 
     protected NetconfClientConfigurationBuilder() {
     }
@@ -86,6 +90,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;
     }
@@ -118,8 +128,12 @@ public class NetconfClientConfigurationBuilder {
         return sslHandlerFactory;
     }
 
+    final List<Uri> getOdlHelloCapabilities() {
+        return odlHelloCapabilities;
+    }
+
     public NetconfClientConfiguration build() {
         return new NetconfClientConfiguration(clientProtocol, address, connectionTimeoutMillis, additionalHeader,
-                sessionListener, reconnectStrategy, authHandler, sslHandlerFactory);
+                sessionListener, reconnectStrategy, authHandler, sslHandlerFactory, odlHelloCapabilities);
     }
 }
index 3c5931e49d924cd382d947ee89f661d4b6f77419..c6885349232bdf054eff8950f7d732228246896e 100644 (file)
@@ -10,12 +10,14 @@ 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.client.SslHandlerFactory;
 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 {
 
@@ -28,9 +30,10 @@ public final class NetconfReconnectingClientConfiguration extends NetconfClientC
                                            final ReconnectStrategy reconnectStrategy,
                                            final ReconnectStrategyFactory connectStrategyFactory,
                                            final AuthenticationHandler authHandler,
-                                           final SslHandlerFactory sslHandlerFactory) {
+                                           final SslHandlerFactory sslHandlerFactory,
+                                           final List<Uri> odlHelloCapabilities) {
         super(clientProtocol, address, connectionTimeoutMillis, additionalHeader, sessionListener, reconnectStrategy,
-                authHandler, sslHandlerFactory);
+                authHandler, sslHandlerFactory, odlHelloCapabilities);
         this.connectStrategyFactory = connectStrategyFactory;
         validateReconnectConfiguration();
     }
index 4d3dcdaaaba79c6e10b630acb0041f9b0d0c9f5c..670c893a00b174602c677126d64e97f107efb5ae 100644 (file)
@@ -8,12 +8,14 @@
 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.client.SslHandlerFactory;
 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 {
 
@@ -37,7 +39,7 @@ public final class NetconfReconnectingClientConfigurationBuilder extends Netconf
     public NetconfReconnectingClientConfiguration build() {
         return new NetconfReconnectingClientConfiguration(getProtocol(), getAddress(), getConnectionTimeoutMillis(),
                 getAdditionalHeader(), getSessionListener(), getReconnectStrategy(), connectStrategyFactory,
-                getAuthHandler(), getSslHandlerFactory());
+                getAuthHandler(), getSslHandlerFactory(), getOdlHelloCapabilities());
     }
 
     // Override setter methods to return subtype
@@ -88,4 +90,9 @@ public final class NetconfReconnectingClientConfigurationBuilder extends Netconf
             final SslHandlerFactory sslHandlerFactory) {
         return (NetconfReconnectingClientConfigurationBuilder) super.withSslHandlerFactory(sslHandlerFactory);
     }
+
+    @Override
+    public NetconfReconnectingClientConfigurationBuilder withOdlHelloCapabilities(List<Uri> odlHelloCapabilities) {
+        return (NetconfReconnectingClientConfigurationBuilder) super.withOdlHelloCapabilities(odlHelloCapabilities);
+    }
 }
index 1e1f85545e350ec69cd65fe268506537ba3ce378..231a382f53dc63416b8b258daef35b0a3152f065 100644 (file)
@@ -209,6 +209,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 40511bf781367eeffe2823de3a336a3251fe8f51..e4fd08b77f268c2586206b1388587db3e383a3cf 100644 (file)
@@ -60,7 +60,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;
@@ -291,17 +293,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 1e1f85545e350ec69cd65fe268506537ba3ce378..231a382f53dc63416b8b258daef35b0a3152f065 100644 (file)
@@ -209,6 +209,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 8488211364afddb072be3f7621914dc27f94df4a..231a382f53dc63416b8b258daef35b0a3152f065 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;
+                    }
                 }
             }
         }
@@ -167,6 +200,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 {
@@ -194,6 +245,10 @@ module netconf-node-topology {
                     }
                 }
             }
+            leaf netconf-master-node {
+                config false;
+                type string;
+            }
         }
 
         leaf connected-message {
@@ -283,10 +338,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
+
+}