Creating Network Configurations with Jinja

What is jinja?

Jinja is a templating engine for python. Commonly it is used alongside Django or Flask, both of which provide a way to create websites using python. As network engineers, we often use and create templates for network configurations. Typically for us that consists of a text document with placeholder text for variable items such as IP addresses or VLAN IDs. So of course, jinja is a natural fit for a network engineer as well.

So why use jinja over our usual text file?

One thing jinja can provide is the ability create a single configuration template and use it to iterate over a list to create a block of code for each item. A simple example would be VLAN creation. Perhaps you are configuring a new switch and need to create several vlans. Would you want to copy/paste your code block multiple times and manually change your placeholder text to the correct vlan ID each time? With jinja, you can simply pass in a list of vlan numbers. Heres an example.

Note: These examples assume you have basic knowledge of python. Check this post for recommendations on learning basic python. Syntax is written for python 3.

#start by importing the Template function from jinja2
from jinja2 import Template

#Set up your jinja template
jtemplate = Template("vlan {{ vlan }}\n name VLAN{{ vlan }}_byJinja\n")

#Create the list of VLANs you want to generate configuration for
vlans = [10,20,30,40,50,60,70,80,90,100]

#Iterate over the list of vlans and print a useable configuration
for vlan in vlans:
    output = jtemplate.render(vlan=vlan)
    print(output)

Above is a full ready to go python script that will generate configuration necessary for creating vlans 10,20,30,40,50,60,70,80,90, and 100. Running this code will give the following output:

vlan 10
 name VLAN10_byJinja
vlan 20
 name VLAN20_byJinja
vlan 30
 name VLAN30_byJinja
vlan 40
 name VLAN40_byJinja
vlan 50
 name VLAN50_byJinja
vlan 60
 name VLAN60_byJinja
vlan 70
 name VLAN70_byJinja
vlan 80
 name VLAN80_byJinja
vlan 90
 name VLAN90_byJinja
vlan 100
 name VLAN100_byJinja

We have our vlans with names ready to deploy to our switch. Pretty simple example, so lets break it down.

jtemplate = Template("vlan {{ vlan }}\n name VLAN{{ vlan }}_byJinja\n")

In this example, we first set up a jinja template by creating an object named jtemplate and assigning Jinja’s Template() function to it. We must also pass in our actual template into this function. Jinja uses double curly brackets to identify a variable within a block of configuration. In the above example, you will see {{ vlan }} placed in our template as a placeholder for our VLAN ID. In fact, its used twice. Once to configure the vlan itself, and a second time to help give a name or description to the vlan. You will also notice “\n” in the template, this is used to create a new line to help with the formatting of our output and is not printed literally.

vlans = [10,20,30,40,50,60,70,80,90,100]

for vlan in vlans:
    output = jtemplate.render(vlan=vlan)
    print(output)

Next, we need a list of vlans and then some code to actually generate the configuration. You can create this a variety of ways, however for this example it’s a simple list of vlan ids. We will iterate over this list of vlans using a simple for loop to generate a configuration for each vlan in our list. Within the for loop we create a variable named output to hold our configuration, which is created by using an attribute of our jtemplate object called render(). You need to pass in your variables using keyword/named arguments. The only variable we have in this example is vlan, so we will pass it in using output = jtemplate.render(vlan=vlan). In other words, for each iteration of the for loop we will be telling jinja that vlan is equal to the current item in our list.  Then you can print the results like I have done in my example or retrieve the data in any way you wish, such as saving it to a text file.

While this is a very simple example, you can imagine how quickly you can create a configuration for a huge list of vlans. If you have a contiguous list of VLAN IDs, you could simplify even further with something like “vlans = range(2,1000)” to quickly create a list of VLANs 2 through 999.


The previous example is single file python script, which works just fine for a simple vlan creation. You may be wondering how a much larger configuration template would work. Trying to work a large configuration template into python code isn’t very practical. Jinja allows you to use a separate file containing your template to be used by your main python code. Heres an example of a slightly more complex template using jinja.

interface {{ intf }}
 description {{ intdscr }}
 ip address {{ ip }} {{ mask }}
 service-policy output {{ qospol }}

router bgp {{ bgpasn|default("655123") }}
 neighbor {{ bgpnip }} remote-as {{ remasn }}

ip route 0.0.0.0 0.0.0.0 {{ bgpnip }}

For this, you simply start a new text document and save it. It is recommended to use the file extension “.j2” to clearly identify it as a jinja template. For example “wan.j2”. This looks very similar to something most network engineers already use, we can format it to look like our typical network configuration. You just need to use the jinja double curly bracket format in place of your variables. You can also set default values directly in the jinja template. Here I am using {{ bgpasn|default(“655123”) }}. If the user doesn’t pass in a BGP ASN value, jinja will use the default of 655123.

with open("wan.j2") as file:
    jtemplate = Template(file.read())

Once again you need to set up your jinja template. This time, we are reading our jinja template from a file named “wan.j2” and storing it in a variable named jtemplate. Remember, unless you specify a full path for the file in open(), python will only look in the directory from which you are executing the code. So here, our wan.j2 file needs to be in the same directory where we have the python interpreter running or where our .py file is located if we are executing it that way.

output = jtemplate.render(intf="Ethernet1/0",intdscr="WAN_byJinja",ip="10.1.1.1",
                          mask="255.255.255.252", qospol="200MB_SHAPE",bgpasn="65456",
                          bgpnip="10.1.1.2",remasn="65499")
print(output)

Now we just need to create the output variable to hold our configuration. In this case we are just passing the values in directly as keyword/named arguments instead of iterating over a list. Then we can print output which gives us this:

interface Ethernet1/0
 description WAN_byJinja
 ip address 10.1.1.1 255.255.255.252
 service-policy output 200MB_SHAPE

router bgp 65456
 neighbor 10.1.1.2 remote-as 65499

ip route 0.0.0.0 0.0.0.0 10.1.1.2

Now to put it all in one place:

#Separate jinja template file named wan.j2

interface {{ intf }}
 description {{ intdscr }}
 ip address {{ ip }} {{ mask }}
 service-policy output {{ qospol }}

router bgp {{ bgpasn|default("655123") }}
 neighbor {{ bgpnip }} remote-as {{ remasn }}

ip route 0.0.0.0 0.0.0.0 {{ bgpnip }}
#start by importing the Template function from jinja2
from jinja2 import Template

#Set up the jinja template
with open("wan.j2") as file:
    jtemplate = Template(file.read())

#Create a variable along with some logic to generate the configuration
output = jtemplate.render(intf="Ethernet1/0",intdscr="WAN_byJinja",ip="10.1.1.1",
                          mask="255.255.255.252", qospol="200MB_SHAPE",bgpasn="65456",
                          bgpnip="10.1.1.2",remasn="65499")
print(output)

Since this post is getting pretty long, I believe I will cut it off here and post a follow up with some more advanced uses for jinja. While jinja its self is pretty simple to use, the examples here just scratch the surface on ways you can use python and jinja to simplify creation of configuration. To boil it down, jinja allows you to create templates in a very similar way to how you may already be doing it. The real power comes from the ability to create a template one time and use creative python code to create hundreds of configurations near instantly.

In these very simple examples, I only showed how to use basic python to feed information to the template. You can also pair this with something like REST, YAML, JSON, etc. to obtain your information. Imagine feeding in a YAML file containing WAN information for thousands of devices, you would be able to create a WAN configuration for each device within a matter of seconds.

With this basic knowledge of jinja, I hope this sparks your imagination on the possibilities on how to turn the mundane task of creating the same network configurations over and over again into something simple that only takes seconds.

Leave a Reply