Friday, April 6, 2018

Network Automation with TCL

My company has a large (and not very well managed) network.  Different VLANs have different "ip helper-address" (DHCP) settings.  Some of them are pointing to development DHCP, some of them pointing to production DHCP, some of them are pointing to VDI environment.

For the production environment, there are two DHCP servers (A and B).  They are supposed to back up each other.  However some of the VLANs might be configured to use one of them but not both.

The DHCP administrator wanted to perform a DR test, which he would shut down one of the DHCP servers and see if the clients still be able to get IP address from the other server.

Before he can perform the DR test, he needs to make sure that DHCP server A and B are referenced in pairs, which means a interface either references both servers, or reference neither server.  If the interface references only one of the two, it'd be a problem.  We need to fix this problem before the DR test.

So the workflow is pretty straight forward:
1) SSH into a switch (where the  IP interfaces are configured).
2) Use "show ip interface brief | exclude unassigned" to display the interfaces with IP configured.
3) Use "show run interface xxx" command to review the configuration.  If one of the DHCP servers (A or B) was referenced but the other one of missing, we need to add the other one to the configuration.

* If both are present, it's fine.  If none of them present, that's fine.

This is a simple but tedious work.  Because we have a bunch of switches.  Some of the switches have more than 50 SVIs.  Visual inspection would be  time consuming and prone to human errors.

This is where automation should kick in.  You may use other program languages.  I chose TCL because it was built in on IOS.

In privilege (enable) mode, type "tclsh" to get into TCL shell.  Copy and paste the script into the command line.  It will create a procedure called "check".  Then type "check" (without quotation marks).  Below are some sample outputs:

Example 1: No problem found.

Example 2: Found some interfaces missing one of the helpers.

Script is as below.
proc check {} {

# Define the two commands we want to check
set str_helper1 "ip helper-address"
set str_helper2 "ip helper-address"

# Define missing_commands string
set str_missing_cmds ""

# List all the interfaces with IP address.
set str_sh_ip_int [exec sh ip int br | ex una]

# Break the output into individual lines and put them in a list.  First two lines are headers.
set list_int [split $str_sh_ip_int \n]

# Get the number of lines
set num_num_of_lines [llength $list_int]

# Skip headers, start from 1st interface
set num_current_line 2

# Process each each line (each IP interface).
while { $num_current_line < $num_num_of_lines } {

    # Get the interface name from each line.
    set str_int_name [lindex [split [lindex $list_int $num_current_line]] 0]

    # Do a "show run interface" againt the interface name.
    set str_sh_run_int [exec sh run int $str_int_name]

    # See if helper1 exists but not helper2
    if { [string match "*$str_helper1*" $str_sh_run_int] && ![string match "*$str_helper2*" $str_sh_run_int] } {
        append str_missing_cmds "interface $str_int_name\n $str_helper2\n"

    # See if helper2 exists but not helper1
    } elseif { [string match "*$str_helper2*" $str_sh_run_int] && ![string match "*$str_helper1*" $str_sh_run_int] } {
        append str_missing_cmds "interface $str_int_name\n $str_helper1\n"

    # Move to next line (next IP interface)
    incr num_current_line

# Missing helper on some of the interfaces
if {[string length $str_missing_cmds]} {
    puts "\n\nIP Interface(s):"
    puts "----------------"
    puts $str_sh_ip_int
    puts "\n[expr $num_num_of_lines-2] interface(s) checked.  The following commands are missing:\n"
    puts $str_missing_cmds

# All interfaces are good
} else {
    puts "\n\nIP Interface(s):"
    puts "----------------"
    puts $str_sh_ip_int
    puts "\n[expr $num_num_of_lines-2] interface(s) checked.  No Problem Found."