provisioning/docs/book/development/configuration.html
Jesús Pérez 6a59d34bb1
chore: update provisioning configuration and documentation
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.
2025-12-11 21:50:42 +00:00

1091 lines
41 KiB
HTML
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<!DOCTYPE HTML>
<html lang="en" class="ayu sidebar-visible" dir="ltr">
<head>
<!-- Book generated using mdBook -->
<meta charset="UTF-8">
<title>Configuration Guide - Provisioning Platform Documentation</title>
<!-- Custom HTML head -->
<meta name="description" content="Complete documentation for the Provisioning Platform - Infrastructure automation with Nushell, KCL, and Rust">
<meta name="viewport" content="width=device-width, initial-scale=1">
<meta name="theme-color" content="#ffffff">
<link rel="icon" href="../favicon.svg">
<link rel="shortcut icon" href="../favicon.png">
<link rel="stylesheet" href="../css/variables.css">
<link rel="stylesheet" href="../css/general.css">
<link rel="stylesheet" href="../css/chrome.css">
<link rel="stylesheet" href="../css/print.css" media="print">
<!-- Fonts -->
<link rel="stylesheet" href="../FontAwesome/css/font-awesome.css">
<link rel="stylesheet" href="../fonts/fonts.css">
<!-- Highlight.js Stylesheets -->
<link rel="stylesheet" id="highlight-css" href="../highlight.css">
<link rel="stylesheet" id="tomorrow-night-css" href="../tomorrow-night.css">
<link rel="stylesheet" id="ayu-highlight-css" href="../ayu-highlight.css">
<!-- Custom theme stylesheets -->
<!-- Provide site root and default themes to javascript -->
<script>
const path_to_root = "../";
const default_light_theme = "ayu";
const default_dark_theme = "navy";
</script>
<!-- Start loading toc.js asap -->
<script src="../toc.js"></script>
</head>
<body>
<div id="mdbook-help-container">
<div id="mdbook-help-popup">
<h2 class="mdbook-help-title">Keyboard shortcuts</h2>
<div>
<p>Press <kbd></kbd> or <kbd></kbd> to navigate between chapters</p>
<p>Press <kbd>S</kbd> or <kbd>/</kbd> to search in the book</p>
<p>Press <kbd>?</kbd> to show this help</p>
<p>Press <kbd>Esc</kbd> to hide this help</p>
</div>
</div>
</div>
<div id="body-container">
<!-- Work around some values being stored in localStorage wrapped in quotes -->
<script>
try {
let theme = localStorage.getItem('mdbook-theme');
let sidebar = localStorage.getItem('mdbook-sidebar');
if (theme.startsWith('"') && theme.endsWith('"')) {
localStorage.setItem('mdbook-theme', theme.slice(1, theme.length - 1));
}
if (sidebar.startsWith('"') && sidebar.endsWith('"')) {
localStorage.setItem('mdbook-sidebar', sidebar.slice(1, sidebar.length - 1));
}
} catch (e) { }
</script>
<!-- Set the theme before any content is loaded, prevents flash -->
<script>
const default_theme = window.matchMedia("(prefers-color-scheme: dark)").matches ? default_dark_theme : default_light_theme;
let theme;
try { theme = localStorage.getItem('mdbook-theme'); } catch(e) { }
if (theme === null || theme === undefined) { theme = default_theme; }
const html = document.documentElement;
html.classList.remove('ayu')
html.classList.add(theme);
html.classList.add("js");
</script>
<input type="checkbox" id="sidebar-toggle-anchor" class="hidden">
<!-- Hide / unhide sidebar before it is displayed -->
<script>
let sidebar = null;
const sidebar_toggle = document.getElementById("sidebar-toggle-anchor");
if (document.body.clientWidth >= 1080) {
try { sidebar = localStorage.getItem('mdbook-sidebar'); } catch(e) { }
sidebar = sidebar || 'visible';
} else {
sidebar = 'hidden';
}
sidebar_toggle.checked = sidebar === 'visible';
html.classList.remove('sidebar-visible');
html.classList.add("sidebar-" + sidebar);
</script>
<nav id="sidebar" class="sidebar" aria-label="Table of contents">
<!-- populated by js -->
<mdbook-sidebar-scrollbox class="sidebar-scrollbox"></mdbook-sidebar-scrollbox>
<noscript>
<iframe class="sidebar-iframe-outer" src="../toc.html"></iframe>
</noscript>
<div id="sidebar-resize-handle" class="sidebar-resize-handle">
<div class="sidebar-resize-indicator"></div>
</div>
</nav>
<div id="page-wrapper" class="page-wrapper">
<div class="page">
<div id="menu-bar-hover-placeholder"></div>
<div id="menu-bar" class="menu-bar sticky">
<div class="left-buttons">
<label id="sidebar-toggle" class="icon-button" for="sidebar-toggle-anchor" title="Toggle Table of Contents" aria-label="Toggle Table of Contents" aria-controls="sidebar">
<i class="fa fa-bars"></i>
</label>
<button id="theme-toggle" class="icon-button" type="button" title="Change theme" aria-label="Change theme" aria-haspopup="true" aria-expanded="false" aria-controls="theme-list">
<i class="fa fa-paint-brush"></i>
</button>
<ul id="theme-list" class="theme-popup" aria-label="Themes" role="menu">
<li role="none"><button role="menuitem" class="theme" id="default_theme">Auto</button></li>
<li role="none"><button role="menuitem" class="theme" id="light">Light</button></li>
<li role="none"><button role="menuitem" class="theme" id="rust">Rust</button></li>
<li role="none"><button role="menuitem" class="theme" id="coal">Coal</button></li>
<li role="none"><button role="menuitem" class="theme" id="navy">Navy</button></li>
<li role="none"><button role="menuitem" class="theme" id="ayu">Ayu</button></li>
</ul>
<button id="search-toggle" class="icon-button" type="button" title="Search (`/`)" aria-label="Toggle Searchbar" aria-expanded="false" aria-keyshortcuts="/ s" aria-controls="searchbar">
<i class="fa fa-search"></i>
</button>
</div>
<h1 class="menu-title">Provisioning Platform Documentation</h1>
<div class="right-buttons">
<a href="../print.html" title="Print this book" aria-label="Print this book">
<i id="print-button" class="fa fa-print"></i>
</a>
<a href="https://github.com/provisioning/provisioning-platform" title="Git repository" aria-label="Git repository">
<i id="git-repository-button" class="fa fa-github"></i>
</a>
<a href="https://github.com/provisioning/provisioning-platform/edit/main/provisioning/docs/src/development/configuration.md" title="Suggest an edit" aria-label="Suggest an edit">
<i id="git-edit-button" class="fa fa-edit"></i>
</a>
</div>
</div>
<div id="search-wrapper" class="hidden">
<form id="searchbar-outer" class="searchbar-outer">
<input type="search" id="searchbar" name="searchbar" placeholder="Search this book ..." aria-controls="searchresults-outer" aria-describedby="searchresults-header">
</form>
<div id="searchresults-outer" class="searchresults-outer hidden">
<div id="searchresults-header" class="searchresults-header"></div>
<ul id="searchresults">
</ul>
</div>
</div>
<!-- Apply ARIA attributes after the sidebar and the sidebar toggle button are added to the DOM -->
<script>
document.getElementById('sidebar-toggle').setAttribute('aria-expanded', sidebar === 'visible');
document.getElementById('sidebar').setAttribute('aria-hidden', sidebar !== 'visible');
Array.from(document.querySelectorAll('#sidebar a')).forEach(function(link) {
link.setAttribute('tabIndex', sidebar === 'visible' ? 0 : -1);
});
</script>
<div id="content" class="content">
<main>
<h1 id="configuration-management"><a class="header" href="#configuration-management">Configuration Management</a></h1>
<p>This document provides comprehensive guidance on provisionings configuration architecture, environment-specific configurations, validation, error handling, and migration strategies.</p>
<h2 id="table-of-contents"><a class="header" href="#table-of-contents">Table of Contents</a></h2>
<ol>
<li><a href="#overview">Overview</a></li>
<li><a href="#configuration-architecture">Configuration Architecture</a></li>
<li><a href="#configuration-files">Configuration Files</a></li>
<li><a href="#environment-specific-configuration">Environment-Specific Configuration</a></li>
<li><a href="#user-overrides-and-customization">User Overrides and Customization</a></li>
<li><a href="#validation-and-error-handling">Validation and Error Handling</a></li>
<li><a href="#interpolation-and-dynamic-values">Interpolation and Dynamic Values</a></li>
<li><a href="#migration-strategies">Migration Strategies</a></li>
<li><a href="#troubleshooting">Troubleshooting</a></li>
</ol>
<h2 id="overview"><a class="header" href="#overview">Overview</a></h2>
<p>Provisioning implements a sophisticated configuration management system that has migrated from environment variable-based configuration to a hierarchical TOML configuration system with comprehensive validation and interpolation support.</p>
<p><strong>Key Features</strong>:</p>
<ul>
<li><strong>Hierarchical Configuration</strong>: Multi-layer configuration with clear precedence</li>
<li><strong>Environment-Specific</strong>: Dedicated configurations for dev, test, and production</li>
<li><strong>Dynamic Interpolation</strong>: Template-based value resolution</li>
<li><strong>Type Safety</strong>: Comprehensive validation and error handling</li>
<li><strong>Migration Support</strong>: Backward compatibility with existing ENV variables</li>
<li><strong>Workspace Integration</strong>: Seamless integration with development workspaces</li>
</ul>
<p><strong>Migration Status</strong>: ✅ <strong>Complete</strong> (2025-09-23)</p>
<ul>
<li><strong>65+ files migrated</strong> across entire codebase</li>
<li><strong>200+ ENV variables replaced</strong> with 476 config accessors</li>
<li><strong>16 token-efficient agents</strong> used for systematic migration</li>
<li><strong>92% token efficiency</strong> achieved vs monolithic approach</li>
</ul>
<h2 id="configuration-architecture"><a class="header" href="#configuration-architecture">Configuration Architecture</a></h2>
<h3 id="hierarchical-loading-order"><a class="header" href="#hierarchical-loading-order">Hierarchical Loading Order</a></h3>
<p>The configuration system implements a clear precedence hierarchy (lowest to highest precedence):</p>
<pre><code>Configuration Hierarchy (Low → High Precedence)
┌─────────────────────────────────────────────────┐
│ 1. config.defaults.toml │ ← System defaults
│ (System-wide default values) │
├─────────────────────────────────────────────────┤
│ 2. ~/.config/provisioning/config.toml │ ← User configuration
│ (User-specific preferences) │
├─────────────────────────────────────────────────┤
│ 3. ./provisioning.toml │ ← Project configuration
│ (Project-specific settings) │
├─────────────────────────────────────────────────┤
│ 4. ./.provisioning.toml │ ← Infrastructure config
│ (Infrastructure-specific settings) │
├─────────────────────────────────────────────────┤
│ 5. Environment-specific configs │ ← Environment overrides
│ (config.{dev,test,prod}.toml) │
├─────────────────────────────────────────────────┤
│ 6. Runtime environment variables │ ← Runtime overrides
│ (PROVISIONING_* variables) │
└─────────────────────────────────────────────────┘
</code></pre>
<h3 id="configuration-access-patterns"><a class="header" href="#configuration-access-patterns">Configuration Access Patterns</a></h3>
<p><strong>Configuration Accessor Functions</strong>:</p>
<pre><code class="language-nushell"># Core configuration access
use core/nulib/lib_provisioning/config/accessor.nu
# Get configuration value with fallback
let api_url = (get-config-value "providers.upcloud.api_url" "https://api.upcloud.com")
# Get required configuration (errors if missing)
let api_key = (get-config-required "providers.upcloud.api_key")
# Get nested configuration
let server_defaults = (get-config-section "defaults.servers")
# Environment-aware configuration
let log_level = (get-config-env "logging.level" "info")
# Interpolated configuration
let data_path = (get-config-interpolated "paths.data") # Resolves {{paths.base}}/data
</code></pre>
<h3 id="migration-from-env-variables"><a class="header" href="#migration-from-env-variables">Migration from ENV Variables</a></h3>
<p><strong>Before (ENV-based)</strong>:</p>
<pre><code class="language-bash">export PROVISIONING_UPCLOUD_API_KEY="your-key"
export PROVISIONING_UPCLOUD_API_URL="https://api.upcloud.com"
export PROVISIONING_LOG_LEVEL="debug"
export PROVISIONING_BASE_PATH="/usr/local/provisioning"
</code></pre>
<p><strong>After (Config-based)</strong>:</p>
<pre><code class="language-toml"># config.user.toml
[providers.upcloud]
api_key = "your-key"
api_url = "https://api.upcloud.com"
[logging]
level = "debug"
[paths]
base = "/usr/local/provisioning"
</code></pre>
<h2 id="configuration-files"><a class="header" href="#configuration-files">Configuration Files</a></h2>
<h3 id="system-defaults-configdefaultstoml"><a class="header" href="#system-defaults-configdefaultstoml">System Defaults (<code>config.defaults.toml</code>)</a></h3>
<p><strong>Purpose</strong>: Provides sensible defaults for all system components
<strong>Location</strong>: Root of the repository
<strong>Modification</strong>: Should only be modified by system maintainers</p>
<pre><code class="language-toml"># System-wide defaults - DO NOT MODIFY in production
# Copy values to config.user.toml for customization
[core]
version = "1.0.0"
name = "provisioning-system"
[paths]
# Base path - all other paths derived from this
base = "/usr/local/provisioning"
config = "{{paths.base}}/config"
data = "{{paths.base}}/data"
logs = "{{paths.base}}/logs"
cache = "{{paths.base}}/cache"
runtime = "{{paths.base}}/runtime"
[logging]
level = "info"
file = "{{paths.logs}}/provisioning.log"
rotation = true
max_size = "100MB"
max_files = 5
[http]
timeout = 30
retries = 3
user_agent = "provisioning-system/{{core.version}}"
use_curl = false
[providers]
default = "local"
[providers.upcloud]
api_url = "https://api.upcloud.com/1.3"
timeout = 30
max_retries = 3
[providers.aws]
region = "us-east-1"
timeout = 30
[providers.local]
enabled = true
base_path = "{{paths.data}}/local"
[defaults]
[defaults.servers]
plan = "1xCPU-2GB"
zone = "auto"
template = "ubuntu-22.04"
[cache]
enabled = true
ttl = 3600
path = "{{paths.cache}}"
[orchestrator]
enabled = false
port = 8080
bind = "127.0.0.1"
data_path = "{{paths.data}}/orchestrator"
[workflow]
storage_backend = "filesystem"
parallel_limit = 5
rollback_enabled = true
[telemetry]
enabled = false
endpoint = ""
sample_rate = 0.1
</code></pre>
<h3 id="user-configuration-configprovisioningconfigtoml"><a class="header" href="#user-configuration-configprovisioningconfigtoml">User Configuration (<code>~/.config/provisioning/config.toml</code>)</a></h3>
<p><strong>Purpose</strong>: User-specific customizations and preferences
<strong>Location</strong>: Users configuration directory
<strong>Modification</strong>: Users should customize this file for their needs</p>
<pre><code class="language-toml"># User configuration - customizations and personal preferences
# This file overrides system defaults
[core]
name = "provisioning-{{env.USER}}"
[paths]
# Personal installation path
base = "{{env.HOME}}/.local/share/provisioning"
[logging]
level = "debug"
file = "{{paths.logs}}/provisioning-{{env.USER}}.log"
[providers]
default = "upcloud"
[providers.upcloud]
api_key = "your-personal-api-key"
api_secret = "your-personal-api-secret"
[defaults.servers]
plan = "2xCPU-4GB"
zone = "us-nyc1"
[development]
auto_reload = true
hot_reload_templates = true
verbose_errors = true
[notifications]
slack_webhook = "https://hooks.slack.com/your-webhook"
email = "your-email@domain.com"
[git]
auto_commit = true
commit_prefix = "[{{env.USER}}]"
</code></pre>
<h3 id="project-configuration-provisioningtoml"><a class="header" href="#project-configuration-provisioningtoml">Project Configuration (<code>./provisioning.toml</code>)</a></h3>
<p><strong>Purpose</strong>: Project-specific settings shared across team
<strong>Location</strong>: Project root directory
<strong>Version Control</strong>: Should be committed to version control</p>
<pre><code class="language-toml"># Project-specific configuration
# Shared settings for this project/repository
[core]
name = "my-project-provisioning"
version = "1.2.0"
[infra]
default = "staging"
environments = ["dev", "staging", "production"]
[providers]
default = "upcloud"
allowed = ["upcloud", "aws", "local"]
[providers.upcloud]
# Project-specific UpCloud settings
default_zone = "us-nyc1"
template = "ubuntu-22.04-lts"
[defaults.servers]
plan = "2xCPU-4GB"
storage = 50
firewall_enabled = true
[security]
enforce_https = true
require_mfa = true
allowed_cidr = ["10.0.0.0/8", "172.16.0.0/12"]
[compliance]
data_region = "us-east"
encryption_at_rest = true
audit_logging = true
[team]
admins = ["alice@company.com", "bob@company.com"]
developers = ["dev-team@company.com"]
</code></pre>
<h3 id="infrastructure-configuration-provisioningtoml"><a class="header" href="#infrastructure-configuration-provisioningtoml">Infrastructure Configuration (<code>./.provisioning.toml</code>)</a></h3>
<p><strong>Purpose</strong>: Infrastructure-specific overrides
<strong>Location</strong>: Infrastructure directory
<strong>Usage</strong>: Overrides for specific infrastructure deployments</p>
<pre><code class="language-toml"># Infrastructure-specific configuration
# Overrides for this specific infrastructure deployment
[core]
name = "production-east-provisioning"
[infra]
name = "production-east"
environment = "production"
region = "us-east-1"
[providers.upcloud]
zone = "us-nyc1"
private_network = true
[providers.aws]
region = "us-east-1"
availability_zones = ["us-east-1a", "us-east-1b", "us-east-1c"]
[defaults.servers]
plan = "4xCPU-8GB"
storage = 100
backup_enabled = true
monitoring_enabled = true
[security]
firewall_strict_mode = true
encryption_required = true
audit_all_actions = true
[monitoring]
prometheus_enabled = true
grafana_enabled = true
alertmanager_enabled = true
[backup]
enabled = true
schedule = "0 2 * * *" # Daily at 2 AM
retention_days = 30
</code></pre>
<h2 id="environment-specific-configuration"><a class="header" href="#environment-specific-configuration">Environment-Specific Configuration</a></h2>
<h3 id="development-environment-configdevtoml"><a class="header" href="#development-environment-configdevtoml">Development Environment (<code>config.dev.toml</code>)</a></h3>
<p><strong>Purpose</strong>: Development-optimized settings
<strong>Features</strong>: Enhanced debugging, local providers, relaxed validation</p>
<pre><code class="language-toml"># Development environment configuration
# Optimized for local development and testing
[core]
name = "provisioning-dev"
version = "dev-{{git.branch}}"
[paths]
base = "{{env.PWD}}/dev-environment"
[logging]
level = "debug"
console_output = true
structured_logging = true
debug_http = true
[providers]
default = "local"
[providers.local]
enabled = true
fast_mode = true
mock_delays = false
[http]
timeout = 10
retries = 1
debug_requests = true
[cache]
enabled = true
ttl = 60 # Short TTL for development
debug_cache = true
[development]
auto_reload = true
hot_reload_templates = true
validate_strict = false
experimental_features = true
debug_mode = true
[orchestrator]
enabled = true
port = 8080
debug = true
file_watcher = true
[testing]
parallel_tests = true
cleanup_after_tests = true
mock_external_apis = true
</code></pre>
<h3 id="testing-environment-configtesttoml"><a class="header" href="#testing-environment-configtesttoml">Testing Environment (<code>config.test.toml</code>)</a></h3>
<p><strong>Purpose</strong>: Testing-specific configuration
<strong>Features</strong>: Mock services, isolated environments, comprehensive logging</p>
<pre><code class="language-toml"># Testing environment configuration
# Optimized for automated testing and CI/CD
[core]
name = "provisioning-test"
version = "test-{{build.timestamp}}"
[logging]
level = "info"
test_output = true
capture_stderr = true
[providers]
default = "local"
[providers.local]
enabled = true
mock_mode = true
deterministic = true
[http]
timeout = 5
retries = 0
mock_responses = true
[cache]
enabled = false
[testing]
isolated_environments = true
cleanup_after_each_test = true
parallel_execution = true
mock_all_external_calls = true
deterministic_ids = true
[orchestrator]
enabled = false
[validation]
strict_mode = true
fail_fast = true
</code></pre>
<h3 id="production-environment-configprodtoml"><a class="header" href="#production-environment-configprodtoml">Production Environment (<code>config.prod.toml</code>)</a></h3>
<p><strong>Purpose</strong>: Production-optimized settings
<strong>Features</strong>: Performance optimization, security hardening, comprehensive monitoring</p>
<pre><code class="language-toml"># Production environment configuration
# Optimized for performance, reliability, and security
[core]
name = "provisioning-production"
version = "{{release.version}}"
[logging]
level = "warn"
structured_logging = true
sensitive_data_filtering = true
audit_logging = true
[providers]
default = "upcloud"
[http]
timeout = 60
retries = 5
connection_pool = 20
keep_alive = true
[cache]
enabled = true
ttl = 3600
size_limit = "500MB"
persistence = true
[security]
strict_mode = true
encrypt_at_rest = true
encrypt_in_transit = true
audit_all_actions = true
[monitoring]
metrics_enabled = true
tracing_enabled = true
health_checks = true
alerting = true
[orchestrator]
enabled = true
port = 8080
bind = "0.0.0.0"
workers = 4
max_connections = 100
[performance]
parallel_operations = true
batch_operations = true
connection_pooling = true
</code></pre>
<h2 id="user-overrides-and-customization"><a class="header" href="#user-overrides-and-customization">User Overrides and Customization</a></h2>
<h3 id="personal-development-setup"><a class="header" href="#personal-development-setup">Personal Development Setup</a></h3>
<p><strong>Creating User Configuration</strong>:</p>
<pre><code class="language-bash"># Create user config directory
mkdir -p ~/.config/provisioning
# Copy template
cp src/provisioning/config-examples/config.user.toml ~/.config/provisioning/config.toml
# Customize for your environment
$EDITOR ~/.config/provisioning/config.toml
</code></pre>
<p><strong>Common User Customizations</strong>:</p>
<pre><code class="language-toml"># Personal configuration customizations
[paths]
base = "{{env.HOME}}/dev/provisioning"
[development]
editor = "code"
auto_backup = true
backup_interval = "1h"
[git]
auto_commit = false
commit_template = "[{{env.USER}}] {{change.type}}: {{change.description}}"
[providers.upcloud]
api_key = "{{env.UPCLOUD_API_KEY}}"
api_secret = "{{env.UPCLOUD_API_SECRET}}"
default_zone = "de-fra1"
[shortcuts]
# Custom command aliases
quick_server = "server create {{name}} 2xCPU-4GB --zone us-nyc1"
dev_cluster = "cluster create development --infra {{env.USER}}-dev"
[notifications]
desktop_notifications = true
sound_notifications = false
slack_webhook = "{{env.SLACK_WEBHOOK_URL}}"
</code></pre>
<h3 id="workspace-specific-configuration"><a class="header" href="#workspace-specific-configuration">Workspace-Specific Configuration</a></h3>
<p><strong>Workspace Integration</strong>:</p>
<pre><code class="language-toml"># Workspace-aware configuration
# workspace/config/developer.toml
[workspace]
user = "developer"
type = "development"
[paths]
base = "{{workspace.root}}"
extensions = "{{workspace.root}}/extensions"
runtime = "{{workspace.root}}/runtime/{{workspace.user}}"
[development]
workspace_isolation = true
per_user_cache = true
shared_extensions = false
[infra]
current = "{{workspace.user}}-development"
auto_create = true
</code></pre>
<h2 id="validation-and-error-handling"><a class="header" href="#validation-and-error-handling">Validation and Error Handling</a></h2>
<h3 id="configuration-validation"><a class="header" href="#configuration-validation">Configuration Validation</a></h3>
<p><strong>Built-in Validation</strong>:</p>
<pre><code class="language-bash"># Validate current configuration
provisioning validate config
# Validate specific configuration file
provisioning validate config --file config.dev.toml
# Show configuration with validation
provisioning config show --validate
# Debug configuration loading
provisioning config debug
</code></pre>
<p><strong>Validation Rules</strong>:</p>
<pre><code class="language-nushell"># Configuration validation in Nushell
def validate_configuration [config: record] -&gt; record {
let errors = []
# Validate required fields
if not ("paths" in $config and "base" in $config.paths) {
$errors = ($errors | append "paths.base is required")
}
# Validate provider configuration
if "providers" in $config {
for provider in ($config.providers | columns) {
if $provider == "upcloud" {
if not ("api_key" in $config.providers.upcloud) {
$errors = ($errors | append "providers.upcloud.api_key is required")
}
}
}
}
# Validate numeric values
if "http" in $config and "timeout" in $config.http {
if $config.http.timeout &lt;= 0 {
$errors = ($errors | append "http.timeout must be positive")
}
}
{
valid: ($errors | length) == 0,
errors: $errors
}
}
</code></pre>
<h3 id="error-handling"><a class="header" href="#error-handling">Error Handling</a></h3>
<p><strong>Configuration-Driven Error Handling</strong>:</p>
<pre><code class="language-nushell"># Never patch with hardcoded fallbacks - use configuration
def get_api_endpoint [provider: string] -&gt; string {
# Good: Configuration-driven with clear error
let config_key = $"providers.($provider).api_url"
let endpoint = try {
get-config-required $config_key
} catch {
error make {
msg: $"API endpoint not configured for provider ($provider)",
help: $"Add '($config_key)' to your configuration file"
}
}
$endpoint
}
# Bad: Hardcoded fallback defeats IaC purpose
def get_api_endpoint_bad [provider: string] -&gt; string {
try {
get-config-required $"providers.($provider).api_url"
} catch {
# DON'T DO THIS - defeats configuration-driven architecture
"https://default-api.com"
}
}
</code></pre>
<p><strong>Comprehensive Error Context</strong>:</p>
<pre><code class="language-nushell">def load_provider_config [provider: string] -&gt; record {
let config_section = $"providers.($provider)"
try {
get-config-section $config_section
} catch { |e|
error make {
msg: $"Failed to load configuration for provider ($provider): ($e.msg)",
label: {
text: "configuration missing",
span: (metadata $provider).span
},
help: [
$"Add [$config_section] section to your configuration",
"Example configuration files available in config-examples/",
"Run 'provisioning config show' to see current configuration"
]
}
}
}
</code></pre>
<h2 id="interpolation-and-dynamic-values"><a class="header" href="#interpolation-and-dynamic-values">Interpolation and Dynamic Values</a></h2>
<h3 id="interpolation-syntax"><a class="header" href="#interpolation-syntax">Interpolation Syntax</a></h3>
<p><strong>Supported Interpolation Variables</strong>:</p>
<pre><code class="language-toml"># Environment variables
base_path = "{{env.HOME}}/provisioning"
user_name = "{{env.USER}}"
# Configuration references
data_path = "{{paths.base}}/data"
log_file = "{{paths.logs}}/{{core.name}}.log"
# Date/time values
backup_name = "backup-{{now.date}}-{{now.time}}"
version = "{{core.version}}-{{now.timestamp}}"
# Git information
branch_name = "{{git.branch}}"
commit_hash = "{{git.commit}}"
version_with_git = "{{core.version}}-{{git.commit}}"
# System information
hostname = "{{system.hostname}}"
platform = "{{system.platform}}"
architecture = "{{system.arch}}"
</code></pre>
<h3 id="complex-interpolation-examples"><a class="header" href="#complex-interpolation-examples">Complex Interpolation Examples</a></h3>
<p><strong>Dynamic Path Resolution</strong>:</p>
<pre><code class="language-toml">[paths]
base = "{{env.HOME}}/.local/share/provisioning"
config = "{{paths.base}}/config"
data = "{{paths.base}}/data/{{system.hostname}}"
logs = "{{paths.base}}/logs/{{env.USER}}/{{now.date}}"
runtime = "{{paths.base}}/runtime/{{git.branch}}"
[providers.upcloud]
cache_path = "{{paths.cache}}/providers/upcloud/{{env.USER}}"
log_file = "{{paths.logs}}/upcloud-{{now.date}}.log"
</code></pre>
<p><strong>Environment-Aware Configuration</strong>:</p>
<pre><code class="language-toml">[core]
name = "provisioning-{{system.hostname}}-{{env.USER}}"
version = "{{release.version}}+{{git.commit}}.{{now.timestamp}}"
[database]
name = "provisioning_{{env.USER}}_{{git.branch}}"
backup_prefix = "{{core.name}}-backup-{{now.date}}"
[monitoring]
instance_id = "{{system.hostname}}-{{core.version}}"
tags = {
environment = "{{infra.environment}}",
user = "{{env.USER}}",
version = "{{core.version}}",
deployment_time = "{{now.iso8601}}"
}
</code></pre>
<h3 id="interpolation-functions"><a class="header" href="#interpolation-functions">Interpolation Functions</a></h3>
<p><strong>Custom Interpolation Logic</strong>:</p>
<pre><code class="language-nushell"># Interpolation resolver
def resolve_interpolation [template: string, context: record] -&gt; string {
let interpolations = ($template | parse --regex '\{\{([^}]+)\}\}')
mut result = $template
for interpolation in $interpolations {
let key_path = ($interpolation.capture0 | str trim)
let value = resolve_interpolation_key $key_path $context
$result = ($result | str replace $"{{($interpolation.capture0)}}" $value)
}
$result
}
def resolve_interpolation_key [key_path: string, context: record] -&gt; string {
match ($key_path | split row ".") {
["env", $var] =&gt; ($env | get $var | default ""),
["paths", $path] =&gt; (resolve_path_key $path $context),
["now", $format] =&gt; (resolve_time_format $format),
["git", $info] =&gt; (resolve_git_info $info),
["system", $info] =&gt; (resolve_system_info $info),
$path =&gt; (get_nested_config_value $path $context)
}
}
</code></pre>
<h2 id="migration-strategies"><a class="header" href="#migration-strategies">Migration Strategies</a></h2>
<h3 id="env-to-config-migration"><a class="header" href="#env-to-config-migration">ENV to Config Migration</a></h3>
<p><strong>Migration Status</strong>: The system has successfully migrated from ENV-based to config-driven architecture:</p>
<p><strong>Migration Statistics</strong>:</p>
<ul>
<li><strong>Files Migrated</strong>: 65+ files across entire codebase</li>
<li><strong>Variables Replaced</strong>: 200+ ENV variables → 476 config accessors</li>
<li><strong>Agent-Based Development</strong>: 16 token-efficient agents used</li>
<li><strong>Efficiency Gained</strong>: 92% token efficiency vs monolithic approach</li>
</ul>
<h3 id="legacy-support"><a class="header" href="#legacy-support">Legacy Support</a></h3>
<p><strong>Backward Compatibility</strong>:</p>
<pre><code class="language-nushell"># Configuration accessor with ENV fallback
def get-config-with-env-fallback [
config_key: string,
env_var: string,
default: string = ""
] -&gt; string {
# Try configuration first
let config_value = try {
get-config-value $config_key
} catch { null }
if $config_value != null {
return $config_value
}
# Fall back to environment variable
let env_value = ($env | get $env_var | default null)
if $env_value != null {
return $env_value
}
# Use default if provided
if $default != "" {
return $default
}
# Error if no value found
error make {
msg: $"Configuration value not found: ($config_key)",
help: $"Set ($config_key) in configuration or ($env_var) environment variable"
}
}
</code></pre>
<h3 id="migration-tools"><a class="header" href="#migration-tools">Migration Tools</a></h3>
<p><strong>Available Migration Scripts</strong>:</p>
<pre><code class="language-bash"># Migrate existing ENV-based setup to configuration
nu src/tools/migration/env-to-config.nu --scan-environment --create-config
# Validate migration completeness
nu src/tools/migration/validate-migration.nu --check-env-usage
# Generate configuration from current environment
nu src/tools/migration/generate-config.nu --output-file config.migrated.toml
</code></pre>
<h2 id="troubleshooting"><a class="header" href="#troubleshooting">Troubleshooting</a></h2>
<h3 id="common-configuration-issues"><a class="header" href="#common-configuration-issues">Common Configuration Issues</a></h3>
<h4 id="configuration-not-found"><a class="header" href="#configuration-not-found">Configuration Not Found</a></h4>
<p><strong>Error</strong>: <code>Configuration file not found</code></p>
<pre><code class="language-bash"># Solution: Check configuration file paths
provisioning config paths
# Create default configuration
provisioning config init --template user
# Verify configuration loading order
provisioning config debug
</code></pre>
<h4 id="invalid-configuration-syntax"><a class="header" href="#invalid-configuration-syntax">Invalid Configuration Syntax</a></h4>
<p><strong>Error</strong>: <code>Invalid TOML syntax in configuration file</code></p>
<pre><code class="language-bash"># Solution: Validate TOML syntax
nu -c "open config.user.toml | from toml"
# Use configuration validation
provisioning validate config --file config.user.toml
# Show parsing errors
provisioning config check --verbose
</code></pre>
<h4 id="interpolation-errors"><a class="header" href="#interpolation-errors">Interpolation Errors</a></h4>
<p><strong>Error</strong>: <code>Failed to resolve interpolation: {{env.MISSING_VAR}}</code></p>
<pre><code class="language-bash"># Solution: Check available interpolation variables
provisioning config interpolation --list-variables
# Debug specific interpolation
provisioning config interpolation --test "{{env.USER}}"
# Show interpolation context
provisioning config debug --show-interpolation
</code></pre>
<h4 id="provider-configuration-issues"><a class="header" href="#provider-configuration-issues">Provider Configuration Issues</a></h4>
<p><strong>Error</strong>: <code>Provider 'upcloud' configuration invalid</code></p>
<pre><code class="language-bash"># Solution: Validate provider configuration
provisioning validate config --section providers.upcloud
# Show required provider fields
provisioning providers upcloud config --show-schema
# Test provider configuration
provisioning providers upcloud test --dry-run
</code></pre>
<h3 id="debug-commands"><a class="header" href="#debug-commands">Debug Commands</a></h3>
<p><strong>Configuration Debugging</strong>:</p>
<pre><code class="language-bash"># Show complete resolved configuration
provisioning config show --resolved
# Show configuration loading order
provisioning config debug --show-hierarchy
# Show configuration sources
provisioning config sources
# Test specific configuration keys
provisioning config get paths.base --trace
# Show interpolation resolution
provisioning config interpolation --debug "{{paths.data}}/{{env.USER}}"
</code></pre>
<h3 id="performance-optimization"><a class="header" href="#performance-optimization">Performance Optimization</a></h3>
<p><strong>Configuration Caching</strong>:</p>
<pre><code class="language-bash"># Enable configuration caching
export PROVISIONING_CONFIG_CACHE=true
# Clear configuration cache
provisioning config cache --clear
# Show cache statistics
provisioning config cache --stats
</code></pre>
<p><strong>Startup Optimization</strong>:</p>
<pre><code class="language-toml"># Optimize configuration loading
[performance]
lazy_loading = true
cache_compiled_config = true
skip_unused_sections = true
[cache]
config_cache_ttl = 3600
interpolation_cache = true
</code></pre>
<p>This configuration management system provides a robust, flexible foundation that supports development workflows while maintaining production reliability and security requirements.</p>
</main>
<nav class="nav-wrapper" aria-label="Page navigation">
<!-- Mobile navigation buttons -->
<a rel="prev" href="../development/COMMAND_HANDLER_GUIDE.html" class="mobile-nav-chapters previous" title="Previous chapter" aria-label="Previous chapter" aria-keyshortcuts="Left">
<i class="fa fa-angle-left"></i>
</a>
<a rel="next prefetch" href="../development/workspace-management.html" class="mobile-nav-chapters next" title="Next chapter" aria-label="Next chapter" aria-keyshortcuts="Right">
<i class="fa fa-angle-right"></i>
</a>
<div style="clear: both"></div>
</nav>
</div>
</div>
<nav class="nav-wide-wrapper" aria-label="Page navigation">
<a rel="prev" href="../development/COMMAND_HANDLER_GUIDE.html" class="nav-chapters previous" title="Previous chapter" aria-label="Previous chapter" aria-keyshortcuts="Left">
<i class="fa fa-angle-left"></i>
</a>
<a rel="next prefetch" href="../development/workspace-management.html" class="nav-chapters next" title="Next chapter" aria-label="Next chapter" aria-keyshortcuts="Right">
<i class="fa fa-angle-right"></i>
</a>
</nav>
</div>
<!-- Livereload script (if served using the cli tool) -->
<script>
const wsProtocol = location.protocol === 'https:' ? 'wss:' : 'ws:';
const wsAddress = wsProtocol + "//" + location.host + "/" + "__livereload";
const socket = new WebSocket(wsAddress);
socket.onmessage = function (event) {
if (event.data === "reload") {
socket.close();
location.reload();
}
};
window.onbeforeunload = function() {
socket.close();
}
</script>
<script>
window.playground_copyable = true;
</script>
<script src="../elasticlunr.min.js"></script>
<script src="../mark.min.js"></script>
<script src="../searcher.js"></script>
<script src="../clipboard.min.js"></script>
<script src="../highlight.js"></script>
<script src="../book.js"></script>
<!-- Custom JS scripts -->
</div>
</body>
</html>