DefaultDict for the Network Engineer

There might come a time as a Network Engineer you will need to create a data structure to process your information. A common one I’ve had to do is creating Dictionaries. 

My_little_dictionary = { My_key, My_value}

As your use cases increase in complexity you will need to dig deeper into the python ecosystem. One such handy features is DefaultDict. It is extremely versatile, I’m only going to cover one such use case. 

So let’s decide on what our key is going to be, I started with using the hostname. I have a list that I create with the hosts. 

from collections import defaultdict
my_list = ['Host1', 'Host2', 'Host3']
d = defaultdict(list)

I’ll pause here point out the data structure for you default dictionary. 

defaultdict(list, {})

https://docs.python.org/3/library/collections.html#collections.defaultdict – “Using list as the default_factory, it is easy to group a sequence of key-value pairs into a dictionary of list.”

This simplifies dictionary lists generation, with an elegant way of calling the code, making it easy to read and follow. 

for item in my_list:
my_config = [f'hostname {item}','int gi1/0/1', ' no shut’]
d[item] = my_config

What I’m doing here is looping through my list by each item, Host1-3. I’m generating a list that calls the hostname so each list would look like – [‘hostname Host1’, ‘int gi1/0/1’, ‘ no shut’]. Then it takes that list and assigns it to the defaultdict called ‘d’. As you call each Key in the default dict, it creates an entry for the key. The variable it’s looking for is it’s list. You can insert your list into it just like you’re assigning a variable. Since it’s a for loop, it does this so on until you fill in all the hosts. The results:

defaultdict(list,
{'Host1': ['hostname Host1', 'int gi1/0/1', ' no shut'],
'Host2': ['hostname Host2', 'int gi1/0/1', ' no shut'],
'Host3': ['hostname Host3', 'int gi1/0/1', ' no shut']})

It’s a dictionary of lists. Key being the hostname and it’s values the list. Very handy when you’re needing something a little more complex and scary simple to implement. You can even pass this to pandas and have it work some magic. Running the following code generates a Table like below. 

df = pd.DataFrame.from_dict(d)
df2 = df.transpose()
df2.columns = ['Hostname', 'Interface', 'State']

UntitledImage

 

 

 

 

 

 

Hopefully this can help, if you can think of anything I should include or am wrong about? Drop me a line. I’m happy to learn.

Ansible – Infrastructure as Code Part 3 (Let’s do something interesting!)

We’ve collected our state data in Part 2.

Now let’s do something interesting with our data. I’ve switched out the role I will be using. So this will be a long blog post on how to set up and finally make something pretty with your data!

 

The Setup

What you’ll need –

The reason I’m using a different module for this, is that it will automatically grab a snapshot and format it into JSON. It has other features, like compare that I won’t get into. But for now, this will be good enough to start manipulating data.

The Play Book

---
- hosts: localhost
connection: local
gather_facts: no

- name: Interface Snapshot
hosts: switches
gather_facts: no
connection: network_cli
roles:
- ansible-pyats

tasks:
- name: Gather Snapshot
include_role:
name: ansible-pyats
tasks_from: snapshot_command

vars:
command: show interfaces
file: "snapshots/{{ inventory_hostname }}_interface_snapshot.json"

This play book is assigned to the switches in the inventory. It calls the role that we downloaded from GitHub with the task snapshot_command. I’m telling it to snapshot the show interfaces command. 

Step 1 – Grab the state of the interfaces using your playbook and output to JSON.

Step 2 – Import the data into Jupyter Notebook and convert it into useable information using Pandas.

Now you may be asking why Pandas and why Jupyter? I have a blog post here on why it’s easier to work with. On the note about Pandas, it’s a great tool for quickly putting information into a structure that easier to analyze. Need to do math based on Date time? Need to do some quick counting on cell values? Or maybe convert row data to columns? Very quick an easy to do in Pandas. So let’s get started.

Now this may seem a little denser than normal. But this is a direct export from Jupyter. This is using Python and the two modules to make the magic happen. If you want to try it out, you can copy the code below into Jupyter and use this JSON document. 

import pandas as pd #import pandas for data manipulation
import plotly.express as px #For a quick pretty graph at the end

df
= pd.read_json('/Users/**/Automation/ansible/snapshots/SW1_interface_snapshot.json') #Import the JSON document df.loc['arp_timeout':'bandwidth' , 'FastEthernet0/1':'FastEthernet0/13'] #grab the first 5 columns and top 3 rows
  FastEthernet0/1 FastEthernet0/10 FastEthernet0/11 FastEthernet0/12 FastEthernet0/13
arp_timeout 04:00:00 04:00:00 04:00:00 04:00:00 04:00:00
arp_type arpa arpa arpa arpa arpa
bandwidth 100000 10000 10000 10000 10000
df2 = df.loc[ ['line_protocol', 'last_input'] , : ] #export the desired values
df2.loc['line_protocol':'last_input', 'FastEthernet0/1':'FastEthernet0/13']
  FastEthernet0/1 FastEthernet0/10 FastEthernet0/11 FastEthernet0/12 FastEthernet0/13
line_protocol up down down down down
last_input 00:00:01 never never never never
df2 = df2.transpose() #flip the columns and rows; by default the interfaces are the columns
df2.head(3)
  line_protocol last_input
FastEthernet0/1 up 00:00:01
FastEthernet0/10 down never
FastEthernet0/11 down never
df2.loc[(df2.last_input == "never"), 'last_input']='23:59:59' #convert never to time value
df2.head(3)
  line_protocol last_input
FastEthernet0/1 up 00:00:01
FastEthernet0/10 down 23:59:59
FastEthernet0/11 down 23:59:59
df2["last_input"]= pd.to_datetime(df2["last_input"]) #convert time values to datetime; panda adds todays date
df2.head(3)
  line_protocol last_input
FastEthernet0/1 up 2020-06-18 00:00:01
FastEthernet0/10 down 2020-06-18 23:59:59
FastEthernet0/11 down 2020-06-18 23:59:59
df_value_counts = df2['line_protocol'].value_counts() #grab value counts and put into new dataframe
df_value_counts = df_value_counts.reset_index() #reset the index
df_value_counts.columns = ['State', 'Count'] #set column values
df_value_counts #display values
  State Count
0 down 26
1 up 6
fig = px.bar(df_value_counts,              # dataframe
       x="State",         # x will be the 'State' column of the dataframe
       y="Count",   # y will be the 'Count' column of the dataframe
       color="State", # color gets assigned to the State axis
       title=f"Interface State",
       labels={"State": "Up/Down","Count": "Count"}, # the axis names
       color_discrete_sequence=["red", "green"], # the colors used
       height=500,
       width=800) 
fig.show()
Interface State Graph

 

Scroll to Top