diff --git a/tech_docs/Jinja2_guide.md b/tech_docs/Jinja2_guide.md new file mode 100644 index 0000000..bbff87b --- /dev/null +++ b/tech_docs/Jinja2_guide.md @@ -0,0 +1,214 @@ +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`** +```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. \ No newline at end of file