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")