From 9144f30a18aa1b02b222d246244f58292cb97148 Mon Sep 17 00:00:00 2001 From: host Date: Sun, 9 Aug 2026 14:31:01 +0300 Subject: [PATCH] =?UTF-8?q?=D0=94=D0=BE=D0=B1=D0=B0=D0=B2=D0=BB=D0=B5?= =?UTF-8?q?=D0=BD=D1=8B=20=D0=BC=D0=BE=D0=B4=D0=B5=D0=BB=D0=B8=20=D1=88?= =?UTF-8?q?=D0=B0=D0=B1=D0=BB=D0=BE=D0=BD=D0=BE=D0=B2=20=D0=B8=20=D0=B8?= =?UTF-8?q?=D0=BD=D1=81=D1=82=D0=B0=D0=BD=D1=81=D0=BE=D0=B2?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- backend/app/models.py | 70 +++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 68 insertions(+), 2 deletions(-) diff --git a/backend/app/models.py b/backend/app/models.py index 1bf4d5e..14bad38 100644 --- a/backend/app/models.py +++ b/backend/app/models.py @@ -1,8 +1,8 @@ from datetime import datetime, timezone from enum import Enum -from sqlalchemy import Boolean, DateTime, Enum as SqlEnum, Integer, String -from sqlalchemy.orm import Mapped, mapped_column +from sqlalchemy import Boolean, DateTime, Enum as SqlEnum, ForeignKey, Integer, String, Text +from sqlalchemy.orm import Mapped, mapped_column, relationship from .database import Base @@ -14,6 +14,24 @@ class UserRole(str, Enum): client = "client" +class GuestType(str, Enum): + """Тип виртуализированной системы.""" + + vm = "vm" + lxc = "lxc" + + +class InstanceStatus(str, Enum): + """Состояние инстанса в панели.""" + + creating = "creating" + running = "running" + stopped = "stopped" + error = "error" + deleting = "deleting" + deleted = "deleted" + + class User(Base): """Пользователь панели с Argon2id-хешем пароля.""" @@ -31,3 +49,51 @@ class User(Base): default=lambda: datetime.now(timezone.utc), nullable=False, ) + instances: Mapped[list["Instance"]] = relationship(back_populates="owner") + + +class Template(Base): + """Тарифный шаблон VM или LXC, доступный клиентам.""" + + __tablename__ = "templates" + + id: Mapped[int] = mapped_column(Integer, primary_key=True) + name: Mapped[str] = mapped_column(String(64), unique=True, index=True) + description: Mapped[str] = mapped_column(Text, default="") + guest_type: Mapped[GuestType] = mapped_column(SqlEnum(GuestType), nullable=False) + source_vmid: Mapped[int | None] = mapped_column(Integer, nullable=True) + source_template: Mapped[str | None] = mapped_column(String(512), nullable=True) + cores: Mapped[int] = mapped_column(Integer, default=1, nullable=False) + memory_mb: Mapped[int] = mapped_column(Integer, default=1024, nullable=False) + disk_gb: Mapped[int] = mapped_column(Integer, default=10, nullable=False) + is_active: Mapped[bool] = mapped_column(Boolean, default=True, nullable=False) + created_at: Mapped[datetime] = mapped_column( + DateTime(timezone=True), + default=lambda: datetime.now(timezone.utc), + nullable=False, + ) + instances: Mapped[list["Instance"]] = relationship(back_populates="template") + + +class Instance(Base): + """Инстанс VM/LXC, принадлежащий пользователю.""" + + __tablename__ = "instances" + + id: Mapped[int] = mapped_column(Integer, primary_key=True) + name: Mapped[str] = mapped_column(String(63)) + vmid: Mapped[int | None] = mapped_column(Integer, unique=True, nullable=True) + node: Mapped[str] = mapped_column(String(64)) + guest_type: Mapped[GuestType] = mapped_column(SqlEnum(GuestType), nullable=False) + status: Mapped[InstanceStatus] = mapped_column( + SqlEnum(InstanceStatus), default=InstanceStatus.creating, nullable=False + ) + owner_id: Mapped[int] = mapped_column(ForeignKey("users.id"), index=True) + template_id: Mapped[int] = mapped_column(ForeignKey("templates.id"), index=True) + created_at: Mapped[datetime] = mapped_column( + DateTime(timezone=True), + default=lambda: datetime.now(timezone.utc), + nullable=False, + ) + owner: Mapped[User] = relationship(back_populates="instances") + template: Mapped[Template] = relationship(back_populates="instances")