This series is made for people that want to get into network automation with Python, have gone through the classes at www.codecademy.com or equivalent and don’t know where to go from there. If you missed part 1 it’s over here and we will be building on what we have already gone over. With the information, there it should be very easy to pull the running config and put it in a file. As always I am not a great programmer. I am just writing a blog I wish had been around when I first started doing this.
In this overview, I’ll be adding the library CiscoConfParse with the documentation over here and the code over here CiscoConfParse is excellent when you are trying to figure out what data child describes what parent which doesn’t make a lot of sense without an example:
In this “Ethernet 0 is up, line protocol is up” would be the parent, each line indented more than the parent are it’s “children”, however some of the children are parents to their own children. Since I want to keep this short we’ll just be using “all_children” so in this example it basically returns everything indented under “Ethernet 0 is up, line protocol is up”. To save on example code, I did a “show run” on this device and copied it to a file called “running_config.txt”.
Where this really shines is the fact that Cisco’s outputs vary WILDLY depending on the platform. I didn’t want to make this quite this long but I think it’s worth it to do two examples, one will be pulling the interface configs from a router, the second example will be getting a normalized output from CDP.
Let’s see some code. This code will define a function that will
⦁ Make an “interface list” that will contain the interface, and all the config for it
⦁ Find each interface’s name and put that into the list
⦁ Add each interface config line to the list
⦁ Add the “interface list” to an “all interfaces” list
⦁ The “all interfaces” list will be returned to the main program
Now let’s hop to it, Please note moving Python into a blog format is not fool proof, so there is a VERY good chance the spacing will get screwed up. The code is on my Github here I suggest using that if you want to try running this code.
#Import the library from ciscoconfparse import CiscoConfParse #set a varable to the file name, #you might want to change it later #this way you only have to change it in 1 place filename = "running_config.txt" #Make a function, in this example we are handing it the running config and #the string "nterface" def find_child_text (file, text): #"all" will end up holding all the info we are looking for being returned all =  #Give the file to CiscoConfParse to look at parse = CiscoConfParse(file) #Here we are finding all the lines with "nterface" in them for obj in parse.find_objects(text): #Make a list that will contain the parent and the children each_obj =  #Add the parent to the list as a string each_obj.append(obj.text) #For all the parent's children for each in obj.all_children: #Add the child to the list as a string each_obj.append(each.text) #Add the device/config to a list of devices and configs all.append(each_obj) #Once all the interfaces have gone through this the #function hands the list of all interfaces to the main program #At this point all is a list of lists, each sub list is the interface #And all the config for each interface return all interfaces = (find_child_text (filename, "nterface" )) #Look at each interface for interface in interfaces: print ("n") for each in interface: print (each)
And I get
interface Ethernet0 ip address 10.10.88.50 255.255.255.254 interface Ethernet1 ip address 10.86.194.176 255.255.254.0 interface Ethernet2 shutdown no ip address
Wee! I can print out the config exactly the same if I was just looking at the file big woop. What can I do with that info? Let’s try looking for shutdown ports.
#Look at each interface for interface_config in interfaces: #Look at each line of the config for interface_line in interface_config: if "shut" in interface_line: print (interface_config)
Now it just prints out:
C:UsersDanielDesktopPythonClass 2>"cisco int finder.py" interface Ethernet2
Now we are printing out any interface that is shut down… but what if instead of looking for “shutdown” we were looking for “authentication violation restrict”? If that were the case it would print out any interface that has 802.1x configured on it. With a little work we could make it print out ports without 802.1x on it, and I know I have seen people asking for a program to do that in forums. Perhaps instead of a static line it’s looking for you can make a list of lines it’s looking for.
As I said before Cisco is a bit of a jerk as it changes its output on a regular basis between devices and IOS versions. Let’s look how CiscoConfigParse helps us out with that using CDP. First thing you’ll notice is that Cisco isn’t doing the indent thing here that CiscoConfigParse requires. Like jerks.
*Pulls out wand*
def fix_for_ciscoconfparse(file_name): cdp = read_doc(file_name) cdp_str = "" for line in cdp: if "---" not in line: line = " "+line cdp_str = cdp_str+line #print (cdp_str) to_doc(file_name, cdp_str)
There we go, much better!
There we go! Now we can break this down a bit. The code for this is very long so I am not going to put all the code in this blog, If you want the full code it’s over here. (Note I haven’t done a lot of testing with this code I am sure there are IOS versions it doesn’t work well with)
So, the basic idea is we are looking at the object “—-“. From here there are key terms used in almost all Cisco output, but the order varies between IOS/models/etc. So we search per line for the key words like this
if "Platform: " in cdp_line.text: platform_start = str(cdp_line.text).find(":")+2 tmp = str(cdp_line.text)[platform_start:] platform_end = tmp.find(",") platform = tmp[:platform_end] cdp_parse['platform'] = platform
Using this code we can find all the data we want, and end up with a list of dictionaries, the output for the CDP I have shown above is below.