We all know how painful it is to enter the same text in to the CLI, to program the same network VLANs, over, and over, and over and over, and over…. We also know a better way that exists, with network programmability, but this solution could be a few years out before your company adopts the newest network programmability standards. What are you to do???
Using Python and Jinja2 to automate network configuration templates is a really useful way to simplify repetitive network tasks, that as engineers, we often face on a daily basis. In using this alternative method to automate our tasks we can remove the common error mistakes experienced in the copying/pasting of commands into the CLI (command line interface). If you are new to network automation, this is a fantastic way to get started with network programmability.
Firstly, let’s cover the basic concepts we will run over here.
◈ What are CLI Templates? CLI templates are a set of re-usable device configuration commands with the ability to parameterize select elements of the configuration as well as add control logic statements. This template is used to generate a device deployable configuration by replacing the parameterized elements (variables) with actual values and evaluating the control logic statements.
◈ What is Jinja2? Jinja2 is one of the most used template engines for Python. It is inspired by Django’s templating system but extends it with an expressive language that gives template authors a more powerful set of tools.
Jinja2 works with Python 2.6.x, 2.7.x and >= 3.3. If you are using Python 3.2 you can use an older release of Jinja2 (2.6) as support for Python 3.2 was dropped in Jinja2 version 2.7. To install this use pip.
pip install jinja2
Now we have Jinja2 installed let us take a quick look at this with a simple “Hello World” example with Python. To start with, create a Jinja2 file with “Hello World” inside (I am saving this into the same directory I am going to write my python code in). A quick way to create this file is with echo.
echo "Hello World" > ~/automation_fun/hello_world.j2
Now let us create our python code. We import Environment and FileSystemLoader, which allows us to use external files with the template. Feel free to create your python code in the way you feel is best for you. You can use the python interpreter or an IDE such as PyCharm.
from jinja2 import Environment, FileSystemLoader
#This line uses the current directory
file_loader = FileSystemLoader('.')
env = Environment(loader=file_loader)
template = env.get_template('hello_world.j2')
output = template.render()
#Print the output
print(output)
Use the following command to run your python program.
STUACLAR-M-R6EU:automation_fun stuaclar$ python hello_template.py
Hello World
Congratulations, your first template was a success!
Next, we will look at variables with Jinja2.
Template variables are defined by the context dictionary passed to the template. You can change and update the variables in templates provided they are passed in by the application. What attributes a variable has depends heavily on the application providing that variable. If a variable or attribute does not exist, you will get back an undefined value.
In this example, we will build a new BGP neighbor with a new peer. Let’s start by creating another Jinja2 file, this time using variables. The outer double-curly braces are not part of the variable, what is inside will be what is printed out.
router bgp {{local_asn}}
neighbor {{bgp_neighbor}} remote-as {{remote_asn}}
!
address-family ipv4
neighbor {{bgp_neighbor}} activate
exit-address-family
This python code will look similar to what we used before, however, we are passing three variables
from jinja2 import Environment, FileSystemLoader
#This line uses the current directory
file_loader = FileSystemLoader('.')
# Load the enviroment
env = Environment(loader=file_loader)
template = env.get_template('bgp_template.j2')
#Add the varibles
output = template.render(local_asn='1111', bgp_neighbor='192.168.1.1', remote_asn='2222')
#Print the output
print(output)
This will then print this output, notice that as we have repetitive syntax (the neighbor IP address), the variable is used again.
STUACLAR-M-R6EU:automation_fun stuaclar$ python bgp_builder.py
router bgp 1111
neighbor 192.168.1.1 remote-as 2222
!
address-family ipv4
neighbor 192.168.1.1 activate
exit-address-family
If we have some syntax that will appear multiple times throughout our configuration, we can use for loops to remove redundant syntax.
The for loop allows us to iterate over a sequence, in this case, ‘vlan’. Here we use one curly brace and a percent symbol. Also, we are using some whitespace control with the minus sign on the first and last line. By adding a minus sign to the start or end of a block the whitespaces before or after that block will be removed. (You can try this and see the output difference once the Python code has been built). The last line tells Jinja2 that the template loop is finished, and to move on with the template.
Create another Jinja2 file with the following.
{% for vlan in vlans -%}
{{vlan}}
{% endfor -%}
In the python code, we add a list of vlans.
from jinja2 import Environment, FileSystemLoader
#This line uses the current directory
file_loader = FileSystemLoader('.')
# Load the enviroment
env = Environment(loader=file_loader)
template = env.get_template('vlan.j2')
vlans = ['vlan10', 'vlan20', 'vlan30']
output = template.render(vlans=vlans)
#Print the output
print(output)
Now we can run with python code and see our result.
STUACLAR-M-R6EU:automation_fun stuaclar$ python vlan_builder.py
vlan10
vlan20
vlan30
All of the code for these examples can be found on my GitHub https://github.com/bigevilbeard/jinja2-template
Firstly, let’s cover the basic concepts we will run over here.
◈ What are CLI Templates? CLI templates are a set of re-usable device configuration commands with the ability to parameterize select elements of the configuration as well as add control logic statements. This template is used to generate a device deployable configuration by replacing the parameterized elements (variables) with actual values and evaluating the control logic statements.
◈ What is Jinja2? Jinja2 is one of the most used template engines for Python. It is inspired by Django’s templating system but extends it with an expressive language that gives template authors a more powerful set of tools.
Prerequisites:
Jinja2 works with Python 2.6.x, 2.7.x and >= 3.3. If you are using Python 3.2 you can use an older release of Jinja2 (2.6) as support for Python 3.2 was dropped in Jinja2 version 2.7. To install this use pip.
pip install jinja2
Now we have Jinja2 installed let us take a quick look at this with a simple “Hello World” example with Python. To start with, create a Jinja2 file with “Hello World” inside (I am saving this into the same directory I am going to write my python code in). A quick way to create this file is with echo.
echo "Hello World" > ~/automation_fun/hello_world.j2
Now let us create our python code. We import Environment and FileSystemLoader, which allows us to use external files with the template. Feel free to create your python code in the way you feel is best for you. You can use the python interpreter or an IDE such as PyCharm.
from jinja2 import Environment, FileSystemLoader
#This line uses the current directory
file_loader = FileSystemLoader('.')
env = Environment(loader=file_loader)
template = env.get_template('hello_world.j2')
output = template.render()
#Print the output
print(output)
Use the following command to run your python program.
STUACLAR-M-R6EU:automation_fun stuaclar$ python hello_template.py
Hello World
Congratulations, your first template was a success!
Next, we will look at variables with Jinja2.
Variables With Jinja2
Template variables are defined by the context dictionary passed to the template. You can change and update the variables in templates provided they are passed in by the application. What attributes a variable has depends heavily on the application providing that variable. If a variable or attribute does not exist, you will get back an undefined value.
router bgp {{local_asn}}
neighbor {{bgp_neighbor}} remote-as {{remote_asn}}
!
address-family ipv4
neighbor {{bgp_neighbor}} activate
exit-address-family
This python code will look similar to what we used before, however, we are passing three variables
from jinja2 import Environment, FileSystemLoader
#This line uses the current directory
file_loader = FileSystemLoader('.')
# Load the enviroment
env = Environment(loader=file_loader)
template = env.get_template('bgp_template.j2')
#Add the varibles
output = template.render(local_asn='1111', bgp_neighbor='192.168.1.1', remote_asn='2222')
#Print the output
print(output)
This will then print this output, notice that as we have repetitive syntax (the neighbor IP address), the variable is used again.
STUACLAR-M-R6EU:automation_fun stuaclar$ python bgp_builder.py
router bgp 1111
neighbor 192.168.1.1 remote-as 2222
!
address-family ipv4
neighbor 192.168.1.1 activate
exit-address-family
If we have some syntax that will appear multiple times throughout our configuration, we can use for loops to remove redundant syntax.
For Loops with Jinja2
The for loop allows us to iterate over a sequence, in this case, ‘vlan’. Here we use one curly brace and a percent symbol. Also, we are using some whitespace control with the minus sign on the first and last line. By adding a minus sign to the start or end of a block the whitespaces before or after that block will be removed. (You can try this and see the output difference once the Python code has been built). The last line tells Jinja2 that the template loop is finished, and to move on with the template.
Create another Jinja2 file with the following.
{% for vlan in vlans -%}
{{vlan}}
{% endfor -%}
In the python code, we add a list of vlans.
from jinja2 import Environment, FileSystemLoader
#This line uses the current directory
file_loader = FileSystemLoader('.')
# Load the enviroment
env = Environment(loader=file_loader)
template = env.get_template('vlan.j2')
vlans = ['vlan10', 'vlan20', 'vlan30']
output = template.render(vlans=vlans)
#Print the output
print(output)
Now we can run with python code and see our result.
STUACLAR-M-R6EU:automation_fun stuaclar$ python vlan_builder.py
vlan10
vlan20
vlan30
All of the code for these examples can be found on my GitHub https://github.com/bigevilbeard/jinja2-template