Example Usage: A Contrived Configuration Audit

Suppose you have a large switched network and need to run audits on your configurations; assume you need to build configurations which conform to the following criteria:

  • Access switchports must be configured with storm-control

  • Trunk ports must not have port-security

  • Timestamps must be enabled on logging and debug messages

You should follow the following steps.

Assume that you start with the following Cisco IOS configuration saved as short.conf (All the interfaces need to be changed, to conform with audit requirements):

! Filename: short.conf
!
interface FastEthernet0/1
 switchport mode access
 switchport access vlan 532
!
interface FastEthernet0/2
 switchport mode trunk
 switchport trunk allowed 300,532
 switchport nonegotiate
 switchport port-security maximum 2
 switchport port-security violation restrict
 switchport port-security
!
interface FastEthernet0/3
 switchport mode access
 switchport access vlan 300
!
end

Next, we build this script to read and change the config:

from ciscoconfparse import CiscoConfParse

def standardize_intfs(parse):

    ## Search all switch interfaces and modify them
    #
    # r'^interface.+?thernet' is a regular expression, for ethernet intfs
    for intf in parse.find_objects(r'^interface.+?thernet'):

        has_stormcontrol = intf.has_child_with(r' storm-control broadcast')
        is_switchport_access = intf.has_child_with(r'switchport mode access')
        is_switchport_trunk = intf.has_child_with(r'switchport mode trunk')

        ## Add missing features
        if is_switchport_access and (not has_stormcontrol):
            intf.append_to_family(' storm-control action trap')
            intf.append_to_family(' storm-control broadcast level 0.4 0.3')

        ## Remove dot1q trunk misconfiguration...
        elif is_switchport_trunk:
            intf.delete_children_matching('port-security')

## Parse the config
parse = CiscoConfParse('short.conf')

## Add a new switchport at the bottom of the config...
parse.append_line('interface FastEthernet0/4')
parse.append_line(' switchport')
parse.append_line(' switchport mode access')
parse.append_line('!')
parse.commit()     # commit() **must** be called before searching again

## Search and standardize the interfaces...
standardize_intfs(parse)
parse.commit()     # commit() **must** be called before searching again

## I'm illustrating regular expression usage in has_line_with()
if not parse.has_line_with(r'^service\stimestamp'):
    ## prepend_line() adds a line at the top of the configuration
    parse.prepend_line('service timestamps debug datetime msec localtime show-timezone')
    parse.prepend_line('service timestamps log datetime msec localtime show-timezone')

## Write the new configuration
parse.save_as('short.conf.new')

Normally, regular expressions should be used in .has_child_with(); however, you can technically get away with the bare strings that I used in standardize_intfs() in some cases. That said, regular expressions are more powerful, and reliable when searching text. Usage of the has_line_with() and find_objects() methods illustrate regular expression syntax.

After the script runs, the new configuration (short.conf.new) looks like this:

service timestamps log datetime msec localtime show-timezone
service timestamps debug datetime msec localtime show-timezone
!
interface FastEthernet0/1
 switchport mode access
 switchport access vlan 532
 storm-control broadcast level 0.4 0.3
 storm-control action trap
!
interface FastEthernet0/2
 switchport mode trunk
 switchport trunk allowed 300,532
 switchport nonegotiate
!
interface FastEthernet0/3
 switchport mode access
 switchport access vlan 300
 storm-control broadcast level 0.4 0.3
 storm-control action trap
!
interface FastEthernet0/4
 switchport
 switchport mode access
 storm-control broadcast level 0.4 0.3
 storm-control action trap
!
end

The script:

  • Added an access switchport: interface FastEthernet0/4

  • Added storm-control to Fa0/1, Fa0/3, and Fa0/4

  • Removed port-security from Fa0/2

  • Added timestamps to logs and debug messages