feat: Add guest execution agent and vsock support
- Introduced a standalone guest execution agent to facilitate command execution within the guest VM over Firecracker's vsock. - Enhanced FirecrackerClient to support vsock configuration, validating guest CID and UDS path. - Updated configuration to include vsock settings by default. - Refactored FirecrackerProcessManager to manage runtime sockets more effectively. - Implemented guest agent installation and provisioning in the image store. - Added API endpoints for executing commands in the VM and installing the guest agent. - Improved error handling for guest execution failures and agent availability.
This commit is contained in:
+38
-1
@@ -5,9 +5,12 @@ from __future__ import annotations
|
||||
from ipaddress import IPv4Address
|
||||
from typing import Literal
|
||||
|
||||
from pydantic import BaseModel, ConfigDict, Field, SecretStr
|
||||
from pydantic import BaseModel, ConfigDict, Field, SecretStr, model_validator
|
||||
|
||||
from .domain import VmRecord
|
||||
from .errors import ValidationError
|
||||
from .guest_agent import DEFAULT_TIMEOUT_SECONDS, MAX_COMMAND_BYTES, MAX_TIMEOUT_SECONDS
|
||||
from .guest_exec import validate_exec
|
||||
|
||||
|
||||
class HealthResponse(BaseModel):
|
||||
@@ -112,6 +115,40 @@ class VmLogResponse(BaseModel):
|
||||
truncated: bool
|
||||
|
||||
|
||||
class VmExecRequest(BaseModel):
|
||||
model_config = ConfigDict(extra="forbid")
|
||||
|
||||
command: str = Field(strict=True, min_length=1, max_length=MAX_COMMAND_BYTES, repr=False,
|
||||
description="Command or multiline script interpreted by /bin/sh inside the guest; at most 64 KiB UTF-8")
|
||||
sudo: bool = Field(default=False, strict=True, description="Run as guest root instead of the VM's configured login user")
|
||||
timeout_seconds: float = Field(default=DEFAULT_TIMEOUT_SECONDS, strict=True, gt=0,
|
||||
le=MAX_TIMEOUT_SECONDS, allow_inf_nan=False)
|
||||
|
||||
@model_validator(mode="before")
|
||||
@classmethod
|
||||
def validate_execution(cls, value: object) -> object:
|
||||
# Use the domain error envelope: echoing NaN or unpaired surrogates in
|
||||
# FastAPI's validation-error input can itself fail JSON serialization.
|
||||
if not isinstance(value, dict) or set(value) - {"command", "sudo", "timeout_seconds"}:
|
||||
raise ValidationError("execution requires an object with command, sudo, and timeout_seconds fields only")
|
||||
validate_exec(value.get("command"), value.get("sudo", False), value.get("timeout_seconds", DEFAULT_TIMEOUT_SECONDS))
|
||||
return value
|
||||
|
||||
|
||||
class VmExecResponse(BaseModel):
|
||||
exit_code: int | None
|
||||
stdout: str
|
||||
stderr: str
|
||||
timed_out: bool
|
||||
truncated: bool
|
||||
|
||||
|
||||
class VmAgentInstallResponse(BaseModel):
|
||||
id: str
|
||||
status: Literal["installed"] = "installed"
|
||||
restart_required: bool = True
|
||||
|
||||
|
||||
class DiagnosticResponse(BaseModel):
|
||||
name: str
|
||||
ok: bool
|
||||
|
||||
Reference in New Issue
Block a user