Update core components including CLI, Nushell libraries, plugins system, and utility scripts for the provisioning system. CLI Updates: - Command implementations - CLI utilities and dispatching - Help system improvements - Command validation Library Updates: - Configuration management system - Infrastructure validation - Extension system improvements - Secrets management - Workspace operations - Cache management system Plugin System: - Interactive form plugin (inquire) - KCL integration plugin - Performance optimization plugins - Plugin registration system Utilities: - Build and distribution scripts - Installation procedures - Testing utilities - Development tools Documentation: - Library module documentation - Extension API guides - Plugin usage guides - Service management documentation All changes are backward compatible. No breaking changes.
249 lines
6.2 KiB
Plaintext
249 lines
6.2 KiB
Plaintext
# 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}
|
|
}
|