# VM Lifecycle Management # # Higher-level VM operations: create, start, stop, delete with state tracking. # Rule 1: Single purpose, Rule 4: Pure functions, Rule 5: Atomic operations use ./backend_libvirt.nu * use ./persistence.nu * export def "vm-create" [ vm_config: record # VM configuration (from KCL) --backend: string = "libvirt" # Backend to use ]: record { """ Create a virtual machine. Creates VM disk, defines in hypervisor, and records state. Examples: # Create temporary test VM vm-create { name: "test-k8s" cpu: 4 memory_mb: 8192 temporary: true auto_cleanup: true } # Create permanent dev VM vm-create { name: "dev-rust" cpu: 8 memory_mb: 16384 disk_gb: 50 permanent: true } """ # Validation (Rule 3: Early return) let validation = (validate-vm-config $vm_config) if not $validation.valid { return { success: false error: $validation.error } } # Create disk let disk_result = (libvirt-create-disk $vm_config.name $vm_config.disk_gb) if not $disk_result.success { return { success: false error: $"Disk creation failed: ($disk_result.error)" } } # Define VM in libvirt let define_result = (libvirt-create-vm $vm_config) if not $define_result.success { # Cleanup disk on failure bash -c $"rm -f ($disk_result.path)" return $define_result } # Record VM state (Rule 5: Atomic operation) let state_result = (record-vm-creation $vm_config) if not $state_result.success { # Try to cleanup on failure libvirt-delete-vm $vm_config.name | ignore return $state_result } { success: true vm_name: $vm_config.name vm_id: $define_result.vm_id message: $"VM ($vm_config.name) created successfully" disk_path: $disk_result.path } } export def "vm-start" [ vm_name: string # VM name ]: record { """Start a virtual machine""" if ($vm_name | is-empty) { return {success: false, error: "VM name required"} } let start_result = (libvirt-start-vm $vm_name) if not $start_result.success { return $start_result } # Update state update-vm-state $vm_name "running" | ignore $start_result } export def "vm-stop" [ vm_name: string # VM name --force = false # Force shutdown ]: record { """Stop a virtual machine""" if ($vm_name | is-empty) { return {success: false, error: "VM name required"} } let stop_result = (libvirt-stop-vm $vm_name --force=$force) if not $stop_result.success { return $stop_result } # Update state update-vm-state $vm_name "stopped" | ignore $stop_result } export def "vm-delete" [ vm_name: string # VM name --force = false # Force deletion ]: record { """Delete a virtual machine""" if ($vm_name | is-empty) { return {success: false, error: "VM name required"} } # Delete from libvirt let delete_result = (libvirt-delete-vm $vm_name) if not $delete_result.success { return $delete_result } # Remove state record remove-vm-state $vm_name | ignore $delete_result } export def "vm-list" [ --permanent = false # List only permanent VMs --temporary = false # List only temporary VMs --running = false # List only running VMs ]: table { """List virtual machines""" let all_vms = (libvirt-list-vms) let vms = ( $all_vms | each {|vm| let state = (get-vm-state $vm.name) { name: $vm.name status: $vm.state permanent: ($state.permanent 2>/dev/null ?? false) temporary: ($state.temporary 2>/dev/null ?? false) cpu: ($state.cpu 2>/dev/null ?? "unknown") memory_mb: ($state.memory_mb 2>/dev/null ?? "unknown") } } ) # Apply filters let filtered = ( $vms | if $permanent { where permanent == true } else if $temporary { where temporary == true } else { . } | if $running { where status == "running" } else { . } ) $filtered } export def "vm-info" [ vm_name: string # VM name ]: record { """Get detailed VM information""" if ($vm_name | is-empty) { return {error: "VM name required"} } let libvirt_info = (libvirt-get-vm-info $vm_name) let state_info = (get-vm-state $vm_name) let ip_address = (libvirt-get-vm-ip $vm_name) { name: $vm_name status: $libvirt_info.state id: $libvirt_info.id cpu_cores: $libvirt_info.cpu_cores memory_mb: $libvirt_info.memory_mb ip_address: $ip_address permanent: ($state_info.permanent 2>/dev/null ?? false) temporary: ($state_info.temporary 2>/dev/null ?? false) created_at: ($state_info.created_at 2>/dev/null ?? "unknown") } } def validate-vm-config [config: record]: record { """Validate VM configuration""" # Name validation if ($config.name | is-empty) { return {valid: false, error: "VM name required"} } if not ($config.name | str match '^[a-z0-9][a-z0-9-]*[a-z0-9]$') { return { valid: false error: "Invalid VM name format" } } # Resource validation if ($config.cpu // 0) <= 0 or ($config.cpu // 0) > 64 { return {valid: false, error: "CPU must be 1-64"} } if ($config.memory_mb // 0) < 512 { return {valid: false, error: "Memory must be >= 512MB"} } if ($config.disk_gb // 0) < 5 { return {valid: false, error: "Disk must be >= 5GB"} } # Lifecycle validation if ($config.permanent and $config.temporary) { return {valid: false, error: "Cannot be both permanent and temporary"} } {valid: true} }