Image of terminal

Expect Scripting For Network Engineers (Cisco)

Have you ever spent a good portion of your day repeatedly logging into all of the network devices in your data center to add the IP address of a new syslog server? Or perhaps removing the local user account of a former peer who jumped ship to greener pastures?

As a Network Engineer there have undoubtedly been times when you have had to make the same configuration change to a large group of devices. Unless you spent a few years honing your scripting skills as a Systems Administrator in the past, chances are that your idea of “automating” the process involved manually logging into devices and pasting the same configuration from a text file over and over.

You know that scripting could help, but who has time to learn to write code when you’re busy researching connectivity issues? After all you’re a Network Engineer and not a Developer, right?

Why Use Expect?

1. It’s Easy!

Expect is a scripting program written in Tcl that was built to automate tasks for other interactive programs, such as Cisco’s IOS and NX-OS command line interfaces. It’s rather intuitive to understand at the basic level.

Once you have a working baseline script, such as the one I am providing below, it’s fast and easy to modify it for use in any situation where you need to make the same configuration change on multiple devices.

2. It’s Already Installed

If you’re primary workstation is a Mac then there is no installation necessary! Expect is already installed in /usr/bin/expect.

3. Excellent Online Resources Available

The more you use Expect, the more you’re going to want to do with it. Luckily you don’t need to take an online course or buy the O’Reilly Media book like you would with Python and Perl. You can Google search your way to just about anything.

Simple Expect Script For Cisco Network Devices

I’m sharing a basic Expect script which you can use to make configuration changes to Cisco IOS and NX-OS devices from a Mac. If you want to run it from a Linux server, just update the path from /usr/bin/expect to wherever the program is located locally.

The script simply establishes an SSH session, enters enable mode (if you’re not already dropped in it), enters configure mode, sends whatever commands you specify, then does a write to memory before exiting and moving onto the next device. You need three files to accomplish this:

device-list.txt

This is simply a text file with IP addresses and/or hostnames of the devices with which you want the script to connect to:

core1.mydomain.com
nexus1a
nexus1b
10.0.0.1

configure-cisco.sh

This is a bash shell script which you will run to start the entire process. It will prompt for your ssh password and an enable password, and then feed it to the Expect script along with the contents of device_list.txt. I found this more secure then reading the passwords from a file and easier to do in bash than in expect.

 #!/bin/bash
 # Collect the current user's ssh and enable passwords
 echo -n "Enter the SSH password for $(whoami) "
 read -s -e password
 echo -ne '\n'
 echo -n "Enter the Enable password for $(whoami) "
 read -s -e enable
 echo -ne '\n'
# Feed the expect script a device list & the collected passwords
for device in `cat device-list.txt`; do
 ./configure-cisco.exp $device $password $enable ;
 done

configure-cisco.exp

This is the expect script that I explained earlier. It has some intelligence built in to gracefully handle ssh connectivity issues and will send results both to the screen and to a file called results.log in your home directory:

#!/usr/bin/expect -f

# Set variables
 set hostname [lindex $argv 0]
 set username $env(USER)
 set password [lindex $argv 1]
 set enablepassword [lindex $argv 2]

# Log results
 log_file -a ~/results.log

# Announce which device we are working on and at what time
 send_user "\n"
 send_user ">>>>>  Working on $hostname @ [exec date] <<<<<\n"
 send_user "\n"

# Don't check keys
 spawn ssh -o StrictHostKeyChecking=no $username\@$hostname

# Allow this script to handle ssh connection issues
 expect {
 timeout { send_user "\nTimeout Exceeded - Check Host\n"; exit 1 }
 eof { send_user "\nSSH Connection To $hostname Failed\n"; exit 1 }
 "*#" {}
 "*assword:" {
 send "$password\n"
 }
 }

# If we're not already in enable mode, get us there
 expect {
 default { send_user "\nEnable Mode Failed - Check Password\n"; exit 1 }
 "*#" {}
 "*>" {
 send "enable\n"
 expect "*assword"
 send "$enablepassword\n"
 expect "*#"
 }
 }

# Let's go to configure mode
 send "conf t\n"
 expect "(config)#"

# Enter your commands here. Examples listed below
 #send "tacacs-server host 10.0.0.5\n"
 #expect "(config)#"
 #send "tacacs-server directed-request\n"
 #expect "(config)#"
 #send "tacacs-server key 7 0000000000000\n"
 #expect "(config)#"
 #send "ntp server 10.0.0.9\n"
 #expect "(config)#"
 #send "ip domain-name yourdomain.com\n"
 #expect "(config)#"

 send "end\n"
 expect "#"
 send "write mem\n"
 expect "#"
 send "exit\n"
 expect ":~\$"
 exit

To run the script, create all three files in your Mac home directory, chmod+x the scripts, then run configure-cisco.sh.

[12/07/2012 1:45pm @paul-mac-air:~]% ./configure-cisco.sh
 Enter the SSH password for paul
 Enter the Enable password for paul
>  Working on core1.mydomain.com @ Fri Dec  7 13:45:22 PST 2012 <
spawn ssh -o StrictHostKeyChecking=no paul@core1.mydomain.com
...

Examples of Simple Enhancements

The scripts I included above have been stripped down to the bare essentials so that there are fewer lines of code to get started with. It gets the job done, but the more you use the scripts the more you may want to enhance it.

I am by no means an expert in Expect or Bash, but I’ve spent a little time playing with both to help tailor my scripts to do the things I want. The more you use Expect, the more you may want to tailor it as well. Below are a few very basic examples.

1. Add terminal vt100 to for connecting to Nexus devices

I simply got tired of seeing this line every time I connected to a Nexus device:

Nexus 5000 Switch
Password:
Bad terminal type: “xterm-256color”. Will assume vt100.

You can specify a terminal type of vt100 by adding this line to the configure-cisco.sh script (assuming you don’t want to do it in your terminal settings):

# Set terminal to vt100 so Nexus devices don't complain
export TERM=vt100

2. Save and rotate logs

I like to log all of the input from my script to a single file called “results.log” which I can then parse later and/or save for reference. To make sure I don’t overwrite a previous log file, I added a few lines of code to configure-cisco.sh to copy and rename “results.log” to “results.log.timestamp”

timestamp=`date +%m%d%H%M`
logdir=~/logs/expect

# This will rotate and append date stamp...
logfile=$logdir/results.log
newlogfile=$logfile.$timestamp
cp $logfile $newlogfile

Summary

Expect is the perfect tool for easily automating redundant tasks and configuration changes on network equipment. It’s preloaded on Mac OS X and simple to install on server running the Linux flavor of your choice. You don’t need to fully dive in to the language in order to take advantage of it’s time saving capabilities.

//
// ]]>

94 comments

  1. Hi there,

    At first I want to thank you for sharing this wonderful script. It saved me a lot of research time, since it perfectly fits my needs till the login-part was done.

    Currently I am working on a troubleshooting-system which monitors interfaces’ health and displays the ports on a website depending on their status (good, alert, critical). Later on, I want the system to repair itself on logical base. If you have to check for physical issues you (the network specialist) get contacted.

    Although your post is several years old: If you are interested in working together, please feel free to contact me via e-mail. I also do have some more ideas about Cisco automatization.

    Thankful regards
    Fred

  2. I know this is an older post, but I’m trying to get this setup and going.

    When I run configure-cisco.sh it prompts for passwords then quits with:

    “: no such file or directory

    I’m not super versed on scripting, so I might be missing something stupid simple.

    Things I’ve checked:

    All three files are in the same directory. CHMOD applied appropriately.

    Things I’ve modified:

    I’ve changed the configure-cisco.sh script to allow for using one of our Tacacs usernames.

    I’ve changed the configure-cisco.exp script to reflect the username rather than whoami response.

    I did some tweaking to the log file for the expect script, not sure if this works, haven’t gotten this far.

    set Directory ~/logs

    # Log results
    log_file -a $Directory/session_$hostname.log
    send_log “### /START-SSH-SESSION/ IP: @hostname @ [exec date] ###\r”

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 )

Twitter picture

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

Facebook photo

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

Google+ photo

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

Connecting to %s