How do you use Jinja2 templates to generate network configs?
Show the answer
Say this first
Jinja2 separates data from config. The template holds the config text with placeholders; YAML or the
source of truth holds the values per device. {{ var }} prints a value, {% for %} and {% if %}
add loops and conditions, and filters such as upper, default or join transform values. The same
template renders the same structure for every device, which is where consistency comes from.
Go deeper
Template
hostname {{ hostname }}
{% for server in ntp_servers %}
ntp server {{ server }}
{% endfor %}
{% if snmp_location is defined %}
snmp-server location {{ snmp_location }}
{% endif %}Data
hostname: ASW1
ntp_servers:
- 10.0.0.5
- 10.0.0.6
snmp_location: Building A floor 2Render in Python
import yaml
from jinja2 import Environment, FileSystemLoader, StrictUndefined
env = Environment(
loader=FileSystemLoader("templates"),
trim_blocks=True,
lstrip_blocks=True,
undefined=StrictUndefined,
)
template = env.get_template("base.j2")
with open("data/asw1.yml") as f:
data = yaml.safe_load(f)
print(template.render(**data))hostname ASW1
ntp server 10.0.0.5
ntp server 10.0.0.6
snmp-server location Building A floor 2Things that trip people
- Whitespace. Without
trim_blocksandlstrip_blocks, every{% %}line leaves a blank line or indentation. You can also trim per tag with{%-and-%}. - Undefined variables. The default prints an empty string, which can produce
ntp serverwith no address.StrictUndefinedmakes it fail instead. Ansible fails on undefined variables by default. - Logic creep. Keep templates simple and push decisions into the data.
In Ansible, the ansible.builtin.template module renders a .j2 file, and modules such as ios_config
accept rendered config through src.
They will ask next
How would you test a template?
Render it for a set of sample devices in CI and compare with known-good output files, and render with
StrictUndefinedso missing data fails the build. For extra safety, feed the rendered configs to Batfish or push them to a lab device.
Traps
- Putting device-specific values inside the template instead of the data.
- Forgetting whitespace control and shipping configs full of blank lines and stray spaces.