feat: Add storage management for VM creation and resizing

- Introduced storage parameter in VmCreateRequest and VmResizeRequest models.
- Implemented storage validation to ensure minimum and maximum limits.
- Enhanced CLI to support storage options during VM creation and resizing.
- Updated lifecycle management to handle pending resize operations for VM resources.
- Added methods for resizing VM disks and validating storage capacity.
- Updated API endpoints to accommodate new storage functionality.
- Refactored related validation and configuration logic to support storage management.
This commit is contained in:
2026-09-21 19:16:33 +05:30
parent 781ee753ec
commit fb80ce7c8a
38 changed files with 728 additions and 98 deletions
+23 -13
View File
@@ -3,21 +3,16 @@
from __future__ import annotations
import os
from dataclasses import dataclass
from dataclasses import dataclass, field
from ipaddress import IPv4Address, IPv4Network
from pathlib import Path
from .errors import ConfigurationError
DEFAULT_KERNEL_URL = (
"https://s3.amazonaws.com/spec.ccfc.min/img/quickstart_guide/"
"x86_64/kernels/vmlinux.bin"
)
DEFAULT_ROOTFS_URL = (
"https://s3.amazonaws.com/spec.ccfc.min/img/quickstart_guide/"
"x86_64/rootfs/bionic.rootfs.ext4"
)
DEFAULT_GUEST_ASSETS_URL = "https://s3.amazonaws.com/spec.ccfc.min/img/quickstart_guide"
MIN_STORAGE_MIB = 30 * 1024
MAX_STORAGE_MIB = (2**63 - 1) // (1024 * 1024)
@dataclass(frozen=True, slots=True)
@@ -29,12 +24,14 @@ class Settings:
network: IPv4Network = IPv4Network("10.42.0.0/24")
gateway: IPv4Address = IPv4Address("10.42.0.1")
bridge: str = "uvm0"
architecture: str = field(default_factory=lambda: os.uname().machine)
firecracker_version: str = "v1.16.1"
default_ram_mib: int = 512
default_storage_mib: int = MIN_STORAGE_MIB
default_vcpu: float = 1
default_ssh_user: str = "root"
kernel_url: str = DEFAULT_KERNEL_URL
rootfs_url: str = DEFAULT_ROOTFS_URL
kernel_url: str = ""
rootfs_url: str = ""
firecracker_sha256: str | None = None
firecracker_binary_sha256: str | None = None
kernel_sha256: str | None = None
@@ -48,6 +45,19 @@ class Settings:
terminate_timeout_s: float = 5.0
def __post_init__(self) -> None:
architecture = self.architecture.lower()
architecture = {"amd64": "x86_64", "arm64": "aarch64"}.get(architecture, architecture)
if architecture not in ("x86_64", "aarch64"):
raise ConfigurationError(f"unsupported host architecture: {self.architecture}")
object.__setattr__(self, "architecture", architecture)
# Resolve defaults at construction time, while preserving individual URL overrides.
asset_base = f"{DEFAULT_GUEST_ASSETS_URL}/{architecture}"
if not self.kernel_url:
object.__setattr__(self, "kernel_url", f"{asset_base}/kernels/vmlinux.bin")
if not self.rootfs_url:
object.__setattr__(self, "rootfs_url", f"{asset_base}/rootfs/bionic.rootfs.ext4")
if self.gateway not in self.network:
raise ConfigurationError(
f"gateway {self.gateway} is outside configured network {self.network}"
@@ -124,8 +134,8 @@ class Settings:
network=network,
gateway=gateway,
bridge=os.environ.get("UVM_BRIDGE", "uvm0"),
kernel_url=os.environ.get("UVM_KERNEL_URL", DEFAULT_KERNEL_URL),
rootfs_url=os.environ.get("UVM_ROOTFS_URL", DEFAULT_ROOTFS_URL),
kernel_url=os.environ.get("UVM_KERNEL_URL", ""),
rootfs_url=os.environ.get("UVM_ROOTFS_URL", ""),
firecracker_sha256=_optional_environment_value("UVM_FIRECRACKER_SHA256"),
firecracker_binary_sha256=_optional_environment_value(
"UVM_FIRECRACKER_BINARY_SHA256"