Basic Cisco router automation workflow with pexpect

Network automation can take many forms depending on the technologies and environments. Sometimes though, we have to dive deep into low-level automation, where we can’t use REST API or other more-convenient technologies. In this article, we will take a brief look at the pexpect python library, which can be used for low-level automation.

As an example, we will automate the ssh connection to the Cisco router. The whole workflow will look like this:

  1. Login to the Cisco router via ssh
  2. Execute show platform command
  3. Print output of the show command to the console

Bear in mind, that there are more user-friendly libraries to handle ssh connections to the Cisco routers, for example Netmiko.

Workflow overview

First, let’s take a look at the console output from the workflow we want to automate.

garzum@server:~$ ssh [email protected]
Password:


Router#show platform
Chassis type: C1113-8PMLTEEA

Slot      Type                State                 Insert time (ago)
--------- ------------------- --------------------- -----------------
0         C1113-8PMLTEEA      ok                    2w0d
 0/0      C1113-1x1GE         ok                    2w0d
 0/1      C1113-ES-8          ok                    2w0d
 0/2      C1113-LTE           ok                    2w0d
 0/3      C1113-GFAST-M       ok                    2w0d
R0        C1113-8PMLTEEA      ok, active            2w0d
F0        C1113-8PMLTEEA      ok, active            2w0d
P0        PWR-12V             ok                    2w0d

Slot      CPLD Version        Firmware Version
--------- ------------------- ---------------------------------------
0         17100501            17.5(1r)
R0        17100501            17.5(1r)
F0        17100501            17.5(1r)

Router#

Since we know what the output looks like, let’s start coding!

Establishing connection

In the beginning, we need to import pexpect library.

import pexpect

For convenience and code readability, let’s create variables with login data.

username = "admin"
password = "admin"
ip = "10.0.1.2"

The last variable before the connection will have a string with a router prompt assigned to it.

prompt = "Router#"

Now, we’re ready to establish a connection!

child = pexpect.spawn(f"ssh {username}@{ip}")
child.expect("Password:")
child.sendline(password)
child.expect(prompt)

To establish a connection we need to use the spawn method from pexpect library. As an argument, we’re passing a command which initiates it. In our case, it’s ssh [email protected]. After that, we can interact with the router using the child variable.

If you take a look at the workflow output, right after executing ssh command, the router asks us for the password. So in our code, we’re expecting, that router(child) will send us a line with Password: string.

To send password, we’re using the sendline method. As an argument, we’re passing a variable password, which contains a string.

What happens next? Router displays its prompt – Router#. The following expect waits for it.

But what if we don’t know what’s the hostname of the router? Fortunately, you can pass a string with regex as an argument to the expect method, for example “.+#”.

Now, we’re ready to display router platform information.

Show command execution

child.sendline("show platform")
child.expect(prompt)

After sending show platform command to the router, we’re again expecting a prompt. That way we know that the execution of show command is over.

“But where is the output?” – You may ask. In pexpect, we have to pull it out of the child object. The whole interaction with the router is not printed directly to the console.

output = child.before.decode()
print(output)

The output of the show platform command is stored in the before variable, that’s in the child object. We can refer to it with child.before. In the same line, we’re using a decode method before assignment to the output variable. It’s because child.before is a bytes type. The decode method converts bytes to the str, which is printed to the console in the next line.

The complete code is as follows.

import pexpect

username = "admin"
password = "admin"
ip = "10.0.1.2"
prompt = "Router#"

child = pexpect.spawn(f"ssh {username}@{ip}")
child.expect("Password:")
child.sendline(password)
child.expect(prompt)
child.sendline("show platform")
child.expect(prompt)
output = child.before.decode()
print(output)

You can also access the code on my GitLab page

It produces the following output.

show platform
Chassis type: C1113-8PMLTEEA

Slot      Type                State                 Insert time (ago) 
--------- ------------------- --------------------- ----------------- 
0         C1113-8PMLTEEA      ok                    2w1d          
 0/0      C1113-1x1GE         ok                    2w1d          
 0/1      C1113-ES-8          ok                    2w1d          
 0/2      C1113-LTE           ok                    2w1d          
 0/3      C1113-GFAST-M       ok                    2w1d          
R0        C1113-8PMLTEEA      ok, active            2w1d          
F0        C1113-8PMLTEEA      ok, active            2w1d          
P0        PWR-12V             ok                    2w1d          

Slot      CPLD Version        Firmware Version                        
--------- ------------------- --------------------------------------- 
0         17100501            17.5(1r)                            
R0        17100501            17.5(1r)                            
F0        17100501            17.5(1r)                            

Summary

That’s for the basics of the pexpect library. In this article, the ssh connection was used as an example but personally, I like to use pexpect more when I’m interacting with devices via the console connection.

I hope that you’ve gained a basic overview of how it works. In the next articles, I’ll show you more complicated examples as we will dive deeper into the pexpect abyss.

Share

Leave a Reply

Your email address will not be published. Required fields are marked *