ciscoconfparse is a Python library for querying Cisco-style configurations. The purpose of this workbook is to examine some features that are, in my view, not very well presented in the official documentation.
In [227]:
# The line below can be ignored but I didn't set up my environment properly
import sys ; sys.path.append('/home/mjuenemann/.virtualenvs/ciscoconfparse/lib/python3.6/site-packages')
In [228]:
import ciscoconfparse
I am going to use a very stripped down version of the Secure IOS Template by Team Cymru. This is not a fully functional IOS configuration!
In [229]:
CONFIG = """
!
hostname router01
!
tacacs-server host 192.0.2.34
tacacs-server key cheezit
!
interface Ethernet2/0
description Unprotected interface, facing towards Internet
ip address 192.0.2.14 255.255.255.240
no ip unreachables
ntp disable
no mop enable
mtu 900
!
interface Ethernet2/1
description Protected interface, facing towards DMZ
ip address 192.0.2.17 255.255.255.240
no mop enable
"""
First, he configuration must be parsed by creating an instance of ciscoconfparse.CiscoConfParse()
. The class expects either a file object or a list of configuration lines.
In [230]:
config = ciscoconfparse.CiscoConfParse(CONFIG.split('\n'))
config
Out[230]:
When CiscoConfParse()
reads a configuration, it stores parent-child relationships as a special IOSCfgLine
object. IOSCfgLine
instances are returned when one queries the parsed configuration.
In [231]:
tacacs_lines = config.find_objects(r'^tacacs')
tacacs_lines
Out[231]:
In [232]:
first_tacacs_line = tacacs_lines[0]
type(first_tacacs_line)
Out[232]:
IOSCfgLine
instances have several useful attributes.
In [233]:
first_tacacs_line.linenum
Out[233]:
In [234]:
first_tacacs_line.indent
Out[234]:
In [235]:
first_tacacs_line.text
Out[235]:
In [236]:
interfaces_with_ntp_disabled = config.find_objects_w_child(r'^interface', r'ntp disable')
interfaces_with_ntp_disabled
Out[236]:
The .text
attribute only returns the matching line whereas the .ioscfg
attributes includes all children lines as a list.
In [237]:
interfaces_with_ntp_disabled[0].text
Out[237]:
In [238]:
interfaces_with_ntp_disabled[0].ioscfg
Out[238]:
In [239]:
interfaces_with_ntp_not_disabled = config.find_objects_wo_child(r'^interface', r'ntp disable')
interfaces_with_ntp_not_disabled
Out[239]:
In [240]:
interfaces_with_ntp_not_disabled[0].ioscfg
Out[240]:
In [241]:
results = config.find_objects_w_all_children(r'interface', [r'no ip unreachables', r'no mop enable'])
results
Out[241]:
In [242]:
results[0].ioscfg
Out[242]:
In [243]:
results = config.find_objects_w_parents(r'^interface', 'no mop enable')
results
Out[243]:
This can be handy in combination with the IOSCfgLine.delete()
method which I haven't covered yet.
IOSCfgLine
objects provide several methods for changing an existing configuration. Let's delete all no mop enable
lines.
In [244]:
for result in results:
result.delete()
# Call .commit() after changing the configuration
config.commit()
The no mop enable
lines are now missing.
In [245]:
config.ioscfg
Out[245]:
In [246]:
config.append_line('ntp server 192.168.1.1')
# Call .commit() before searching again!!!
config.commit()
config.ioscfg
Out[246]:
In [247]:
# Delete all existing MTU lines.
for interface in config.find_objects(r'^interface.+Ethernet'):
interface.delete_children_matching('mtu \d+')
config.commit()
# Add the correct MTU. Note the use of the correct indentation value for children.
for interface in config.find_objects(r'^interface.+Ethernet'):
interface.append_to_family('mtu 1500', indent=interface.child_indent)
config.commit()
In [248]:
config.ioscfg
Out[248]:
In [ ]: