Repository: ktbyers/netmiko

Issue:
delay_factor for connection initialization
Hi Kirk,

We intermittently get this stack trace when connecting to Nexus devices:

```
SSH connection established to X.X.X.X:22
Interactive SSH session established
Traceback (most recent call last):
  File "/Users/mzb/.ansible/tmp/ansible-tmp-1447101573.0-35515167451694/ntc_show_command", line 1843, in <module>
    main()
  File "/Users/mzb/.ansible/tmp/ansible-tmp-1447101573.0-35515167451694/ntc_show_command", line 211, in main
    password=password
  File "/Library/Python/2.7/site-packages/netmiko/ssh_dispatcher.py", line 54, in ConnectHandler
    return ConnectionClass(*args, **kwargs)
  File "/Library/Python/2.7/site-packages/netmiko/base_connection.py", line 45, in __init__
    self.session_preparation()
  File "/Library/Python/2.7/site-packages/netmiko/base_connection.py", line 61, in session_preparation
    self.set_base_prompt()
  File "/Library/Python/2.7/site-packages/netmiko/base_connection.py", line 187, in set_base_prompt
    raise ValueError("Router prompt not found: {0}".format(prompt))
ValueError: Router prompt not found:
```

Our belief is that increasing the `delay_factor` in `set_base_prompt()` would solve this to account for the latency within the switch itself and whatever network latency there may be. Another option would be pushing the `delay_factor` param up the stack to `ConnectHandler()`. If you like either of those options, we'd be happy to submit a PR.

Thanks,
Michael



Discussion:
@mzbenami We should probably put in a while loop and a check for recv_ready (something somewhat similar to the following). This is inside the set_base_prompt method.

```
        i = 0
        while i <= 10:
            time.sleep(1 * delay_factor)
            if self.remote_conn.recv_ready():
                prompt = self.remote_conn.recv(MAX_BUFFER).decode('utf-8')
            else:
                i += 1
```

I think I have documented on a separate issue converting delay_factor to a variable that gets initialized when the object is created, but this is a lot more work and has a lot more implications.

I will try to work on this today or tomorrow.


Resolving patch:
diff --git a/netmiko/base_connection.py b/netmiko/base_connection.py
--- a/netmiko/base_connection.py
+++ b/netmiko/base_connection.py
@@ -143,6 +143,20 @@ def disable_paging(self, command="terminal length 0\n", delay_factor=.5):
         return output
 
 
+    def wait_for_recv_ready(self, delay_factor, max_loops):
+        '''
+        Wait for data to be in the buffer so it can be received.
+
+        delay_factor can be used to increase the delays.
+
+        max_loops can be used to increase the number of times it reads the data buffer
+        '''
+        i = 0
+        while not self.remote_conn.recv_ready() and i < max_loops:
+            time.sleep(1 * delay_factor)
+            i += 1
+
+    
     def set_base_prompt(self, pri_prompt_terminator='#',
                         alt_prompt_terminator='>', delay_factor=.5):
         '''
@@ -164,7 +178,8 @@ def set_base_prompt(self, pri_prompt_terminator='#',
 
         self.clear_buffer()
         self.remote_conn.sendall("\n")
-        time.sleep(1 * delay_factor)
+        
+        self.wait_for_recv_ready(delay_factor, 10)
 
         prompt = self.remote_conn.recv(MAX_BUFFER).decode('utf-8')
 
@@ -238,7 +253,6 @@ def clear_buffer(self):
         else:
             return None
 
-
     def send_command(self, command_string, delay_factor=.5, max_loops=30,
                      strip_prompt=True, strip_command=True):
         '''
@@ -270,18 +284,14 @@ def send_command(self, command_string, delay_factor=.5, max_loops=30,
 
         self.remote_conn.sendall(command_string)
 
-        time.sleep(1 * delay_factor)
-        not_done = True
-        i = 1
-
-        while (not_done) and (i <= max_loops):
-            time.sleep(1 * delay_factor)
-            i += 1
-            # Keep reading data as long as available (up to max_loops)
-            if self.remote_conn.recv_ready():
-                output += self.remote_conn.recv(MAX_BUFFER).decode('utf-8')
-            else:
-                not_done = False
+        # Wait for recv_ready()
+        self.wait_for_recv_ready(delay_factor, max_loops)
+        
+        # Keep reading data as long as available (up to max_loops)
+        i = 0
+        while self.remote_conn.recv_ready() and i < max_loops:
+            output += self.remote_conn.recv(MAX_BUFFER).decode('utf-8')
+            self.wait_for_recv_ready(delay_factor, max_loops)
 
         # Some platforms have ansi_escape codes
         if self.ansi_escape_codes:


Test patch: