Files
nest/uvm/firecracker/config.py
T
kstyagi fb80ce7c8a 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.
2026-09-21 19:16:33 +05:30

97 lines
2.5 KiB
Python

"""Build and persist Firecracker configuration for one VM."""
from __future__ import annotations
import json
import math
import os
import tempfile
from collections.abc import Mapping
from ipaddress import IPv4Address, IPv4Network
from pathlib import Path
from typing import Any
from ..config import Settings
from ..domain import VmRecord
def vcpu_count(cpu: float) -> int:
"""Firecracker accepts whole vCPUs; fractional capacity rounds up for now."""
return max(1, math.ceil(cpu))
def boot_ip_argument(
guest_ip: IPv4Address,
gateway: IPv4Address,
network: IPv4Network,
) -> str:
return f"ip={guest_ip}::{gateway}:{network.netmask}::eth0:off"
def build_config(
settings: Settings,
vm: VmRecord,
kernel: Path,
rootfs: Path,
) -> dict[str, Any]:
boot_args = " ".join(
(
"console=ttyS0",
"reboot=k",
"panic=1",
"pci=off",
boot_ip_argument(IPv4Address(vm.guest_ip), settings.gateway, settings.network),
)
)
if settings.architecture == "aarch64":
boot_args = f"keep_bootcon {boot_args}"
return {
"boot-source": {
"kernel_image_path": str(kernel),
"boot_args": boot_args,
},
"drives": [
{
"drive_id": "rootfs",
"path_on_host": str(rootfs),
"is_root_device": True,
"is_read_only": False,
}
],
"machine-config": {
"vcpu_count": vcpu_count(vm.cpu),
"mem_size_mib": vm.ram_mib,
},
"network-interfaces": [
{
"iface_id": "eth0",
"guest_mac": vm.mac,
"host_dev_name": vm.tap,
}
],
}
def write_config(path: Path, config: Mapping[str, Any]) -> None:
"""Atomically publish a rendered Firecracker configuration file."""
path.parent.mkdir(parents=True, exist_ok=True)
descriptor, temporary_name = tempfile.mkstemp(
prefix=f".{path.name}.",
suffix=".tmp",
dir=path.parent,
)
try:
with os.fdopen(descriptor, "w", encoding="utf-8") as temporary_file:
json.dump(config, temporary_file, indent=2)
temporary_file.write("\n")
temporary_file.flush()
os.fsync(temporary_file.fileno())
os.replace(temporary_name, path)
finally:
try:
os.unlink(temporary_name)
except FileNotFoundError:
pass