Command Output Parsers
CiscoAutomationFramework provides integrated parsers for various command outputs. These parsers allow you to pass in the output from the network device and be able to iterate over output and/or extract data from the output in a programatic way versus needing to build your own parsers
Show Interface Status Parser
Pass in the raw output from “show interface status” command to this parser and you will be able to iterate over the table and interact with the entries individually
- class CiscoAutomationFramework.Parsers.InterfaceStatusParser.InterfaceStatusOutputParser(raw_table)
Provide the output directly from the device after issuing the command ‘show interface status’ to this object to parse it
- property interfaces
Parses the raw output from the command and provides a list of all entries from the table
- Returns:
LineParser
- Return type:
list[LineParser]
- class CiscoAutomationFramework.Parsers.InterfaceStatusParser.LineParser(raw_line)
- property description
Description set on interface
- Returns:
Confiured Description
- Return type:
str
- property duplex
Interface duplex settings ex. auto, a-full a-half
- Returns:
Duplex Setting
- Return type:
str
- property name
Name of the interface ex. Gi1/0/1
- Returns:
Interface Name abbriviated
- Return type:
str
- property not_present
Returns True/False if the text “not present” in the lowercase line
- Returns:
True/False
- Return type:
bool
- property speed
Interface Operating Speed ex. auto, a-100, a-1000
- Returns:
Interface Speed
- Return type:
str
- property status
Status of interface ex. connected, notconnected, disabled, err-disable, etc
- Returns:
interface status
- Return type:
str
- property type
Interface Type ex. 10/100/1000BaseTX, Not Present
- Returns:
Interface Type
- Return type:
str
- property vlan
Vlan configuration of interface ex. 1, 100, trunk, routed
- Returns:
vlan configuration
- Return type:
str
IP Device Tracking Parser
Pass in the raw output from “show ip device tracking all” and this parser allows you to iterate over the contents of the table one at a time.
- class CiscoAutomationFramework.Parsers.IpDeviceTrackingParser.DeviceTrackingOutputParser(output_from_device)
- property entries
Extracts the entires from the table and returns them as a list
- Returns:
List of table entries as EntryParser instances
- Return type:
list[EntryParser]
- class CiscoAutomationFramework.Parsers.IpDeviceTrackingParser.EntryParser(entry_data)
- property interface
Extracts interface of the ip device tracking entry
- Returns:
Switch Interface
- Return type:
str
- property ip_address
IP address of the IP device tracking entry
- Returns:
IP address
- Return type:
str
- property is_apipa
True/False if the IP address in the entry is an APIPA address.
- Returns:
True/False
- Return type:
bool
- property mac_address
MAC address of the ip device tracking entry
- Returns:
MAC Address
- Return type:
str
- property probe_timeout
Extracts probe timeout of the ip device tracking entry
- Returns:
Probe Timeout
- Return type:
str
- property source
Extracts source of the ip device tracking entry
- Returns:
Source
- Return type:
str
- property state
Extracts state of the ip device tracking entry
- Returns:
State
- Return type:
str
- property vlan
Extracts vlan of the ip device tracking entry
- Returns:
Vlan
- Return type:
str
MAC Address Table Parser
Pass in the raw output from “show mac address-table” and this parser allows you to iterate over the contents of the table one at a time and also analyze the table in other ways.:
from CiscoAutomationFramework import connect_ssh
from CiscoAutomationFramework.Parsers.MacAddressTableParser import MacAddressTableParser
with connect_ssh('ip', 'username', 'password') as ssh:
mac_table = MacAddressTableParser(ssh.mac_address_table)
for entry in mac_table:
print(f'{entry.interface} - {entry.vlan} - {entry.mac_address}')
- class CiscoAutomationFramework.Parsers.MacAddressTableParser.MacAddressTableParser(raw_table)
- property is_nexus
Checks the raw table for specific key words to determine if it is a Nexus platform or not returning True if it is False if it is not
- Returns:
True/False
- Return type:
bool
- property table_entries
Parses the mac address table and returns a list of the entries
- Returns:
List of entries from the MAC address table
- Return type:
list[MacEntryParser]
- class CiscoAutomationFramework.Parsers.MacAddressTableParser.MacEntryParser(raw_entry)
- property interface
Interface on device that the MAC address is on ex. Gi1/0/8
- Returns:
Interface on Device
- Return type:
str
- property is_nexus
Searches the entire mac address table, checking if any of a set of keywords are in it
- property mac_address
MAC address from the row
- Returns:
MAC Address
- Return type:
str
- property type
Address type from the row ex. dynamic, static
- Returns:
Address Type
- Return type:
str
- property vlan
Vlan from the row
- Returns:
Vlan
- Return type:
str
Power Inline Parser
Pass the raw output from ‘show power inline’ to this parser and you will be able to iterate over the entries in the power inline table:
from CiscoAutomationFramework import connect_ssh
from CiscoAutomationFramework.Parsers.PowerInlineParser import PowerInlineParser
with connect_ssh('ip', 'username', 'password') as ssh:
parser = PowerInlineParser(ssh.send_command_get_output('show power inline'))
for entry in parser:
print(f'{entry.name} - {entry.watts} - {entry.detected_device}')
- class CiscoAutomationFramework.Parsers.PowerInlineParser.PowerInlineParser(sh_power_inline)
- property interfaces
Returns list of interfaces in the power inline table to extract the values from the entry
- Returns:
List of entries in the power inline table
- Return type:
list[PowerInlineInterface]
- class CiscoAutomationFramework.Parsers.PowerInlineParser.PowerInlineInterface(interface_data)
- property admin
Admin column of the entry ex. auto
- Returns:
Admin column
- Return type:
str
- property detected_device
Detected device type of connected device
- Returns:
Detected device
- Return type:
str
- property max_watts
Max watts capable of being drawn on port
- Returns:
Max watts supported
- Return type:
float
- property name
Interface name ex. Gi1/0/5
- Returns:
Interface Name
- Return type:
str
- property oper
Oper column of the entry, off/on weather it is providing power or not
- Returns:
Operation status
- Return type:
str
- property poe_class
POE class of connected device ex. 0, 1, 2, 3, n/a
- Returns:
POE Class
- Return type:
str
- property watts
Watts currently being drawn on port by connected device
- Returns:
Watts currently drawn
- Return type:
float
Running Config Parser
The config parser is one of the most useful features of the CiscoAutomationFramework. It allows integrated functions to recursively search configuration, compare configuration, and modify configuration in line.
you can access this object by ssh.config_parser or you can access the object directly and load in config from anywhere such as a configuration backup text file.
1'''
2
3Copyright 2025 Kyle Kowalczyk
4
5Licensed under the Apache License, Version 2.0 (the "License");
6you may not use this file except in compliance with the License.
7You may obtain a copy of the License at
8
9 http://www.apache.org/licenses/LICENSE-2.0
10
11Unless required by applicable law or agreed to in writing, software
12distributed under the License is distributed on an "AS IS" BASIS,
13WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14See the License for the specific language governing permissions and
15limitations under the License.
16
17=========================================================================
18
19Author: Kyle Kowalczyk
20
21This is an example script for how you can use the ConfigParser class to
22search for and dynamically generate the configuration needed to remove multiple BGP neighbors.
23
24My hope is that this script gives you inspiration to other uses for dynamic configuration generation
25weather that be for removal, modification, etc.
26
27The output of this script will be:
28
29router bgp 65100
30 address-family ipv4 vrf CustA
31 no neighbor 10.88.52.13 peer-group MyPeers
32 no neighbor 10.88.52.13 activate
33 address-family ipv4 vrf CustB
34 no neighbor 10.88.55.25 remote-as 65102
35 no neighbor 10.88.55.25 description To Router 1
36 no neighbor 10.88.55.25 timers 20 60
37 no neighbor 10.88.55.25 fall-over bfd
38 no neighbor 10.88.55.25 activate
39 no neighbor 10.88.55.25 send-community
40 no neighbor 10.88.55.25 next-hop-self
41 no neighbor 10.88.55.25 soft-reconfiguration inbound
42
43=======================================================
44
45This is meant to demonstrate how easy it is to read in the config, modify a portion of it, and getting
46usable configuration right out of the box that you can either manually or via a larger script automatically apply.
47
48Notice how there is not duplicated configuration such as multiple router bgp lines or address-family lines.
49Also because we performed the search and modify function, only the configuration paths that were matched in our
50search are shown, it omitted all other parts of our config.
51
52Keep in mind the more generic the search like for an IP address like I did here could yield incorrect results if
53there is a description somewhere with that IP so keep things as specific as possible when you can.
54'''
55from CiscoAutomationFramework.Parsers.ConfigParser import ConfigParser
56
57# example running configuration
58example_config = '''interface GigabitEthernet1/0/1
59 description InterfaceDescription
60 mtu 1500
61!
62router bgp 65100
63 address-family ipv4
64 network 10.5.5.1 mask 255.255.255.255
65 neighbor 10.88.51.13 activate
66 neighbor 10.88.51.17 activate
67 neighbor 10.88.51.25 activate
68 maximum-paths 2
69 exit-address-family
70 !
71 address-family ipv4 vrf CustA
72 bgp router-id 172.20.61.205
73 network 10.88.52.190 mask 255.255.255.255
74 neighbor 10.88.52.13 peer-group MyPeers
75 neighbor 10.88.52.13 activate
76 neighbor 10.88.52.17 peer-group MyPeers
77 neighbor 10.88.52.17 activate
78 neighbor 10.88.52.25 remote-as 65102
79 neighbor 10.88.52.25 description asdf
80 neighbor 10.88.52.25 timers 20 60
81 neighbor 10.88.52.25 fall-over bfd
82 neighbor 10.88.52.25 activate
83 neighbor 10.88.52.25 send-community
84 neighbor 10.88.52.25 next-hop-self
85 neighbor 10.88.52.25 soft-reconfiguration inbound
86 maximum-paths 2
87 exit-address-family
88 !
89 address-family ipv4 vrf CustB
90 bgp router-id 172.20.93.205
91 neighbor 10.88.55.13 peer-group MyPeers
92 neighbor 10.88.55.13 activate
93 neighbor 10.88.55.17 peer-group MyPeers
94 neighbor 10.88.55.17 activate
95 neighbor 10.88.55.25 remote-as 65102
96 neighbor 10.88.55.25 description To Router 1
97 neighbor 10.88.55.25 timers 20 60
98 neighbor 10.88.55.25 fall-over bfd
99 neighbor 10.88.55.25 activate
100 neighbor 10.88.55.25 send-community
101 neighbor 10.88.55.25 next-hop-self
102 neighbor 10.88.55.25 soft-reconfiguration inbound
103 maximum-paths 2
104 exit-address-family
105!
106line console 0
107 logging synchronous
108'''
109
110neighbors_to_remove = ['10.88.52.13', '10.88.55.25']
111
112parser = ConfigParser(example_config)
113modified_config_tree = parser.search_and_modify_config_tree(search_terms=neighbors_to_remove, full_match=False, prepend_text='no ')
114formatted_config = modified_config_tree.config_tree_to_list(indent_step=1)
115
116for line in formatted_config:
117 print(line)
1'''
2This is an example script that will check your BGP config, get all of the referenced route maps, then check
3if there is a route map with that name configured on the device.
4
5This script is intended to show the power of the ConfigParser and the level of insights you can gain
6through integrated search utilities.
7'''
8from CiscoAutomationFramework.Parsers.ConfigParser import ConfigParser
9from CiscoAutomationFramework.util import extract_line_from_tree
10
11# Update path to the path of your config file
12config_file_path = '/path/to/config_file.txt'
13
14# read in config file
15with open(config_file_path, 'r') as f:
16 conf = f.read()
17
18
19def extract_route_map_names(rm_definition_lines):
20 """Helper function to extract the route map name from the route map definition
21 ex. neighbor 192.168.10.5 route-map TEST in || will extract "TEST"
22 """
23 map_names = []
24 for map_statement in rm_definition_lines:
25 for idx, word in enumerate(map_statement.split()):
26 if word == 'route-map':
27 map_names.append(map_statement.split()[idx + 1])
28 return map_names
29
30
31parser = ConfigParser(conf)
32# extract only BGP config
33bgp_config = parser.search_config_tree('router bgp')
34# From BGP config extract all lines that contain the text "route-map"
35maps = extract_line_from_tree(bgp_config.config_tree, 'route-map', find_all=True)
36# use helper function to extract the name of the route map from all references
37configured_route_maps = extract_route_map_names(maps)
38
39# Iterate over each route map name, try and get the route map definition from the config, printing out the name
40# if not found
41for route_map in configured_route_maps:
42 if not parser.get_route_map(route_map):
43 print(f'Route map {route_map} is referenced but not configured!')
- class CiscoAutomationFramework.Parsers.ConfigParser.ConfigParser(running_config)
- property config_tree
The running config that was passed in, parsed into a string format
- Returns:
dictionary tree
- Return type:
dict
- config_tree_to_list(tree=None, indent=0, indent_step=0)
Converts a tree representation of the configuration into a list that can be pasted into a device
- Parameters:
tree (dict) – Tree representation of a configuration file
indent (int) – number of spaces to indent root with
indent_step – number of indent spaces to increment when going from a root to a branch (default 0, no indent)
- Returns:
List representation of config tree
- Return type:
list
- extract_line_from_tree(search_term, case_sensitive=True, full_match=False, find_all=True)
Extracts the first (or all) occurances of “search_term” from “tree”. Can specify case sensitive, and full match in the search
- get_config_section(title_startswith, return_all=True)
Extracts a specific configuration section whos first line starts with your variable. Because we search if the title startswith your variable you could have multiple results so instead of always returning the first one, I give the option to return all
- Parameters:
title_startswith (str) – Text that the first line of the section starts with (ex. line vty)
return_all (bool) – If there are multiple matches return all if True (default True)
- Returns:
list of lists containing the sections of config
- Return type:
list
- get_config_sections(search_terms, case_sensitive=True, full_match=False, min_search_depth=0, max_search_depth=0, tree=None)
Searches the configuration tree for section headers that match the given search terms and returns the full path to root and the complete nested section(s) under those matches. This works very similar to search_config_tree with the exception that it will not only return the full path to root for any matches, but the full nested path.
- Parameters:
search_terms (str | list | tuple) – Search term(s) (string, list, or tuple)
case_sensitive (bool) – Whether the search is case-sensitive
full_match (bool) – If True, requires exact match; if False, allows partial matches
min_search_depth (int) – Minimum nesting level to include matches (0 = no restriction)
max_search_depth (int) – Maximum nesting level to include matches (0 = infinite)
- Returns:
Config Parser with results of search
- Return type:
- has_global_config(config_string)
True/False if in the global configuration the string is found. The line must NOT start with a space so if it is nested it will not be found
- Parameters:
config_string –
- Returns:
- modify_config_tree_inline(search_terms, case_sensitive=True, full_match=False, min_search_depth=0, max_search_depth=0, prepend_text='', append_text='', replace_tuple=('', ''), modifier_callback=None, prematch_extend_callback=None, postmatch_extend_callback=None, tree=None)
Searches the config tree for a set of search terms, and any match will be eligible for modification. Any line that DOES not match the search terms will still be returned, but not eligible to be modified by the modification arguments that are passed in. THis allows you to modify only certain config but return the entire config tree that was passed in.
This function is very similar to search_and_modify_config_tree but instead of only returning the matches and the outdened path to the root, it will return everything that was passed in, but still only allowing modification of lines that contain the search_terms matches
Modification will ONLY occur to lines that CONTAIN a match! if you search for “description example” it will also return in the tree the interface name ex. interface GigabitEthernet1/0/1, however that line will NOT be eligible for the string modification because it does not contain “description example”.
Additionally using that same interface example, the interface will likely have other config besides the description, but if you search for the description, all other commands in that layer of the tree will not be returned, just the path up to the root which in this case is the interface name.
You may also specify if you want your search to be case sensitive, and you may also specify if you want a full or partial match. For example if I do a full match for “description” but the line of configuration is “description example” it will NOT match. Also if I do a partial match (by setting full match to false) for “descrip”, and the line is “description example” it WILL match.
If the integrated prepend, append, or replace functionality does not provide enough flexibility in terms of modification, you can pass in a modifier_callback function and implement your own modification algorthm. One thing to note is the function you pass in MUST accept a single argument as the line which matches your search term will be passed in. Keep in mind the prepend, append, and modify will still run after your modifier_callback runs. Your modifier callback will overwrite all lines that are passed into it so make sure that you take into account that every match will be run through your modifier_callback and will be overwritten with whatever your modifier_callback returns
If you need to add additional lines to the configuration before and/or after the match line you also have the ability to pass in a “pre_extend_callback” to extend a single or multiple lines before the match line and a “post_extend_callback” function to extend a single or multiple lines after the match line. Both of these user defined functions MUST accept a single argument which will be the matched line, and you may return a single string, list of strings, and tuple of strings to extend the config. Unlike the modifier_callback, the integrated prepend, append, and find/replace features of this function will NOT be applied to what is returned by the pre/post_extend_callback functions.
These functions are especially useful when generating change configuration where you need to “no” the command and re apply it with different paramaters
Keep in mind when using the postmatch_extend_callback, if your match line has nested configuration under it such as the following example matching “router bgp”: router bgp 65000
nested config1 nested config2
nested config3
and your post match callback returns “Post Match Line” it would come after the last line of nested config on the same level as your match line such as below:
- router bgp 65000
nested config1 nested config2
nested config3
Post Match Line
- Parameters:
search_terms (list) – List of search terms to search for.
case_sensitive (bool) – Whether the search is case-sensitive.
full_match (bool) – If True, matches the whole word exactly; else, allows partial matches.
prepend_text (str) – Text to prepend to matches.
append_text (str) – Text to append to matches.
replace_tuple (tuple or None) – A tuple (old_text, new_text) for replacing matches.
modifier_callback (function) – User defined function to call whenever a line matches search terms, MUST accept a single argument as the matching line of config will be passed in.
prematch_extend_callback (function) – User defined function to insert a line or multiple lines before the match line. User defined function may return string, list, or tuple.
postmatch_extend_callback (function) – User defined function to insert a line or multiple lines after the match line. User defined function may return string, list, or tuple.
tree (dict or None) – The configuration tree to search. Do not specify this, its only used for recursion
- Default case_sensitive:
True
- Default full_match:
False
- Default prepend_text:
“”
- Default append_text:
“”
- Default replace_tuple:
None
- Default modifier_callback:
None
- Default tree:
None
- Returns:
A dictionary containing matched and modified results.
- Return type:
- search_and_modify_config_tree(search_terms, case_sensitive=True, full_match=False, min_search_depth=0, max_search_depth=0, prepend_text='', append_text='', replace_tuple=('', ''), modifier_callback=None, prematch_extend_callback=None, postmatch_extend_callback=None, tree=None)
Searches the config tree for a set of search terms, and if specified will run each line that matches a search term through a modification algorithm to prepend, append, and find/replace specified text on that line.
Modification will ONLY occur to lines that CONTAIN a match! if you search for “description example” it will also return in the tree the interface name ex. interface GigabitEthernet1/0/1, however that line will NOT be eligible for the string modification because it does not contain “description example”.
Additionally using that same interface example, the interface will likely have other config besides the description, but if you search for the description, all other commands in that layer of the tree will not be returned, just the path up to the root which in this case is the interface name.
You may also specify if you want your search to be case sensitive, and you may also specify if you want a full or partial match. For example if I do a full match for “description” but the line of configuration is “description example” it will NOT match. Also if I do a partial match (by setting full match to false) for “descrip”, and the line is “description example” it WILL match.
If the integrated prepend, append, or replace functionality does not provide enough flexibility in terms of modification, you can pass in a modifier_callback function and implement your own modification algorthm. One thing to note is the function you pass in MUST accept a single argument as the line which matches your search term will be passed in. Keep in mind the prepend, append, and modify will still run after your modifier_callback runs. Your modifier callback will overwrite all lines that are passed into it so make sure that you take into account that every match will be run through your modifier_callback and will be overwritten with whatever your modifier_callback returns
If you need to add additional lines to the configuration before and/or after the match line you also have the ability to pass in a “pre_extend_callback” to extend a single or multiple lines before the match line and a “post_extend_callback” function to extend a single or multiple lines after the match line. Both of these user defined functions MUST accept a single argument which will be the matched line, and you may return a single string, list of strings, and tuple of strings to extend the config. Unlike the modifier_callback, the integrated prepend, append, and find/replace features of this function will NOT be applied to what is returned by the pre/post_extend_callback functions.
These functions are especially useful when generating change configuration where you need to “no” the command and re apply it with different paramaters
Keep in mind when using the postmatch_extend_callback, if your match line has nested configuration under it such as the following example matching “router bgp”: router bgp 65000
nested config1 nested config2
nested config3
and your post match callback returns “Post Match Line” it would come after the last line of nested config on the same level as your match line such as below:
- router bgp 65000
nested config1 nested config2
nested config3
Post Match Line
- Parameters:
search_terms (list) – List of search terms to search for.
case_sensitive (bool) – Whether the search is case-sensitive.
full_match (bool) – If True, matches the whole word exactly; else, allows partial matches.
prepend_text (str) – Text to prepend to matches.
append_text (str) – Text to append to matches.
replace_tuple (tuple or None) – A tuple (old_text, new_text) for replacing matches.
modifier_callback (function) – User defined function to call whenever a line matches search terms, MUST accept a single argument as the matching line of config will be passed in.
prematch_extend_callback (function) – User defined function to insert a line or multiple lines before the match line. User defined function may return string, list, or tuple.
postmatch_extend_callback (function) – User defined function to insert a line or multiple lines after the match line. User defined function may return string, list, or tuple.
tree (dict or None) – The configuration tree to search. Do not specify this, its only used for recursion
- Default case_sensitive:
True
- Default full_match:
False
- Default prepend_text:
“”
- Default append_text:
“”
- Default replace_tuple:
None
- Default modifier_callback:
None
- Default tree:
None
- Returns:
A dictionary containing matched and modified results.
- Return type:
- search_config_tree(search_terms, case_sensitive=True, full_match=False, min_search_depth=0, max_search_depth=0, tree=None)
Searches the config tree for a set of search terms and returns the path to root for that match. Note: the search will not return child branches after the match, just parent branches back to the root.
You may also specify if you want your search to be case sensitive, and you may also specify if you want a full or partial match. For example if I do a full match for “description” but the line of configuration is “description example” it will NOT match. Also if I do a partial match (by setting full match to false) for “descrip”, and the line is “description example” it WILL match.
- Parameters:
search_terms (list) – List of search terms to search for.
case_sensitive (bool) – Whether the search is case-sensitive.
full_match (bool) – If True, matches the whole word exactly; else, allows partial matches.
tree (dict or None) – The configuration tree to search, Do not specify this, its only used for recursion.
- Default case_sensitive:
True
- Default tree:
None
- Returns:
A dictionary containing matched and modified results.
- Return type:
- sections_config_referenced_in(config_match, prepend_space_in_search=True)
Searches through all detected ‘sections’ of config for the supplied config_match string. If it finds it nested in the section (in the indented section) it will return the first line of that config section in a list with other matches.