Files
the_information_nexus/tech_docs/jinja2_project.md

1656 lines
49 KiB
Markdown

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**
```python
# 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**
```bash
# Network-specific tools
pip install netmiko nornir napalm textfsm
pip install ipaddress netaddr
```
**Power Combo Example:**
```python
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**
```bash
# Documentation tools
pip install mkdocs mkdocs-material
pip install graphviz plotly mermaid-cli
npm install -g @mermaid-js/mermaid-cli # For diagram generation
```
**Workflow:**
```python
# 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**
```bash
# Document generation
pip install python-docx reportlab pandoc
```
**Pro Tip:**
```python
# 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**
```bash
# Cloud automation
pip install boto3 azure-identity google-cloud-storage
pip install kubernetes docker-py
```
**Multi-Cloud Template Example:**
```jinja2
{# 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**
```bash
# Pipeline tools
pip install github3.py python-gitlab
pip install pre-commit black flake8
```
**GitHub Actions Integration:**
```yaml
# .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**
```python
# 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**
```bash
pip install pytest jsonschema yamale
```
**Template Testing:**
```python
# 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**
```python
# 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**
```bash
pip install prometheus_client grafana-api
pip install loguru structlog
```
**Template Metrics:**
```python
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**
```bash
# Essential CLI tools
pip install jinja2-cli j2cli cookiecutter
npm install -g js-yaml # YAML validation
```
**Quick CLI Usage:**
```bash
# 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**
```bash
# Core tools only
pip install jinja2 pyyaml click rich
git clone https://github.com/your-templates/network-templates
```
### **Month 2: Specialization**
```bash
# 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**
```bash
# 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**
```python
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**
```jinja2
{# 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**
```python
# 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**
```yaml
# .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**
```jinja2
{# 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.
---
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Jinja2 Mastery Playground</title>
<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>
<body>
<div class="container">
<div class="panel">
<h2>🎯 Template Editor</h2>
<textarea id="template" placeholder="Enter your Jinja2 template here...">
# {{ network.name }} Configuration
## Devices
{% for device in network.devices -%}
- **{{ device.name }}** ({{ device.type }})
- Management IP: {{ device.mgmt_ip }}
- Role: {{ device.role | default('Unknown') }}
{% if device.interfaces -%}
- Interfaces:
{% for intf in device.interfaces -%}
- {{ intf.name }}: {{ intf.description | default('No description') }}
{% endfor %}
{% endif %}
{% endfor %}
## VLAN Summary
{% 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 %}
</textarea>
<button onclick="renderTemplate()">🚀 Render Template</button>
</div>
<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]
</textarea>
<div class="output" id="output">Rendered output will appear here...</div>
</div>
<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>
</div>
<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>
</div>
<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>
</div>
<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>
</div>
<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>
</div>
<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 %}</div>
</div>
</div>
</div>
<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.
## Recommended Solution
{% 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 | sum(attribute='total') }}** |
## 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 }}<br/>{{ 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.
## Recommended Solution
{% 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 | sum(attribute='total') }}** |
## 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 }}<br/>{{ 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