Update configuration files, templates, and internal documentation for the provisioning repository system. Configuration Updates: - KMS configuration modernization - Plugin system settings - Service port mappings - Test cluster topologies - Installation configuration examples - VM configuration defaults - Cedar authorization policies Documentation Updates: - Library module documentation - Extension API guides - AI system documentation - Service management guides - Test environment setup - Plugin usage guides - Validator configuration documentation All changes are backward compatible.
12 KiB
Configuration Templates
Purpose: Template files for generating workspace configurations
Template Extension Conventions
This project uses TWO template extensions for different purposes:
.template Extension (This Directory)
- Purpose: Workspace initialization only
- Engine: Simple string substitution (
{{variable}}) - Usage: One-time generation during workspace creation
- Dependency: None (no plugins required)
- Complexity: Low (no loops/conditionals needed)
Example:
workspace:
name: "{{workspace.name}}"
created: "{{now.iso}}"
When to use:
- Workspace initialization templates
- One-time setup files
- No dynamic logic needed
.j2 Extension (Rest of Codebase)
- Purpose: Runtime configuration generation
- Engine: Jinja2 (via
nu_plugin_tera) - Usage: Dynamic config rendering during operations
- Dependency: Requires
nu_plugin_teraplugin - Complexity: High (conditionals, loops, filters)
Example:
{%- if taskserv.mode == "ha" %}
REPLICAS={{taskserv.replicas}}
{%- endif %}
{% for node in cluster.nodes -%}
NODE_{{loop.index}}={{node.hostname}}
{% endfor %}
When to use:
- Runtime configuration generation
- Dynamic values from environment
- Complex logic (conditionals, loops)
Why Two Extensions?
-
Separation of Concerns: Init and runtime are fundamentally different operations
- Init happens once during workspace creation
- Runtime happens continuously during operations
-
No Plugin Dependency for Init: Workspace creation works without external plugins
- Simple string replacement is sufficient for initialization
nu_plugin_terais only needed for runtime rendering- Initialization is more portable and reliable
-
Semantic Clarity: Extension signals the purpose immediately
- Developers see
.templateand know: "This is for initialization" - Developers see
.j2and know: "This is for runtime rendering" - No ambiguity about usage context
- Developers see
-
Appropriate Complexity: Each extension matches its use case
- Init templates don't need loops/conditionals (simple substitution is enough)
- Runtime templates need full Jinja2 power (conditionals, loops, filters)
- Using the right tool for the job
Codebase Statistics
Template Distribution:
.j2templates: 134 files (88%) - Runtime generation.templatetemplates: 16 files (10%) - Workspace initialization.teratemplates: 3 files (2%) - Plugin examples
The two-tier system reflects the actual use case distribution in the codebase.
KCL Module Structure
Workspaces use a clear directory structure for KCL modules:
workspace/
├── config/
│ ├── kcl.mod # Workspace package, imports provisioning from ../.kcl
│ └── provisioning.k # Workspace-specific config overrides (SST pattern)
├── .provisioning/ # Metadata only
│ └── metadata.yaml # Workspace metadata and version info
└── .kcl/ # Main KCL package "provisioning"
├── kcl.mod # Package definition
├── workspace_config.k # Schema definitions (SST)
├── workspace_config_defaults.k # Default values (SST)
├── batch.k
├── cluster.k
└── ... other KCL modules
Directory Purposes
| Directory | Purpose | Contents |
|---|---|---|
.provisioning/ |
Metadata only | metadata.yaml - workspace versioning and compatibility |
.kcl/ |
KCL modules | All KCL configuration files and schemas |
config/ |
Workspace config | Runtime configuration files generated from templates |
SST Pattern (Single Source of Truth)
Workspace configuration follows the SST pattern:
- Schema (
.kcl/workspace_config.k) - Type-safe schema definitions - Defaults (
.kcl/workspace_config_defaults.k) - Base default values - Overrides (
config/provisioning.k) - Workspace-specific customizations
Never edit .provisioning/workspace_config.k or .provisioning/workspace_config_defaults.k - they are copies only.
Always edit in .kcl/ directory instead.
Important
These files are TEMPLATES ONLY. They are NEVER loaded at runtime.
The provisioning system generates workspace configurations from these templates during workspace initialization. Once generated, the workspace uses its own config/provisioning.yaml and related configs.
Available Templates
1. workspace-provisioning.yaml.template
Main workspace configuration template. Generates: {workspace}/config/provisioning.yaml
Variables:
{{workspace.name}}- Workspace name{{workspace.path}}- Absolute workspace path{{now.iso}}- Timestamp
Sections:
- workspace - Workspace metadata
- paths - All system paths
- core - Core settings
- debug - Debug configuration
- output - Output preferences
- providers - Provider settings
- platform - Platform services
- secrets - Secret management
- kms - Key management
- sops - SOPS configuration
- taskservs - Task service paths
- clusters - Cluster paths
- cache - Cache settings
2. provider-aws.toml.template
AWS provider configuration template. Generates: {workspace}/config/providers/aws.toml
Variables:
{{workspace.name}}- Workspace name{{workspace.path}}- Absolute workspace path{{now.iso}}- Timestamp
Sections:
- provider - Provider metadata
- provider.auth - AWS authentication
- provider.paths - Provider-specific paths
- provider.api - API settings
3. provider-local.toml.template
Local provider configuration template. Generates: {workspace}/config/providers/local.toml
Variables:
{{workspace.name}}- Workspace name{{workspace.path}}- Absolute workspace path{{now.iso}}- Timestamp
Sections:
- provider - Provider metadata
- provider.auth - Local auth (minimal)
- provider.paths - Provider-specific paths
4. provider-upcloud.toml.template
UpCloud provider configuration template. Generates: {workspace}/config/providers/upcloud.toml
Variables:
{{workspace.name}}- Workspace name{{workspace.path}}- Absolute workspace path{{now.iso}}- Timestamp
Sections:
- provider - Provider metadata
- provider.auth - UpCloud authentication
- provider.paths - Provider-specific paths
- provider.api - API settings (UpCloud API URL)
5. kms.toml.template
Key Management Service configuration template. Generates: {workspace}/config/kms.toml
Variables:
{{workspace.name}}- Workspace name{{workspace.path}}- Absolute workspace path{{now.iso}}- Timestamp
Sections:
- kms - KMS mode and settings
- kms.local - Local KMS (Age)
- kms.remote - Remote KMS server
6. user-context.yaml.template
User context configuration template. Generates: ~/Library/Application Support/provisioning/ws_{name}.yaml
Variables:
{{workspace.name}}- Workspace name{{workspace.path}}- Absolute workspace path{{now.iso}}- Timestamp
Sections:
- workspace - Workspace reference
- debug - User debug overrides
- output - User output preferences
- providers - User provider preferences
- paths - User path overrides
Template Variable Syntax
Templates use {{variable}} syntax for interpolation:
# Example
workspace:
name: "{{workspace.name}}"
path: "{{workspace.path}}"
created: "{{now.iso}}"
Supported Variables
Core Variables
{{workspace.name}}- Workspace name (string){{workspace.path}}- Absolute workspace path (string)
Timestamp Variables
{{now.iso}}- ISO 8601 timestamp (YYYY-MM-DDTHH:MM:SSZ){{now.date}}- Date only (YYYY-MM-DD){{now.timestamp}}- Unix timestamp
Environment Variables (safe list)
{{env.HOME}}- User home directory{{env.USER}}- Current user{{env.HOSTNAME}}- System hostname
Usage
Generate Workspace from Template
use provisioning/core/nulib/lib_provisioning/workspace/init.nu *
# Initialize workspace with AWS and Local providers
workspace-init "my-workspace" "/path/to/workspace" \
--providers ["aws" "local"] \
--activate
What Happens
- Templates are read from this directory
- Variables are interpolated with actual values
- Generated configs are saved to workspace
- User context (if --activate) is created
Generated Structure
/path/to/workspace/
├── config/
│ ├── provisioning.yaml # From workspace-provisioning.yaml.template
│ ├── kms.toml # From kms.toml.template
│ └── providers/
│ ├── aws.toml # From provider-aws.toml.template
│ └── local.toml # From provider-local.toml.template
~/Library/Application Support/provisioning/
└── ws_my-workspace.yaml # From user-context.yaml.template
Adding New Templates
1. Create Template File
# Example: New provider template
touch provider-gcp.toml.template
2. Add Template Content
# GCP Provider Configuration for Workspace: {{workspace.name}}
# Generated: {{now.iso}}
[provider]
name = "gcp"
enabled = true
workspace = "{{workspace.name}}"
[provider.auth]
project = "default"
region = "us-central1"
[provider.paths]
base = "{{workspace.path}}/.providers/gcp"
cache = "{{workspace.path}}/.providers/gcp/cache"
3. Update Workspace Init
Add GCP template handling to workspace/init.nu:
def generate-provider-config [
workspace_path: string
workspace_name: string
provider_name: string
] {
let template_path = $"/path/to/templates/provider-($provider_name).toml.template"
if not ($template_path | path exists) {
print $"⚠️ No template for provider '($provider_name)'"
return
}
# Generate config...
}
Template Best Practices
1. Always Include Metadata
# Configuration for Workspace: {{workspace.name}}
# Generated: {{now.iso}}
# DO NOT EDIT - Regenerate from template
2. Use Absolute Paths
paths:
base: "{{workspace.path}}" # ✅ Absolute
cache: "{{workspace.path}}/.cache" # ✅ Absolute
# NOT relative:
# cache: ".cache" # ❌ Relative
3. Provide Sensible Defaults
debug:
enabled: false # Safe default
log_level: "info" # Reasonable default
providers:
default: "local" # Safe default
4. Document Sections
# Debug settings (can be overridden by user context)
debug:
enabled: false
log_level: "info"
5. Group Related Settings
[kms]
mode = "local"
[kms.local]
provider = "age"
key_path = "{{workspace.path}}/.kms/keys/age.txt"
[kms.remote]
server = ""
Validation
Templates should be validated before use:
- Syntax Valid: YAML/TOML parseable
- Variables Complete: All
{{variables}}have values - Paths Absolute: All paths use
{{workspace.path}} - Sensible Defaults: Safe, secure defaults
Troubleshooting
Template Not Found
⚠️ Warning: No template found for provider 'xyz'
Solution: Create template or check provider name spelling.
Variable Not Interpolated
Config shows {{workspace.name}} instead of actual name.
Solution: Check variable exists in interpolation list, update workspace/init.nu.
Invalid YAML/TOML
Generated config fails to parse.
Solution: Validate template syntax, ensure proper escaping.
Related Files
- Workspace Init:
provisioning/core/nulib/lib_provisioning/workspace/init.nu - Config Loader:
provisioning/core/nulib/lib_provisioning/config/loader.nu - Documentation:
docs/configuration/workspace-config-architecture.md
Summary
- Templates are source files only, never loaded at runtime
- Used to generate workspace configs during initialization
- Support variable interpolation with
{{variable}}syntax - Each template creates specific config file in workspace
- Modify templates to change default workspace structure