2025-12-11 22:17:44 +00:00

253 lines
8.5 KiB
Plaintext

# 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"