Skip to content

Latest commit

 

History

History
272 lines (202 loc) · 6.86 KB

File metadata and controls

272 lines (202 loc) · 6.86 KB

YAML Template Conventions

This document describes conventions for Tera templates that generate YAML files in the Torrust Tracker Deployer project.

See Also: For general Tera template syntax, see Tera Template Guide. For architectural details, see Template System Architecture.

📋 Header Placement Convention

CRITICAL: For YAML templates (both .yml.tera and static .yml files), the AI-discoverable documentation header MUST be placed BEFORE the --- YAML document marker.

✅ Correct Header Placement

# ============================================================================
# Torrust Tracker Deployer - Generated Configuration
# ============================================================================
#
# This file was generated by the Torrust Tracker Deployer.
# Generated at: {{ generated_at }}
#
# DOCUMENTATION:
#   Repository:    https://github.com/torrust/torrust-tracker-deployer
#   Template:      templates/ansible/variables.yml.tera
#   Rust Wrapper:  src/infrastructure/templating/ansible/template/wrappers/variables/context.rs
#   API Docs:      https://docs.rs/torrust-tracker-deployer/latest/
#
# DESCRIPTION:
#   Centralized Ansible variables used across playbooks for system configuration.
#
# For configuration options and valid values, see the API documentation link above.
# ============================================================================

---
# YAML content starts here
variable_name: { { value } }

❌ Incorrect Header Placement

---
# ❌ WRONG - Header after the document marker
# ============================================================================
# Torrust Tracker Deployer - Generated Configuration
# ============================================================================

📝 Rationale

The --- marker in YAML indicates the start of a YAML document. The header contains metadata about the file (repository links, generation info, documentation), not YAML content. Therefore:

  1. Header = Metadata → Comes first
  2. --- = Document Start → Comes after metadata
  3. YAML Content → Comes after document marker

This convention ensures:

  • Clear separation between metadata and content
  • Consistency across all YAML templates (dynamic .tera and static)
  • Proper YAML document structure
  • AI agents can discover documentation before parsing YAML

📂 Files Following This Convention

Dynamic Templates (.yml.tera):

  • templates/ansible/variables.yml.tera
  • templates/ansible/inventory.yml.tera
  • templates/grafana/provisioning/datasources/prometheus.yml.tera
  • templates/prometheus/prometheus.yml.tera
  • templates/tofu/common/cloud-init.yml.tera

Static Templates (.yml):

  • templates/ansible/configure-firewall.yml
  • templates/ansible/configure-security-updates.yml
  • templates/ansible/create-grafana-storage.yml
  • And all other Ansible playbooks...

🎯 YAML-Specific Tera Patterns

Control Flow with Whitespace Control

When using Tera control flow in YAML templates, use {%- to prevent inserting extra blank lines:

# ✅ GOOD - No extra blank lines
services:
{%- if mysql_enabled %}
  mysql:
    image: mysql:8.0
{%- endif %}
{%- if grafana_enabled %}
  grafana:
    image: grafana/grafana:latest
{%- endif %}
# ❌ BAD - Creates blank lines between services
services:
{% if mysql_enabled %}
  mysql:
    image: mysql:8.0
{% endif %}
{% if grafana_enabled %}
  grafana:
    image: grafana/grafana:latest
{% endif %}

Result of bad approach:

services:
  mysql:
    image: mysql:8.0

  grafana:
    image: grafana/grafana:latest

Conditional Indentation

YAML is indentation-sensitive. When using conditionals, ensure proper indentation:

# ✅ CORRECT - Maintains proper YAML indentation
networks:
{%- if database_enabled %}
  db_network:
    driver: bridge
{%- endif %}
{%- if metrics_enabled %}
  metrics_network:
    driver: bridge
{%- endif %}

List Items with Templates

When generating YAML lists with Tera:

# ✅ CORRECT - Consistent list formatting
hosts:
{%- for host in inventory_hosts %}
  - name: {{ host.name }}
    address: {{ host.ip }}
{%- endfor %}

Multi-line Strings

YAML supports multi-line strings. Be careful with Tera variable placement:

# ✅ CORRECT - Preserves YAML multi-line syntax
description: |
  {{ service_description }}

  Additional context goes here.

# ✅ CORRECT - Folded scalar
summary: >
  {{ short_summary }}
  continues on next line

🔍 Common Pitfalls

Pitfall 1: Wrong Document Marker Placement

# ❌ WRONG
---
# Header comments after document marker

Fix: Move header before ---

Pitfall 2: Extra Blank Lines from Control Flow

# ❌ WRONG
{% if condition %}
  key: value
{% endif %}

Fix: Use {%- and -%} for whitespace control

Pitfall 3: Breaking YAML Indentation

# ❌ WRONG - Incorrect indentation
parent:
{% if condition %}
child: value
{% endif %}

Fix: Maintain consistent indentation inside control blocks

Pitfall 4: Unquoted Special Characters

# ❌ RISKY - May break if variable contains YAML special chars
description: {{ user_description }}

# ✅ SAFER - Quote the value
description: "{{ user_description }}"

📚 Best Practices

1. Validate Rendered Output

Always check the rendered YAML in the build/ directory:

# Check rendered Ansible variables
cat build/your-env/ansible/variables.yml

# Validate YAML syntax
yamllint build/your-env/ansible/variables.yml

2. Use Comments for User Guidance

Add comments to explain configuration options:

# Set to true when ANY HTTP tracker uses Caddy TLS termination
caddy_enabled: { { caddy_enabled } }

# HTTP tracker external port (must match your Caddy configuration)
http_tracker_port: { { http_tracker_port } }

3. Group Related Configuration

Organize YAML content logically:

# Database Configuration
mysql_enabled: { { mysql_enabled } }
mysql_root_password: "{{ mysql_root_password }}"

# Monitoring Configuration
prometheus_enabled: { { prometheus_enabled } }
grafana_enabled: { { grafana_enabled } }

4. Whitespace Control Strategy

  • Use {%- at start of control flow to trim preceding whitespace
  • Use -%} at end only when needed to prevent trailing blank lines
  • Test rendered output to ensure no extra blank lines

🔗 Related Documentation

📖 External References