Ciscoconfparse
Parse, Audit, Query, Build, and Modify Arista / Cisco / Juniper / Palo Alto / F5 configurations.
Install / Use
/learn @mpenning/CiscoconfparseREADME
ciscoconfparse
[![git commits][41]][42] [![Version][2]][3] [![Downloads][6]][7] [![License][8]][9]
[![SonarCloud][51]][52] [![SonarCloud Maintainability Rating][53]][54] [![SonarCloud Lines of Code][55]][56] [![SonarCloud Bugs][59]][60] [![SonarCloud Code Smells][57]][58] [![SonarCloud Tech Debt][61]][62]
[![Snyk Package Health][37]][38]
Important: ciscoconfparse2
ciscoconfparse is End of Life
As of December 14, 2023 [ciscoconfparse2][64] is released; this is equivalent to version 2.0 of [ciscoconfparse][17], but [ciscoconfparse2][64] is a different PYPI project.
You should upgrade; here's why, [ciscoconfparse2][64]:
- It supports all major network vendor text configuration files (Arista, Cisco, F5, Juniper, Palo Alto)
- It supports searching across any number of configuration levels ([ciscoconfparse][17] only supports two config levels : a parent and child)
- It adds a string methods so you don't need to use regex matching if you don't want to
- It adds a CLI command
- Revamped documentation
- It simplifies the user interface and fixes broken [ciscoconfparse][17] default parameters (this could require changing old scripts using the original API)
- It intentionally uses a new python import to minimize confusion between itself and the original
NOTE [ciscoconfparse2][64] deprecates many legacy [ciscoconfparse][17] APIs; overall this is a good thing because [ciscoconfparse2][64] is easier to use. As such, test your code before using [ciscoconfparse2][64] as a drop-in replacement.
Introduction: What is ciscoconfparse?
Short answer: ciscoconfparse is a [Python][10] library that helps you quickly answer questions like these about your Cisco configurations:
- What interfaces are shutdown?
- Which interfaces are in trunk mode?
- What address and subnet mask is assigned to each interface?
- Which interfaces are missing a critical command?
- Is this configuration missing a standard config line?
It can help you:
- Audit existing router / switch / firewall / wlc configurations
- Modify existing configurations
- Build new configurations
Speaking generally, the library examines an IOS-style config and breaks it into a set of linked parent / child relationships. You can perform complex queries about these relationships.
[![Cisco IOS config: Parent / child][11]][11]
Generic Usage
The following code will parse a configuration stored in
exampleswitch.conf and select interfaces that are shutdown.
In this case, the parent is a line containing interface and
the child is a line containing the word shutdown.
from ciscoconfparse import CiscoConfParse
parse = CiscoConfParse('exampleswitch.conf', syntax='ios')
for intf_obj in parse.find_parent_objects('^interface', '^\s+shutdown'):
print("Shutdown: " + intf_obj.text)
The next example will find the IP address assigned to interfaces.
from ciscoconfparse import CiscoConfParse
parse = CiscoConfParse('exampleswitch.conf', syntax='ios')
for ccp_obj in parse.find_objects('^interface'):
intf_name = ccp_obj.re_match_typed('^interface\s+(\S.+?)$')
# Search children of all interfaces for a regex match and return
# the value matched in regex match group 1. If there is no match,
# return a default value: ''
intf_ip_addr = ccp_obj.re_match_iter_typed(
r'ip\saddress\s(\d+\.\d+\.\d+\.\d+)\s', result_type=str,
group=1, default='')
print(f"{intf_name}: {intf_ip_addr}")
Cisco IOS Factory Usage
CiscoConfParse has a special feature that abstracts common IOS / NXOS / ASA / IOSXR fields; at this time, it is only supported on those configuration types. You will see factory parsing in CiscoConfParse code as parsing the configuration with factory=True. A fraction of these pre-parsed Cisco IOS fields follows; some variables are not used below, but simply called out for quick reference.
from ciscoconfparse import IPv4Obj, IPv6Obj
from ciscoconfparse import CiscoConfParse
##############################################################################
# Parse an example Cisco IOS HSRP configuration from:
# tests/fixtures/configs/sample_08.ios
#
# !
# interface FastEthernet0/0
# ip address 172.16.2.1 255.255.255.0
# ipv6 dhcp server IPV6_2FL_NORTH_LAN
# ipv6 address fd01:ab00::/64 eui-64
# ipv6 address fe80::1 link-local
# ipv6 enable
# ipv6 ospf 11 area 0
# standby 110 ip 172.16.2.254
# standby 110 ipv6 autoconfig
# standby 110 priority 150
# standby 110 preempt delay minimum 15
# standby 110 track Dialer1 75
# standby 110 track FastEthernet 0/1
# standby 110 track FastEthernet1/0 30
# standby 111 ip 172.16.2.253
# standby 111 priority 150
# standby 111 preempt delay minimum 15
# standby 111 track Dialer1 50
#
##############################################################################
parse = CiscoConfParse('tests/fixtures/configs/sample_08.ios', syntax='ios', factory=True)
for ccp_obj in parse.find_objects('^interface'):
# Skip if there are no HSRPInterfaceGroup() instances...
if len(ccp_obj.hsrp_interfaces) == 0:
continue
# Interface name, such as 'FastEthernet0/0'
intf_name = ccp_obj.name
# Interface description
intf_description = ccp_obj.description
# IPv4Obj
intf_v4obj = ccp_obj.ipv4_addr_object
# IPv4 address object: ipaddress.IPv4Address()
intf_v4addr = ccp_obj.ipv4_addr_object.ip
# IPv4 netmask object: ipaddress.IPv4Address()
intf_v4masklength = ccp_obj.ipv4_addr_object.masklength
# set() of IPv4 secondary address/prefixlen strings
intf_v4secondary_networks = ccp_obj.ip_secondary_networks
# set() of IPv4 secondary address strings
intf_v4secondary_addresses = ccp_obj.ip_secondary_addresses
# List of HSRP IPv4 addrs from the ciscoconfpasre/models_cisco.py HSRPInterfaceGroup()
intf_hsrp_addresses = [hsrp_grp.ip for hsrp_grp in ccp_obj.hsrp_interfaces]
# A bool for using HSRP bia mac-address...
intf_hsrp_usebia = any([ii.use_bia for ii in ccp_obj.hsrp_interfaces])
##########################################################################
# Print a simple interface summary
##########################################################################
print("----")
print(f"Interface {ccp_obj.interface_object.name}: {intf_v4addr}/{intf_v4masklength}")
print(f" Interface {intf_name} description: {intf_description}")
##########################################################################
# Print HSRP Group interface tracking information
##########################################################################
print("")
print(f" HSRP tracking for {set([ii.interface_name for ii in ccp_obj.hsrp_interfaces])}")
for hsrp_intf_group in ccp_obj.hsrp_interfaces:
group = hsrp_intf_group.hsrp_group
# hsrp_intf_group.interface_tracking is a list of dictionaries
if len(hsrp_intf_group.interface_tracking) > 0:
print(f" --- HSRP Group {group} ---")
for track_intf in hsrp_intf_group.interface_tracking:
print(f" --- Tracking {track_intf.interface} ---")
print(f" Tracking interface: {track_intf.interface}")
print(f" Tracking decrement: {track_intf.decrement}")
print(f" Tracking weighting: {track_intf.weighting}")
##########################################################################
# Break out inidividual interface name components
# Example: 'Serial3/4/5.6:7 multipoint'
##########################################################################
# The base ciscoconfparse/ccp_util.py CiscoInterface() instance
intf_cisco_interface = ccp_obj.interface_object
# The ciscoconfparse/ccp_util.py CiscoInterface() name, 'Serial3/4/5.6:7 multipoint'
intf_name = ccp_obj.interface_object.name
# The ciscoconfparse/ccp_util.py CiscoInterface() prefix, 'Serial'
intf_prefix = ccp_obj.interface_object.prefix
# The ciscoconfparse/ccp_util.py CiscoInterface() digit separator, '/'
digit_separator = ccp_obj.interface_object.digit_separator or ""
# The ciscoconfparse/ccp_util.py CiscoInterface() slot, 3
intf_slot = ccp_obj.interface_object.slot or ""
# The ciscoconfparse/ccp_util.py CiscoInterface() card, 4
intf_card = ccp_obj.interface_object.card or ""
# The ciscoconfparse/ccp_util.py CiscoInterface() card, 5
intf_port = ccp_obj.interface_object.port
# The ciscoconfparse/ccp_util.py CiscoInterface() subinterface, 6
intf_subinterface = ccp_obj.interface_object.subinterface or ""
# The ciscoconfparse/ccp_util.py CiscoInterface() channel, 7
intf_channel = ccp_obj.interface_object.channel or ""
# The ciscoconfparse/ccp_util.py CiscoInterface() interface_class, 'multipoint'
intf_class = ccp_obj.interface_object.interface_class or ""
##########################################################################
# Extract all IPv4Obj() with re_match_iter_typed()
##########################################################################
_default = None
for _obj in ccp_obj.children:
# Get a dict() from re_match_iter_typed() by caling it with 'groupdict'
intf_dict = _obj.re_match_iter_typed(
# Add a regex match-group called 'v4addr'
r"ip\s+address\s+(?P<v4addr>\S.+?\d)\s*(?P<secondary>secondary)*$",
# Cast the v4addr regex match group as an IPv4Obj() type
groupdict={"v4addr": IPv4Obj, "secondary": str},
# Default to None if there is no regex match
default=_default,
)
intf_ipv4obj = intf_dict["v4addr"]
##########################################################################
# Extract all IPv6Obj() with re_match_iter_typed()
#####################
