from datetime import datetime from typing import Literal from pydantic import BaseModel, Field, field_validator from app.schemas.validators import normalize_required_text, validate_host, validate_ssh_username ConnectionType = Literal["ssh", "docker_api", "agent"] EnvironmentName = Literal["production", "staging", "development", "other"] class ServerBase(BaseModel): name: str = Field(min_length=1, max_length=128) host: str = Field(min_length=1, max_length=255) port: int = Field(default=22, ge=1, le=65535) ssh_username: str | None = Field(default=None, min_length=1, max_length=128) connection_type: ConnectionType = "ssh" environment: EnvironmentName = "production" is_active: bool = True @field_validator("name") @classmethod def validate_name_value(cls, value: str) -> str: return normalize_required_text(value, field_name="name") @field_validator("host") @classmethod def validate_host_value(cls, value: str) -> str: return validate_host(value) @field_validator("ssh_username") @classmethod def validate_ssh_username_value(cls, value: str | None) -> str | None: return validate_ssh_username(value) class ServerCreate(ServerBase): pass class ServerUpdate(BaseModel): name: str | None = Field(default=None, min_length=1, max_length=128) host: str | None = Field(default=None, min_length=1, max_length=255) port: int | None = Field(default=None, ge=1, le=65535) ssh_username: str | None = Field(default=None, min_length=1, max_length=128) connection_type: ConnectionType | None = None environment: EnvironmentName | None = None is_active: bool | None = None @field_validator("name") @classmethod def validate_name_value(cls, value: str | None) -> str | None: if value is None: return None return normalize_required_text(value, field_name="name") @field_validator("host") @classmethod def validate_host_value(cls, value: str | None) -> str | None: if value is None: return None return validate_host(value) @field_validator("ssh_username") @classmethod def validate_ssh_username_value(cls, value: str | None) -> str | None: return validate_ssh_username(value) class ServerRead(ServerBase): id: int created_at: datetime model_config = {"from_attributes": True} class ServerHealthRead(BaseModel): server_id: int reachable: bool status: str checked_at: datetime detail: str | None = None class ServerMetricsRead(BaseModel): server_id: int cpu_percent: float memory_percent: float disk_percent: float uptime_seconds: int load_average: list[float] collected_at: datetime