# Nested Provisioning System (Phase 4) # # Support for nested VMs (VM → VM → Containers). # Rule 1: Single purpose, Rule 5: Atomic operations # Selective imports (ADR-025 Phase 3 Layer 2). use platform/vm/lifecycle.nu [vm-info] use platform/vm/volume_management.nu [volume-attach volume-detach] use platform/vm/network_management.nu [network-connect network-disconnect] export def "nested-vm-create" [ name: string # VM name parent_vm: string # Parent VM name --cpu: int = 2 # CPU cores --memory: int = 2048 # Memory in MB --disk: int = 20 # Disk in GB --networks: list = [] # Networks to connect --volumes: list = [] # Volumes to attach --auto-start = false # Auto-start on parent boot --nested-virt = true # Enable nested virtualization ]: record { """ Create a nested VM inside another VM. Enables multi-level virtualization for complex deployments. """ if ($name | is-empty) { return {success: false, error: "VM name required"} } if ($parent_vm | is-empty) { return {success: false, error: "Parent VM required"} } if ($cpu < 1 or $cpu > 32) { return {success: false, error: "CPU must be 1-32"} } if ($memory < 512 or $memory > 65536) { return {success: false, error: "Memory must be 512MB-64GB"} } # Verify parent VM exists let parent_info = (vm-info $parent_vm) if ("error" in $parent_info) { return {success: false, error: "Parent VM not found"} } # Check nesting depth let nesting_depth = (get-nesting-depth $parent_vm) if $nesting_depth >= 3 { return {success: false, error: "Maximum nesting depth (3) exceeded"} } let nested_dir = (get-nested-directory) bash -c $"mkdir -p ($nested_dir)" | complete let nested_meta = { name: $name parent_vm: $parent_vm nesting_depth: ($nesting_depth + 1) cpu: $cpu memory_mb: $memory disk_gb: $disk networks: $networks volumes: $volumes auto_start: $auto_start nested_virt: $nested_virt created_at: (date now | format date "%Y-%m-%dT%H:%M:%SZ") status: "created" } # Create VM disk (no try-catch) let create_result = (do { bash -c $"qemu-img create -f qcow2 ($nested_dir)/($name).qcow2 ($disk)G" } | complete) if $create_result.exit_code != 0 { return {success: false, error: $"Failed to create VM disk: ($create_result.stderr)"} } # Save metadata (no try-catch) let save_result = (do { bash -c $"cat > ($nested_dir)/($name).json << 'EOF'\n($nested_meta | to json)\nEOF" } | complete) if $save_result.exit_code != 0 { return {success: false, error: $"Failed to save metadata: ($save_result.stderr)"} } # Connect to networks (no try-catch) $networks | each {|network| network-connect $network $name } # Attach volumes (no try-catch) $volumes | each {|volume| volume-attach $volume $name } { success: true nested_vm: $name parent_vm: $parent_vm cpu: $cpu memory_mb: $memory disk_gb: $disk nesting_depth: ($nesting_depth + 1) } } export def "nested-vm-list" [ parent_vm: string = "" # Filter by parent (empty = all) ]: table { """ List nested VMs, optionally filtered by parent. """ let nested_dir = (get-nested-directory) if (not ($nested_dir | path exists)) { return [] } bash -c $"ls -1 ($nested_dir)/*.json 2>/dev/null" | lines | each {|file| # Guard: Check if file can be opened and parsed as JSON (no try-catch) let json_result = (do { open $file | from json } | complete) if $json_result.exit_code == 0 { let meta = ($json_result.stdout) if ($parent_vm | is-empty) or ($meta.parent_vm == $parent_vm) { { name: $meta.name parent: $meta.parent_vm depth: $meta.nesting_depth cpu: $meta.cpu memory_mb: $meta.memory_mb disk_gb: $meta.disk_gb status: $meta.status created: $meta.created_at } } } else { null } } | compact } export def "nested-vm-info" [ name: string # VM name ]: record { """ Get detailed nested VM information. """ let nested_dir = (get-nested-directory) let meta_file = $"($nested_dir)/($name).json" if (not ($meta_file | path exists)) { return {success: false, error: "Nested VM not found"} } # Load metadata (no try-catch) let meta_result = (do { open $meta_file | from json } | complete) if $meta_result.exit_code != 0 { return {success: false, error: $"Failed to load metadata: ($meta_result.stderr)"} } let meta = ($meta_result.stdout) { success: true name: $meta.name parent_vm: $meta.parent_vm nesting_depth: $meta.nesting_depth cpu: $meta.cpu memory_mb: $meta.memory_mb disk_gb: $meta.disk_gb networks: $meta.networks volumes: $meta.volumes auto_start: $meta.auto_start nested_virt: $meta.nested_virt created: $meta.created_at status: $meta.status } } export def "nested-vm-delete" [ name: string # VM name --force = false # Force delete ]: record { """ Delete a nested VM. """ let nested_dir = (get-nested-directory) let meta_file = $"($nested_dir)/($name).json" if (not ($meta_file | path exists)) { return {success: false, error: "Nested VM not found"} } # Load metadata (no try-catch) let meta_result = (do { open $meta_file | from json } | complete) if $meta_result.exit_code != 0 { return {success: false, error: $"Failed to load metadata: ($meta_result.stderr)"} } let meta = ($meta_result.stdout) # Detach volumes and networks (no try-catch) $meta.volumes | each {|volume| volume-detach $volume $name } $meta.networks | each {|network| network-disconnect $network $name } # Delete VM disk and metadata (no try-catch) let rm_disk_result = (do { bash -c $"rm -f ($nested_dir)/($name).qcow2" } | complete) if $rm_disk_result.exit_code != 0 { return {success: false, error: $"Failed to delete VM disk: ($rm_disk_result.stderr)"} } let rm_meta_result = (do { bash -c $"rm -f ($meta_file)" } | complete) if $rm_meta_result.exit_code != 0 { return {success: false, error: $"Failed to delete metadata: ($rm_meta_result.stderr)"} } { success: true message: "Nested VM deleted" } } export def "container-create" [ name: string # Container name image: string # Container image parent_vm: string # Parent VM name --tag: string = "latest" # Image tag --cpu-millicores: int = 1000 # CPU in millicores --memory-mb: int = 512 # Memory in MB --networks: list = [] # Networks --volumes: list = [] # Volume mounts --ports: list = [] # Port mappings --env: record = {} # Environment variables --auto-start = false # Auto-start ]: record { """ Create a container inside a nested VM. Supports Docker, Podman, and containerd runtimes. """ if ($name | is-empty) { return {success: false, error: "Container name required"} } if ($image | is-empty) { return {success: false, error: "Image required"} } let containers_dir = (get-containers-directory) bash -c $"mkdir -p ($containers_dir)" | complete let container_meta = { name: $name image: $"($image):($tag)" parent_vm: $parent_vm cpu_millicores: $cpu_millicores memory_mb: $memory_mb networks: $networks volumes: $volumes ports: $ports environment: $env auto_start: $auto_start created_at: (date now | format date "%Y-%m-%dT%H:%M:%SZ") status: "created" } # Save container metadata (no try-catch) let save_result = (do { bash -c $"cat > ($containers_dir)/($name).json << 'EOF'\n($container_meta | to json)\nEOF" } | complete) if $save_result.exit_code != 0 { return {success: false, error: $"Failed to save container metadata: ($save_result.stderr)"} } { success: true container: $name image: $container_meta.image parent_vm: $parent_vm cpu_millicores: $cpu_millicores memory_mb: $memory_mb } } export def "container-list" [ parent_vm: string = "" # Filter by parent VM ]: table { """ List containers, optionally filtered by parent VM. """ let containers_dir = (get-containers-directory) if (not ($containers_dir | path exists)) { return [] } bash -c $"ls -1 ($containers_dir)/*.json 2>/dev/null" | lines | each {|file| # Guard: Check if file can be opened and parsed as JSON (no try-catch) let json_result = (do { open $file | from json } | complete) if $json_result.exit_code == 0 { let meta = ($json_result.stdout) if ($parent_vm | is-empty) or ($meta.parent_vm == $parent_vm) { { name: $meta.name image: $meta.image parent_vm: $meta.parent_vm cpu_millicores: $meta.cpu_millicores memory_mb: $meta.memory_mb status: $meta.status created: $meta.created_at } } } else { null } } | compact } export def "container-delete" [ name: string # Container name ]: record { """ Delete a container. """ let containers_dir = (get-containers-directory) let meta_file = $"($containers_dir)/($name).json" if (not ($meta_file | path exists)) { return {success: false, error: "Container not found"} } # Delete container metadata (no try-catch) let rm_result = (do { bash -c $"rm -f ($meta_file)" } | complete) if $rm_result.exit_code != 0 { return {success: false, error: $"Failed to delete container: ($rm_result.stderr)"} } { success: true message: "Container deleted" } } export def "nesting-stats" []: record { """ Get nested provisioning statistics. """ let nested_vms = (nested-vm-list) let containers = (container-list) let max_depth = ( if ($nested_vms | length) > 0 { $nested_vms | get depth | math max } else { 0 } ) { nested_vms: ($nested_vms | length) containers: ($containers | length) max_nesting_depth: $max_depth by_depth: ( $nested_vms | group-by {|vm| $vm.depth} | each {|group| {depth: ($group | first | get depth), count: ($group | length)}} ) } } def get-nested-directory []: string { """Get nested VMs directory""" "{{paths.workspace}}/vms/nested" } def get-containers-directory []: string { """Get containers directory""" "{{paths.workspace}}/vms/containers" } def get-nesting-depth [vm: string]: int { """Get nesting depth of VM""" let nested_dir = (get-nested-directory) let meta_file = $"($nested_dir)/($vm).json" if ($meta_file | path exists) { let meta = (open $meta_file | from json) $meta.nesting_depth } else { 0 } }