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.

An example script that will take live configuration and generate the removal config that needs to be entered into the device.
  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)
Example script that finds all referenced route maps in BGP and lists any that are not configured.
 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:

ConfigParser

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:

ConfigParser

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:

ConfigParser

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:

ConfigParser

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.