Automate your Cisco CCIE Home Lab for the INE Workbook v5

I recently gained access to an INE All Access Pass, which includes the Cisco CCIE Route and Switch v5 Workbook and various labs with a view to taking my lab exam.

Whilst it included some rack rental tokens I have the resources to build my own lab and use it whenever i see fit, no scheduling, no ongoing costs.  My only problem – how to automate the INE Workbook v5 initial config’s to my home lab as its a royal pain to have to copy and paste the config’s to potentially 24 devices each time i want to run a lab.

My goal was simple;

  1. Be able to VPN to the lab from anywhere
  2. Select a configuration
  3. Have expect, telnet to each router and apply the configuration
  4. Grab a coffee and come back with the routers ready to rock and roll for the INE workbook
  5. When INE release new labs, be able to easily update it without any further code changes

!!!!!
DISCLAIMER: I am NOT a programmer, my code is certainly rubbish and inefficient – but it works for me.. YMMV
!!!!! 

So, enter some bash scripting and the awesome Expect. There are newer/better alternatives, but this does the job and my small no-programer brain could figure this out.

Massive shout out to http://paulgporter.net/2012/12/08/30/ for his article which is where i found out how to pass variables through to expect from a bash script.

My goal realised;

  1. Be able to VPN in
    This ones easy – Cisco ASA in front and configure split tunnelling so i can stay connected and still get what i need.
  2. Select a configuration
    My bash script (start-lab.sh) works by presenting a menu, the menu items come from indexing all the folders within the INE configurations folder (which are in /var/lab/configs/). The reason for this is if INE release a new set of configurations, i simply delete the ones i have and upload the new set, the menu system will pickup all the new config’s – no code changes required!.

    <Screenshot>Screen Shot 2015-02-01 at 19.08.13


    prompt="Please select a lab:"
    options=( $(find /var/lab/configs/ -mindepth 2 -maxdepth 2 -type d) )
    PS3="$prompt "
    select opt in "${options[@]}" "Quit" ; do
    if (( REPLY == 1 + ${#options[@]} )) ; then
    exit
    elif (( REPLY > 0 && REPLY <= ${#options[@]} )) ; then
    echo "Your starting lab $REPLY which is lab $opt"
    break
    else
    echo "Invalid option. Try another one."
    fi
    done

  3. Once you select the menu item ($opt) (notice it actually shows a full path) it index’s the contents of said folder to work out which devices it needs to configure and dumps this to a text file for the next bit of code to use.  The reason for this is some labs contain 10 routers, others 20, some include the switches some don’t.


    ls -1 $opt | sed -e 's/..*$//' > /var/lab/tmp/lab-devices.txt

  4. I then pass the same variable ($opt) to the expect script (exp-start-lab.sh) for each device found in the text file generated in the last step ($device)


    for device in `cat /var/lab/tmp/lab-devices.txt`; do
    /var/lab/exp-start-lab.exp $opt $device &
    done

    Quick Node: using the & it executes each router in parallel, you can do each router sequentially if you would prefer (obviously much slower but helps with troubleshooting) by changing it to;


    /var/lab/exp-start-lab.exp $opt $device;

  5. the expect script then starts and configures two variables ($opt becomes $lab and $device becomes $hostname) based on the information passed through from the bash script.


    #!/usr/bin/expect -f
    set timeout 2
    exp_log_user 0
    log_user 1
    # Set variables
    set lab [lindex $argv 0]
    set hostname [lindex $argv 1]

  6. Now, because each cisco router listens on a different port/IP address i have to generate a hostname and port for each $device which expect can actually use;


    if { $hostname == "R1" } {
    set address 192.168.1.101;
    set port 3001;
    } elseif { $hostname == "R2" } {
    set address 192.168.1.101;
    set port 3002;
    } elseif { $hostname == "R3" } {
    set address 192.168.1.101;
    set port 3003;
    } elseif { $hostname == "R4" } {
    set address 192.168.1.101;
    set port 3004;
    ----- SNIP ----- you get the idea
    } elseif { $hostname == "R20" } {
    set address 192.168.1.101;
    set port 3020;
    } elseif { $hostname == "SW1" } {
    set address 192.168.1.102;
    set port 4001;
    ----- SNIP ----- you get the idea
    } elseif { $hostname == "SW4" } {
    set address 192.168.1.102;
    set port 4004;
    } else {
    error "no hostname"
    }

  7. Now we have the routers names and variables defined we can spawn telnet and start sending commands with expect. My process first makes sure its at at the enable prompt and then does a ‘configure replace’ to replace the routers running configuration with that of the ‘flash:base.config’ which i created earlier (contains priv level 15 for the console, no shut on gig1, no ip domain lookup etc). It then submits each configuration line from the devices configuration file on the device its connected to.


    # Spawn telnet
    spawn telnet $address $port
    sleep 5
    send "!n"
    expect {
    "(config*#" {
    send "endr"
    send_user ">>> Had to end to get Enable <<>> Got Enable <<

Problems I came across

Problem 1: The INE configurations were a mix of binary and text files - Expect can't work with these binary file types

Fix: This one took me a while, loads of options just plain didn't work. The fix seemed to be to remove the 'NULL' character's from the files, I created a quick script that looked for all the text files, scanned through them all and removed it.

This only needs run once, after you've put your configurations in the 'configs' directory.

Full script: convert-configs-to-ascii.sh


#!/bin/bash
# Cleanup after the last run
rm -f /var/lab/tmp/all-txt-files.txt
# Create a useable Directory List
find /var/lab/configs/ -mindepth 2 -maxdepth 3 -type f -name *.txt > /var/lab/tmp/all-txt-files.txt
# Remove the null char's
for configfile in `cat /var/lab/tmp/all-txt-files.txt`; do
cat $configfile | tr -d '00' > $configfile.tmp; mv -f $configfile.tmp $configfile &
done

Problem 2: The INE configurations had a load of stuff in that i don't want Expect to waste time executing, instead i put the common commands in my base configuration - but how do I clean up these config's?

Fix: Similar to the approach above looking for 'NULL' characters, i thought why can't I do the same for each command i want to remove from the configurations.

This only needs run once, and must be done AFTER you've converted the files to ascii as shown in problem 1.

Full script: clean-configs.sh


#!/bin/bash
# Create a useable Directory List
rm -f /var/lab/tmp/all-txt-files.txt
find /var/lab/configs/ -mindepth 2 -maxdepth 3 -type f -name *.txt > /var/lab/tmp/all-txt-files.txt
# Grep out the config we dont want
for configfile in `cat /var/lab/tmp/all-txt-files.txt`; do
grep -v '!' $configfile > $configfile.tmp; mv -f $configfile.tmp $configfile &
done
for configfile in `cat /var/lab/tmp/all-txt-files.txt`; do
grep -v '^$' $configfile > $configfile.tmp; mv -f $configfile.tmp $configfile &
done
for configfile in `cat /var/lab/tmp/all-txt-files.txt`; do
grep -v 'end' $configfile > $configfile.tmp; mv -f $configfile.tmp $configfile &
done
for configfile in `cat /var/lab/tmp/all-txt-files.txt`; do
grep -v 'platform console serial' $configfile > $configfile.tmp; mv -f $configfile.tmp $configfile &
done

 

My Setup

My setup includes;

  • 1x ESXi Host, running 20x Cisco CSR1000v routers, each one configured with a telnet connection for the console (2x nic's minumum required)
    Screen Shot 2015-02-01 at 18.58.55
  •  

  • 4x Cisco WS-C3560-24TS-S switches with the consoles hooked upto console server with an Octo Cable.
  •  

  • Basic Layer 2 switch and a firewall to VPN in to, this is obviously optional and could be plugged into a LAN of some sorts, but i wanted access from wherever i may happen to be  and i'd prefer not to have the ESXi host on the public internet for obvious reasons.
  •  

  • A vanila CentOS 6.6 VM to run my expect scripts (yum install expect telnet)

Diagram

Screen Shot 2015-02-01 at 20.15.18

 

Leave a Reply

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