# VM Host Preparation System # # Prepares hosts for VM management by installing necessary hypervisors. # Supports three modes: explicit, automatic, and auto-detect. use ./detector.nu * export def "prepare-host-for-vms" [ host: string # Host identifier ("local" or remote hostname) --auto-install # Auto-install missing hypervisors --check-only # Only check, don't modify ]: record { """ Prepare a host for virtual machine management. Detects available hypervisors and optionally installs missing ones. Examples: # Check local host capability prepare-host-for-vms "local" --check-only # Prepare local host with auto-install prepare-host-for-vms "local" --auto-install # Check remote host prepare-host-for-vms "upcloud-server-01" --check-only """ let capabilities = (check-vm-capability $host) if $check_only { return $capabilities } if not $auto_install { return $capabilities } # Auto-install hypervisors prepare-host-install $host $capabilities } def prepare-host-install [host: string, capabilities: record]: record { """Install hypervisors on host""" let needs_installation = ( ($capabilities.primary_backend == "none") ) if not $needs_installation { return { host: $host status: "ready" message: $"Host has ($capabilities.primary_backend) hypervisor available" } } print $"Preparing host ($host) for VM support..." # Determine what to install let to_install = [ "kvm", "libvirt", "qemu", ] # Install each hypervisor let results = ( $to_install | each {|taskserv| install-hypervisor-taskserv $host $taskserv } ) # Check results let failures = ($results | where success == false) if ($failures | length) > 0 { return { host: $host status: "partial" message: $"Installed successfully but ($failures | length) failed" failed_taskservs: ($failures | each {|x| $x.taskserv}) } } { host: $host status: "success" message: "Host prepared successfully for VM management" installed_taskservs: $to_install } } def install-hypervisor-taskserv [host: string, taskserv: string]: record { """Install a hypervisor taskserv on host""" print $" Installing ($taskserv)..." let cmd = ( if $host == "local" { $"provisioning taskserv create ($taskserv)" } else { $"provisioning taskserv create ($taskserv) --on-host ($host)" } ) let result = ( try { (shell-exec-safe $cmd) } catch {|err| { taskserv: $taskserv success: false error: $err } } ) if ($result | type) == "record" and ("success" in $result) { return $result } { taskserv: $taskserv success: true message: $"Installed successfully" } } def shell-exec-safe [cmd: string]: record { """Execute shell command safely""" let result = ( try { (bash -c $cmd | complete) } catch {|err| error make {msg: $err} } ) if $result.exit_code != 0 { error make {msg: $result.stderr} } $result } export def "get-host-hypervisor-status" [host: string]: table { """Get detailed hypervisor status for a host""" let capabilities = (check-vm-capability $host) $capabilities.available_hypervisors | map {|h| { host: $host hypervisor: $h.name status: $h.available description: $h.description ready: ($h.available == "ready") } } } export def "list-vm-capable-hosts" []: table { """List all hosts that can run VMs""" # Get local host capability let local_status = (check-vm-capability "local") [ { name: "local" can_run_vms: $local_status.can_run_vms primary_hypervisor: $local_status.primary_backend } ] # In future, could add remote hosts from infrastructure config } export def "ensure-vm-support" [host: string]: record { """ Ensure host has VM support, installing if necessary. Returns success only when VM support is confirmed ready. """ let status1 = (check-vm-capability $host) if $status1.primary_backend != "none" { return { host: $host status: "ready" message: $"Host already has VM support via ($status1.primary_backend)" } } # Need to install print $"Host ($host) needs VM hypervisor installation" let install_result = (prepare-host-install $host $status1) if $install_result.status != "success" { return $install_result } # Verify installation let status2 = (check-vm-capability $host) { host: $host status: "ready" message: $"VM support installed and verified" primary_hypervisor: $status2.primary_backend } }