from datetime import datetime from pydantic import BaseModel, ConfigDict, EmailStr, Field, model_validator from .models import GuestType, InstanceStatus, UserRole class UserCreate(BaseModel): """Данные для регистрации пользователя.""" email: EmailStr password: str = Field(min_length=12, max_length=128) class UserOut(BaseModel): """Публичное представление пользователя без пароля.""" model_config = ConfigDict(from_attributes=True) id: int email: EmailStr role: UserRole is_active: bool created_at: datetime class TokenOut(BaseModel): """Ответ с access token.""" access_token: str token_type: str = "bearer" class TemplateCreate(BaseModel): """Данные для создания шаблона администратором.""" name: str = Field(min_length=1, max_length=64, pattern=r"^[a-zA-Z0-9][a-zA-Z0-9-]*$") description: str = Field(default="", max_length=2000) guest_type: GuestType source_vmid: int | None = Field(default=None, gt=0) source_template: str | None = Field(default=None, min_length=1, max_length=512) cores: int = Field(default=1, ge=1, le=64) memory_mb: int = Field(default=1024, ge=128, le=262144) disk_gb: int = Field(default=10, ge=1, le=4096) @model_validator(mode="after") def validate_source(self): """Проверяет источник в зависимости от типа гостя.""" if self.guest_type == GuestType.vm and self.source_vmid is None: raise ValueError("Для VM требуется source_vmid") if self.guest_type == GuestType.lxc and not self.source_template: raise ValueError("Для LXC требуется source_template") return self class TemplateOut(BaseModel): """Публичное представление активного шаблона.""" model_config = ConfigDict(from_attributes=True) id: int name: str description: str guest_type: GuestType cores: int memory_mb: int disk_gb: int is_active: bool class InstanceCreate(BaseModel): """Запрос на синхронное создание VM или LXC из шаблона.""" name: str = Field(min_length=1, max_length=63, pattern=r"^[a-zA-Z0-9][a-zA-Z0-9-]*$") template_id: int = Field(gt=0) username: str = Field(default="paneluser", min_length=1, max_length=32, pattern=r"^[a-z_][a-z0-9_-]*$") password: str = Field(min_length=12, max_length=128) class InstanceOut(BaseModel): """Инстанс без credentials и внутренних секретов.""" model_config = ConfigDict(from_attributes=True) id: int name: str vmid: int | None node: str guest_type: GuestType status: InstanceStatus owner_id: int template_id: int created_at: datetime class InstanceCreateOut(InstanceOut): """Ответ создания с паролем, который показывается только один раз.""" initial_password: str