# VM Configuration Schema (Phase 1) # # Core virtual machine configuration schema with validation. # Follows KCL idiomatic patterns: schema-first, explicit types, check blocks. import regex schema VmConfig: """ Virtual Machine configuration for lifecycle management. Defines complete VM specification including resources, networking, storage, and lifecycle policies. Examples: # Temporary test VM VmConfig { name = "kubernetes-test" base_image = "ubuntu-22.04" cpu = 4 memory_mb = 8192 temporary = True auto_cleanup = True } # Permanent development VM VmConfig { name = "dev-rust" base_image = "ubuntu-22.04" cpu = 8 memory_mb = 16384 disk_gb = 50 permanent = True taskservs = ["rust", "git", "docker"] } """ # VM Identity name: str description?: str # Image Configuration (Pattern 2: Schema-first development) # Base OS image base_image: str = "ubuntu-22.04" # Hardware Resources (Pattern 7: Default values) # CPU cores (1-64) cpu: int = 2 # Memory in MB memory_mb: int = 4096 # Disk space in GB disk_gb: int = 20 # Hypervisor Backend (Pattern 8: Union types for enums) backend: "libvirt" | "qemu" | "docker-vm" = "libvirt" # Lifecycle Configuration (Pattern 9: Optional fields with ?) # Keep after restart permanent: bool = False # Auto-cleanup temporary: bool = False # Auto-delete after TTL auto_cleanup: bool = False # TTL before cleanup auto_cleanup_hours?: int # Taskservs to Install (Pattern 10: Composition) # Single taskserv taskserv?: str # Multiple taskservs taskservs: [str] = [] # Networking (Pattern 8: Union types) network_mode: "bridge" | "nat" | "host" = "bridge" # Custom networks networks?: [VmNetwork] # Port mappings (Pattern 10: Composition with VmPortMapping) ports?: [VmPortMapping] # Storage and Mounts (Pattern 10: Composition) # Host directory mounts mounts?: [VmMount] # Additional volumes volumes?: [VmVolume] # Cloud-init Configuration # ⚠️ SECURITY: Scripts are executed with root privileges # Use vault:// or kms:// references for sensitive data in scripts cloud_init?: VmCloudInit # Advanced Options # Enable nested virtualization nested_virt?: bool = False # Enable graphics graphics_enable?: bool = False # Enable serial console serial_console?: bool = True check: # Validation (Pattern 4: Check blocks for validation) # Name validation len(name) > 0, "Name required" len(name) <= 64, "Name must be <= 64 characters" regex.match(name, r'^[a-z0-9][a-z0-9-]*[a-z0-9]$'), "Name must start/end with alphanumeric, contain only lowercase/numbers/hyphens" # Resource validation cpu > 0 and cpu <= 64, "CPU must be 1-64 cores" memory_mb >= 512 and memory_mb <= 131072, "Memory must be 512MB-128GB" disk_gb >= 5 and disk_gb <= 2048, "Disk must be 5GB-2TB" # Lifecycle validation not (permanent and temporary), "Cannot be both permanent and temporary" not (auto_cleanup and permanent), "Auto-cleanup incompatible with permanent" not auto_cleanup or temporary, "Auto-cleanup only for temporary VMs" # Taskserv validation (Pattern 9: XOR logic - either single or multiple, not both) not (taskserv != Undefined and len(taskservs) > 0), "Specify either 'taskserv' or 'taskservs', not both" # If neither specified, both are allowed (rely on consumer defaults) auto_cleanup_hours == Undefined or (auto_cleanup_hours > 0 and auto_cleanup_hours <= 720), "TTL must be 1-720 hours if specified" # Image validation len(base_image) > 0, "Base image required" schema VmNetwork: """VM network configuration""" name: str = "default" type: "bridge" | "nat" | "host" = "nat" # CIDR notation (e.g., "192.168.122.0/24") subnet?: str check: len(name) > 0, "Network name required" subnet == Undefined or regex.match(subnet, r'^\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}/\d{1,2}$'), "Invalid CIDR notation" schema VmPortMapping: """Port mapping configuration for VM network access""" # Port on host machine host_port: int # Port inside VM guest_port: int # Network protocol protocol: "tcp" | "udp" = "tcp" # Optional IP address to bind to (default: all interfaces) bind_addr?: str check: host_port > 0 and host_port <= 65535, "Host port must be 1-65535" guest_port > 0 and guest_port <= 65535, "Guest port must be 1-65535" bind_addr == Undefined or len(bind_addr) > 0, "Bind address cannot be empty if specified" schema VmMount: """Host directory mount in VM""" host_path: str guest_path: str readonly: bool = False # Mount mode (e.g., "rbind") mode?: str check: len(host_path) > 0, "Host path required" len(guest_path) > 0, "Guest path required" schema VmVolume: """Additional storage volume for VM""" name: str size_gb: int mount_path?: str format: "qcow2" | "raw" = "qcow2" check: len(name) > 0, "Volume name required" size_gb > 0, "Volume size must be positive" schema VmCloudInit: """Cloud-init configuration for VM provisioning""" enabled: bool = True # Cloud-init user-data script user_data?: str # Cloud-init metadata meta_data?: str # Cloud-init vendor-data vendor_data?: str schema VmImage: """Virtual Machine disk image""" name: str format: "qcow2" | "raw" | "vmdk" = "qcow2" path: str size_gb: int base_os: "ubuntu" | "debian" | "rocky" | "arch" = "ubuntu" os_version: str = "22.04" check: len(name) > 0, "Image name required" len(path) > 0, "Image path required" size_gb > 0, "Image size must be positive" schema VmState: """VM runtime state tracking""" vm_name: str state: "stopped" | "starting" | "running" | "stopping" | "error" = "stopped" permanent: bool # ISO 8601 timestamp created_at: str started_at?: str last_action?: str auto_cleanup_at?: str # Assigned IP ip_address?: str # Assigned MAC mac_address?: str # Which hypervisor running on hypervisor?: str # Backend-specific ID (libvirt domain ID) backend_id?: str check: len(vm_name) > 0, "VM name required" len(created_at) > 0, "Creation timestamp required" regex.match(created_at, r'^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}(Z|[+-]\d{2}:\d{2})$'), "created_at must be ISO 8601 format" started_at == Undefined or regex.match(started_at, r'^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}(Z|[+-]\d{2}:\d{2})$'), "started_at must be ISO 8601 format if specified" auto_cleanup_at == Undefined or regex.match(auto_cleanup_at, r'^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}(Z|[+-]\d{2}:\d{2})$'), "auto_cleanup_at must be ISO 8601 format if specified" schema VmRegistry: """Registry of all VMs on system""" # All VMs vms: [VmState] # Number of permanent VMs permanent_count: int # Number of temporary VMs temporary_count: int # Last registry update (ISO 8601 format) updated_at: str check: len(vms) >= 0, "VM list cannot be negative length" permanent_count >= 0, "Permanent VM count cannot be negative" temporary_count >= 0, "Temporary VM count cannot be negative" permanent_count + temporary_count <= len(vms), "Sum of counts should not exceed total VMs" regex.match(updated_at, r'^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}(Z|[+-]\d{2}:\d{2})$'), "updated_at must be ISO 8601 format" schema VmCapacity: """Host capacity information for VM placement""" host_name: str total_cpu_cores: int used_cpu_cores: int total_memory_mb: int used_memory_mb: int total_disk_gb: int used_disk_gb: int # Maximum VMs on host max_vms: int running_vms: int check: total_cpu_cores > 0, "Total CPU cores must be positive" total_memory_mb > 0, "Total memory must be positive" total_disk_gb > 0, "Total disk must be positive" used_cpu_cores >= 0 and used_cpu_cores <= total_cpu_cores, "Used CPU cannot exceed total" used_memory_mb >= 0 and used_memory_mb <= total_memory_mb, "Used memory cannot exceed total" used_disk_gb >= 0 and used_disk_gb <= total_disk_gb, "Used disk cannot exceed total"