Patch for ONOS-6840 NETCONF timeouts per device

Change-Id: Ia2e578245b97e0f68ea720cefe783e708e255ca7
diff --git a/protocols/netconf/api/src/main/java/org/onosproject/netconf/NetconfDeviceInfo.java b/protocols/netconf/api/src/main/java/org/onosproject/netconf/NetconfDeviceInfo.java
index 887e1dd..c991762 100644
--- a/protocols/netconf/api/src/main/java/org/onosproject/netconf/NetconfDeviceInfo.java
+++ b/protocols/netconf/api/src/main/java/org/onosproject/netconf/NetconfDeviceInfo.java
@@ -19,6 +19,8 @@
 import com.google.common.base.Preconditions;
 import org.onlab.packet.IpAddress;
 import org.onosproject.net.DeviceId;
+import org.onosproject.netconf.config.NetconfDeviceConfig;
+import org.onosproject.netconf.config.NetconfSshClientLib;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -26,6 +28,8 @@
 import java.net.URI;
 import java.net.URISyntaxException;
 import java.util.Objects;
+import java.util.Optional;
+import java.util.OptionalInt;
 
 /**
  * Represents a Netconf device information.
@@ -43,6 +47,10 @@
     //File keyFile @deprecated 1.9.0
     @Deprecated
     private File keyFile;
+    private Optional<NetconfSshClientLib> sshClientLib;
+    private OptionalInt connectTimeoutSec;
+    private OptionalInt replyTimeoutSec;
+    private OptionalInt idleTimeoutSec;
     private DeviceId deviceId;
 
 
@@ -63,6 +71,10 @@
         this.password = password;
         this.ipAddress = ipAddress;
         this.port = port;
+        this.sshClientLib = Optional.empty();
+        this.connectTimeoutSec = OptionalInt.empty();
+        this.replyTimeoutSec = OptionalInt.empty();
+        this.idleTimeoutSec = OptionalInt.empty();
     }
 
     /**
@@ -90,6 +102,73 @@
         this.port = port;
         this.key = keyString.toCharArray();
         this.keyFile = new File(keyString);
+        this.sshClientLib = Optional.empty();
+        this.connectTimeoutSec = OptionalInt.empty();
+        this.replyTimeoutSec = OptionalInt.empty();
+        this.idleTimeoutSec = OptionalInt.empty();
+    }
+
+    /**
+     * Convenieince constructor that converts all known fields from NetCfg data.
+     * @param netconfConfig NetCf configuration
+     */
+    public NetconfDeviceInfo(NetconfDeviceConfig netconfConfig) {
+        Preconditions.checkArgument(!netconfConfig.username().isEmpty(), "Empty device name");
+        Preconditions.checkNotNull(netconfConfig.port() > 0, "Negative port");
+        Preconditions.checkNotNull(netconfConfig.ip(), "Null ip address");
+
+        this.name = netconfConfig.username();
+        this.password = netconfConfig.password();
+        this.ipAddress = netconfConfig.ip();
+        this.port = netconfConfig.port();
+        if (netconfConfig.sshKey() != null && !netconfConfig.sshKey().isEmpty()) {
+            this.key = netconfConfig.sshKey().toCharArray();
+        }
+        this.keyFile = new File(netconfConfig.sshKey());
+        if (netconfConfig.sshClient().isPresent()) {
+            this.sshClientLib = Optional.of(NetconfSshClientLib.getEnum(netconfConfig.sshClient().get()));
+        } else {
+            this.sshClientLib = Optional.empty();
+        }
+        this.connectTimeoutSec = netconfConfig.connectTimeout();
+        this.replyTimeoutSec = netconfConfig.replyTimeout();
+        this.idleTimeoutSec = netconfConfig.idleTimeout();
+    }
+
+    /**
+     * Allows the NETCONF SSH Client library to be set.
+     *
+     * @param sshClientLib An enumerated value
+     */
+    public void setSshClientLib(Optional<NetconfSshClientLib> sshClientLib) {
+        this.sshClientLib = sshClientLib;
+    }
+
+    /**
+     * Allows the NETCONF SSH session initial connect timeout to be set.
+     *
+     * @param connectTimeoutSec value in seconds
+     */
+    public void setConnectTimeoutSec(OptionalInt connectTimeoutSec) {
+        this.connectTimeoutSec = connectTimeoutSec;
+    }
+
+    /**
+     * Allows the NETCONF SSH session replies timeout to be set.
+     *
+     * @param replyTimeoutSec value in seconds
+     */
+    public void setReplyTimeoutSec(OptionalInt replyTimeoutSec) {
+        this.replyTimeoutSec = replyTimeoutSec;
+    }
+
+    /**
+     * Allows the NETCONF SSH session idle timeout to be set.
+     *
+     * @param idleTimeoutSec value in seconds
+     */
+    public void setIdleTimeoutSec(OptionalInt idleTimeoutSec) {
+        this.idleTimeoutSec = idleTimeoutSec;
     }
 
     /**
@@ -153,6 +232,42 @@
     }
 
     /**
+     * Exposes the Client library implementation.
+     *
+     * @return Enumerated value
+     */
+    public Optional<NetconfSshClientLib> sshClientLib() {
+        return sshClientLib;
+    }
+
+    /**
+     * Exposes the device specific connect timeout.
+     *
+     * @return The timeout value in seconds
+     */
+    public OptionalInt getConnectTimeoutSec() {
+        return connectTimeoutSec;
+    }
+
+    /**
+     * Exposes the device specific reply timeout.
+     *
+     * @return The timeout value in seconds
+     */
+    public OptionalInt getReplyTimeoutSec() {
+        return replyTimeoutSec;
+    }
+
+    /**
+     * Exposes the device specific idle timeout.
+     *
+     * @return The timeout value in seconds
+     */
+    public OptionalInt getIdleTimeoutSec() {
+        return idleTimeoutSec;
+    }
+
+    /**
      * Return the info about the device in a string.
      * String format: "netconf:name@ip:port"
      *
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 7a4df0b..06c8b9c 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
@@ -593,4 +593,28 @@
      */
     void removeDeviceOutputListener(NetconfDeviceOutputEventListener listener);
 
+    /**
+     * Read the connect timeout that this session was created with.
+     * @return timeout in seconds
+     */
+    default int timeoutConnectSec() {
+        return 0;
+    };
+
+    /**
+     * Read the reply timeout that this session was created with.
+     * @return timeout in seconds
+     */
+    default int timeoutReplySec() {
+        return 0;
+    };
+
+    /**
+     * Read the idle timeout that this session was created with.
+     * @return timeout in seconds
+     */
+    default int timeoutIdleSec() {
+        return 0;
+    };
+
 }
diff --git a/protocols/netconf/api/src/main/java/org/onosproject/netconf/config/NetconfDeviceConfig.java b/protocols/netconf/api/src/main/java/org/onosproject/netconf/config/NetconfDeviceConfig.java
index 1accaec..28758b5 100644
--- a/protocols/netconf/api/src/main/java/org/onosproject/netconf/config/NetconfDeviceConfig.java
+++ b/protocols/netconf/api/src/main/java/org/onosproject/netconf/config/NetconfDeviceConfig.java
@@ -21,6 +21,10 @@
 import org.onlab.packet.IpAddress;
 import org.onosproject.net.DeviceId;
 import org.onosproject.net.config.Config;
+
+import java.util.Optional;
+import java.util.OptionalInt;
+
 import static com.google.common.base.Preconditions.checkNotNull;
 
 /**
@@ -34,16 +38,20 @@
      */
     public static final String CONFIG_KEY = "netconf";
 
-    private static final String IP = "ip";
-    private static final String PORT = "port";
-    private static final String USERNAME = "username";
-    private static final String PASSWORD = "password";
-    private static final String SSHKEY = "sshkey";
+    public static final String IP = "ip";
+    public static final String PORT = "port";
+    public static final String USERNAME = "username";
+    public static final String PASSWORD = "password";
+    public static final String SSHKEY = "sshkey";
+    public static final String SSHCLIENT = "ssh-client";
+    public static final String CONNECT_TIMEOUT = "connect-timeout";
+    public static final String REPLY_TIMEOUT = "reply-timeout";
+    public static final String IDLE_TIMEOUT = "idle-timeout";
 
     @Override
     public boolean isValid() {
-        return hasOnlyFields(IP, PORT, USERNAME, PASSWORD, SSHKEY) &&
-                ip() != null;
+        return hasOnlyFields(IP, PORT, USERNAME, PASSWORD, SSHKEY, SSHCLIENT,
+                CONNECT_TIMEOUT, REPLY_TIMEOUT, IDLE_TIMEOUT) && ip() != null;
     }
 
     /**
@@ -92,6 +100,47 @@
     }
 
     /**
+     * Gets the NETCONF SSH Client implementation.
+     * Expecting "apache-mina" or "ethz-ssh2"
+     *
+     * @return sshClient
+     */
+    public Optional<String> sshClient() {
+        String sshClient = get(SSHCLIENT, "");
+        return (sshClient.isEmpty() ? Optional.empty() : Optional.ofNullable(sshClient));
+    }
+
+    /**
+     * Gets the connect timeout of the SSH connection.
+     *
+     * @return connectTimeout
+     */
+    public OptionalInt connectTimeout() {
+        int connectTimeout = get(CONNECT_TIMEOUT, 0);
+        return (connectTimeout == 0) ? OptionalInt.empty() : OptionalInt.of(connectTimeout);
+    }
+
+    /**
+     * Gets the reply timeout of the SSH connection.
+     *
+     * @return replyTimeout
+     */
+    public OptionalInt replyTimeout() {
+        int replyTimeout = get(REPLY_TIMEOUT, 0);
+        return (replyTimeout == 0) ? OptionalInt.empty() : OptionalInt.of(replyTimeout);
+    }
+
+    /**
+     * Gets the idle timeout of the SSH connection.
+     *
+     * @return idleTimeout
+     */
+    public OptionalInt idleTimeout() {
+        int idleTimeout = get(IDLE_TIMEOUT, 0);
+        return (idleTimeout == 0) ? OptionalInt.empty() : OptionalInt.of(idleTimeout);
+    }
+
+    /**
      * Sets the Ip for the Device.
      *
      * @param ip the ip
@@ -141,6 +190,59 @@
         return (NetconfDeviceConfig) setOrClear(SSHKEY, sshKey);
     }
 
+    /**
+     * Sets the NETCONF Ssh client implementation for the Device.
+     * Must be 'apache-mina' or 'ethz-ssh2'
+     * When specified, overrides NetconfControllerImpl.sshLibrary for this device
+     *
+     * @param sshimpl sshimpl as string
+     * @return instance for chaining
+     */
+    public NetconfDeviceConfig setSshImpl(String sshimpl) {
+        return (NetconfDeviceConfig) setOrClear(SSHCLIENT, sshimpl);
+    }
+
+    /**
+     * Sets the NETCONF Connect Timeout for the Device.
+     * This is the amount of time in seconds allowed for the SSH handshake to take place
+     * Minimum 1 second
+     * When specified, overrides NetconfControllerImpl.netconfConnectTimeout for this device
+     *
+     * @param connectTimeout connectTimeout as int
+     * @return instance for chaining
+     */
+    public NetconfDeviceConfig setConnectTimeout(Integer connectTimeout) {
+        return (NetconfDeviceConfig) setOrClear(CONNECT_TIMEOUT, connectTimeout);
+    }
+
+    /**
+     * Sets the NETCONF Reply Timeout for the Device.
+     * This is the amount of time in seconds allowed for the NETCONF Reply to a command
+     * Minimum 1 second
+     * When specified, overrides NetconfControllerImpl.netconfReplyTimeout for this device
+     *
+     * @param replyTimeout replyTimeout as int
+     * @return instance for chaining
+     */
+    public NetconfDeviceConfig setReplyTimeout(Integer replyTimeout) {
+        return (NetconfDeviceConfig) setOrClear(REPLY_TIMEOUT, replyTimeout);
+    }
+
+    /**
+     * Sets the NETCONF Idle Timeout for the Device.
+     * This is the amount of time in seconds after which the SSH connection will
+     * close if no traffic is detected
+     * Minimum 10 second
+     * When specified, overrides NetconfControllerImpl.netconfIdleTimeout for this device
+     *
+     * @param idleTimeout idleTimeout as int
+     * @return instance for chaining
+     */
+    public NetconfDeviceConfig setIdleTimeout(Integer idleTimeout) {
+        return (NetconfDeviceConfig) setOrClear(IDLE_TIMEOUT, idleTimeout);
+    }
+
+
     private Pair<String, Integer> extractIpPort() {
         // Assuming one of
         //  - netconf:ip:port
diff --git a/protocols/netconf/api/src/main/java/org/onosproject/netconf/config/NetconfSshClientLib.java b/protocols/netconf/api/src/main/java/org/onosproject/netconf/config/NetconfSshClientLib.java
new file mode 100644
index 0000000..8ca1e93
--- /dev/null
+++ b/protocols/netconf/api/src/main/java/org/onosproject/netconf/config/NetconfSshClientLib.java
@@ -0,0 +1,39 @@
+/*
+ * Copyright 2015-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.config;
+
+/**
+ * Enumerated list of SSH client library types.
+ */
+public enum NetconfSshClientLib {
+    APACHE_MINA("apache-mina"),
+    ETHZ_SSH2("ethz-ssh2");
+
+    private String impl;
+
+    private NetconfSshClientLib(String impl) {
+        this.impl = impl;
+    }
+
+    @Override
+    public String toString() {
+        return impl;
+    }
+
+    public static NetconfSshClientLib getEnum(String valueOf) {
+        return valueOf(valueOf.toUpperCase().replace('-', '_'));
+    }
+}