5.3 KiB
This is exactly the kind of tactical, network-focused Jinja2 guide I wish I had when I started automating configs. Let’s sharpen it further with battle-tested patterns and CLI-ready examples. Here’s your playbook:
1. Immediate Wins: Stop Hand-Editing Configs
A. Interface Templating (Multi-Vendor)
Problem: Vendor-specific syntax for the same logical interface.
Solution: One YAML → Cisco/Juniper/Arista templates.
vars/interface.yml
interfaces:
- name: Eth1/1
description: "Server Farm Uplink"
mode: trunk
vlans: [100, 200]
mtu: 9214
templates/cisco_interface.j2
interface {{ interface.name }}
description {{ interface.description }}
{% if interface.mode == 'trunk' %}
switchport mode trunk
switchport trunk allowed vlan {{ interface.vlans | join(',') }}
{% endif %}
mtu {{ interface.mtu }}
templates/juniper_interface.j2
interfaces {
{{ interface.name | replace('Eth','ge-') }} {
description "{{ interface.description }}";
{% if interface.mode == 'trunk' %}
unit 0 {
family ethernet-switching {
vlan members [ {{ interface.vlans | join(' ') }} ];
}
}
{% endif %}
mtu {{ interface.mtu }};
}
}
Render Both:
# Cisco
jinja2 templates/cisco_interface.j2 vars/interface.yml
# Juniper
jinja2 templates/juniper_interface.j2 vars/interface.yml
B. BGP Config Generation (With Error-Prone Logic)
Problem: Complex BGP configs with neighbor policies.
Solution: Template + YAML with validation.
vars/bgp.yml
bgp:
asn: 65001
neighbors:
- ip: 10.0.0.2
remote_as: 65002
policies: [ "PREVENT_LEAK" ]
- ip: 192.168.1.1
remote_as: 65123
policies: [ "CUSTOMER_ROUTES" ]
templates/bgp.j2
router bgp {{ bgp.asn }}
{% for neighbor in bgp.neighbors %}
neighbor {{ neighbor.ip }} remote-as {{ neighbor.remote_as }}
{% if "PREVENT_LEAK" in neighbor.policies %}
neighbor {{ neighbor.ip }} route-map BLOCK_DEFAULT in
{% endif %}
{% endfor %}
Key Trick: Use | selectattr to filter neighbors:
{% for neighbor in bgp.neighbors | selectattr("policies", "contains", "CUSTOMER_ROUTES") %}
...customer-specific config...
{% endfor %}
2. Advanced: Network-as-Code Patterns
A. Generate Device-Specific Configs from NetBox API
Problem: NetBox has device data, but CLI configs are manual.
Solution: Fetch NetBox data → Jinja2.
fetch_netbox_data.py
import requests
import json
devices = requests.get("https://netbox/api/dcim/devices/").json()
with open('vars/netbox_devices.yml', 'w') as f:
json.dump(devices, f)
templates/netbox_cisco.j2
hostname {{ device.name }}
{% for iface in device.interfaces %}
interface {{ iface.name }}
description {{ iface.description }}
{% endfor %}
Render All Devices:
python fetch_netbox_data.py
jinja2 templates/netbox_cisco.j2 vars/netbox_devices.yml
B. Auto-Generate Port-Channel Configs (LACP)
Problem: Port-channel members change frequently.
Solution: Dynamic YAML + template.
vars/portchannel.yml
portchannel:
id: 10
members: [ "Eth1/1", "Eth1/2" ]
mode: "active"
vlan: 100
templates/portchannel.j2
interface Port-channel{{ portchannel.id }}
channel-group {{ portchannel.id }} mode {{ portchannel.mode }}
switchport access vlan {{ portchannel.vlan }}
{% for member in portchannel.members %}
interface {{ member }}
channel-group {{ portchannel.id }} mode {{ portchannel.mode }}
{% endfor %}
3. Pro Tooling: Network-Specific Tricks
A. Ansible + Jinja2 for Zero-Touch Deployment
ansible_playbook.yml
- name: Push Interface Configs
hosts: switches
tasks:
- name: Generate Config
template:
src: templates/cisco_interface.j2
dest: /tmp/{{ inventory_hostname }}.cfg
- name: Deploy Config
cisco.ios.ios_config:
src: /tmp/{{ inventory_hostname }}.cfg
B. Validate Configs Before Deployment
# Check for missing variables
jinja2 --format vars:yaml templates/interface.j2 vars/device.yml
# Dry-run with Ansible
ansible-playbook playbook.yml --check
C. Secret Management (Ansible Vault)
# Encrypted vars.yml
ansible-vault encrypt vars/secrets.yml
Template:
username {{ vaulted_username }}
password {{ vaulted_password }}
4. Your Battle Plan
-
Start Tonight:
- Pick 1 repetitive config (VLANs/ACLs) → template it.
- Render with
jinja2-clilocally.
-
Next Week:
- Integrate with NetBox/Python to auto-generate configs.
- Use Ansible to push to devices.
-
Go Pro:
- Build a GitLab pipeline that auto-generates configs on NetBox changes.
Example Repo Structure:
network-automation/
├── templates/ # .j2 files
├── vars/ # .yml device vars
├── scripts/ # Python/Ansible helpers
└── outputs/ # Rendered configs
Key Takeaway: Jinja2 turns network configs from manual CLI work into version-controlled code. The more you template now, the more time you save later.