Automation Principles – Inheritance
This is part of a series of posts intended to provide an understanding of Network Automation Principles.
The term inheritance
has its origin rooted in object-oriented programming, dating back to the ’60s. As the name suggests, it describes the relationship between objects and how their attributes are handed down, using similar hierarchical relationship naming as used in a family tree (parent, child, grandparent, etc.).
Inheritance is one of the tools in the arsenal that allow programmers to simplify their code and generally keep it more DRY.
Inheritance in Computer Science
A common example used to portray this would be classifying a vehicle, specifically with vehicle being the parent object and vehicle types such as cars, vans, motorcycles being the child object.
class Vehicle():
def __init__(self, manufacturer, model, color):
self.manufacturer = manufacturer
self.model = model
self.color = color
class Car(Vehicle):
@property
def tires(self):
return 4
@property
def doors(self):
return 4
class MotorCycle(Vehicle):
@property
def tires(self):
return 2
@property
def doors(self):
return 0
Working with this simple example, we can start to see how Inheritance works in Python:
>>> honda_civic = Car('Honda', "Civic", "blue")
>>> honda_civic.color
'blue'
>>> honda_civic.tires
4
>>> honda_civic.doors
4
>>>
>>>
>>>
>>> honda_cbr = MotorCycle('Honda', "CBR", "red")
>>> honda_cbr.color
'red'
>>> honda_cbr.tires
2
>>> honda_cbr.doors
0
>>>
Example in Networks
Let’s take a look at a similar construct using network-focused terms.
class NetworkDevice():
def __init__(self, manufacturer, model, memory):
self.manufacturer = manufacturer
self.model = model
self.memory = memory
class Router(NetworkDevice):
@property
def ports(self):
return 8
@property
def tunneling_protocols(self):
return ["dmvpn", "gre"]
class Switch(NetworkDevice):
@property
def ports(self):
return 48
@property
def rmon(self):
return True
One thing you may notice here is that while Router
has the property of tunneling_protocols
, the Switch
does not. The same is true in reverse for rmon
support. So with the use of inheritance, you can use the same interface as the Router for the properties that are on both or inherited from the parent, which supports the ability to be DRY.
>>> cisco_asr = Router("Cisco", "ASR1000", "1Gb")
>>> cisco_asr.tunneling_protocols
['dmvpn', 'gre']
>>> cisco_asr.ports
8
>>>
>>>
>>> cisco_nexus = Switch("Cisco", "NX9K", "1Gb")
>>> cisco_nexus.ports
48
>>> cisco_nexus.rmon
True
>>>
You can add multiple levels of inheritance in Python. Oftentimes a strategy would be to use a Mixin
, which is a conceptual idea of a class that has the sole use of being mixed in with other classes. Take the following example.
class SuperNetworkDeviceMixin():
@property
def cpu(self):
return "8 cores"
@property
def routing_protocols(self):
return ["bgp", "ospf", "isis"]
class Router(NetworkDevice, SuperNetworkDeviceMixin):
@property
def ports(self):
return 8
@property
def tunneling_protocols(self):
return ["dmvpn", "gre"]
You can see that SuperNetworkDeviceMixin
can be used to add the properties cpu
and routing_protocols
to the Router
class.
This ability to have multiple levels of inheritance is based on the Method Resolution Order (MRO), if you are interested in learning more.
Inheritance in Ansible
Ansible provides the ability to have set the hash_behaviour
, however the default is replace
. With this, it works the same way as inheritance, in that the more specific attribute overrides the parent.
Given the files:
group_vars/all.yml
ntp:
- 10.1.1.1
- 10.1.1.2
dns:
- 10.10.10.10
- 10.10.10.11
snmp:
- 10.20.20.20
- 10.20.20.21
group_vars/eu.yml
ntp:
- 10.200.200.1
- 10.200.200.2
host_vara/lon-rt01.yml
snmp:
- 10.150.150.1
- 10.150.150.2
Would result in the variables being “flattened” via inheritance to:
ntp:
- 10.200.200.1
- 10.200.200.2
dns:
- 10.10.10.10
- 10.10.10.11
snmp:
- 10.150.150.1
- 10.150.150.2
As the ntp would be inherited from the eu.yml
file and dns inherited from the all.yml
file. The layout of the inheritance structure is found in Ansible Variable Precedence documentation.
Real-Life Use Case with NAPALM
NAPALM heavily relies on inheritance to provide a consistent interface to many vendors, while still having drastically different code for each vendor. In this seriously truncated code taken directly from NAPALM’s source code, you can see how the base class (NetworkDriver
) works and how a child class (IOSDriver
) is implemented.
class NetworkDriver(object):
def get_ntp_peers(self) -> Dict[str, models.NTPPeerDict]:
"""
Returns the NTP peers configuration as dictionary.
The keys of the dictionary represent the IP Addresses of the peers.
Inner dictionaries do not have yet any available keys.
Example::
{
'192.168.0.1': {},
'17.72.148.53': {},
'37.187.56.220': {},
'162.158.20.18': {}
}
"""
raise NotImplementedError
class IOSDriver(NetworkDriver):
def get_ntp_peers(self):
"""Implementation of get_ntp_peers for IOS."""
ntp_stats = self.get_ntp_stats()
return {
napalm.base.helpers.ip(ntp_peer.get("remote")): {}
for ntp_peer in ntp_stats
if ntp_peer.get("remote")
}
This way, each class that inherits from the base class clearly indicates which methods it implements (by explicitly overwriting those methods) and which ones it doesn’t (and thus will raise a NotImplementedError
if called).
Inheritance in Django
One great example of Inheritance is Django. Its usage of object-oriented programming can be amazing when you understand it and frustrating when you don’t. Knowing how the MRO works and is implemented in Django is a must to start to understand how Django works. In that pursuit, I have found the “classy” pages for Django and DRF to be helpful.
Conclusion
Inheritance is used extensively throughout object oriented-programming languages such as Python. Additionally, there are concepts are used elsewhere, such as in Ansible’s variable structure.
Understanding the concept can help you in your day-to-day automation as well as provide the ability to build more scalable solutions.
-Ken
Contact Us to Learn More
Share details about yourself & someone from our team will reach out to you ASAP!