Python package – “netmiko” … Part 2

Objective: The primary objective of this Blog is to demonstrate following –

  1. Handling commands which requires further inputs
  2. Importance of “delay_factor”

Handling Interactive commands

Let’s take a case where execute one command may ask for additional information & requires users to interact e.g. If we run below command it will ask for multiple additional parameters to execute further. (IP 192.168.1.2 is representing FTP server)

Router##ping
Protocol [ip]: ip
Target IP address: 192.168.1.2
Repeat count [5]: 5
Datagram size [100]:
Timeout in seconds [2]:
Extended commands [n]:
Sweep range of sizes [n]:
Type escape sequence to abort.
Sending 5, 100-byte ICMP Echos to 192.168.1.2, timeout is 2 seconds:
.....
Success rate is 0 percent (0/5)

So, how do we handle these interactive commands in Python? – One of the way is to use the “expect_string” argument to “send_command()” method. The “expect_string” argument tells Netmiko what to look for in the output. Refer to updated code for this –

OUTPUT = CONNECT.send_command('ping', expect_string=r'Protocol')
OUTPUT = OUTPUT + CONNECT.send_command('ip', expect_string=r'Target IP address')
OUTPUT = OUTPUT + CONNECT.send_command('192.168.1.2', expect_string=r'Repeat count')
OUTPUT = OUTPUT + CONNECT.send_command('\n', expect_string=r'Datagram size')
OUTPUT = OUTPUT + CONNECT.send_command('\n', expect_string=r'Timeout in seconds')
OUTPUT = OUTPUT + CONNECT.send_command('\n', expect_string=r'Extended commands')
OUTPUT = OUTPUT + CONNECT.send_command('\n', expect_string=r'Sweep range of sizes')
try:
    OUTPUT = OUTPUT + CONNECT.send_command('\n', expect_string=r'#')
except Exception:
    EXECUTION = time.time() - start
    print('Total time to execute this code is ' + str(EXECUTION))
    CONNECT.disconnect()
    raise
else:
    EXECUTION = time.time() - start
    print('Total time to execute this code is ' + str(EXECUTION))
    print(OUTPUT)

Here is the output that we receive when we execute this:

$python demo_netmiko_interactive.py
Total time to execute this code is 21.20832872390747
Protocol [ip]: Target IP address: Repeat count [5]: Datagram size [100]: Timeout in seconds [2]: Extended commands [n]: Sweep range of sizes [n]: Type escape
 sequence to abort.
Sending 5, 100-byte ICMP Echos to 192.168.1.2, timeout is 2 seconds:
.....
Success rate is 0 percent (0/5)

Importance of delay_factor

Let’s begin this with a use case of copying a file “test.bin” from Router to an FTP server 192.168.1.1 . To copy this we will use following command on the Router CLI

Router#copy flash:test.bin tftp:
Address or name of remote host []? 192.168.1.2
Destination filename [test.bin]?
!!!.!!!!.!!.!.!!!.!.!.!.!!!
2431050 bytes copied in 262.212 secs (9271 bytes/sec)

Note that this file copy took ~262 seconds to complete. Let’s execute this with the python program and observe the results.

OUTPUT = CONNECT.send_command('copy flash:pp-adv-isr4000-155-3.S2-23-21.0.0.pack tftp:', expect_string=r'Address or name of remote host')
OUTPUT = OUTPUT + CONNECT.send_command('192.168.1.2', expect_string=r'Destination filename')

try:
    OUTPUT = OUTPUT + CONNECT.send_command('\n', expect_string=r'#')
except Exception:
    EXECUTION = time.time() - start
    print('Total time to execute this code is ' + str(EXECUTION))
    CONNECT.disconnect()
    raise
else:
    EXECUTION = time.time() - start
    print('Total time to execute this code is ' + str(EXECUTION))
    print(OUTPUT)
    CONNECT.disconnect()
$python demo_netmiko_delay.py
Total time to execute this code is 110.00358414649963
Traceback (most recent call last):
  File "demo_netmiko_delay.py", line 89, in <module>
    OUTPUT = OUTPUT + CONNECT.send_command('\n', expect_string=r'#')
  File "C:\ProgramData\Anaconda3\lib\site-packages\netmiko\base_connection.py", line 1322, in send_command
    search_pattern
OSError: Search pattern never detected in send_command_expect: #

From this output, we can refer netmiko actually waited for 110 seconds to complete though. So, what’s happening behind the scene? – the default timeout of send_command() is roughly 100 seconds; the additional 10 seconds is overhead time. But our actual file copy requires ~262 seconds to complete and netmiko’s send_command() only waits for 100 sec. Hence, we need a mechanism to modify these timers. To achieve this we can leverage the delay_factor.

delay_factor is an argument that can be pass into method send_command(); its effect is to modify all of the delays embedded in send_command (for example, a delay_factor=2 will double all of the delays; a delay_factor=3 will make delay by 3 times). In our case, file transfer requires ~262 seconds therefore delay_factor=3 would suffice. Since, network delay may cause further slowness hence to be on safer side we can consider delay_factor=4

try:
OUTPUT = OUTPUT + CONNECT.send_command('\n', expect_string=r'#', delay_factor=4)
except Exception:
EXECUTION = time.time() - start
print('Total time to execute this code is ' + str(EXECUTION))
CONNECT.disconnect()
raise
else:
EXECUTION = time.time() - start
print('Total time to execute this code is ' + str(EXECUTION))
print(OUTPUT)
CONNECT.disconnect()
$ python demo_pexpect.py
Total time to execute this code is 356.93184757232666
Address or name of remote host []? Destination filename [test.bin]? !!.!.!!.!.!!.!!.!.!.!!.!.!!.!.!.!.!!!.!.!!.!.!!.!.!.!
2431050 bytes copied in 345.926 secs (7028 bytes/sec)

This time program runs successfully and no error is observed.

Total time to execute this code is 8.49181580543518

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google photo

You are commenting using your Google account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s

This site uses Akismet to reduce spam. Learn how your comment data is processed.