feat: add tool catalog and installation endpoints with models for tool management
This commit is contained in:
@@ -0,0 +1,46 @@
|
||||
"""Authenticated tool catalog, installation jobs, and guest inventory."""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
from fastapi import APIRouter, Depends, status
|
||||
|
||||
from ..api_models import ToolCatalogResponse, ToolInstallRequest, ToolJobResponse, VmToolsResponse
|
||||
from ..app import Application
|
||||
from ..errors import UvmError
|
||||
from ..tool_catalog import CATALOG, normalize_tools
|
||||
from .dependencies import get_authorized_application
|
||||
|
||||
|
||||
router = APIRouter(tags=["tools"])
|
||||
|
||||
|
||||
def tool_service(application):
|
||||
service = getattr(application, "tools", None)
|
||||
if service is None:
|
||||
raise UvmError("guest tool installation is unavailable in this application")
|
||||
return service
|
||||
|
||||
|
||||
@router.get("/tools", response_model=list[ToolCatalogResponse])
|
||||
def catalog(application: Application = Depends(get_authorized_application)):
|
||||
return list(CATALOG)
|
||||
|
||||
|
||||
@router.get("/vms/{vm_id}/tools", response_model=VmToolsResponse)
|
||||
def vm_tools(vm_id: str, refresh: bool = False, application: Application = Depends(get_authorized_application)):
|
||||
"""Return cached observations; refresh=true probes the running guest without installing."""
|
||||
return tool_service(application).snapshot(vm_id, refresh=refresh)
|
||||
|
||||
|
||||
@router.post("/vms/{vm_id}/tools/install", response_model=ToolJobResponse, status_code=status.HTTP_202_ACCEPTED)
|
||||
def install_tools(vm_id: str, request: ToolInstallRequest,
|
||||
application: Application = Depends(get_authorized_application)):
|
||||
return tool_service(application).submit(
|
||||
vm_id, normalize_tools([item.model_dump() for item in request.tools]),
|
||||
start_if_stopped=request.start_if_stopped, restart=request.restart, request_id=request.request_id,
|
||||
)
|
||||
|
||||
|
||||
@router.get("/vms/{vm_id}/tools/jobs/{job_id}", response_model=ToolJobResponse)
|
||||
def tool_job(vm_id: str, job_id: str, application: Application = Depends(get_authorized_application)):
|
||||
return tool_service(application).store.get_job(vm_id, job_id)
|
||||
@@ -22,6 +22,7 @@ from ..api_models import (
|
||||
from ..app import Application
|
||||
from ..domain import PortRule, VmRecord, VmSpec
|
||||
from ..errors import ValidationError
|
||||
from ..tool_catalog import normalize_tools
|
||||
from ..validation import (
|
||||
parse_cpu,
|
||||
parse_name,
|
||||
@@ -33,6 +34,7 @@ from ..validation import (
|
||||
parse_username,
|
||||
)
|
||||
from .dependencies import get_authorized_application
|
||||
from .tools import tool_service
|
||||
|
||||
|
||||
router = APIRouter(prefix="/vms", tags=["vms"])
|
||||
@@ -73,6 +75,9 @@ def create_vm(
|
||||
ports = parse_ports([f"{rule.port}:{rule.protocol}" for rule in request.ports or ()])
|
||||
if not request.no_default_ports and not any(rule.port == 22 for rule in ports):
|
||||
ports = tuple(sorted((*ports, PortRule(22)), key=lambda rule: rule.port))
|
||||
tools = normalize_tools([item.model_dump() for item in request.tools], allow_empty=True)
|
||||
if tools:
|
||||
tool_service(application).start()
|
||||
vm = application.lifecycle.create(
|
||||
VmSpec(
|
||||
cpu=parse_cpu(str(request.cpu)),
|
||||
@@ -83,8 +88,11 @@ def create_vm(
|
||||
password=parse_password(request.password.get_secret_value()),
|
||||
name=parse_name(request.name) if request.name is not None else None,
|
||||
ports=ports,
|
||||
tools=tools,
|
||||
)
|
||||
)
|
||||
if tools:
|
||||
tool_service(application).notify()
|
||||
return vm_response(vm, policy_status=_mutation_policy_status(vm))
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user