SDN Python: representation of a network device

SDN Python architecture explained.

Share This Post

The beauty of SDN is that you don’t care about the way, you care about the results. This is possible by using abstraction: the software takes care of the technical part, and you only set the goals. While this may seem sci-fi, it is a reality if you know how to prepare SDN Python scripts. In this article, we go way beyond the script, and we start to structure our SDN Python Application SDNCore.

SDNCore in a minute

Even if we wrote several articles about SDNCore, you don’t need to read them all before understanding this one. However, you may want a quick explanation on this project. SDNCore is an open-source project that allows you to control network devices (and more) in software. Before writing this article, it simply gave you a way of controlling the CLI of such devices. Instead of sending the commands using PuTTY or another terminal, you can use Python and control many devices at once.

While this is great, it is not in the real spirit of SDN. In fact, the administrator (you) must define the script and prepare the actual commands to send to all the devices. We need to go further so that the administrator defines just the goal and the application does the rest. As said in the introduction, we can do that with abstractions. Thus, we need to represent network devices in our SDN Python application. To do that, we will use the new class Device. If you are curious about SDN, you can start from our first article on it or check GitHub.

SDN Python representation of devices

The Architecture

To make the abstraction possible, we need to expand the architecture of SDNCore. Nothing to complex here. First, we need to have an entity that represents our device so that Python controls it like an object. Thus, our best bet is a class, something designed to represent objects. However, we need to standardize and simplify the management of such a device.

To make things simple, we can say that the device is just the device itself. Username, credentials, and protocol you use to access it are not attributes of such a device. Thus, we remove them from the class and create another class dedicated to them, the CliProfile. This class will contain all the settings you need to access a device and can be applied to multiple devices as well. To make things standard, we also create a generic Profile class that acts as the superclass for the CliProfile. This way, when we later add SNMP to our SDN Python application we can create a SNMPProfile based on the same superclass.

In the end, our architecture looks something like this.

A simple and scalable Python SDN Architecture allows you to abstract the device.
Our simple yet scalable Python SDN Architecture.

We can pack all this abstraction-related stuff into a dedicated module we can call devices. For now, it will only use our vty module, but in the future, we will add other fancy items like SNMP or FTP.

Access Profiles

An access profile is just a box providing credentials in a standard way. In fact, it abstracts them from the Session class (the one taking care of CLI connection) and makes them stand-alone. It has just one property, the pack. This is a dictionary containing all the credentials, in a way that – if unpacked – will be accepted from the function processing the credentials.

The Profile is the superclass, and has an empty pack. However, we want to create a set of credentials and other settings tailored for VTY access, thus the CliProfile. In the end, the accessprofiles.py file (in devices package) will look like this.

from sdncore.vty.session import Session


class Profile:
    def __init__(self):
        self.pack = {}


class CliProfile(Profile):
    def __init__(self, proto, username, password, port=None, stop_character="#", driver_parameters={}):
        super(Profile).__init__()
        proto = proto.lower()
        if proto == 'ssh':
            proto = Session.SSH
            if port is None:
                port = 22
        elif proto == 'telnet':
            proto = Session.Telnet
            if port is None:
                port = 23
        else:
            raise Exception
        self.pack = {
            'driver': proto,
            'username': username,
            'password': password,
            'port': port,
            'stop_character': stop_character,
            'driver_parameters': driver_parameters
        }

If you want to see the docstrings, go check this file on GitHub. Besides creating abstraction, we allow the user to specify the protocol as a case-insensitive string, instead of Session.SSH or Session.Telnet objects. Then, we take care of converting the string in the right object. This allows the user of SDNCore to avoid importing the Session class just to set a parameter.

The Device

Now, the core of our abstraction, the device. This class represents a generic device, on which SDNCore can perform operations. We can handle all of that in the device.py file in the devices package. As of now, we start using the Device class to control a VTY session only. Later in the development of SDNCore, we will expand it to perform more advanced operations like SNMP and FTP. Thus, the user does not create a Session toward a target anymore. It simply opens the CLI session of the device. The device automatically processes the Access Profile and grants access. This is done easily, simply with the __init__ method.

from .accessprofiles import Profile
from sdncore.vty.session import Session


class Device:
    def __init__(self, host, access_profile=Profile(), name=None):
        self.manage_host = host
        self.access_profile = access_profile
        self.name = name
        self.cli = Session(self.manage_host, **self.access_profile.pack)

The name you see in the constructor is just an explicative name to identify the device, thus it is optional. To check the whole code, including docstrings, take a quick tour on GitHub.

Using our device

Now that we have our SDN Python application set up with basic device settings we are ready to test it. Instead of opening a connection to a target manually, test how does it look using a Device. Below an example.

from sdncore.devices.device import Device
from sdncore.devices.accessprofiles import CliProfile


d = Device('rainmaker.wunderground.com', CliProfile('telnet', '', '', stop_character=':'), 'weather')
d.cli.open()
d.cli.command('')
print(d.cli.command('SFO'))
d.cli.close()

You can replicate this exact test at home! In fact, rainmaker.wunderground.com is a public and free service that provides weather information with Telnet. We represent this Internet server as a device (d), and then open its CLI. Then, we send an empty line to skip the initial message and ask the weather for San Francisco (SFO). You will be pleased to see it on-screen!

Wrapping it up

Even if these new files do not add real features to our SDNCore project, they are an important part of the SDN Python application. Abstracting the device and separating it from the session will allow us to do amazing stuff. For example, we can create a topology of devices by making each reference another, and we can abstract the result we want from the way it is achieved.

Do you like using this concept of device when automating your network? Did you prefer using plain-vanilla Sessions as we did before? Let me know your style in the comments!

Picture of Alessandro Maggio

Alessandro Maggio

Project manager, critical-thinker, passionate about networking & coding. I believe that time is the most precious resource we have, and that technology can help us not to waste it. I founded ICTShore.com with the same principle: I share what I learn so that you get value from it faster than I did.
Picture of Alessandro Maggio

Alessandro Maggio

Project manager, critical-thinker, passionate about networking & coding. I believe that time is the most precious resource we have, and that technology can help us not to waste it. I founded ICTShore.com with the same principle: I share what I learn so that you get value from it faster than I did.

Alessandro Maggio

2019-01-17T16:30:03+00:00

Unspecified

Networking

Unspecified