A commenter on my previous post directed me to the module CiscoConfParse which would have likely made this a much easier exercise.  Even so, this was a great exercise for me to go through, as it allowed me to learn a new programming language.
I’ll still post my solution to this problem, along with the supporting files.  The first file below is the Python script.  Running it with a –h option will show you the proper format for the parameters.  The supporting file “verification.txt” is also listed below.  It describes the format to use for the verification seed file.
If you happen to see anything wrong with this script, or room for improvement, please share your thoughts via comment or email.  I am always looking to learn, and I know there is room for improvement in my Python programming!
Jeremy
--------------------------
configcheck.py:
#   
# configcheck.py - A script that verifies the existence or     
#   absence of specific configuration lines in a Cisco switch config    
# 
import os   
import re    
import sys    
import getopt 
#   
# Checks router interface configuration against a base config    
# 
def get_config_snmp():   
    pass 
def get_config_file(filename):   
    """getconfig loads a router config and returns an array with individual lines"""    
    if os.path.isfile(filename) == 0:    
        sys.exit("ERROR: File does not exist")    
    contents = []    
    with open(filename, 'r') as file:    
        for a in file: contents.append(a)    
    file.closed    
#    
# Clear '/r', '/n', ' ' characters from file (to allow interchangeability between Unix/Windows)    
#    
    for x in range(0, len(contents)):    
        if len(contents[x]) > 1:    
            while contents[x][-1:] in ('\r', '\n', ' '): contents[x] = contents[x][:-1]    
    return contents 
def gethostname(config):   
    """gethostname retrieves the device hostname from configuration file"""    
    n = 0    
    for n in range (0, len(config)):    
        if len(config[n-1]) > 9:    
            if config[n-1][:8] == "hostname":    
                return config[n-1][9:]    
    return "No Hostname Found" 
def check_interfaces(config, int_type, verify_config):   
    """check_interfaces retrieves interface configuration\    
 from the config and sends it to verify"""    
    n = -1    
    while n <= (len(config) - 2):    
        n += 1    
        if len(config[n]) > 9:    
            if config[n][:9] == "interface":    
                interface = []    
                interface.append(config[n])    
                n += 1    
                while config[n][0] == ' ':    
                    interface.append(config[n])    
                    n += 1    
                if re.search(int_type, interface[1]):    
                    verify(interface, verify_config) 
def verify(interface, verify_config):   
    """verify takes an interface config and a list of required statements\    
 and verifies that each is present""" 
    s = "\n\n! The Following Interface is Missing the Command(s) Below: \n\n"\   
    + interface[0] + '\n' + interface[1]     
    error = 0    
    for a in verify_config:    
        if a[1] == "!":    
           b = " " + a[2:] + " "    
           if interface.count(b):    
               error += 1    
               if b[1:2] == "no":    
                   s += " " + b[3:] + '\n'    
               else:    
                   s += " no" + b + '\n'    
        elif not interface.count(a):    
            error += 1    
            s += a + '\n'    
#Print Error Interfaces    
    if error: print s 
#   
# Main Program Body    
# 
#   
# Process command-line arguments    
#    
config = []    
verify_file = "verification.txt"    
try:    
    opts, args = getopt.getopt(sys.argv[1:], "hs:f:v:", ["help", "snmp=", "file=", "verify="])    
except getopt.GetoptError, err:    
    # print help information and exit:    
    print str(err) # will print something like "option -a not recognized"    
    sys.exit(2)    
for o, a in opts:    
    if o in ("-h", "--help"):    
        sys.exit("\nOptions:\n\    
-s, --snmp: Use SNMP to retrieve configuration (not implemented in this version)\n\    
-f, --file: Load configuration from local file\n\    
-v, --verify: Load verification file from local file (default is verification.txt)\n\    
-h, --help: This message")    
    elif o in ("-v", "--verify"):    
        verify_file = a    
    elif o in ("-s", "--snmp"):    
        config = get_config_snmp(a)    
        break    
    elif o in ("-f", "--file"):    
        config = get_config_file(a)    
        break    
    else:    
        assert False, "unhandled option" 
print "\n\n\nHostname (from configuration file): " + str(gethostname(config))   
#    
# Cycle through verification.txt to retrieve individual verification configuration    
#    
contents = []    
with open(verify_file, 'r') as file:    
    for a in file:    
        if len(a) >= 4:    
            if a[0] == '[':    
                int_type = a[1:5]    
            elif a[0] == ' ':    
#    
# Clear '/r', '/n', ' ' characters from file (to allow interchangeability between Unix/Windows)    
#    
                while a[-1:] in ('\r', '\n', ' '): a = a[:-1]    
                contents.append(a)    
            elif a[0] == "#":    
                pass    
        elif a[0] == "#":    
            pass    
        else:    
            check_interfaces(config, int_type, contents)    
            contents = []    
file.closed
------------------------------------------------------
verification.txt:
#   
# Comments begin with "#"    
# Commands that must not be in the switchport configuration should begin with " !"    
# Each interface type is headed with [XXXX]    
# There is to be a blank line between each type    
#    
[ENDU]    
 switchport access vlan 10    
 switchport mode access    
 !mls qos trust dscp    
 service-policy input END-USER-IN    
 ip dhcp snooping limit rate 100    
 spanning-tree portfast    
 spanning-tree bpduguard enable    
 no logging event link-status    
 no snmp trap link-status    
 load-interval 30    
 switchport voice vlan 12 
[SRVR]   
 !mls qos trust dscp    
 service-policy input SERVER-IN    
 ip dhcp snooping limit rate 100    
 spanning-tree portfast    
 spanning-tree bpduguard enable    
 logging event link-status    
 no snmp trap link-status    
 load-interval 30 
[MPBX]   
 switchport mode access    
 mls qos trust dscp    
 flowcontrol receive desired    
 flowcontrol send off    
 ip dhcp snooping limit rate 100    
 logging event link-status    
 snmp trap link-status    
 load-interval 30
-------------
And to be complete, here is a sample switch configuration to use
sampleswitch.log:
!   
hostname SampleSwitch    
!    
interface GigabitEthernet1/2    
 description ENDU; User A - Properly Configured    
 switchport    
 switchport access vlan 10    
 switchport mode access    
 switchport voice vlan 12    
 no logging event link-status    
 load-interval 30    
 wrr-queue bandwidth 5 25 70     
 wrr-queue queue-limit 5 25 40     
 wrr-queue random-detect min-threshold 1 80 100 100 100 100 100 100 100     
 wrr-queue random-detect min-threshold 2 80 100 100 100 100 100 100 100     
 wrr-queue random-detect min-threshold 3 50 60 70 80 90 100 100 100     
 wrr-queue random-detect max-threshold 1 100 100 100 100 100 100 100 100     
 wrr-queue random-detect max-threshold 2 100 100 100 100 100 100 100 100     
 wrr-queue random-detect max-threshold 3 60 70 80 90 100 100 100 100     
 wrr-queue cos-map 1 1 1     
 wrr-queue cos-map 2 1 0     
 wrr-queue cos-map 3 1 4     
 wrr-queue cos-map 3 2 2     
 wrr-queue cos-map 3 3 3     
 wrr-queue cos-map 3 4 6     
 wrr-queue cos-map 3 5 7     
 mls qos trust dscp    
 flowcontrol receive desired    
 flowcontrol send off    
 spanning-tree portfast    
 spanning-tree bpduguard enable    
 service-policy input END-USER-IN    
 ip dhcp snooping limit rate 100    
 no snmp trap link-status    
!    
interface GigabitEthernet1/3    
 description SRVR; Server A - Properly Configured    
 switchport    
 switchport access vlan 15    
 switchport mode access    
 logging event link-status    
 load-interval 30    
 wrr-queue bandwidth 5 25 70     
 wrr-queue queue-limit 5 25 40     
 wrr-queue random-detect min-threshold 1 80 100 100 100 100 100 100 100     
 wrr-queue random-detect min-threshold 2 80 100 100 100 100 100 100 100     
 wrr-queue random-detect min-threshold 3 50 60 70 80 90 100 100 100     
 wrr-queue random-detect max-threshold 1 100 100 100 100 100 100 100 100     
 wrr-queue random-detect max-threshold 2 100 100 100 100 100 100 100 100     
 wrr-queue random-detect max-threshold 3 60 70 80 90 100 100 100 100     
 wrr-queue cos-map 1 1 1     
 wrr-queue cos-map 2 1 0     
 wrr-queue cos-map 3 1 4     
 wrr-queue cos-map 3 2 2     
 wrr-queue cos-map 3 3 3     
 wrr-queue cos-map 3 4 6     
 wrr-queue cos-map 3 5 7     
 mls qos trust dscp    
 flowcontrol receive desired    
 flowcontrol send off    
 spanning-tree portfast    
 spanning-tree bpduguard enable    
 service-policy input SERVER-IN    
 ip dhcp snooping limit rate 100    
 no snmp trap link-status    
!    
interface GigabitEthernet1/4    
 description SRVR; Purposely Misconfigured    
 switchport    
 switchport trunk encapsulation dot1q    
 switchport mode trunk    
 logging event link-status    
 load-interval 30    
 wrr-queue bandwidth 5 25 70     
 wrr-queue queue-limit 5 25 40     
 wrr-queue random-detect min-threshold 1 80 100 100 100 100 100 100 100     
 wrr-queue random-detect min-threshold 2 80 100 100 100 100 100 100 100     
 wrr-queue random-detect min-threshold 3 50 60 70 80 90 100 100 100     
 wrr-queue random-detect max-threshold 1 100 100 100 100 100 100 100 100     
 wrr-queue random-detect max-threshold 2 100 100 100 100 100 100 100 100     
 wrr-queue random-detect max-threshold 3 60 70 80 90 100 100 100 100     
 wrr-queue cos-map 1 1 1     
 wrr-queue cos-map 2 1 0     
 wrr-queue cos-map 3 1 4     
 wrr-queue cos-map 3 2 2     
 wrr-queue cos-map 3 3 3     
 wrr-queue cos-map 3 4 6     
 wrr-queue cos-map 3 5 7     
 mls qos trust dscp    
 flowcontrol receive desired    
 flowcontrol send off    
 spanning-tree portfast    
 spanning-tree bpduguard enable    
 ip dhcp snooping trust    
!    
interface GigabitEthernet1/5    
 description ENDU; Purposely Misconfigured    
 switchport    
 switchport access vlan 30    
 switchport mode access    
 switchport voice vlan 125    
 no logging event link-status    
 load-interval 30    
 wrr-queue bandwidth 5 25 70     
 wrr-queue queue-limit 5 25 40     
 wrr-queue random-detect min-threshold 1 80 100 100 100 100 100 100 100     
 wrr-queue random-detect min-threshold 2 80 100 100 100 100 100 100 100     
 wrr-queue random-detect min-threshold 3 50 60 70 80 90 100 100 100     
 wrr-queue random-detect max-threshold 1 100 100 100 100 100 100 100 100     
 wrr-queue random-detect max-threshold 2 100 100 100 100 100 100 100 100     
 wrr-queue random-detect max-threshold 3 60 70 80 90 100 100 100 100     
 wrr-queue cos-map 1 1 1     
 wrr-queue cos-map 2 1 0     
 wrr-queue cos-map 3 1 4     
 wrr-queue cos-map 3 2 2     
 wrr-queue cos-map 3 3 3     
 wrr-queue cos-map 3 4 6     
 wrr-queue cos-map 3 5 7     
 snmp trap mac-notification change added    
 mls qos trust dscp    
 flowcontrol receive desired    
 flowcontrol send off    
 spanning-tree portfast    
 spanning-tree bpduguard enable    
 service-policy input END-USER-IN    
 ip dhcp snooping limit rate 100 
I've been attempting to do a bit of Python lately for network admin type tasks and just came across your blog. Thanks for sharing your script!
ReplyDelete