354 lines
9.6 KiB
Markdown
Raw Normal View History

# Templates
Jinja2 and Nickel templates for configuration and deployment generation.
## Purpose
Templates provide:
- **Nickel output generation** - Jinja2 templates for TypeDialog nickel-roundtrip
- **Docker Compose generation** - Infrastructure-as-code for containerized deployment
- **Kubernetes manifests** - Declarative deployment manifests
- **TOML export** - Service configuration generation for Rust codebase
## File Organization
```
templates/
├── README.md # This file
├── orchestrator-config.ncl.j2 # Nickel output template (Jinja2)
├── control-center-config.ncl.j2 # Nickel output template (Jinja2)
├── mcp-server-config.ncl.j2 # Nickel output template (Jinja2)
├── installer-config.ncl.j2 # Nickel output template (Jinja2)
├── docker-compose/ # Docker Compose templates
│ ├── platform-stack.solo.yml.ncl
│ ├── platform-stack.multiuser.yml.ncl
│ ├── platform-stack.cicd.yml.ncl
│ └── platform-stack.enterprise.yml.ncl
├── kubernetes/ # Kubernetes templates
│ ├── orchestrator-deployment.yaml.ncl
│ ├── orchestrator-service.yaml.ncl
│ ├── control-center-deployment.yaml.ncl
│ ├── control-center-service.yaml.ncl
│ └── platform-ingress.yaml.ncl
└── configs/ # Service config templates (optional)
├── orchestrator-config.toml.ncl
├── control-center-config.toml.ncl
└── mcp-server-config.toml.ncl
```
## Jinja2 Config Templates
**Critical for TypeDialog nickel-roundtrip workflow**:
```bash
typedialog-web nickel-roundtrip "$CONFIG" "forms/{service}-form.toml" --output "$CONFIG" --template "templates/{service}-config.ncl.j2"
```
### Template Pattern: orchestrator-config.ncl.j2
```nickel
# Orchestrator Configuration - Nickel Format
# Auto-generated by provisioning TypeDialog
# Edit via: nu scripts/configure.nu orchestrator {mode}
{
orchestrator = {
# Workspace Configuration
workspace = {
{%- if workspace_name %}
name = "{{ workspace_name }}",
{%- endif %}
{%- if workspace_path %}
path = "{{ workspace_path }}",
{%- endif %}
{%- if workspace_enabled is defined %}
enabled = {{ workspace_enabled | lower }},
{%- endif %}
{%- if multi_workspace is defined %}
multi_workspace = {{ multi_workspace | lower }},
{%- endif %}
},
# Server Configuration
server = {
{%- if server_host %}
host = "{{ server_host }}",
{%- endif %}
{%- if server_port %}
port = {{ server_port }},
{%- endif %}
{%- if server_workers %}
workers = {{ server_workers }},
{%- endif %}
{%- if server_keep_alive %}
keep_alive = {{ server_keep_alive }},
{%- endif %}
},
# Storage Configuration
storage = {
{%- if storage_backend %}
backend = '{{ storage_backend }},
{%- endif %}
{%- if storage_path %}
path = "{{ storage_path }}",
{%- endif %}
{%- if surrealdb_url %}
surrealdb_url = "{{ surrealdb_url }}",
{%- endif %}
},
# Queue Configuration
queue = {
{%- if max_concurrent_tasks %}
max_concurrent_tasks = {{ max_concurrent_tasks }},
{%- endif %}
{%- if retry_attempts %}
retry_attempts = {{ retry_attempts }},
{%- endif %}
{%- if retry_delay %}
retry_delay = {{ retry_delay }},
{%- endif %}
{%- if task_timeout %}
task_timeout = {{ task_timeout }},
{%- endif %}
},
# Monitoring Configuration (optional)
{%- if enable_monitoring is defined and enable_monitoring %}
monitoring = {
enabled = true,
{%- if metrics_interval %}
metrics_interval = {{ metrics_interval }},
{%- endif %}
{%- if health_check_interval %}
health_check_interval = {{ health_check_interval }},
{%- endif %}
},
{%- endif %}
},
}
```
### Key Jinja2 Patterns
**Conditional blocks** (only include if field is set):
```nickel
{%- if workspace_name %}
name = "{{ workspace_name }}",
{%- endif %}
```
**String values** (with quotes):
```nickel
{%- if storage_backend %}
backend = '{{ storage_backend }}, # Enum (atom syntax)
{%- endif %}
```
**Numeric values** (no quotes):
```nickel
{%- if server_port %}
port = {{ server_port }}, # Number
{%- endif %}
```
**Boolean values** (lower case):
```nickel
{%- if workspace_enabled is defined %}
enabled = {{ workspace_enabled | lower }}, # Boolean (true/false)
{%- endif %}
```
**Comments** (for generated files):
```nickel
# Auto-generated by provisioning TypeDialog
# Edit via: nu scripts/configure.nu orchestrator {mode}
```
## Docker Compose Templates
Nickel templates that import from `values/*.ncl`:
```nickel
# templates/docker-compose/platform-stack.solo.yml.ncl
# Docker Compose Platform Stack - Solo Mode
# Imports config from values/orchestrator.solo.ncl
let orchestrator_config = import "../../values/orchestrator.solo.ncl" in
let control_center_config = import "../../values/control-center.solo.ncl" in
{
version = "3.8",
services = {
orchestrator = {
image = "provisioning-orchestrator:latest",
container_name = "orchestrator",
ports = [
"%{std.to_string orchestrator_config.orchestrator.server.port}:9090",
],
environment = {
ORCHESTRATOR_SERVER_HOST = orchestrator_config.orchestrator.server.host,
ORCHESTRATOR_SERVER_PORT = std.to_string orchestrator_config.orchestrator.server.port,
ORCHESTRATOR_STORAGE_BACKEND = orchestrator_config.orchestrator.storage.backend,
},
volumes = [
"./data/orchestrator:%{orchestrator_config.orchestrator.storage.path}",
],
restart = "unless-stopped",
},
control-center = {
image = "provisioning-control-center:latest",
container_name = "control-center",
ports = [
"%{std.to_string control_center_config.control_center.server.port}:8080",
],
environment = {
CONTROL_CENTER_SERVER_HOST = control_center_config.control_center.server.host,
CONTROL_CENTER_SERVER_PORT = std.to_string control_center_config.control_center.server.port,
},
restart = "unless-stopped",
},
},
}
```
### Rendering Docker Compose
```bash
# Export Nickel template to YAML
nickel export --format json templates/docker-compose/platform-stack.solo.yml.ncl | yq -P > docker-compose.solo.yml
```
## Kubernetes Templates
Nickel templates for Kubernetes manifests:
```nickel
# templates/kubernetes/orchestrator-deployment.yaml.ncl
let config = import "../../values/orchestrator.solo.ncl" in
{
apiVersion = "apps/v1",
kind = "Deployment",
metadata = {
name = "orchestrator",
labels = {
app = "orchestrator",
},
},
spec = {
replicas = 1,
selector = {
matchLabels = {
app = "orchestrator",
},
},
template = {
metadata = {
labels = {
app = "orchestrator",
},
},
spec = {
containers = [
{
name = "orchestrator",
image = "provisioning-orchestrator:latest",
ports = [
{
containerPort = 9090,
},
],
env = [
{
name = "ORCHESTRATOR_SERVER_PORT",
value = std.to_string config.orchestrator.server.port,
},
{
name = "ORCHESTRATOR_STORAGE_BACKEND",
value = config.orchestrator.storage.backend,
},
],
volumeMounts = [
{
name = "data",
mountPath = config.orchestrator.storage.path,
},
],
},
],
volumes = [
{
name = "data",
persistentVolumeClaim = {
claimName = "orchestrator-pvc",
},
},
],
},
},
},
}
```
## Rendering Templates
### Render to JSON
```bash
nickel export --format json templates/orchestrator-config.ncl.j2 > config.json
```
### Render to YAML (via yq)
```bash
nickel export --format json templates/kubernetes/orchestrator-deployment.yaml.ncl | yq -P > deployment.yaml
```
### Render to TOML
```bash
nickel export --format toml templates/configs/orchestrator-config.toml.ncl > config.toml
```
## Template Variables
Variables in templates come from:
1. **Form values** (TypeDialog input)
2. **Imported configs** (Nickel imports)
3. **Constraint interpolation** (constraints.toml)
## Best Practices
1. **Use conditional blocks** - Only include fields if set
2. **Import configs** - Reuse Nickel configs in templates
3. **Type conversion** - Use `std.to_string` for numeric values
4. **Comments** - Explain generated/auto-edited markers
5. **Validation** - Use `nickel typecheck` to verify templates
6. **Environment variables** - Prefer env over hardcoding
## Template Testing
```bash
# Typecheck Jinja2 + Nickel template
nickel typecheck templates/orchestrator-config.ncl.j2
# Evaluate and view output
nickel eval templates/orchestrator-config.ncl.j2
# Export and validate output
nickel export --format json templates/orchestrator-config.ncl.j2 | jq '.'
```
## Adding a New Template
1. **Create template file** (`{service}-config.ncl.j2` or `{name}.yml.ncl`)
2. **Define structure** (Nickel or Jinja2)
3. **Import configs** (if Nickel)
4. **Use variables** (from forms or imports)
5. **Typecheck**: `nickel typecheck templates/{file}`
6. **Test rendering**: `nickel export {format} templates/{file}`
---
**Version**: 1.0.0
**Last Updated**: 2025-01-05