The Pexpect overview

Let's take a look at how you would interact with the router if you were to Telnet into the device:

echou@ubuntu:~$ telnet 172.16.1.20
Trying 172.16.1.20...
Connected to 172.16.1.20.
Escape character is '^]'.
<skip>
User Access Verification

Username: cisco
Password:

I used VIRL AutoNetkit to automatically generate initial configuration of the routers, which generated the default username of cisco, and the password of cisco. Notice the user is already in the privileged mode:

iosv-1#sh run | i cisco
enable password cisco
username cisco privilege 15 secret 5 $1$Wiwq$7xt2oE0P9ThdxFS02trFw.
password cisco
password cisco
iosv-1#

Also note that the auto config generated vty access for both telnet and SSH:

line vty 0 4
exec-timeout 720 0
password cisco
login local
transport input telnet ssh

Let's see a Pexpect example using the Python interactive shell:

Python 3.5.2 (default, Nov 17 2016, 17:05:23)
[GCC 5.4.0 20160609] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> import pexpect
>>> child = pexpect.spawn('telnet 172.16.1.20')
>>> child.expect('Username')
0
>>> child.sendline('cisco')
6
>>> child.expect('Password')
0
>>> child.sendline('cisco')
6
>>> child.expect('iosv-1#')
0
>>> child.sendline('show version | i V')
19
>>> child.expect('iosv-1#')
0
>>> child.before
b'show version | i VrnCisco IOS Software, IOSv Software (VIOS-ADVENTERPRISEK9-M), Version 15.6(2)T, RELEASE SOFTWARE (fc2)rnProcessor board ID 9MM4BI7B0DSWK40KV1IIRrn'
>>> child.sendline('exit')
5
>>> exit()
Starting from Pexpect version 4.0, you can run Pexpect on a Windows platform. But as noted on the documentation, running Pexpect on Windows should be considered experimental for now.

One thing to note in the previous interactive example is that as you can see, Pexpect spawns off a child process and watches over it in an interactive fashion. There are two important methods shown in the example, expect() and sendline(). There is also a method called send() but sendline() includes a linefeed, which is similar to pressing the enter key at the end of your line in your previous telnet session. From the router's perspective, it is just as if someone typed in the text from a Terminal. In other words, we are tricking the router into thinking they are interfacing with a human being when they are actually communicating with a computer.

The before and after properties will be set to the text printed by the child application. The before properties will be set to the text printed by child application up to the expected pattern. The after string will contain the text that was matched by the expected pattern. In our case, the before text will be set to the output between the two expected matches (iosv-1#) including the show version command. The after text is the router hostname prompt:

>>> child.sendline('show version | i V')
19
>>> child.expect('iosv-1#')
0
>>> child.before
b'show version | i VrnCisco IOS Software, IOSv Software (VIOS-ADVENTERPRISEK9-M), Version 15.6(2)T, RELEASE SOFTWARE (fc2)rnProcessor board ID 9MM4BI7B0DSWK40KV1IIRrn'
>>> child.after
b'iosv-1#'

What would happen if you expect the wrong term? For example, if you type in the lowercase username instead of Username after you spawn the child application, then the Pexpect process will be looking for a string of username from the child process. In this case, the Pexpect process will just hang because the word username would never be returned by the router. The session will eventually timeout, or you can manually exit out via Ctrl + C.

The expect() method waits for the child application to return a given string, so in the previous example, if you would like to accommodate for both lower and upper case u, you can use this term:

>>> child.expect('[Uu]sername')

The square bracket serves as an or operation that tells the child application to expect a lower or upper case u followed by 'sername' as the string. What we are telling the process is that we will accept either 'Username' or 'username' as the expected string.

For more information on Python regular expression, go to https://docs.python.org/3.5/library/re.html.

The expect() method can also contain a list of options instead of just a single string; these options can also be regular expression themselves. Going back to the previous example, you can use the following list of options to accommodate the two different possible string:

>>> child.expect(['Username', 'username'])

Generally speaking, use the regular expression for a single expect string when you can fit the different hostname in a regular expression, whereas use the possible options if you need to catch completely different responses from the router, such as a password rejection. For example, if you use several different passwords for your login, you want to catch% Login invalid as well as the device prompt.

One important difference between Pexpect RE and Python RE is that the Pexpect matching is non-greedy, which means they will match as little as possible when using special characters. Because Pexpect performs regular expression on a stream, you cannot look ahead, as the child process generating the stream may not be finished. This means the special character called $ for the end of the line match is useless, .+ will always return no characters, and .* pattern will match as little as possible. In general, just keep this in mind and be as specific as you can be on the expect match strings.

Let's consider the following scenario:

>>> child.sendline('show run | i hostname')
22
>>> child.expect('iosv-1')
0
>>> child.before
b'show run | i hostnamernhostname '
>>>

Hmm.. something is not quit right here. Compare to the terminal output before; the output you expect would be hostname iosv-1:

iosv-1#show run | i hostname
hostname iosv-1
iosv-1#

A closer look at the expected string will reveal the mistake. In this case, we were missing the hash (#) sign behind the hostname called iosv-1. Therefore, the child application treated the second part of the return string as the expected string:

>>> child.sendline('show run | i hostname')
22
>>> child.expect('iosv-1#')
0
>>> child.before
b'show run | i hostnamernhostname iosv-1rn'
>>>

Pretty quickly, you can see a pattern emerging from the usage of Pexpect. The user maps out the sequence of interaction between the Pexpect process and the child application. With some Python variables and loops, we can start to construct a useful program that will help us gather information and make changes to network devices.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
3.147.80.100