This post is the fifth in a series exploring Python libraries that are commonly used for interacting with network devices. The previous entries in this series covered libraries for directly interacting with network devices. Libraries such as Netmiko, NAPALM, Scrapli, and Nornir greatly ease the process of connecting to, and configuring, a network device. This blog will examine Netutils, a Python library that is a collection of objects for common network automation tasks.
What Is Netutils?
Netutils is a library created by Network to Code that has a series of functions that are aggregated in a single location. The intention is to find things that network engineers commonly have to do in their job and provide them in one place. The high-level buckets include:
Bandwidth
Banner
BGP ASN
Configuration
DNS
Interface
IP Address
Library Mapper
MAC Address
Password
Ping
Protocol Mapper
Route
Time
VLANs
While initially explored here when introduced, this article will deep dive into parts not already covered.
Installation
You can install Netutils via pip:
pip install netutils
Or, if you are using Poetry for dependency management:
poetry add netutils
Bandwidth
This is a new addition since Netutils was introduced. The functions provide the ability to swap between names to bits/bytes floats. This is especially helpful when dealing with systems that are better suited for human reading (such as interface stats) versus machine read comparison.
>>> from netutils.bandwidth import name_to_bits>>> name_to_bits("10Gbps")10000000000>>> name_to_bits("33.6Kbps")33600>>> name_to_bits("2.5Gbps")2500000000>>> >>> >>> from netutils.bandwidth import name_to_bytes>>> name_to_bytes("10Gbps")1250000000.0>>> name_to_bytes("100Mbps")12500000.0>>> name_to_bytes("100GBps")100000000000.0>>> >>> >>> from netutils.bandwidth import bits_to_name>>> bits_to_name(125000)'125Kbps'>>> bits_to_name(1000000000)'1Gbps'>>> >>> >>> from netutils.bandwidth import bytes_to_name>>> bytes_to_name(10000.0)'10.0KBps'>>> bytes_to_name(10000000.0)'10.0MBps'
Protocol Mapper
When initially released, Netutils had the ability to map IP protocols, but it has since been extended to map TCP, UDP, DCCP, and SCTP. This is rather helpful when dealing with firewall rules, when you may be given number and need name or vice versa.
BGP configurations sometimes use the integer value, which is the same with 2-byte ASNs, but different when using 4-byte ASNs. This can show up in Cisco configurations in both manners, depending on the bgp asnotation configuration setting.
>>> from netutils.asn import asn_to_int>>> asn_to_int("65000")65000>>> asn_to_int("65000.111")4259840111>>>
Ping
A pure Python ping can be helpful. One strategy used to eliminate connectivity check issues with high-level libraries like Netmiko is to test that there is basic connectivity beforehand.
>>> from netutils.ping import tcp_ping>>> tcp_ping("1.1.1.1", 443)True>>> tcp_ping("1.0.100.0", 27)False>>>
MAC Address
MAC addresses can be stored in a variety of ways, but the configuration expected is generally uniform. These functions help verify that the MAC addresses are valid and transpose them.
>>> from netutils.mac import mac_to_format>>> mac_to_format("aa.bb.cc.dd.ee.ff","MAC_DASH_FOUR")'aabb-ccdd-eeff'>>>>>> mac_to_format("aa.bb.cc.dd.ee.ff","MAC_DOT_FOUR")'aabb.ccdd.eeff'>>> mac_to_format("aa.bb.cc.dd.ee.ff","MAC_DOT_TWO")'aa.bb.cc.dd.ee.ff'>>>
IP Address
There is a whole series of options for manipulating and gathering information about IP addresses.
Adding and subtracting IP addresses can be used when you want to “plan” your IP address configuration. Such as, always use the first IP address as the HSRP, the second on the primary device’s interface, and the third on the backup device’s interface.
>>> from netutils.ip import ip_addition>>> ip_addition("10.100.100.100", 200)'10.100.101.44'>>>>>> from netutils.ip import ip_subtract>>> ip_subtract("10.100.100.100", 200)'10.100.99.156'>>>
Many systems store in one format (between cidr/netmask), but the configuration systems require differences. For example, Cisco IOS uses netmask, but Arista uses cidr.
>>> from netutils.ip import netmask_to_cidr>>> netmask_to_cidr("255.255.255.0")24>>> netmask_to_cidr("255.255.254.0")23>>>>>> from netutils.ip import cidr_to_netmask>>> cidr_to_netmask(24)'255.255.255.0'>>> cidr_to_netmask(17)'255.255.128.0'
Getting a peer IP address can be a bit more complicated, as you need to consider /30 & /31’s and understand which would give you the opposite sides IP address. It is helpful to have such a solution centralized and well tested.
>>> from netutils.ip import get_peer_ip>>> get_peer_ip('10.0.0.1/255.255.255.252')'10.0.0.2'>>> get_peer_ip('10.0.0.2/30')'10.0.0.1'>>> get_peer_ip('10.0.0.1/255.255.255.254')'10.0.0.0'>>> get_peer_ip('10.0.0.0/31')'10.0.0.1'>>>
Providing an interface range is helpful to communicate with those less familiar with IPs and networking in general.
>>> from netutils.ip import get_usable_range>>> get_usable_range("10.100.100.0/29")'10.100.100.1 - 10.100.100.6'>>>
Time
Many Network Operating Systems (NOSs) use human-readable time formats, which are not great for automation. The functions provided help unify them to integers.
>>> from netutils.time import uptime_seconds_to_string>>> uptime_seconds_to_string(7250)'2 hours, 50 seconds'
>>> from netutils.time import uptime_string_to_seconds>>> uptime_string_to_seconds("58 minutes")3480>>> from netutils.time import uptime_string_to_seconds>>> uptime_string_to_seconds("4m15s")255
Other Updates
There have been many updates since the initial release:
Bandwidth conversion added
Protocol mapper updates for tcp/tdp/dccp/sccp
Parsers added for
Cisco ASA
Fortinet FortiOS
Nokia SR OS
Interface Range
Interface Sorting
Added a Jinja2 convenience function
Added Uptime Conversion
What’s Next?
The Netutils repo is alive and well; and I, for one, believe it hasn’t reached its full potential. There are many ideas that you can track in issues, but I wanted to call out a few ideas that I would love to get completed.
Installed Parser List such as showing which TextFSM, Genie, or NAPALM getters you have installed
Conclusion
Netutils is simple in nature, generally only functions, which makes it great for newer developers to contribute. Its mission is simple and light, but it solves real-world problems. Any help from the community is welcome, and don’t forget to meet us at the #networktocode channel on Slack.
-Ken
New to Python libraries? NTC’s Training Academy is holding a three-day course Automating Networks with Python I September 26-28, 2022, half of which is labs so you can get up to speed.
Visit our 2022 public course schedule to see our full list.
Does this all sound amazing? Want to know more about how Network to Code can help you do this, reach out to our sales team. If you want to help make this a reality for our clients, check out our careers page.
Django is a popular open-source Python-based framework enabling quick and easy development of web applications. This post will walk through the initial install and setup of Django in order to develop a simple web front end to run a number of network utilities found in Network to Code’s netutils library.
Django Setup
To get started it is necessary to install the Django python package using pip. As a best practice this example installs Django inside a Python virtual environment, which thus should be activated before running pip install. As shown below, Django has been successfully installed and verified by confirming the installed version of the module.
Once Django is installed, the first step to get up and running is to create a Django project. Using the django-admin startproject command we can create our first Django project, named network_utilities. In this instance the project has been created in a parent django-projects directory, which was created manually before starting the Django project and not created by Django itself.
Looking inside this directory we can see that Django automatically created a number of subdirectories and Python files. What has been created is a directory store of our main project settings.
Django creates a topmost directory with the same name as our project (i.e., network_utilities) which contains manage.py. This is the Python script most used to interact with Django for functions such as creating Django apps, starting the web server, updating database schema, etc.
In the project parent directory we have a subdirectory that also has the same name as our project. This directory contains a number of Python scripts used to manage and define project settings:
settings.py – Django project settings including declaring installed Django apps, database connections, etc.
urls.py – here we can define the urls for our project
asgi.py & wsgi.py – Web server environment settings
Django’s built-in web server is not suited for production use. When deploying to production you should consider a deployment platform such as wsgi. For the purposes of describing how to get started with Django, the built-in web server will suffice, thus the asgi.py and wsgi.py files will not be used.
Running Django for the First Time
We can verify the installation by running the Django server using the manage.py script. For this we should be in the parent network_utilities directory.
(env) ntc@ubuntu:~/django-projects/network_utilities$ python manage.py runserverWatching for file changes with StatReloaderPerforming system checks...System check identified no issues (0 silenced).You have 18 unapplied migration(s). Your project may not work properly until you apply the migrations for app(s): admin, auth, contenttypes, sessions.Run 'python manage.py migrate' to apply them.August 12,2021-16:36:57Django version 3.2.6,using settings 'network_utilities.settings'Starting development server at http://127.0.0.1:8000/Quit the server with CONTROL-C.
As can be seen from the output, Django has launched on our localhost on TCP port 8000, i.e., http://127.0.0.1:8000. Browsing to this URL verifies Django has been installed correctly. To stop the server we simply send the CONTROL-C command as instructed above.
A Quick Note on Django Models
You may have noticed from the output above there is now a db.sqlite3 file included in the project root directory. This was created when we ran the Django runserver option with the manage.py script.
We were also warned when executing runserver that there are a number of unapplied migrations. One of the built-in features of Django is an Object-Relational Mapper (ORM) allowing you to define and manage database schemas without the need to understand SQL. Django uses models and migrations to manage your database schema.
Models are Python classes used to describe the database schema (i.e. your database table structure), stored in models.py under each Django application. Migrations are Python scripts that modify your database when changes to the models are made. In this post we are not creating our own models, but it is worth noting that Django by default supports a number of databases, including SQLite (the default, being used here), MySQL, and Oracle, and through third-party integrations can support others (configured in settings.pyDATABASES dictionary).
There are a number of Django apps included by default (listed in settings.py under INSTALLED_APPS) which provide “under the hood” Django functionality. The unapplied migrations warning simply states that Django wants to create the necessary database schema for these apps. We can use the manage.py script to apply these initial migrations:
(env) ntc@ubuntu:~/django-projects/network_utilities$ python manage.py migrateOperations to perform: Apply all migrations: admin, auth, contenttypes, sessionsRunning migrations: Applying contenttypes.0001_initial... OK Applying auth.0001_initial... OK Applying admin.0001_initial... OK Applying admin.0002_logentry_remove_auto_add... OK Applying admin.0003_logentry_add_action_flag_choices... OK Applying contenttypes.0002_remove_content_type_name... OK Applying auth.0002_alter_permission_name_max_length... OK Applying auth.0003_alter_user_email_max_length... OK Applying auth.0004_alter_user_username_opts... OK Applying auth.0005_alter_user_last_login_null... OK Applying auth.0006_require_contenttypes_0002... OK Applying auth.0007_alter_validators_add_error_messages... OK Applying auth.0008_alter_user_username_max_length... OK Applying auth.0009_alter_user_last_name_max_length... OK Applying auth.0010_alter_group_name_max_length... OK Applying auth.0011_update_proxy_permissions... OK Applying auth.0012_alter_user_first_name_max_length... OK Applying sessions.0001_initial... OK
Django Apps
Django uses the concept of an “application” to provide modularity to our code, one of the built-in advantages of using the framework. A Django app is simply a collection of code that enables a particular function for your web application. When creating the app, a number of Django components are “tied together” within the app, namely:
The view – contains code for the feature we wish to develop
The URL pattern – where we define URL’s and map to a view
The view is a Python function with an argument request which handles the requests for the web page we create. There are other optional components, but to get started, we will just define the view and URL within our Django app for our first simple webpage.
Again we use the manage.py script , this time to create our Django app. Here the app we create is called network_tools:
In order to create our first view it is necessary to declare our Django app in the INSTALLED_APPS list in settings.py (in the network_utilities sub-directory).
A simple home page can be created in the views.py file under the network_tools app. Here we create a simple function called home with a single argument, request. This argument will capture the HTTP requests which we will use later. The function returns a welcome message using Django’s HttpResponse, which we import on line 1.
network_tools/views.py
from django.http import HttpResponsedef home(request): return HttpResponse("Welcome to NTC netutils Django demo")
Next we must map a URL to this view. Currently we have one urls.py file in the project settings directory i.e. network_utilities/network_utilities. It is possible to declare all our URL’s here but we also have an option to create a per-Django-application urls.py. As well as modularity this approach allows us to have a common prefix for each app. This is the approach we will take allowing us to create a /netutils prefix as we add webpages. We will create this prefix later when adding pages for the netutils utilities, but first we will setup the project and application urls.py for the home page.
In the project urls.py we map the home page URL (signified via a blank path '' ) to our Django app by including network_tools.urls.
We then create a urls.py file in the application directory (network_utilities/network_tools) in order to map the URL to our view, you can see that the path ('') is the same in both files.
Now if we run the Django server again and browse to http://127.0.0.1:8000 we will be presented with the welcome message and we have created our first Django webpage.
Building the Web App
Having covered the basics of Django we can build our web frontend for the NTC netutils library (python -m pip install netutils)
So far we have created a simple webpage with a welcome message, now we can use Django templates to write HTML code to develop the page further. The templates support an inheritance model whereby we can ensure that each page we create has a similar look and feel. To start we will create a base.html file, from which all other pages will inherit.
First we must create a templates directory inside our app directory. Django by default will look in this directory for the base.html file. This directory should also have a sub-directory with the same name as the app (network_tools) where HTML files for all the app pages will be stored. Similarly a static directory with a network_tools sub directory is created to store an image that will be displayed on each page inherited from base.html.
The base.html file includes 2 blocks (title and body) which act as placeholders for subsequent pages to display page specific content. The header also includes a PNG image (the Network to Code logo); each page that extends from base.html will display this image. In order to load the image the load static instruction is necessary i.e. line 1.
templates/base.html
{%loadstatic%}<!DOCTYPE html><htmllang="en"><head><metacharset="UTF-8"><title>{% block title %}{% endblock %}</title><imgsrc="{% static 'network_tools/ntc-logo.png' %}"width="200px"></head><body>{% block body %}{% endblock %}</body></html>
We can now update the home page by creating a home.html in the templates/network_tools directory. This HTML file extends from base.html and provides inputs to the title and body blocks.
templates/network_tools/home.html
{%extends"base.html"%}{%blocktitle%}Welcome{%endblock%}{%blockbody%}<h1> Welcome to NTC netutils Django front end demo</h1><body><p> This is the webpage for running NTC netutils utilities.</p></body>{%endblock%}
In order to utilise these HTML templates we must update our view. The Django render function is now used instead of directly constructing an HttpResponse, and thus we can remove the from django.http import HttpResponse statement.
network_tools/views.py
from django.shortcuts import renderdef home(request): return render("network_tools/home.html")
We now have a home page which inherits the NTC logo from base.html.
Integrating netutils
NTC’s netutils Python library is a collection of tools to help with your network automation projects, installed using ‘pip’:
For the purposes of this post we will create a frontend for 2 of the ‘netutils’ tools:
TCP Ping – verify if a host is listening on a particular TCP port
IP Address Utilities – e.g., netmask to CIDR notation and vice-versa
As with our home page, it is necessary to update a number of files in order to create each new page as follows:
ping.html – a new file in the templates/network_tools directory
views.py – define our view for each page
urls.py – In both the project and application directories allows us to map a URL to our new view
First we will create a link on our home page to our new page for the netutils tool. This is configured in home.html we created previously, we have added a sub header and HREF for the “Ping” page to specify a link destination.
templates/network_tools/home.html
{%extends"base.html"%}{%blocktitle%}Welcome{%endblock%}{%blockbody%}<h1> Welcome to NTC netutils Django front end demo.</h1><body><p> This is the webpage for running NTC netutils utilities.</p><h2> Supported Netutils Functions:</h2><ahref="{%url 'ping' %}">Ping</a></body>{%endblock%}
The ping.html template will inherit from base.html as before. We can now complete the page specific details using the 2 blocks declared in base.html, title and body. The title simply labels our browser tab, with ‘TCP Ping’ in this instance. The body block allows us to code the input fields necessary for the netutils TCP Ping utility, note in the body we specify the HTTP method verb which we will use in the view. The netutils ping tool accepts 2 arguments (IP Address and TCP Port number) requiring a form field for each argument, both of which are given a name (“ip” and “number”) which can be referenced in a Django view. We also create a submit button to allow the user to execute the TCP Ping utility.
The HTML code includes input validation on the TCP port to ensure only an integer in the valid TCP port range is accepted. Also a test_result variable is displayed which will be declared in our Django view. A link back to the Home page is added at the bottom of the page.
templates/network_tools/ping.html
{%extends"base.html"%}{%blocktitle%}TCP Ping{%endblock%}{%blockbody%}<h2> TCP Ping </h2><p> Verifies whether a TCP port is open on a given IP address</p><formaction="/ping/"method="get"><labelfor="">Please enter Host IP Address:</label><inputname="ip"><div><labelfor="">Please enter TCP Port:</label><inputtype="number"name="port"min="0"max="65535"></div><div><buttontype="submit">Submit</button></div></form><divclass="result">{{test_result|linebreaks}}</div><ahref="{%url 'home' %}">home</a>{% endblock %}
In views.py we declare a new function to define the code necessary to execute the ping tool. The required functions from the netutils library are imported, as shown on line 2 and 3. The request object contains the data entered by the user, i.e. the ‘ip’ and ‘port’ parameters specified in ping.html.
The “ping” function includes input validation to verify the user input. First it verifies an IP Address has been entered, in this instance we use the get method of the request.GET object to query the 'ip' key. If an IP Address has been entered the netutils is_ip method is used to ensure the IP Address is in a valid format. This input validation is in addition to verification of the TCP port number configured in the HTML template which is enforced by the browser rather than the views.py function.
Having validated the user input, the netutils tcp_ping function is called and the result stored in a test_result dictionary. The function return statement calls Django render to render the ping.html template and passes in the test_result dictionary.
network_tools/views.py
from django.shortcuts import renderfrom netutils.ping import tcp_pingfrom netutils.ip import is_ip, cidr_to_netmask, netmask_to_cidr, is_netmaskdef home(request): return render("network_tools/home.html")def ping(request): test_result = {} if request.GET.get('ip') == '': test_result['test_result'] = f'Please enter an IP Address {request.GET}' elif 'ip' in request.GET: if is_ip(request.GET['ip']) is False: test_result['test_result'] = 'Please enter a valid IP Address' return render(request,"network_tools/ping.html", test_result) host_ip = request.GET['ip'] host_port = request.GET['port'] ping_result = tcp_ping(host_ip, host_port) if ping_result is True: test_result['test_result'] = f"Success: Port {host_port} is Open on host {host_ip}" else: test_result['test_result'] = f"Failure: Cannot open connection to Port {host_port} on host {host_ip}" return render(request,"network_tools/ping.html", test_result)
Finally we must update the project and application urls.py to map a URL to our django view.
In the project urls.py we can now declare a netutils prefix which will be prepended to pages for this Django app.
We now have a new webpage allowing the user to validate if an IP Address is listening on a particular TCP port. The input validation configured will ensure a message is displayed if an invalid IP Address or TCP Port number is entered. In the example output below we entered valid details and were returned a ‘Success’ message.
Adding Additional Pages
This completes all the necessary steps to enable a Django frontend on one of Network to Code’s netutils functions. In order to create additional pages (e.g. the IP Address utilities) we follow the same process:
1. Add a link to the new page on the home page in home.html.2. Add an HTML template for our new page, e.g., ip_addresses.html.3. Define the view in views.py, e.g., an ip_addr(request) functionplusnecessarycodelogic.4. Updatetheapplication-specificurls.pytomapaurltothenewview.
At this stage most of the work is in views.py and the application specific urls.py. Below is shown the changes to these files to add the CIDR/Netmask conversion tool.
templates/network_tools/ip_address.html
{%blockbody%}<h2> cidr_to_netmask</h2><p> Creates a decimal format of a CIDR value.</p><formaction="/ip_addr"method="get"><div><labelfor="">Please enter CIDR value:</label><inputtype="number"name="cidr"min="1"max="32"></div><div><buttontype="submit">Submit</button></div></form><divclass="result">{{netmask_result|linebreaks}}</div></div><h2> netmask_to_cidr</h2><p> Creates a CIDR notation of a given subnet mask in decimal format.</p><formaction="/ip_addr"method="get"><div><labelfor="">Please enter a netmask value:</label><inputname="netmask"></div><div><buttontype="submit">Submit</button></div></form><divclass="result">{{cidr_result|linebreaks}}</div></div><ahref="{%url 'home' %}">home</a>{%endblock%}
network_tools/views.py
def ip_addr(request): test_result ={}if request.GET.get('cidr') =='': test_result['test_result'] ='Please a valid CIDR value [1-24]' elif 'cidr'in request.GET: cidr =int(request.GET['cidr']) netmask_result =cidr_to_netmask(cidr) test_result['netmask_result'] = f"Netmask for CIDR value {cidr} is {netmask_result}" elif 'netmask'in request.GET: netmask = request.GET['netmask']ifis_netmask(netmask) is False: test_result['cidr_result'] ='Please enter a valid Netmask'returnrender(request,"network_tools/ip_address.html", test_result) cidr_value =netmask_to_cidr(netmask) test_result['cidr_result'] = f"CIDR Value for netmask {netmask} is {cidr_value}"returnrender(request,"network_tools/ip_address.html", test_result)
This gives us 2 additional tools to convert CIDR value to Netmask and vice-versa.
Conclusion
We have just scratched the surface of Django, but hopefully this will give you an understanding of how to quickly get started. I hope you find this blog post useful.
Does this all sound amazing? Want to know more about how Network to Code can help you do this, reach out to our sales team. If you want to help make this a reality for our clients, check out our careers page.
If you have been in the Network Automation space for any period of time, you will quickly find yourself recreating the same small snippets of code over and over for common tasks such as IP or MAC address manipulation. I have personally found myself consistently copying code from one project to the next. Netutils intends to be a lightweight Python library that provides quick and easy access to these functions.
In creating this library it was important to keep it well-scoped, which is the genesis for the following tenets.
Must not be any dependencies required to run the library.
May be some dependencies, which will be managed by users in an opt-in fashion.
Shall prefer functional programming over object-oriented programming.
Shall retain a folder and file structure that is flat.
Shall leverage docstrings as the primary documentation mechanism.
Must provide examples in the docstring of every public function.
Shall retain a high test coverage.
As you can see, the tenets are there to protect the project from bloat, and in theory, become more likely to be used as the library will not come with a host of dependencies that do not apply to your specific use case.
Capabilities
At launch, the library has a series of capabilities provided.
BGP ASN – Provides the ability to convert BGP ASN from integer to dot notation.
Configuration
Cleaning – Provides the ability to remove or replace lines based on RegEx matches.
Compliance – Provides the ability to compare two configurations to sanely understand the differences.
Parsing – Provides the ability to parse configuration for the minor differences that are there.
Interface – Provides the ability to work with interface names, expanding, abbreviating, and spliting the names.
IP Address – Provides the ability to work with IP addresses, primarily exposing Python ipaddress functionality.
Library Mapper – Provides mappings in expected vendor names between Netmiko, NAPALM, pyntc, ntc-templates, pyats, and scrapli.
MAC Address – Provides the ability to work with MAC addresses such as validating or converting to integer.
Password – Provides the ability to compare and encrypt common password schemas such as type5 and type7 Cisco passwords.
Protocol Mapper – Provides a mapping for protocol names to numbers, and vice versa.
Route – Provides the ability to pass in a list of routes and an IP Address and return the longest prefix-matched route.
Vlans – Provide the ability to convert configuration into lists or lists into configuration.
Exploration
Let’s explore a few of the more interesting use functions provided by the library.
Configuration Compliance
This is perhaps the most interesting of use cases, and all credit goes to Jacob McGill for developing the library. The netutils.config.compliance.compliance function allows you to send two sets of configuration a compare them. There is a concept of features, which defines the scope or sections of the configuration. This function is the basis of what is used in the Nautobot Golden Config Plugin and can also be used to leverage idempotency. In fact, it was based off Ansible’s *_config module, which we at Network to Code used until we ran into performance limitations.
Given the array of networking libraries out there including Netmiko, NAPALM, pyntc, ntc-templates, pyats, and scrapli, it is unlikely you’re using only one. Maintaining an inventory that maps between them can be a tedious, error-prone task. Netutils library provides dictionaries that allow you to map bi-directionally from one library to another.
Similarly, you can see how to map from protocol integer to protocol name, and back.
>>> from netutils.protocol_mapper import PROTO_NUM_TO_NAME, PROTO_NAME_TO_NUM>>>>>> PROTO_NUM_TO_NAME[1]'ICMP'>>>>>> PROTO_NAME_TO_NUM['ICMP']1>>>
Quick Hits
Just to show a few more, take notice of these quick hits.
The following function will help in deploying a list of VLANs and match the configuration style in a standard IOS-like configuration.
>>> from netutils.vlan import vlanlist_to_config>>>>>> vlan_cfg = vlanlist_to_config([1, 2, 3, 5, 6, 1000, 1002, 1004, 1006, 1008, 1010, 1012, 1014, 1016, 1018])>>>>>> vlan_cfg['1-3,5,6,1000,1002,1004,1006,1008,1010,1012,1014','1016,1018']>>> for index, line in enumerate(vlan_cfg):... if index == 0:... print(f" switchport trunk allowed vlan {line}")... else:... print(f" switchport trunk allowed vlan add {line}")... switchport trunk allowed vlan 1-3,5,6,1000,1002,1004,1006,1008,1010,1012,1014 switchport trunk allowed vlan add 1016,1018>>>
You may want to compare a known password with a given encrypted password. This can help by verifying if the passwords are as expected for compliance reasons.
>>> from netutils.password import compare_type5>>>>>> compare_type5("cisco","$1$nTc1$Z28sUTcWfXlvVe2x.3XAa.")True>>> compare_type5("not_cisco","$1$nTc1$Z28sUTcWfXlvVe2x.3XAa.")False>>>
Oftentimes interfaces will come in various different shortened names, and it is helpful to normalize them.
>>> from netutils.interface import canonical_interface_name>>>>>> canonical_interface_name("Gi1/0/1")'GigabitEthernet1/0/1'>>>>>> canonical_interface_name("Eth1")'Ethernet1'>>>
Testing
Testing is driven largely by doctest (special thanks to Adam Byczkowski for the suggestion) and pytest. Doctest will actually compile the examples of code created and indicate whether or not the result is as intended. This is helpful to keep documentation efforts to a minimum by creating self-documenting code. For configuration-based testing, it largely revolves around creating mocked data tests.
Overall, the intention is to maintain a high percentage of testing, and based on the structure and nature of the project, that should be easily doable.
Origins & Attribution
The code has its roots in common network automation tasks. Therefore, examples can be found throughout the open source world. With few exceptions (that are explicitly noted in the repo) the actual code is either unattributable, or was created by someone at Network to Code, often as a contribution to other open source libraries. In regard to what is “unattributable” code, the best example would be Cisco type7 encryption/decryption. This code was clearly not first introduced in this repo; however, it is unclear who the original author is in the sea of prior art. For further attribution, see the project README.
Conclusion
While simple in concept and implementation, hopefully netutils can have big impact. I hope you can join my fellow maintainers Jeff Kala and Adam Byczkowski in contributing.
Does this all sound amazing? Want to know more about how Network to Code can help you do this, reach out to our sales team. If you want to help make this a reality for our clients, check out our careers page.
We use cookies on our website to give you the most relevant experience by remembering your preferences and repeat visits. By clicking “Accept”, you consent to the use of ALL the cookies. In case of sale of your personal information, you may opt out by using the link Do not sell my personal information. Privacy | Cookies
This website uses cookies to improve your experience while you navigate through the website. Out of these cookies, the cookies that are categorized as necessary are stored on your browser as they are essential for the working of basic functionalities of the website. We also use third-party cookies that help us analyze and understand how you use this website. These cookies will be stored in your browser only with your consent. You also have the option to opt-out of these cookies. But opting out of some of these cookies may have an effect on your browsing experience.
Necessary cookies are absolutely essential for the website to function properly. These cookies ensure basic functionalities and security features of the website, anonymously.
Cookie
Duration
Description
__hssc
30 minutes
HubSpot sets this cookie to keep track of sessions and to determine if HubSpot should increment the session number and timestamps in the __hstc cookie.
__hssrc
session
This cookie is set by Hubspot whenever it changes the session cookie. The __hssrc cookie set to 1 indicates that the user has restarted the browser, and if the cookie does not exist, it is assumed to be a new session.
cookielawinfo-checkbox-advertisement
1 year
Set by the GDPR Cookie Consent plugin, this cookie records the user consent for the cookies in the "Advertisement" category.
cookielawinfo-checkbox-analytics
11 months
This cookie is set by GDPR Cookie Consent plugin. The cookie is used to store the user consent for the cookies in the category "Analytics".
cookielawinfo-checkbox-functional
11 months
The cookie is set by GDPR cookie consent to record the user consent for the cookies in the category "Functional".
cookielawinfo-checkbox-necessary
11 months
This cookie is set by GDPR Cookie Consent plugin. The cookies is used to store the user consent for the cookies in the category "Necessary".
cookielawinfo-checkbox-others
11 months
This cookie is set by GDPR Cookie Consent plugin. The cookie is used to store the user consent for the cookies in the category "Other.
cookielawinfo-checkbox-performance
11 months
This cookie is set by GDPR Cookie Consent plugin. The cookie is used to store the user consent for the cookies in the category "Performance".
CookieLawInfoConsent
1 year
CookieYes sets this cookie to record the default button state of the corresponding category and the status of CCPA. It works only in coordination with the primary cookie.
viewed_cookie_policy
11 months
The cookie is set by the GDPR Cookie Consent plugin and is used to store whether or not user has consented to the use of cookies. It does not store any personal data.
Functional cookies help to perform certain functionalities like sharing the content of the website on social media platforms, collect feedbacks, and other third-party features.
Cookie
Duration
Description
__cf_bm
30 minutes
Cloudflare set the cookie to support Cloudflare Bot Management.
li_gc
5 months 27 days
Linkedin set this cookie for storing visitor's consent regarding using cookies for non-essential purposes.
lidc
1 day
LinkedIn sets the lidc cookie to facilitate data center selection.
UserMatchHistory
1 month
LinkedIn sets this cookie for LinkedIn Ads ID syncing.
Performance cookies are used to understand and analyze the key performance indexes of the website which helps in delivering a better user experience for the visitors.
Analytical cookies are used to understand how visitors interact with the website. These cookies help provide information on metrics the number of visitors, bounce rate, traffic source, etc.
Cookie
Duration
Description
__hstc
5 months 27 days
Hubspot set this main cookie for tracking visitors. It contains the domain, initial timestamp (first visit), last timestamp (last visit), current timestamp (this visit), and session number (increments for each subsequent session).
_ga
1 year 1 month 4 days
Google Analytics sets this cookie to calculate visitor, session and campaign data and track site usage for the site's analytics report. The cookie stores information anonymously and assigns a randomly generated number to recognise unique visitors.
_gat_gtag_UA_*
1 minute
Google Analytics sets this cookie to store a unique user ID.
_gid
1 day
Google Analytics sets this cookie to store information on how visitors use a website while also creating an analytics report of the website's performance. Some of the collected data includes the number of visitors, their source, and the pages they visit anonymously.
AnalyticsSyncHistory
1 month
Linkedin set this cookie to store information about the time a sync took place with the lms_analytics cookie.
CONSENT
2 years
YouTube sets this cookie via embedded YouTube videos and registers anonymous statistical data.
hubspotutk
5 months 27 days
HubSpot sets this cookie to keep track of the visitors to the website. This cookie is passed to HubSpot on form submission and used when deduplicating contacts.
ln_or
1 day
Linkedin sets this cookie to registers statistical data on users' behaviour on the website for internal analytics.
Advertisement cookies are used to provide visitors with relevant ads and marketing campaigns. These cookies track visitors across websites and collect information to provide customized ads.
Cookie
Duration
Description
bcookie
1 year
LinkedIn sets this cookie from LinkedIn share buttons and ad tags to recognize browser IDs.
bscookie
1 year
LinkedIn sets this cookie to store performed actions on the website.
li_sugr
3 months
LinkedIn sets this cookie to collect user behaviour data to optimise the website and make advertisements on the website more relevant.
VISITOR_INFO1_LIVE
5 months 27 days
YouTube sets this cookie to measure bandwidth, determining whether the user gets the new or old player interface.
YSC
session
Youtube sets this cookie to track the views of embedded videos on Youtube pages.
yt-remote-connected-devices
never
YouTube sets this cookie to store the user's video preferences using embedded YouTube videos.
yt-remote-device-id
never
YouTube sets this cookie to store the user's video preferences using embedded YouTube videos.
yt.innertube::nextId
never
YouTube sets this cookie to register a unique ID to store data on what videos from YouTube the user has seen.
yt.innertube::requests
never
YouTube sets this cookie to register a unique ID to store data on what videos from YouTube the user has seen.