Files
the_information_nexus/tech_docs/jinja2_project.md

49 KiB

Based on your Jinja2 mastery goals and the comprehensive use cases in your document, here's the tactical toolchain that will make you unstoppable:

Core Stack (Your Foundation)

1. Python Ecosystem

# Essential Python libraries for Jinja2 mastery
pip install jinja2 pyyaml requests click rich tabulate

Why Each Matters:

  • PyYAML: Parse YAML data files (your primary input format)
  • Requests: Pull data from APIs (NetBox, cloud providers, monitoring systems)
  • Click: Build CLI tools for your templates
  • Rich: Beautiful terminal output for your tools
  • Tabulate: Generate nice tables in outputs

2. Data Sources & APIs

Tool Purpose Jinja2 Integration
NetBox Network documentation SSOT pynetbox → YAML → templates
Nautobot NetBox alternative Same pattern as NetBox
Ansible Automation platform Built-in Jinja2 support
Git Version control Store templates + data

Specialized Tools by Use Case

Network Engineering Stack

# Network-specific tools
pip install netmiko nornir napalm textfsm
pip install ipaddress netaddr

Power Combo Example:

from netmiko import ConnectHandler
from jinja2 import Template
import yaml

# Pull live config from device
device = ConnectHandler(**cisco_device)
running_config = device.send_command("show running-config")

# Generate new config from template
template = Template(open('templates/bgp.j2').read())
new_config = template.render(yaml.safe_load(open('data/bgp.yml')))

# Deploy with error checking
device.send_config_set(new_config.split('\n'))

Documentation & Visualization

# Documentation tools
pip install mkdocs mkdocs-material
pip install graphviz plotly mermaid-cli
npm install -g @mermaid-js/mermaid-cli  # For diagram generation

Workflow:

# Generate network diagrams from templates
template = env.get_template('network_diagram.mmd.j2')
mermaid_output = template.render(topology=network_data)

# Convert to PNG via CLI
subprocess.run(['mmdc', '-i', 'diagram.mmd', '-o', 'diagram.png'])

Sales/Proposal Generation

# Document generation
pip install python-docx reportlab pandoc

Pro Tip:

# Jinja2 → LaTeX → PDF pipeline
template = env.get_template('proposal.tex.j2')
latex_content = template.render(customer_data)

with open('proposal.tex', 'w') as f:
    f.write(latex_content)
    
subprocess.run(['pdflatex', 'proposal.tex'])

DevOps/Automation Stack

Container & Cloud Tools

# Cloud automation
pip install boto3 azure-identity google-cloud-storage
pip install kubernetes docker-py

Multi-Cloud Template Example:

{# Works for AWS, Azure, GCP #}
{% if cloud_provider == 'aws' %}
resource "aws_instance" "{{ instance_name }}" {
  ami           = "{{ ami_id }}"
  instance_type = "{{ instance_type }}"
}
{% elif cloud_provider == 'azure' %}
resource "azurerm_virtual_machine" "{{ instance_name }}" {
  name                = "{{ instance_name }}"
  vm_size            = "{{ vm_size }}"
}
{% endif %}

CI/CD Integration Tools

# Pipeline tools
pip install github3.py python-gitlab
pip install pre-commit black flake8

GitHub Actions Integration:

# .github/workflows/jinja2-render.yml
- name: Render Templates
  run: |
    python scripts/render_all.py
    git add rendered/
    git commit -m "Auto-rendered configs [skip ci]"

Advanced Toolchain

Database Integration

# Pull data from multiple sources
import sqlite3
import psycopg2
from sqlalchemy import create_engine
import pandas as pd

# SQL → Jinja2 pipeline
df = pd.read_sql("SELECT * FROM network_devices", engine)
devices = df.to_dict('records')
template.render(devices=devices)

Testing & Validation

pip install pytest jsonschema yamale

Template Testing:

# tests/test_templates.py
def test_cisco_config_template():
    template = env.get_template('cisco.j2')
    result = template.render(test_data)
    
    assert 'hostname TEST-SW-01' in result
    assert 'interface GigabitEthernet0/1' in result
    assert 'no shutdown' in result

Performance & Scalability

# For high-volume templating
from concurrent.futures import ThreadPoolExecutor
from functools import lru_cache

@lru_cache(maxsize=128)
def get_template(template_name):
    return env.get_template(template_name)

# Parallel rendering
with ThreadPoolExecutor(max_workers=4) as executor:
    configs = list(executor.map(render_device_config, devices))

Monitoring & Observability

pip install prometheus_client grafana-api
pip install loguru structlog

Template Metrics:

from prometheus_client import Counter, Histogram
import time

TEMPLATE_RENDERS = Counter('jinja2_renders_total', 'Total template renders')
RENDER_TIME = Histogram('jinja2_render_seconds', 'Template render time')

@RENDER_TIME.time()
def render_with_metrics(template, data):
    TEMPLATE_RENDERS.inc()
    return template.render(**data)

IDE & Development Tools

VS Code Extensions

  • Jinja2: Syntax highlighting for .j2 files
  • YAML: Better YAML editing
  • Python: Obviously
  • GitLens: Track template changes
  • REST Client: Test APIs that feed your templates

CLI Tools

# Essential CLI tools
pip install jinja2-cli j2cli cookiecutter
npm install -g js-yaml  # YAML validation

Quick CLI Usage:

# One-liner template rendering
j2 template.j2 data.yml --format=yaml > output.cfg

# Template from stdin
echo "Hello {{ name }}" | j2 --undefined -D name=World

Your 90-Day Mastery Stack

Month 1: Foundation

# Core tools only
pip install jinja2 pyyaml click rich
git clone https://github.com/your-templates/network-templates

Month 2: Specialization

# Add your domain-specific tools
pip install netmiko ansible  # Network
# OR
pip install boto3 kubernetes  # Cloud
# OR  
pip install python-docx reportlab  # Documentation

Month 3: Automation

# Full pipeline
pip install pytest pre-commit
# Set up CI/CD
# Add monitoring

Tool Selection Decision Tree

For Network Engineering:

  • Primary: Jinja2 + PyYAML + Netmiko + Ansible
  • Documentation: MkDocs + Mermaid
  • Advanced: NetBox + Nornir

For Cloud/DevOps:

  • Primary: Jinja2 + PyYAML + Terraform + Helm
  • Multi-Cloud: Boto3 + Azure SDK + Google Cloud
  • Advanced: Kubernetes Python client + ArgoCD

For Sales/Proposals:

  • Primary: Jinja2 + PyYAML + ReportLab/python-docx
  • Advanced: LaTeX + Pandoc
  • Integration: CRM APIs (Salesforce, HubSpot)

Pro Tips for Tool Selection

  1. Start minimal: Jinja2 + PyYAML + Click gets you 80% of the value
  2. Add incrementally: Don't boil the ocean—add tools as you hit specific limitations
  3. Standardize data formats: YAML for configs, JSON for APIs, CSV for bulk data
  4. Version everything: Templates, data, and generated outputs
  5. Test templates like code: Unit tests prevent production surprises

Want to dive deep on any specific toolchain? Pick your primary use case (network, cloud, sales) and I'll show you the exact setup with working examples.


Now you have an interactive Jinja2 playground that brings your document to life! This lets you experiment with all the concepts from your data dump in real-time.

What Makes You Dangerous with Jinja2

Based on your comprehensive document, you've identified the key insight: Jinja2 is the invisible force multiplier. Here's your tactical mastery roadmap:

Level 1: Master the Fundamentals (You're Already Here)

  • Variables: {{ variable }}
  • Loops: {% for item in items %}
  • Conditionals: {% if condition %}
  • Filters: {{ value | default('fallback') }}

Level 2: Advanced Patterns (Your Next Target)

A. Custom Filters for Network Engineering

def subnet_mask(cidr):
    """Convert CIDR to subnet mask"""
    return str(ipaddress.IPv4Network(f'0.0.0.0/{cidr}', strict=False).netmask)

env.filters['subnet_mask'] = subnet_mask

Usage: {{ '24' | subnet_mask }}255.255.255.0

B. Macros for Reusable Components

{# Define once, use everywhere #}
{% macro cisco_interface(name, ip, vlan=None) %}
interface {{ name }}
 ip address {{ ip }}
{% if vlan %} switchport access vlan {{ vlan }}{% endif %}
 no shutdown
{% endmacro %}

{# Use it #}
{{ cisco_interface('Gi0/1', '192.168.1.1', vlan=100) }}

Level 3: Systems Integration (Your Competitive Edge)

A. NetBox + Jinja2 Pipeline

# Pull live data from NetBox
import pynetbox
nb = pynetbox.api('https://netbox.company.com', token='your-token')

devices = []
for device in nb.dcim.devices.all():
    devices.append({
        'name': device.name,
        'type': str(device.device_type),
        'primary_ip': str(device.primary_ip4).split('/')[0]
    })

# Template with live data
template.render(devices=devices)

B. Git-Ops Automation

# .github/workflows/network-configs.yml
name: Generate Network Configs
on:
  push:
    paths: ['network-data/**']
jobs:
  generate:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v2
      - name: Render configs
        run: |
          pip install jinja2-cli
          jinja2 templates/cisco.j2 network-data/prod.yml > configs/prod.cfg
      - name: Commit generated configs
        run: |
          git add configs/
          git commit -m "Auto-generated configs"

Level 4: Business Impact (Where You Become Irreplaceable)

A. Proposal Automation (From Your Doc)

  • Before: 8 hours per RFP response
  • After: 30 minutes with templated proposals
  • ROI: 16x time multiplier

B. Compliance as Code

{# NIST 800-53 Control Validation #}
{% for control in nist_controls %}
## {{ control.id }}: {{ control.name }}
Status: {% if control.implemented %}✅ COMPLIANT{% else %}❌ NON-COMPLIANT{% endif %}
{% if not control.implemented %}
**Required Actions:**
{% for action in control.remediation %}
- [ ] {{ action }}
{% endfor %}
{% endif %}
{% endfor %}

Your Next 30 Days

Week 1: Practice the Playground

  • Work through all 6 example scenarios in the artifact
  • Modify each template to match your real-world data structures

Week 2: Build Your First Production Template

  • Choose one repetitive task (device configs, proposals, documentation)
  • Create a template + data file
  • Measure time savings

Week 3: Add Automation

  • Set up a Git repository with templates
  • Add basic CI/CD to auto-generate outputs
  • Share with one colleague

Week 4: Scale & Share

  • Create a template library for your team
  • Document best practices
  • Start building your reputation as "the automation expert"

Pro Tips from Your Document

  1. Start with the pain point: Don't template for templating's sake. Find the manual task that's eating your time.

  2. Embrace the invisible nature: As you noted, Jinja2 works backstage. The cleaner your final output, the more professional you look.

  3. Multi-format mastery: Use the same data to generate Cisco configs AND Mermaid diagrams AND Word proposals. That's your superpower.

  4. Version everything: Templates are code. Treat them like infrastructure.

Want to go deeper on any specific aspect? Pick a scenario from the playground and I'll help you build a production-ready version with real-world data integration.


<html lang="en"> <head> <style> * { margin: 0; padding: 0; box-sizing: border-box; }
    body {
        font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
        background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
        min-height: 100vh;
        color: #333;
    }

    .container {
        max-width: 1400px;
        margin: 0 auto;
        padding: 20px;
        display: grid;
        grid-template-columns: 1fr 1fr;
        gap: 20px;
        min-height: 100vh;
    }

    .panel {
        background: rgba(255, 255, 255, 0.95);
        border-radius: 15px;
        padding: 25px;
        box-shadow: 0 20px 40px rgba(0,0,0,0.1);
        backdrop-filter: blur(10px);
        border: 1px solid rgba(255,255,255,0.2);
    }

    .panel h2 {
        margin-bottom: 20px;
        color: #4a5568;
        font-size: 1.5rem;
        border-bottom: 3px solid #667eea;
        padding-bottom: 10px;
    }

    textarea {
        width: 100%;
        height: 200px;
        padding: 15px;
        border: 2px solid #e2e8f0;
        border-radius: 8px;
        font-family: 'Courier New', monospace;
        font-size: 14px;
        resize: vertical;
        background: #f7fafc;
        transition: border-color 0.3s;
    }

    textarea:focus {
        outline: none;
        border-color: #667eea;
        box-shadow: 0 0 0 3px rgba(102, 126, 234, 0.1);
    }

    .output {
        background: #1a202c;
        color: #e2e8f0;
        padding: 20px;
        border-radius: 8px;
        font-family: 'Courier New', monospace;
        font-size: 14px;
        min-height: 200px;
        white-space: pre-wrap;
        word-wrap: break-word;
        margin-top: 15px;
        border: 2px solid #2d3748;
    }

    .examples {
        grid-column: 1 / -1;
        display: grid;
        grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));
        gap: 20px;
    }

    .example-card {
        background: rgba(255, 255, 255, 0.9);
        border-radius: 12px;
        padding: 20px;
        border: 2px solid transparent;
        transition: all 0.3s ease;
        cursor: pointer;
    }

    .example-card:hover {
        border-color: #667eea;
        transform: translateY(-5px);
        box-shadow: 0 10px 25px rgba(0,0,0,0.15);
    }

    .example-card h3 {
        color: #667eea;
        margin-bottom: 10px;
        font-size: 1.2rem;
    }

    .example-card p {
        color: #666;
        margin-bottom: 15px;
        line-height: 1.6;
    }

    .example-code {
        background: #f1f5f9;
        padding: 10px;
        border-radius: 6px;
        font-family: 'Courier New', monospace;
        font-size: 12px;
        border-left: 4px solid #667eea;
    }

    button {
        background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
        color: white;
        border: none;
        padding: 12px 25px;
        border-radius: 8px;
        cursor: pointer;
        font-size: 14px;
        font-weight: 600;
        transition: all 0.3s;
        margin-top: 15px;
    }

    button:hover {
        transform: translateY(-2px);
        box-shadow: 0 5px 15px rgba(102, 126, 234, 0.4);
    }

    .error {
        color: #e53e3e;
        background: #fed7d7;
        padding: 10px;
        border-radius: 6px;
        border-left: 4px solid #e53e3e;
    }

    .success {
        color: #38a169;
        background: #c6f6d5;
        padding: 10px;
        border-radius: 6px;
        border-left: 4px solid #38a169;
    }
</style>
</head>

🎯 Template Editor

# {{ network.name }} Configuration <h2 id="user-content-devices" dir="auto">Devices</h2> <p dir="auto">{% for device in network.devices -%}</p> <ul dir="auto"> <li><strong>{{ device.name }}</strong> ({{ device.type }}) <ul dir="auto"> <li>Management IP: {{ device.mgmt_ip }}</li> <li>Role: {{ device.role | default('Unknown') }} {% if device.interfaces -%}</li> <li>Interfaces: {% for intf in device.interfaces -%} <ul dir="auto"> <li>{{ intf.name }}: {{ intf.description | default('No description') }} {% endfor %} {% endif %} {% endfor %}</li> </ul> </li> </ul> </li> </ul> <h2 id="user-content-vlan-summary" dir="auto">VLAN Summary</h2> <p dir="auto">{% set vlans = network.devices | selectattr('vlans', 'defined') | map(attribute='vlans') | list | flatten | unique | sort %} {% if vlans %} Active VLANs: {{ vlans | join(', ') }} {% else %} No VLANs configured {% endif %} 🚀 Render Template

    <div class="panel">
        <h2>📊 Data (YAML/JSON)</h2>
        <textarea id="data" placeholder="Enter your YAML or JSON data here...">

network: name: "DataVox Core Network" environment: "production" devices: - name: "Core-SW-01" type: "Cisco Nexus 9000" mgmt_ip: "10.0.1.10" role: "Core Switch" vlans: [10, 20, 30, 100] interfaces: - name: "Eth1/1" description: "Uplink to Firewall" - name: "Eth1/2" description: "Backup uplink" - name: "FW-01" type: "Palo Alto PA-3400" mgmt_ip: "10.0.1.1" role: "Perimeter Firewall" vlans: [100] - name: "Access-SW-01" type: "Cisco Catalyst 9300" mgmt_ip: "10.0.1.20" role: "Access Switch" vlans: [10, 20]

Rendered output will appear here...

    <div class="examples">
        <div class="example-card" onclick="loadExample('network')">
            <h3>🌐 Network Configuration</h3>
            <p>Generate Cisco/Juniper configs from structured data with loops and conditionals.</p>
            <div class="example-code">interface {{ intf.name }}

description {{ intf.desc }} {% if intf.vlan %} switchport access vlan {{ intf.vlan }}{% endif %}

        <div class="example-card" onclick="loadExample('k8s')">
            <h3>☸️ Kubernetes Manifests</h3>
            <p>One template → multiple environment-specific YAML manifests.</p>
            <div class="example-code">apiVersion: apps/v1

kind: Deployment metadata: name: {{ app_name }}-{{ env }} spec: replicas: {{ replicas[env] }}

        <div class="example-card" onclick="loadExample('proposal')">
            <h3>📋 Sales Proposals</h3>
            <p>Auto-generate professional RFP responses with dynamic pricing.</p>
            <div class="example-code"># {{ customer.name }} Proposal

Total: ${{ bom | sum(attribute='cost') }} {% for item in bom %}

  • {{ item.name }}: ${{ item.cost }}{% endfor %}

          <div class="example-card" onclick="loadExample('diagram')">
              <h3>🔀 Network Diagrams</h3>
              <p>Generate Mermaid/Graphviz diagrams from network topology data.</p>
              <div class="example-code">graph TD
    

{% for device in devices %} {{ device.name }}["{{ device.type }}"]{% endfor %} {% for link in links %} {{ link.src }} --> {{ link.dst }}{% endfor %}

        <div class="example-card" onclick="loadExample('security')">
            <h3>🔒 Security Policies</h3>
            <p>Template firewall rules and compliance checks across environments.</p>
            <div class="example-code">{% for rule in acl_rules %}

{{ rule.action }} {{ rule.protocol }} {{ rule.src }} {{ rule.dst }} {% endfor %}

        <div class="example-card" onclick="loadExample('advanced')">
            <h3>⚡ Advanced Patterns</h3>
            <p>Macros, inheritance, custom filters, and complex data transformations.</p>
            <div class="example-code">{% macro render_vlan(vlan) %}

vlan {{ vlan.id }} name {{ vlan.name }} {% endmacro %}

<script>
    // Simple YAML parser for demo purposes
    function parseYAML(yamlStr) {
        try {
            // This is a very basic YAML parser - in production use js-yaml
            const lines = yamlStr.split('\n').filter(line => line.trim() && !line.trim().startsWith('#'));
            const result = {};
            let currentObj = result;
            let objStack = [result];
            let keyStack = [];
            
            for (let line of lines) {
                const indent = line.length - line.trimLeft().length;
                const trimmed = line.trim();
                
                if (trimmed.includes(':')) {
                    const [key, ...valueParts] = trimmed.split(':');
                    const value = valueParts.join(':').trim();
                    
                    // Adjust stack based on indentation
                    while (keyStack.length > 0 && indent <= keyStack[keyStack.length - 1].indent) {
                        keyStack.pop();
                        objStack.pop();
                    }
                    
                    currentObj = objStack[objStack.length - 1];
                    
                    if (value === '' || value === null) {
                        // This is an object
                        currentObj[key.trim()] = {};
                        objStack.push(currentObj[key.trim()]);
                        keyStack.push({key: key.trim(), indent: indent});
                    } else if (value.startsWith('[') && value.endsWith(']')) {
                        // This is an array
                        try {
                            currentObj[key.trim()] = JSON.parse(value);
                        } catch {
                            currentObj[key.trim()] = value.slice(1, -1).split(',').map(v => v.trim());
                        }
                    } else {
                        // This is a simple value
                        let parsedValue = value;
                        if (value === 'true') parsedValue = true;
                        else if (value === 'false') parsedValue = false;
                        else if (!isNaN(value) && value !== '') parsedValue = Number(value);
                        else if (value.startsWith('"') && value.endsWith('"')) parsedValue = value.slice(1, -1);
                        
                        currentObj[key.trim()] = parsedValue;
                    }
                } else if (trimmed.startsWith('- ')) {
                    // Handle array items
                    const parentKey = keyStack[keyStack.length - 1]?.key;
                    if (parentKey && currentObj[parentKey]) {
                        if (!Array.isArray(currentObj[parentKey])) {
                            currentObj[parentKey] = [];
                        }
                        
                        const item = trimmed.slice(2).trim();
                        if (item.includes(':')) {
                            const itemObj = {};
                            const [itemKey, itemValue] = item.split(':');
                            itemObj[itemKey.trim()] = itemValue.trim() || '';
                            currentObj[parentKey].push(itemObj);
                        } else {
                            currentObj[parentKey].push(item);
                        }
                    }
                }
            }
            
            return result;
        } catch (e) {
            console.error('YAML parsing error:', e);
            return {};
        }
    }

    // Simple Jinja2-like template renderer
    function renderJinja2Template(template, data) {
        let result = template;
        
        // Handle variable substitutions {{ var }}
        result = result.replace(/\{\{\s*([^}]+)\s*\}\}/g, (match, expr) => {
            try {
                const parts = expr.split('.');
                let value = data;
                for (let part of parts) {
                    part = part.trim();
                    if (part.includes('|')) {
                        const [key, ...filters] = part.split('|');
                        value = value[key.trim()];
                        
                        for (let filter of filters) {
                            filter = filter.trim();
                            if (filter === 'default("Unknown")' || filter === "default('Unknown')") {
                                value = value || 'Unknown';
                            } else if (filter.startsWith('default(')) {
                                const defaultValue = filter.match(/default\(['"](.+)['"]\)/)?.[1] || '';
                                value = value || defaultValue;
                            } else if (filter === 'join(", ")' || filter === "join(', ')") {
                                value = Array.isArray(value) ? value.join(', ') : value;
                            } else if (filter.startsWith('join(')) {
                                const separator = filter.match(/join\(['"](.+)['"]\)/)?.[1] || '';
                                value = Array.isArray(value) ? value.join(separator) : value;
                            }
                        }
                    } else {
                        value = value?.[part];
                    }
                }
                return value !== undefined ? value : '';
            } catch (e) {
                return match;
            }
        });
        
        // Handle for loops {% for item in items %}
        result = result.replace(/\{%\s*for\s+(\w+)\s+in\s+([\w.]+)\s*-%?\s*%\}([\s\S]*?)\{%\s*endfor\s*%\}/g, (match, itemVar, arrayExpr, loopContent) => {
            try {
                const parts = arrayExpr.split('.');
                let array = data;
                for (let part of parts) {
                    array = array[part];
                }
                
                if (!Array.isArray(array)) return '';
                
                return array.map((item, index) => {
                    let content = loopContent;
                    content = content.replace(new RegExp(`\\{\\{\\s*${itemVar}\\.(\\w+)\\s*\\}\\}`, 'g'), (m, prop) => {
                        return item[prop] || '';
                    });
                    content = content.replace(new RegExp(`\\{\\{\\s*${itemVar}\\s*\\}\\}`, 'g'), item);
                    return content;
                }).join('');
            } catch (e) {
                return match;
            }
        });
        
        // Handle if conditions {% if condition %}
        result = result.replace(/\{%\s*if\s+([^%]+)\s*-%?\s*%\}([\s\S]*?)(?:\{%\s*else\s*-%?\s*%\}([\s\S]*?))?\{%\s*endif\s*%\}/g, (match, condition, ifContent, elseContent = '') => {
            try {
                let conditionResult = false;
                
                if (condition.includes('.')) {
                    const parts = condition.trim().split('.');
                    let value = data;
                    for (let part of parts) {
                        value = value?.[part];
                    }
                    conditionResult = !!value;
                }
                
                return conditionResult ? ifContent : elseContent;
            } catch (e) {
                return ifContent;
            }
        });
        
        // Handle set statements {% set var = expression %}
        result = result.replace(/\{%\s*set\s+(\w+)\s*=\s*([^%]+)\s*%\}/g, (match, varName, expr) => {
            // For demo purposes, just remove set statements
            return '';
        });
        
        // Clean up extra whitespace
        result = result.replace(/\n\s*\n\s*\n/g, '\n\n');
        
        return result;
    }

    function renderTemplate() {
        const template = document.getElementById('template').value;
        const dataStr = document.getElementById('data').value;
        const output = document.getElementById('output');
        
        try {
            let data;
            if (dataStr.trim().startsWith('{')) {
                data = JSON.parse(dataStr);
            } else {
                data = parseYAML(dataStr);
            }
            
            const rendered = renderJinja2Template(template, data);
            output.innerHTML = `<div class="success">✅ Template rendered successfully!</div>\n${rendered}`;
        } catch (error) {
            output.innerHTML = `<div class="error">❌ Error: ${error.message}</div>`;
        }
    }

    function loadExample(type) {
        const examples = {
            network: {
                template: `! {{ device.name }} Configuration

hostname {{ device.name }}

{% for interface in device.interfaces -%} interface {{ interface.name }} description {{ interface.description | default("No description") }} {% if interface.ip -%} ip address {{ interface.ip }} {{ interface.mask }} no shutdown {% endif %} {% if interface.vlan -%} switchport access vlan {{ interface.vlan }} {% endif %} {% endfor %}

! VLAN Configuration {% for vlan in device.vlans -%} vlan {{ vlan }} {% endfor %}, data: device: name: "SW-CORE-01" type: "Cisco Catalyst 9000" interfaces: - name: "GigabitEthernet1/0/1" description: "Uplink to Core" ip: "192.168.1.1" mask: "255.255.255.0" - name: "GigabitEthernet1/0/2" description: "Server Connection" vlan: 100 vlans: [10, 20, 30, 100]}, k8s: { template:apiVersion: apps/v1 kind: Deployment metadata: name: {{ app_name }}-{{ environment }} labels: app: {{ app_name }} env: {{ environment }} spec: replicas: {{ replicas[environment] }} selector: matchLabels: app: {{ app_name }} template: metadata: labels: app: {{ app_name }} env: {{ environment }} spec: containers: - name: {{ app_name }} image: {{ registry }}/{{ app_name }}:{{ tag }} ports: - containerPort: {{ port }} env: {% for key, value in env_vars.items() -%} - name: {{ key }} value: "{{ value }}" {% endfor %} resources: requests: memory: "{{ resources[environment].memory }}" cpu: "{{ resources[environment].cpu }}", data: app_name: "web-api" environment: "production" registry: "docker.io/datavox" tag: "v1.2.3" port: 8080 replicas: development: 1 staging: 2 production: 5 env_vars: DATABASE_URL: "postgresql://prod-db:5432/app" REDIS_URL: "redis://prod-cache:6379" resources: development: memory: "256Mi" cpu: "100m" staging: memory: "512Mi" cpu: "250m" production: memory: "1Gi" cpu: "500m"}, proposal: { template:# {{ customer.name }} Network Modernization Proposal

Executive Summary

Thank you for the opportunity to present DataVox's comprehensive network solution for {{ customer.name }}. Based on your requirements for {{ customer.locations }} locations, we propose the following architecture.

{% for solution in solutions -%}

{{ solution.name }}

  • Technology: {{ solution.technology }}
  • Benefit: {{ solution.benefit }}
  • Investment: ${{ solution.cost }} {% endfor %}

Bill of Materials

Item Quantity Unit Price Extended
{% for item in bom -%}
{{ item.description }} {{ item.qty }} ${{ item.unit_price }} ${{ item.qty * item.unit_price }}
{% endfor %}
TOTAL **${{ bom

Implementation Timeline

{% for phase in timeline -%}

  • {{ phase.name }}: {{ phase.duration }} ({{ phase.description }}) {% endfor %}

Why DataVox?

With over 15 years of network architecture expertise, DataVox delivers enterprise-grade solutions that scale with your business., data: customer: name: "Acme Corporation" locations: 12 industry: "Manufacturing"

solutions:

  • name: "SD-WAN Implementation" technology: "Cisco Viptela" benefit: "40% reduction in WAN costs" cost: 125000
  • name: "Network Security" technology: "Palo Alto NGFW" benefit: "Enterprise-grade threat protection" cost: 85000

bom:

  • description: "Cisco vEdge 1000 (x12)" qty: 12 unit_price: 2500 total: 30000
  • description: "PA-440 Firewall (x3)" qty: 3 unit_price: 3200 total: 9600
  • description: "Professional Services" qty: 1 unit_price: 45000 total: 45000

timeline:

  • name: "Phase 1 - Design" duration: "2 weeks" description: "Network assessment and detailed design"
  • name: "Phase 2 - Deployment" duration: "6 weeks" description: "Equipment installation and configuration"
  • name: "Phase 3 - Cutover" duration: "2 weeks" description: "Migration and testing"}, diagram: { template:# {{ network.name }} Topology

```mermaid graph TD {% for device in network.devices -%} {{ device.name }}["{{ device.type }}
{{ device.ip }}"] {% endfor %}

{% for connection in network.connections -%}
{{ connection.from }} -->|{{ connection.type }}| {{ connection.to }}
{% endfor %}

```

Device Details

{% for device in network.devices -%}

{{ device.name }}

  • Type: {{ device.type }}
  • Management IP: {{ device.ip }}
  • Role: {{ device.role }} {% if device.vlans -%}
  • VLANs: {{ device.vlans | join(', ') }} {% endif %}

{% endfor %}, data: network: name: "DataVox Core Infrastructure" devices: - name: "CORE-SW-01" type: "Cisco Nexus 9300" ip: "10.0.1.10" role: "Core Switch" vlans: [10, 20, 30, 100] - name: "FW-01" type: "Palo Alto PA-5220" ip: "10.0.1.1" role: "Perimeter Firewall" - name: "RTR-01" type: "Cisco ISR 4000" ip: "10.0.1.5" role: "WAN Router" - name: "ACCESS-SW-01" type: "Cisco Catalyst 9200" ip: "10.0.2.10" role: "Access Switch" vlans: [10, 20] connections: - from: "RTR-01" to: "FW-01" type: "1Gbps" - from: "FW-01" to: "CORE-SW-01" type: "10Gbps" - from: "CORE-SW-01" to: "ACCESS-SW-01" type: "1Gbps"}, security: { template:! Security Policy Configuration for {{ environment }} ! Generated on {{ timestamp }}

{% for policy in security_policies -%} ! {{ policy.name }} {% for rule in policy.rules -%} access-list {{ policy.acl_number }} {{ rule.action }} {{ rule.protocol }} {{ rule.source }} {{ rule.destination }}{% if rule.port %} eq {{ rule.port }}{% endif %} {% endfor %}

{% endfor %}

! Interface Application {% for interface in interfaces -%} interface {{ interface.name }} ip access-group {{ interface.acl }} {{ interface.direction }} {% endfor %}

! Logging Configuration logging {{ logging.server }} logging facility {{ logging.facility }} logging trap {{ logging.level }}, data: environment: "production" timestamp: "2024-01-15 10:30:00"

security_policies:

  • name: "Inbound Web Traffic" acl_number: 101 rules:
    • action: "permit" protocol: "tcp" source: "any" destination: "192.168.1.0 0.0.0.255" port: "80"
    • action: "permit" protocol: "tcp" source: "any" destination: "192.168.1.0 0.0.0.255" port: "443"
    • action: "deny" protocol: "ip" source: "any" destination: "any"
  • name: "Database Access" acl_number: 102 rules:
    • action: "permit" protocol: "tcp" source: "192.168.1.0 0.0.0.255" destination: "192.168.100.0 0.0.0.255" port: "3306"

interfaces:

  • name: "GigabitEthernet0/1" acl: 101 direction: "in"
  • name: "GigabitEthernet0/2" acl: 102 direction: "out"

logging: server: "10.0.1.100" facility: "local0" level: "informational"}, advanced: { template:{# Macro Definitions #} {% macro render_interface(interface, base_config={}) -%} interface {{ interface.name }} {% for key, value in base_config.items() -%} {{ key }} {{ value }} {% endfor -%} {% if interface.description -%} description {{ interface.description }} {% endif -%} {% if interface.ip -%} ip address {{ interface.ip }} {{ interface.netmask }} {% endif -%} {% if interface.vlan -%} switchport access vlan {{ interface.vlan }} {% endif -%} {% if interface.enabled -%} no shutdown {% else -%} shutdown {% endif -%} ! {%- endmacro %}

! {{ hostname }} Advanced Configuration hostname {{ hostname }}

! Standard interface configuration {% set base_interface_config = {"duplex": "full", "speed": "auto"} -%} {% for interface in interfaces -%} {{ render_interface(interface, base_interface_config) }} {% endfor %}

! VLAN Configuration with advanced logic {% set all_vlans = interfaces | selectattr('vlan', 'defined') | map(attribute='vlan') | list | unique | sort -%} {% if all_vlans -%} {% for vlan in all_vlans -%} vlan {{ vlan }} name VLAN_{{ vlan }} {% endfor -%} {% endif %}

! Conditional features {% if features.ospf -%} router ospf {{ features.ospf.process_id }} {% for network in features.ospf.networks -%} network {{ network.address }} {{ network.wildcard }} area {{ network.area }} {% endfor -%} {% endif %}

{% if features.snmp -%} snmp-server community {{ features.snmp.community }} {{ features.snmp.access }} snmp-server location {{ features.snmp.location }} snmp-server contact {{ features.snmp.contact }} {% endif %}, data: hostname: "ADVANCED-SW-01"

interfaces:

  • name: "FastEthernet0/1" description: "Server Connection" ip: "192.168.10.1" netmask: "255.255.255.0" vlan: 10 enabled: true
  • name: "FastEthernet0/2" description: "Uplink to Core" ip: "192.168.20.1" netmask: "255.255.255.0" vlan: 20 enabled: true
  • name: "FastEthernet0/3" description: "Management Interface" ip: "10.0.0.10" netmask: "255.255.255.0" enabled: false

features: ospf: process_id: 100 networks: - address: "192.168.10.0" wildcard: "0.0.0.255" area: 0 - address: "192.168.20.0" wildcard: "0.0.0.255" area: 0 snmp: community: "public" access: "ro" location: "DataCenter-A" contact: "netadmin@datavox.com"` } };

        const example = examples[type];
        if (example) {
            document.getElementById('template').value = example.template;
            document.getElementById('data').value = example.data;
            renderTemplate();
        }
    }
        network: {
            template: `! {{ device.name }} Configuration

hostname {{ device.name }}

{% for interface in device.interfaces -%} interface {{ interface.name }} description {{ interface.description | default("No description") }} {% if interface.ip -%} ip address {{ interface.ip }} {{ interface.mask }} no shutdown {% endif %} {% if interface.vlan -%} switchport access vlan {{ interface.vlan }} {% endif %} {% endfor %}

! VLAN Configuration {% for vlan in device.vlans -%} vlan {{ vlan }} {% endfor %}, data: device: name: "SW-CORE-01" type: "Cisco Catalyst 9000" interfaces: - name: "GigabitEthernet1/0/1" description: "Uplink to Core" ip: "192.168.1.1" mask: "255.255.255.0" - name: "GigabitEthernet1/0/2" description: "Server Connection" vlan: 100 vlans: [10, 20, 30, 100]}, k8s: { template:apiVersion: apps/v1 kind: Deployment metadata: name: {{ app_name }}-{{ environment }} labels: app: {{ app_name }} env: {{ environment }} spec: replicas: {{ replicas[environment] }} selector: matchLabels: app: {{ app_name }} template: metadata: labels: app: {{ app_name }} env: {{ environment }} spec: containers: - name: {{ app_name }} image: {{ registry }}/{{ app_name }}:{{ tag }} ports: - containerPort: {{ port }} env: {% for key, value in env_vars.items() -%} - name: {{ key }} value: "{{ value }}" {% endfor %} resources: requests: memory: "{{ resources[environment].memory }}" cpu: "{{ resources[environment].cpu }}", data: app_name: "web-api" environment: "production" registry: "docker.io/datavox" tag: "v1.2.3" port: 8080 replicas: development: 1 staging: 2 production: 5 env_vars: DATABASE_URL: "postgresql://prod-db:5432/app" REDIS_URL: "redis://prod-cache:6379" resources: development: memory: "256Mi" cpu: "100m" staging: memory: "512Mi" cpu: "250m" production: memory: "1Gi" cpu: "500m"}, proposal: { template:# {{ customer.name }} Network Modernization Proposal

Executive Summary

Thank you for the opportunity to present DataVox's comprehensive network solution for {{ customer.name }}. Based on your requirements for {{ customer.locations }} locations, we propose the following architecture.

{% for solution in solutions -%}

{{ solution.name }}

  • Technology: {{ solution.technology }}
  • Benefit: {{ solution.benefit }}
  • Investment: ${{ solution.cost }} {% endfor %}

Bill of Materials

Item Quantity Unit Price Extended
{% for item in bom -%}
{{ item.description }} {{ item.qty }} ${{ item.unit_price }} ${{ item.qty * item.unit_price }}
{% endfor %}
TOTAL **${{ bom

Implementation Timeline

{% for phase in timeline -%}

  • {{ phase.name }}: {{ phase.duration }} ({{ phase.description }}) {% endfor %}

Why DataVox?

With over 15 years of network architecture expertise, DataVox delivers enterprise-grade solutions that scale with your business., data: customer: name: "Acme Corporation" locations: 12 industry: "Manufacturing"

solutions:

  • name: "SD-WAN Implementation" technology: "Cisco Viptela" benefit: "40% reduction in WAN costs" cost: 125000
  • name: "Network Security" technology: "Palo Alto NGFW" benefit: "Enterprise-grade threat protection" cost: 85000

bom:

  • description: "Cisco vEdge 1000 (x12)" qty: 12 unit_price: 2500 total: 30000
  • description: "PA-440 Firewall (x3)" qty: 3 unit_price: 3200 total: 9600
  • description: "Professional Services" qty: 1 unit_price: 45000 total: 45000

timeline:

  • name: "Phase 1 - Design" duration: "2 weeks" description: "Network assessment and detailed design"
  • name: "Phase 2 - Deployment" duration: "6 weeks" description: "Equipment installation and configuration"
  • name: "Phase 3 - Cutover" duration: "2 weeks" description: "Migration and testing"}, diagram: { template:# {{ network.name }} Topology

```mermaid graph TD {% for device in network.devices -%} {{ device.name }}["{{ device.type }}
{{ device.ip }}"] {% endfor %}

{% for connection in network.connections -%}
{{ connection.from }} -->|{{ connection.type }}| {{ connection.to }}
{% endfor %}

```

Device Details

{% for device in network.devices -%}

{{ device.name }}

  • Type: {{ device.type }}
  • Management IP: {{ device.ip }}
  • Role: {{ device.role }} {% if device.vlans -%}
  • VLANs: {{ device.vlans | join(', ') }} {% endif %}

{% endfor %}, data: network: name: "DataVox Core Infrastructure" devices: - name: "CORE-SW-01" type: "Cisco Nexus 9300" ip: "10.0.1.10" role: "Core Switch" vlans: [10, 20, 30, 100] - name: "FW-01" type: "Palo Alto PA-5220" ip: "10.0.1.1" role: "Perimeter Firewall" - name: "RTR-01" type: "Cisco ISR 4000" ip: "10.0.1.5" role: "WAN Router" - name: "ACCESS-SW-01" type: "Cisco Catalyst 9200" ip: "10.0.2.10" role: "Access Switch" vlans: [10, 20] connections: - from: "RTR-01" to: "FW-01" type: "1Gbps" - from: "FW-01" to: "CORE-SW-01" type: "10Gbps" - from: "CORE-SW-01" to: "ACCESS-SW-01" type: "1Gbps"}, security: { template:! Security Policy Configuration for {{ environment }} ! Generated on {{ timestamp }}

{% for policy in security_policies -%} ! {{ policy.name }} {% for rule in policy.rules -%} access-list {{ policy.acl_number }} {{ rule.action }} {{ rule.protocol }} {{ rule.source }} {{ rule.destination }}{% if rule.port %} eq {{ rule.port }}{% endif %} {% endfor %}

{% endfor %}

! Interface Application {% for interface in interfaces -%} interface {{ interface.name }} ip access-group {{ interface.acl }} {{ interface.direction }} {% endfor %}

! Logging Configuration logging {{ logging.server }} logging facility {{ logging.facility }} logging trap {{ logging.level }}, data: environment: "production" timestamp: "2024-01-15 10:30:00"

security_policies:

  • name: "Inbound Web Traffic" acl_number: 101 rules:
    • action: "permit" protocol: "tcp" source: "any" destination: "192.168.1.0 0.0.0.255" port: "80"
    • action: "permit" protocol: "tcp" source: "any" destination: "192.168.1.0 0.0.0.255" port: "443"
    • action: "deny" protocol: "ip" source: "any" destination: "any"
  • name: "Database Access" acl_number: 102 rules:
    • action: "permit" protocol: "tcp" source: "192.168.1.0 0.0.0.255" destination: "192.168.100.0 0.0.0.255" port: "3306"

interfaces:

  • name: "GigabitEthernet0/1" acl: 101 direction: "in"
  • name: "GigabitEthernet0/2" acl: 102 direction: "out"

logging: server: "10.0.1.100" facility: "local0" level: "informational"}, advanced: { template:{# Macro Definitions #} {% macro render_interface(interface, base_config={}) -%} interface {{ interface.name }} {% for key, value in base_config.items() -%} {{ key }} {{ value }} {% endfor -%} {% if interface.description -%} description {{ interface.description }} {% endif -%} {% if interface.ip -%} ip address {{ interface.ip }} {{ interface.netmask }} {% endif -%} {% if interface.vlan -%} switchport access vlan {{ interface.vlan }} {% endif -%} {% if interface.enabled -%} no shutdown {% else -%} shutdown {% endif -%} ! {%- endmacro %}

! {{ hostname }} Advanced Configuration hostname {{ hostname }}

! Standard interface configuration {% set base_interface_config = {"duplex": "full", "speed": "auto"} -%} {% for interface in interfaces -%} {{ render_interface(interface, base_interface_config) }} {% endfor %}

! VLAN Configuration with advanced logic {% set all_vlans = interfaces | selectattr('vlan', 'defined') | map(attribute='vlan') | list | unique | sort -%} {% if all_vlans -%} {% for vlan in all_vlans -%} vlan {{ vlan }} name VLAN_{{ vlan }} {% endfor -%} {% endif %}

! Conditional features {% if features.ospf -%} router ospf {{ features.ospf.process_id }} {% for network in features.ospf.networks -%} network {{ network.address }} {{ network.wildcard }} area {{ network.area }} {% endfor -%} {% endif %}

{% if features.snmp -%} snmp-server community {{ features.snmp.community }} {{ features.snmp.access }} snmp-server location {{ features.snmp.location }} snmp-server contact {{ features.snmp.contact }} {% endif %}, data: hostname: "ADVANCED-SW-01"

interfaces:

  • name: "FastEthernet0/2" description: "Uplink to Core" ip: "192.168.20.1" netmask: "255.255.255.0" vlan: 20 enabled: true
  • name: "FastEthernet0/3" description: "Management Interface" ip: "10.0.0.10" netmask: "255.255.255.0" enabled: false

features: ospf: process_id: 100 networks: - address: "192.168.10.0" wildcard: "0.0.0.255" area: 0 - address: "192.168.20.0" wildcard: "0.0.0.255" area: 0 snmp: community: "public" access: "ro" location: "DataCenter-A" contact: "netadmin@datavox.com"`/1" description: "Server Connection" ip: "192.168.10.1" netmask: "255.255.255.0" vlan: 10 enabled: true

  • name: "FastEthernet0