1656 lines
49 KiB
Markdown
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 |