Archived
97 lines
3.4 KiB
Python
97 lines
3.4 KiB
Python
from datetime import datetime
|
||
from typing import Literal
|
||
|
||
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):
|
||
"""Для VM и LXC требует один из допустимых источников."""
|
||
if self.guest_type == GuestType.vm and self.source_vmid is None:
|
||
raise ValueError("Для VM требуется source_vmid")
|
||
if self.guest_type == GuestType.lxc and self.source_vmid is None and not self.source_template:
|
||
raise ValueError("Для LXC требуется source_vmid или source_template")
|
||
if self.source_vmid is not None and self.source_template is not None:
|
||
raise ValueError("Нельзя одновременно указывать source_vmid и 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 InstanceAction(BaseModel):
|
||
"""Разрешённое действие управления гостем."""
|
||
action: Literal["start", "stop", "shutdown", "reboot"]
|
||
|
||
|
||
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
|