I wrote a couple more scripts this week. These two little gems update my entire lab by running one command from the testlab tftp server. I pass the main script a lab name and it proceeds to update every router and switch in the testlab to the new initial lab configuration. I have tested it on at least one 1841, 2611, 3640, 3550 and 3560. I probably spent more time writing the scripts than it would have taken me to upgrade the testlab by hand for each lab, but I guess I’ll never know. You can download the scripts here.
Let me explain how it is done. Every router and switch has a configuration file named flash:def. When the whole lab has flash:def loaded they can all get to the tftp server for the lab. First side note: it was named flash:default but default is a reserved word in expect so I had to change the name, def is short for default.
In the first round of interaction the script saves every running-config to flash:new and then does a configure replace flash:def. If you just wanted to reset your lab each time, you could stop the script there. Second side note: I was going to save the original running-config as flash:save, that would still be a trivial change to make and then you could go back and review the config if you needed, but some labs build on top of the next, so I didn’t.
After each router and switch has the def configuration file loaded the script does an ls of the correct lab directory on the tftp server and proceeds to tftp the new configuration file as flash:new, overwriting the previously saved running-config. The tftp server is hooked to the switch named Cat4 which is the last host upgraded by the script so all devices can get to the tftp server.
Finally the script goes back through each device doing a round of configure replace:new. The best part of this is that there is no reload. The 2611 can take nearly 10 minutes to reload so I did not want to have to reload any devices.
In summary this is the process:
1. Save every running-config as flash:new.
2. Load the default configuration flash:def that allows for tftp access for the entire lab.
3. Copy the initial configuration for the new lab to flash:new on the routers that need it, overwriting the saved flash:new.
4. Run configure replace flash:new on ever device, bringing up the newest lab.
Here is a listing of the files on R2.
R2#dir flash: Directory of flash:/ 1 -rw- 32632600 <no date> c3640-a3js-mz.124-25b.bin 2 -rw- 1132 <no date> r2-basic-ios.cfg 3 -rw- 1200 <no date> r2-gre.cfg 4 -rw- 6446 May 28 2002 02:23:57 +00:00 ipbasic.cfg 13 -rw- 883 <no date> save 15 -rw- 1061 <no date> def 18 -rw- 1226 <no date> new 33030140 bytes total (372576 bytes free) R2#
This is the tlu script. It is just the simple front end to the tlue script.
#!/bin/bash # 2010-05-25 Jud Bishop # tlu (testlab update) # One of two scripts that updates the entire testlab to the current lab. # This script calls tlue (testlab update expect) that does the heavy lifting. if [ $# -ne 1 ] then echo -e "Usage: ${0} LAB-X\n ${0} LAB-1\n" exit 1 fi LAB=${1} # First go through and set every router or switch to the default configuration. # Calling tlue (testlab update expect) with the def command, the def # configuration sets every router to clean confiuration that allows access to # the tftp server. # R3 is the frame switch so it is not included. config_replace () { LAB=${1} CONFIG=${2} for ROUTER in R1 R2 R4 R5 R6 R7 R8 R9 BB1 BB2 BB3 Cat1 Cat2 Cat3 Cat4 do echo $ROUTER $LAB $CONFIG tlue $ROUTER $LAB $CONFIG sleep 10 done } # ## Main # config_replace $LAB "def" for CONFIG in `ls /tftpboot/VOL-1/${LAB}/INITIAL/` do ROUTER=`basename $CONFIG .txt` echo $ROUTER tlue $ROUTER ${1} tftp sleep 10 done config_replace $LAB "new"
The expect script is the one that does all of the work and took the most time to write.
#!/usr/bin/expect -f # 2010-06-25 Jud Bishop # tlue (testlab update expect) # This script does the heavy lifting of updating the testlab. # If you use this script you will have to change the IP address # in the procedure copy_tftp. set host "testlab.chainringcircus.org" set pass "CHANGEME" set ctrlz \032 set timeout 100 set spawn_telnet 0 # Sent in from the command line. set router [lindex $argv 0] set lab [lindex $argv 1] set config [lindex $argv 2] proc login {router} { puts "login" global host pass ctrlz spawn_telnet spawn telnet $host expect "Password:" { send "$pass\r" } expect "testlab>" { send "telnet $router\r" } sleep 2 expect "Open" { send "\r" } sleep 2 # Just in case we are in configure mode. send "$ctrlz" send "\r" set spawn_telnet $spawn_id } proc save_config {router} { puts "save_config" global spawn_telnet set spawn_id $spawn_telnet # Saving the current config in case I want it for some reason. expect "$router#" { send "copy run flash\:new\r" } # Destination filename [new]? expect { "\[new\]" {send "\r"} } #Do you want to over write? [confirm] expect { -re ".*Do you want to over write.*" {send "y\r"} "$router#" {send "\r"} } sleep 2 # No, do not erase flash:. # Erase flash: before copying? [confirm] expect { -re "Erase flash\:" {send "n"} "$router#" {send "\r"} } sleep 2 } # Pass in the file to load from flash, for me it's either "new" or "def". proc configure_replace {config router} { puts "configure_replace" global spawn_telnet set spawn_id $spawn_telnet # This gets the router/switch to a known configuration that can reach the ftp server. expect "$router#" { send "configure replace flash\:$config\r" } #configure replace flash:default #This will apply all necessary additions and deletions #to replace the current running configuration with the #contents of the specified configuration file, which is #assumed to be a complete configuration, not a partial #configuration. Enter Y if you are sure you want to proceed. ? [no]: expect -re "(.*)(no)(.*)" { send "y\r" } sleep 5 } proc copy_tftp {lab router} { puts "copy_tftp" global spawn_telnet set spawn_id $spawn_telnet #R1#copy tftp://192.168.1.234/R1.txt flash:new expect "$router\#" { send "copy tftp://192.168.1.234/VOL-1/$lab/INITIAL/$router.txt flash:new\r" } #Destination filename [new]? expect { -re "Destination filename" {send "\r"} } #Erase flash: before copying? [confirm]n #OR #Do you want to over write? [confirm]y #expect -re { # "(.*)(before copying)(.*)" {send "n\r"} # "(.*)(over.write)(.*)" {send "y\r"} #} #Do you want to over write? [confirm] expect { -re ".*Do you want to over write.*" {send "y\r"} "$router#" {send "\r"} } sleep 2 #If it was over write above, now it might ask for erase flash or #return the router prompt. #Erase flash: before copying? [confirm] expect { -re "Erase flash" {send "n\r"} "$router#" {send "\r"} } #Loading R1.txt from 192.168.1.234 (via FastEthernet0/0): ! #[OK - 902 bytes] #Verifying checksum... OK (0xFBC4) #902 bytes copied in 0.232 secs (3888 bytes/sec) #R1# expect "$router#" { send "\r" } } # ## Main # # Oh the irony. If only I had known how many problems calling my "default" # configuration flash:default would cause me. As a result I changed it to def. # However instead of a nice switch statement I'm using an if block, default is a # reserved word in Tcl switch statements. I did not take the time to go back and # change it. puts "router $router" puts "lab $lab" puts "config $config" if {[ string compare $config tftp ] == 0} { login $router copy_tftp $lab $router } elseif {[ string compare $config new ] == 0} { login $router configure_replace new $router } elseif {[ string compare $config def ] == 0} { login $router save_config $router configure_replace def $router } else { puts "tlue router lab \[def new tftp\]" puts "Example:" puts "tlue R1 LAB-1 def" puts "default saves the running-config to flash:new and runs configure replace:flash:default" puts "tftp loads the correct configuration for the lab from the tftp server as flash:new" puts "new runs configure replace flash:new, replacing the running config with new" exit } exit