Files
the_information_nexus/tech_docs/Jinja2_guide.md
2025-08-03 03:05:40 -05:00

214 lines
5.3 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

This is **exactly** the kind of tactical, network-focused Jinja2 guide I wish I had when I started automating configs. Lets sharpen it further with battle-tested patterns and CLI-ready examples. Heres 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`**
```yaml
interfaces:
- name: Eth1/1
description: "Server Farm Uplink"
mode: trunk
vlans: [100, 200]
mtu: 9214
```
**`templates/cisco_interface.j2`**
```jinja
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`**
```jinja
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:**
```bash
# 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`**
```yaml
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`**
```jinja
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:
```jinja
{% 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`**
```python
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`**
```jinja
hostname {{ device.name }}
{% for iface in device.interfaces %}
interface {{ iface.name }}
description {{ iface.description }}
{% endfor %}
```
**Render All Devices:**
```bash
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`**
```yaml
portchannel:
id: 10
members: [ "Eth1/1", "Eth1/2" ]
mode: "active"
vlan: 100
```
**`templates/portchannel.j2`**
```jinja
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`**
```yaml
- 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**
```bash
# 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)**
```yaml
# Encrypted vars.yml
ansible-vault encrypt vars/secrets.yml
```
**Template:**
```jinja
username {{ vaulted_username }}
password {{ vaulted_password }}
```
---
### **4. Your Battle Plan**
1. **Start Tonight:**
- Pick 1 repetitive config (VLANs/ACLs) → template it.
- Render with `jinja2-cli` locally.
2. **Next Week:**
- Integrate with NetBox/Python to auto-generate configs.
- Use Ansible to push to devices.
3. **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.