# Design Decisions ## KDL over TOML/JSON KDL (v2) was chosen for all config files because: - Node-based structure maps naturally to zone/pool/template semantics - More readable than TOML for nested structures - `kdl` crate v6.5 supports KDL v2 spec - Note: KDL v2 uses `#true`/`#false` for booleans, not bare `true`/`false` `knuffel` (typed derive) was evaluated but targets KDL v1, incompatible with `kdl` v6. Manual extraction via `kdl_util.rs` helpers is sufficient for our simple schemas. ## Flat Files, No Database All state lives in `/etc/zmgr/` as individual KDL files: - One file per zone, pool, template, publisher - Human-editable with any text editor - Works on minimal illumos installs (no SQLite, no sled) - Easy to back up, version control, or inspect ## IPAM: Zone Files Are the Ledger No separate allocation table. To find allocated IPs: 1. Scan `/etc/zmgr/zones/*.kdl` 2. Parse each zone's `address` field 3. Check which IPs fall within a pool's network This avoids consistency issues between a ledger and registry. ## Global Pools, Template References Pools are defined independently (not inside templates) so multiple templates can share a pool. Templates reference pools by name. This matches the user's preference for a "global pool config" pattern. ## bhyve Exclusion Import logic explicitly skips `brand=bhyve` zones. These are vm-manager's responsibility. This boundary is enforced at the import level, not at the config level. ## Error Handling: miette Diagnostics Every error variant includes: - A descriptive message - A diagnostic code (e.g., `zmgr::pool::exhausted`) - A help message telling the user what to do next This follows the miette diagnostic pattern per project conventions. ## No Daemon, No State Machine zmgr is a one-shot CLI. Each invocation reads config, acts, writes results. No background process, no lock files, no PID management. Zone lifecycle is delegated to the OS (`zoneadm`).