Jinja2 is a template processing toolkit which allows us to create and render text templates.
It is a text based templating system. It renders a template using variable replacement, tags (conditional, lopping, inheritance, macros) and filters.

In this example, I will use Jinja2 to automatically generate a network switch configuration file.

Folder and file Structure
project/
│
├── render_config.py
├── templates/
│   └── switch_interfaces.j2
└── output/

Jinja2 Template
hostname {{ hostname }}

{% for intf in interfaces %}
interface {{ intf.name }}
 description {{ intf.desc }}
 switchport mode {{ intf.mode }}
{% if intf.vlan is defined %}
 switchport access vlan {{ intf.vlan }}
spanning-tree portfast
{% endif %}
!
{% endfor %}

{{ hostname }} is replaced with a value from Python. for example if hostname = "SW-BR-01", the output becomes:

hostname SW-BR-01
For Loop ({% for %})
{% for intf in interfaces %}
...
{% endfor %}

This loop Iterates over a list of interfaces and replace the block once for each interface. we can also have loops in Python code. but I think the loops and Conditions in jibja2 templates are better because they are simple and also we can use the same template with Ansible too.

Conditional Logic ({% if %})
{% if intf.vlan is defined %}
 switchport access vlan {{ intf.vlan }}
{% endif %}

This means only add the VLAN line if the VLAN exists and prevents invalid configs for trunk ports.

Python Script
# you should install Jinja2 module firs: ~ python -m pip install jinja2 

from jinja2 import Environment, FileSystemLoader

data = {
    "hostname": "SW-BR-01",
    "interfaces": [
        {"name": "GigabitEthernet1/0/1", "desc": "POS terminal", "mode": "access", "vlan": 10},
        {"name": "GigabitEthernet1/0/2", "desc": "Printer", "mode": "access", "vlan": 20},
        {"name": "GigabitEthernet1/0/48", "desc": "Uplink to core", "mode": "trunk"},
    ],
}

env = Environment(
    loader=FileSystemLoader("templates"),  # tells Jinja where templates are
    trim_blocks=True,  #removes empty lines
    lstrip_blocks=True  #cleans indentation
)

template = env.get_template("switch_interfaces.j2")

rendered = template.render(data)  #Replaces variables, executes loops+conditions & Produces result

with open("output/SW-BR-01.cfg", "w") as f:
    f.write(rendered)

print("Configuration generated successfully.")

Output
hostname SW-BR-01

interface GigabitEthernet1/0/1
 description POS terminal
 switchport mode access
 switchport access vlan 10
 spanning-tree portfast
!
interface GigabitEthernet1/0/2
 description Printer
 switchport mode access
 switchport access vlan 20
 spanning-tree portfast
!
interface GigabitEthernet1/0/48
 description Uplink to core
 switchport mode trunk
!

Posted in

Leave a comment