# Architecture Diagram & Flow ## Overall Playbook Flow ``` ┌─────────────────────────────────────────────────────────────────────┐ │ ansible-playbook tasks/main.yml │ │ │ │ ┌────────────────────────────────────────────────────────────────┐ │ │ │ PRE_TASKS: Display banner │ │ │ └────────────────────────────────────────────────────────────────┘ │ │ ↓ │ │ ┌────────────────────────────────────────────────────────────────┐ │ │ │ STAGE 1: preflight-checks.yml │ │ │ │ ✓ Proxmox installed? │ │ │ │ ✓ Storage pool exists? │ │ │ │ ✓ SSH key available? │ │ │ │ ✓ IP addresses valid? │ │ │ │ ✓ Permissions okay? │ │ │ └────────────────────────────────────────────────────────────────┘ │ │ ↓ │ │ ┌────────────────────────────────────────────────────────────────┐ │ │ │ STAGE 2: download-image.yml │ │ │ │ ├─ Check if image cached │ │ │ │ ├─ Download if missing (with retry) │ │ │ │ ├─ Verify integrity │ │ │ │ └─ Display image info │ │ │ └────────────────────────────────────────────────────────────────┘ │ │ ↓ │ │ ┌────────────────────────────────────────────────────────────────┐ │ │ │ STAGE 3: create-vm.yml │ │ │ │ ├─ Check if VM exists (skip if yes) │ │ │ │ ├─ Create VM with qm │ │ │ │ ├─ Verify creation │ │ │ │ └─ Display status │ │ │ └────────────────────────────────────────────────────────────────┘ │ │ ↓ │ │ ┌────────────────────────────────────────────────────────────────┐ │ │ │ STAGE 4: configure-vm.yml │ │ │ │ ├─ Configure UEFI + TPM (if enabled) │ │ │ │ ├─ Import & attach disk (with retry) │ │ │ │ ├─ Resize disk (if enabled) │ │ │ │ ├─ Configure GPU (if enabled) │ │ │ │ └─ Apply Cloud-Init config │ │ │ │ ├─ Create snippets │ │ │ │ ├─ Verify SSH key │ │ │ │ └─ Apply Cloud-Init │ │ │ └────────────────────────────────────────────────────────────────┘ │ │ ↓ │ │ ┌────────────────────────────────────────────────────────────────┐ │ │ │ STAGE 5: create-template.yml │ │ │ │ ├─ Check if already templated (skip if yes) │ │ │ │ ├─ Stop VM if running │ │ │ │ ├─ Convert to template │ │ │ │ └─ Verify conversion │ │ │ │ │ │ │ │ 🔄 IDEMPOTENT: Skips if already templated! │ │ │ └────────────────────────────────────────────────────────────────┘ │ │ ↓ │ │ ┌────────────────────────────────────────────────────────────────┐ │ │ │ STAGE 6: create-clones.yml (if enabled) │ │ │ │ │ │ │ │ For each clone in list: │ │ │ │ ├─ Check if clone exists (skip if yes) │ │ │ │ ├─ Clone from template │ │ │ │ ├─ Configure clone (hostname, IP) │ │ │ │ ├─ Start clone │ │ │ │ └─ ⚠️ Error doesn't stop other clones │ │ │ │ │ │ │ │ 🔄 IDEMPOTENT: Skips existing clones! │ │ │ └────────────────────────────────────────────────────────────────┘ │ │ ↓ │ │ ┌────────────────────────────────────────────────────────────────┐ │ │ │ POST_TASKS: Display completion summary │ │ │ │ ✓ VMs created │ │ │ │ ✓ Template converted │ │ │ │ ✓ Clones deployed │ │ │ │ Next steps... │ │ │ └────────────────────────────────────────────────────────────────┘ │ │ ↓ │ │ ┌────────────────────────────────────────────────────────────────┐ │ │ │ RESCUE: Handle errors (if any) │ │ │ │ ✗ Playbook execution failed │ │ │ │ Check messages above for details │ │ │ └────────────────────────────────────────────────────────────────┘ │ └─────────────────────────────────────────────────────────────────────┘ ``` ## Error Handling Strategy ``` ┌──────────────────────────────────────────┐ │ Task Execution │ └──────────────────────────────┬────────────┘ │ ┌────────┴────────┐ │ │ Success Failure │ │ ▼ ▼ ┌─────────────────┐ ┌──────────────────┐ │ Continue with │ │ block/rescue │ │ next task │ │ │ └─────────────────┘ ├──────────────────┤ │ Try recovery? │ └────┬─────────────┘ │ ┌──────┴────────┐ │ │ Recoverable Unrecoverable │ │ ▼ ▼ ┌─────────────────┐ ┌──────────────┐ │ Warn/continue │ │ fail_msg + │ │ to next clone │ │ detailed ctx │ └─────────────────┘ └──────────────┘ ``` ## Idempotency Checks ``` Operation Check Result ───────────────────────────────────────────────────────────── Download Image File exists? Skip if cached Create VM /etc/pve/qemu-server/VM_ID.conf exists? Skip if exists Configure Disk Disk already attached? Skip if yes Template Conversion grep 'template: 1' Skip if already template Clone Creation Clone config exists? Skip if exists ``` ## Task Dependency Graph ``` preflight-checks ↓ download-image ↓ create-vm ↓ configure-vm ├─→ [TPM config] ├─→ [Disk import] ├─→ [GPU config] └─→ [Cloud-Init] ↓ create-template (when: make_template) ↓ create-clones (when: create_clones) └─→ For each clone: ├─ Check if exists ├─ Clone VM ├─ Configure ├─ Start └─ Error: warn, continue ``` ## Tag Structure ``` All tasks tagged: --tags preflight Stage 1 only --tags image Stage 2 only --tags vm,create Stage 3 only --tags vm,configure Stage 4 only --tags template,create Stage 5 only --tags clones,create Stage 6 only --tags image,always Stages 1-2 (image download) --tags vm Stages 3-4 (VM creation & config) --tags template Stages 5-6 (template & clones) --skip-tags template Skip template conversion --skip-tags clones Skip clone deployment --skip-tags image Don't re-download image ``` ## Error Recovery Flow ``` ┌─────────────────────────┐ │ Task fails │ └────────────┬────────────┘ │ ┌──────┴──────┐ │ │ ▼ ▼ Retry? Rescue? │ │ (3x) Handle │ │ ▼ ▼ Success Continue/Fail? or │ Fail ┌──┴──┐ │ │ │ ▼ ▼ ▼ Continue Continue Fail to next to next + task (warn) Msg ``` ## Idempotency Timeline ``` Run 1 (First execution): preflight ✓ pass image ✓ download create-vm ✓ create configure-vm ✓ configure create-template ✓ convert to template create-clones ✓ create clones Run 2 (Re-run): preflight ✓ pass image → skip (cached) create-vm → skip (exists) configure-vm → skip (disk exists) create-template → skip (already template!) create-clones → skip (clones exist) ⏱️ Much faster! ⚡ ``` ## Pre-flight Checks Detail ``` ┌─────────────────────────────────────────────────────┐ │ Preflight Checks (Early failure detection) │ ├─────────────────────────────────────────────────────┤ │ │ │ Environment: │ │ ✓ /etc/pve/nodes exists (Proxmox check) │ │ ✓ qm command available │ │ ✓ qm version readable │ │ │ │ Permissions: │ │ ✓ Can run qm commands (sudo/root) │ │ ✓ Can access storage │ │ │ │ Resources: │ │ ✓ Storage pool {{ storage }} exists │ │ ✓ Snippets directory exists │ │ │ │ Configuration: │ │ ✓ SSH key file exists & readable │ │ ✓ VM ID {{ vm_id }} unique │ │ ✓ Clone IDs unique (if create_clones) │ │ ✓ IP addresses valid (if static) │ │ ✓ Gateway IP valid │ │ ✓ DNS servers valid │ │ │ │ Result: Fail early with context if any check fails │ └─────────────────────────────────────────────────────┘ ``` ## Cloud-Init Configuration Flow ``` ┌──────────────────────────────┐ │ Cloud-Init Application │ ├──────────────────────────────┤ │ │ │ Validate SSH key │ │ ↓ │ │ Create vendor snippet │ │ ↓ │ │ Create user snippet │ │ ↓ │ │ Copy SSH key to snippets │ │ ↓ │ │ Apply cicustom config │ │ with nocloud datasource │ │ ↓ │ │ Set ipconfig0 (DHCP/static) │ │ ↓ │ │ Result: VM ready for boot │ │ │ └──────────────────────────────┘ ``` --- **Legend:** - `✓` = Success/Validation passed - `✗` = Failure - `→` = Skip (idempotent) - `⚠️` = Warning (non-fatal) - `🔄` = Idempotent operation