Refactor VM lifecycle management and enhance validation
- Introduced a new method `installed_kernel` in `ImageStore` to handle kernel verification and checksum validation. - Updated `Installer` to include additional packages: `nftables` and `conntrack`. - Refined `LifecycleService` to improve error handling and state management during VM creation, starting, stopping, and deletion. - Enhanced port management with new methods for setting and syncing ports, including validation for port rules. - Improved error handling in `StateStore` to raise specific `NotFoundError` and `ConflictError` exceptions. - Updated network management to ensure proper TAP device handling and firewall integration. - Enhanced API responses in `vms.py` to include policy status for better client-side handling. - Added validation for VM names and ports in `validation.py` to enforce stricter rules and prevent conflicts.
This commit is contained in:
@@ -4,9 +4,11 @@ from __future__ import annotations
|
||||
|
||||
import math
|
||||
import re
|
||||
from collections.abc import Sequence
|
||||
from decimal import Decimal, InvalidOperation
|
||||
|
||||
from .errors import ValidationError
|
||||
from .domain import PortRule
|
||||
|
||||
|
||||
_RAM_PATTERN = re.compile(r"\s*(\d+(?:\.\d+)?)\s*([BKMG]i?B?)?\s*", re.IGNORECASE)
|
||||
@@ -81,3 +83,35 @@ def parse_password(value: str) -> str:
|
||||
if any(ord(character) < 32 or ord(character) == 127 for character in value):
|
||||
raise ValidationError("password must not contain control characters")
|
||||
return value
|
||||
|
||||
|
||||
def parse_name(value: str) -> str:
|
||||
if re.fullmatch(r"[a-z][a-z0-9-]{0,62}", value) is None:
|
||||
raise ValidationError("VM name must be 1-63 lowercase letters, digits, or hyphens, starting with a letter")
|
||||
if re.fullmatch(r"vm-[0-9a-f]{32}", value):
|
||||
raise ValidationError("VM names must not impersonate generated VM IDs")
|
||||
return value
|
||||
|
||||
|
||||
def parse_ports(values: Sequence[str]) -> tuple[PortRule, ...]:
|
||||
ports: dict[int, PortRule] = {}
|
||||
for value in values:
|
||||
for item in value.split(","):
|
||||
match = re.fullmatch(r"\s*(\d+)(?::(TCP|HTTP|HTTPS))?\s*", item, re.IGNORECASE)
|
||||
if match is None:
|
||||
raise ValidationError(f"invalid private port: {item!r}; use PORT[:TCP|HTTP|HTTPS]")
|
||||
rule = PortRule(int(match.group(1)), match.group(2) or "TCP")
|
||||
if rule.port in ports and ports[rule.port] != rule:
|
||||
raise ValidationError(f"conflicting labels for TCP port {rule.port}")
|
||||
ports[rule.port] = rule
|
||||
return tuple(ports[number] for number in sorted(ports))
|
||||
|
||||
|
||||
def parse_timeout(value: str) -> float:
|
||||
try:
|
||||
timeout = float(value)
|
||||
except (ValueError, TypeError) as error:
|
||||
raise ValidationError("timeout must be a finite non-negative number of seconds") from error
|
||||
if not math.isfinite(timeout) or timeout < 0:
|
||||
raise ValidationError("timeout must be a finite non-negative number of seconds")
|
||||
return timeout
|
||||
|
||||
Reference in New Issue
Block a user