279 lines
8.8 KiB
Markdown
279 lines
8.8 KiB
Markdown
|
|
# SST Pattern - Workspace Configuration Templates
|
||
|
|
|
||
|
|
This directory contains all templates for creating workspace configurations using the KCL SST (Single Source of Truth) pattern.
|
||
|
|
|
||
|
|
## Quick Reference
|
||
|
|
|
||
|
|
### For Creating New Workspaces
|
||
|
|
|
||
|
|
```bash
|
||
|
|
# The provisioning system should use these templates
|
||
|
|
provisioning workspace init <name> \
|
||
|
|
--path /path/to/workspace \
|
||
|
|
--use-templates
|
||
|
|
```
|
||
|
|
|
||
|
|
### File Mapping
|
||
|
|
|
||
|
|
| Template File | Output Location | Purpose |
|
||
|
|
|---------------|-----------------|---------|
|
||
|
|
| `kcl.mod.template` | `{ws}/kcl.mod` | Workspace package definition |
|
||
|
|
| `workspace-config-schema.k.template` | `{ws}/.provisioning/workspace_config.k` | Schema (SST) |
|
||
|
|
| `workspace-config-defaults.k.template` | `{ws}/.provisioning/workspace_config_defaults.k` | Defaults (SST) |
|
||
|
|
| `.provisioning-kcl.mod.template` | `{ws}/.provisioning/kcl.mod` | .provisioning package |
|
||
|
|
| `config-kcl.mod.template` | `{ws}/config/kcl.mod` | config package |
|
||
|
|
| `workspace-config.k.template` | `{ws}/config/provisioning.k` | Workspace overrides (**workspace-specific**) |
|
||
|
|
|
||
|
|
## Template Variables
|
||
|
|
|
||
|
|
These variables are replaced during workspace creation:
|
||
|
|
|
||
|
|
- `{{WORKSPACE_NAME}}` - Workspace identifier (e.g., "librecloud", "production")
|
||
|
|
- `{{WORKSPACE_PATH}}` - Absolute path to workspace directory
|
||
|
|
- `{{PROVISIONING_PATH}}` - Absolute path to provisioning system
|
||
|
|
- `{{CREATED_TIMESTAMP}}` - ISO 8601 creation timestamp
|
||
|
|
- `{{INFRA_NAME}}` - Infrastructure context name (default: "default")
|
||
|
|
|
||
|
|
## Directory Structure
|
||
|
|
|
||
|
|
```
|
||
|
|
provisioning/config/templates/
|
||
|
|
├── README_SST_PATTERN.md ← You are here
|
||
|
|
├── WORKSPACE_CONFIG_TEMPLATES.md ← Detailed documentation
|
||
|
|
│
|
||
|
|
├── workspace-config-schema.k.template
|
||
|
|
├── workspace-config-defaults.k.template
|
||
|
|
├── workspace-config.k.template
|
||
|
|
│
|
||
|
|
├── kcl.mod.template
|
||
|
|
├── config-kcl.mod.template
|
||
|
|
└── .provisioning-kcl.mod.template
|
||
|
|
```
|
||
|
|
|
||
|
|
## The Three-Part SST Pattern
|
||
|
|
|
||
|
|
### 1. Schema (workspace_config.k)
|
||
|
|
```kcl
|
||
|
|
schema WorkspaceConfig:
|
||
|
|
workspace: Workspace
|
||
|
|
paths: Paths
|
||
|
|
# ... 19+ schemas total
|
||
|
|
```
|
||
|
|
**Purpose**: Type definitions and validation rules
|
||
|
|
**Update**: When schema needs to change (all workspaces affected)
|
||
|
|
**Frequency**: Rare (breaking changes)
|
||
|
|
|
||
|
|
### 2. Defaults (workspace_config_defaults.k)
|
||
|
|
```kcl
|
||
|
|
default_workspace_config: WorkspaceConfig = {
|
||
|
|
workspace = { name = "default-workspace", ... }
|
||
|
|
paths = { infra = "infra", cache = ".cache", ... }
|
||
|
|
debug = { enabled = False, ... }
|
||
|
|
# ... all sections with default values
|
||
|
|
}
|
||
|
|
```
|
||
|
|
**Purpose**: Base configuration inherited by all workspaces
|
||
|
|
**Update**: When default values should change globally
|
||
|
|
**Frequency**: Occasional (new features, policy changes)
|
||
|
|
|
||
|
|
### 3. Workspace Overrides (provisioning.k)
|
||
|
|
```kcl
|
||
|
|
workspace_config = defaults.default_workspace_config | {
|
||
|
|
workspace = { name = "librecloud", ... }
|
||
|
|
paths = defaults.default_workspace_config.paths | {
|
||
|
|
base = "/Users/Akasha/project-provisioning/workspace_librecloud"
|
||
|
|
}
|
||
|
|
provisioning = { path = "/Users/Akasha/project-provisioning/provisioning" }
|
||
|
|
}
|
||
|
|
```
|
||
|
|
**Purpose**: Workspace-specific values (only diffs from defaults)
|
||
|
|
**Update**: When workspace settings change
|
||
|
|
**Frequency**: Per-workspace changes
|
||
|
|
|
||
|
|
## KCL Merge Pattern
|
||
|
|
|
||
|
|
The `|` operator merges KCL objects:
|
||
|
|
|
||
|
|
```kcl
|
||
|
|
# Start with defaults
|
||
|
|
base_config = { a: 1, b: 2, c: 3 }
|
||
|
|
|
||
|
|
# Override specific values
|
||
|
|
final_config = base_config | {
|
||
|
|
b: 20 # Override b
|
||
|
|
# a and c remain from base
|
||
|
|
}
|
||
|
|
|
||
|
|
# Result: { a: 1, b: 20, c: 3 }
|
||
|
|
```
|
||
|
|
|
||
|
|
For nested objects:
|
||
|
|
```kcl
|
||
|
|
# Merge sub-sections
|
||
|
|
paths = defaults.paths | {
|
||
|
|
base: "/custom/path" # Override only base, keep others
|
||
|
|
}
|
||
|
|
```
|
||
|
|
|
||
|
|
## Verification After Template Application
|
||
|
|
|
||
|
|
After generating workspace from templates:
|
||
|
|
|
||
|
|
```bash
|
||
|
|
cd {workspace}/config
|
||
|
|
kcl run provisioning.k
|
||
|
|
```
|
||
|
|
|
||
|
|
Expected output:
|
||
|
|
- Valid YAML on stdout
|
||
|
|
- No errors or validation failures
|
||
|
|
- All configuration sections populated
|
||
|
|
- Values properly merged from defaults and overrides
|
||
|
|
|
||
|
|
## Adding New Configuration Sections
|
||
|
|
|
||
|
|
When adding a new section to workspaces:
|
||
|
|
|
||
|
|
1. **Update schema template**:
|
||
|
|
```kcl
|
||
|
|
schema MyNewConfig:
|
||
|
|
field: str
|
||
|
|
```
|
||
|
|
Add to `workspace-config-schema.k.template`
|
||
|
|
|
||
|
|
2. **Add default value**:
|
||
|
|
```kcl
|
||
|
|
my_new_config = {
|
||
|
|
field: "default-value"
|
||
|
|
}
|
||
|
|
```
|
||
|
|
Add to `workspace-config-defaults.k.template`
|
||
|
|
|
||
|
|
3. **Existing workspaces inherit automatically**
|
||
|
|
- No changes needed to `workspace-config.k.template`
|
||
|
|
- New workspaces get the new section by default
|
||
|
|
- Override in workspace's `provisioning.k` if needed
|
||
|
|
|
||
|
|
## Maintenance Tasks
|
||
|
|
|
||
|
|
### Updating All Workspaces (Template-Driven)
|
||
|
|
|
||
|
|
1. Edit the template files in this directory
|
||
|
|
2. Re-generate workspaces using the `workspace init` command
|
||
|
|
3. Or: Run `provisioning workspace sync` to update existing workspaces
|
||
|
|
|
||
|
|
### Updating Single Workspace
|
||
|
|
|
||
|
|
Edit `{workspace}/config/provisioning.k` directly - only this file is workspace-specific.
|
||
|
|
|
||
|
|
### Updating Schema/Defaults Globally
|
||
|
|
|
||
|
|
Edit templates, then sync all workspaces:
|
||
|
|
```bash
|
||
|
|
provisioning workspace sync --all
|
||
|
|
```
|
||
|
|
|
||
|
|
This updates `.provisioning/` files in all workspaces, keeping workspace-specific `config/provisioning.k` files intact.
|
||
|
|
|
||
|
|
## Example: Complete Workspace Creation Flow
|
||
|
|
|
||
|
|
```bash
|
||
|
|
# 1. Initialize workspace structure
|
||
|
|
workspace_name="production"
|
||
|
|
workspace_path="/opt/workspaces/production"
|
||
|
|
provisioning_path="/usr/local/provisioning"
|
||
|
|
|
||
|
|
# 2. Use templates (provisioning should do this)
|
||
|
|
mkdir -p "$workspace_path"
|
||
|
|
|
||
|
|
# Create workspace root kcl.mod
|
||
|
|
sed "s|{{WORKSPACE_NAME}}|$workspace_name|g" \
|
||
|
|
kcl.mod.template > "$workspace_path/kcl.mod"
|
||
|
|
|
||
|
|
# Create .provisioning/ directory
|
||
|
|
mkdir -p "$workspace_path/.provisioning"
|
||
|
|
|
||
|
|
# Copy .provisioning files (no variable replacement needed)
|
||
|
|
cp workspace-config-schema.k.template \
|
||
|
|
"$workspace_path/.provisioning/workspace_config.k"
|
||
|
|
cp workspace-config-defaults.k.template \
|
||
|
|
"$workspace_path/.provisioning/workspace_config_defaults.k"
|
||
|
|
cp .provisioning-kcl.mod.template \
|
||
|
|
"$workspace_path/.provisioning/kcl.mod"
|
||
|
|
|
||
|
|
# Create config/ directory
|
||
|
|
mkdir -p "$workspace_path/config"
|
||
|
|
cp config-kcl.mod.template \
|
||
|
|
"$workspace_path/config/kcl.mod"
|
||
|
|
|
||
|
|
# Create workspace config with variable replacement
|
||
|
|
sed -e "s|{{WORKSPACE_NAME}}|$workspace_name|g" \
|
||
|
|
-e "s|{{WORKSPACE_PATH}}|$workspace_path|g" \
|
||
|
|
-e "s|{{PROVISIONING_PATH}}|$provisioning_path|g" \
|
||
|
|
-e "s|{{CREATED_TIMESTAMP}}|$(date -u +%Y-%m-%dT%H:%M:%SZ)|g" \
|
||
|
|
workspace-config.k.template > "$workspace_path/config/provisioning.k"
|
||
|
|
|
||
|
|
# 3. Verify
|
||
|
|
cd "$workspace_path/config"
|
||
|
|
kcl run provisioning.k
|
||
|
|
|
||
|
|
echo "✅ Workspace created successfully"
|
||
|
|
```
|
||
|
|
|
||
|
|
## Links
|
||
|
|
|
||
|
|
- **Schema Documentation**: See `workspace-config-schema.k.template`
|
||
|
|
- **Defaults Reference**: See `workspace-config-defaults.k.template`
|
||
|
|
- **Workspace Override Pattern**: See `workspace-config.k.template`
|
||
|
|
- **Detailed Guide**: See `WORKSPACE_CONFIG_TEMPLATES.md`
|
||
|
|
- **Architecture Decision**: See `docs/architecture/adr/ADR-010-configuration-format-strategy.md`
|
||
|
|
|
||
|
|
## Benefits
|
||
|
|
|
||
|
|
✅ **Single Source of Truth** - Schema and defaults defined once
|
||
|
|
✅ **DRY Principle** - No duplication across workspaces
|
||
|
|
✅ **Type-Safe** - Full KCL schema validation
|
||
|
|
✅ **Maintainable** - Update templates to affect all new workspaces
|
||
|
|
✅ **Clear Intent** - Workspace configs show only differences
|
||
|
|
✅ **Mergeable** - Clean KCL merge semantics
|
||
|
|
✅ **Scalable** - Easy to add new config sections
|
||
|
|
|
||
|
|
## Template Extension Convention: `.template`
|
||
|
|
|
||
|
|
The workspace initialization templates in this directory use the **`.template`** extension (not `.j2`) for specific reasons:
|
||
|
|
|
||
|
|
### Why `.template` for Initialization?
|
||
|
|
|
||
|
|
1. **Simple Substitution Only**: Workspace init doesn't need complex logic
|
||
|
|
- Just `{{variable}}` replacement for workspace-specific values
|
||
|
|
- No conditionals, loops, or filters needed
|
||
|
|
|
||
|
|
2. **No Plugin Dependency**: Initialization works without external tools
|
||
|
|
- `nu_plugin_tera` (Jinja2) is not required for workspace creation
|
||
|
|
- More portable, reliable, simpler to bootstrap
|
||
|
|
|
||
|
|
3. **Semantic Clarity**: Extension signals the purpose immediately
|
||
|
|
- `.template` = one-time initialization
|
||
|
|
- `.j2` = runtime configuration generation
|
||
|
|
- Developers know intent at a glance
|
||
|
|
|
||
|
|
4. **Appropriate Complexity**: Using the right tool for the job
|
||
|
|
- Runtime templates (`.j2`): Complex logic, full Jinja2 syntax
|
||
|
|
- Init templates (`.template`): Simple substitution, no complexity
|
||
|
|
|
||
|
|
### Codebase Template Distribution
|
||
|
|
|
||
|
|
- **`.j2` templates**: 134 files (88%) - Runtime configuration generation
|
||
|
|
- **`.template` templates**: 16 files (10%) - Workspace initialization
|
||
|
|
- **`.tera` templates**: 3 files (2%) - Plugin examples only
|
||
|
|
|
||
|
|
See `provisioning/config/templates/README.md` for complete template conventions documentation.
|
||
|
|
|
||
|
|
## Status
|
||
|
|
|
||
|
|
✅ Templates implemented and tested with librecloud workspace
|
||
|
|
✅ SST pattern functional (verified with `kcl run`)
|
||
|
|
✅ Template convention documented (`.template` for init, `.j2` for runtime)
|
||
|
|
⏳ Integration into workspace initialization system (TODO)
|
||
|
|
⏳ Documentation in ADR-010 (TODO)
|