Objective: The primary objective of this Blog is to demonstrate following –
- Handling commands which requires further inputs
- 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