253 lines
8.5 KiB
Plaintext
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"
|
|
|