This repository has been archived on 2026-08-09. You can view files and clone it. You cannot open issues or pull requests or push a commit.
Files
Proxmox-VPS-Panel-secure/backend/app/routers/instances.py
T

108 lines
4.8 KiB
Python

import logging
from fastapi import APIRouter, Depends, HTTPException, status
from sqlalchemy import select
from sqlalchemy.orm import Session
from .. import models, proxmox_client as pve, schemas
from ..config import settings
from ..database import get_db
from ..deps import get_current_user
from ..proxmox_actions import delete_guest
logger = logging.getLogger(__name__)
router = APIRouter(prefix="/instances", tags=["instances"])
@router.get("", response_model=list[schemas.InstanceOut])
def list_instances(db: Session = Depends(get_db), user: models.User = Depends(get_current_user)):
"""Клиент видит только свои инстансы, администратор — все."""
query = select(models.Instance).where(models.Instance.status != models.InstanceStatus.deleted)
if user.role != models.UserRole.admin:
query = query.where(models.Instance.owner_id == user.id)
return list(db.scalars(query.order_by(models.Instance.created_at.desc())))
def _save_error(db: Session, instance: models.Instance, exc: Exception) -> None:
"""Помечает инстанс ошибочным без сохранения деталей Proxmox пользователю."""
instance.status = models.InstanceStatus.error
db.commit()
logger.exception("Ошибка провижининга instance_id=%s: %s", instance.id, exc)
@router.post("", response_model=schemas.InstanceCreateOut, status_code=status.HTTP_201_CREATED)
def create_instance(payload: schemas.InstanceCreate, db: Session = Depends(get_db), user: models.User = Depends(get_current_user)):
"""Создаёт и запускает VM/LXC из активного шаблона."""
template = db.scalar(select(models.Template).where(
models.Template.id == payload.template_id,
models.Template.is_active.is_(True),
))
if template is None:
raise HTTPException(status_code=404, detail="Активный шаблон не найден")
try:
vmid = pve.next_vmid()
except Exception as exc:
logger.exception("Не удалось получить VMID из Proxmox: %s", exc)
raise HTTPException(status_code=502, detail="Proxmox недоступен")
instance = models.Instance(
name=payload.name, vmid=vmid, node=settings.pve_node,
guest_type=template.guest_type, status=models.InstanceStatus.creating,
owner_id=user.id, template_id=template.id,
)
db.add(instance)
db.commit()
db.refresh(instance)
try:
if template.guest_type == models.GuestType.vm:
pve.provision_vm(
source_vmid=template.source_vmid, vmid=vmid, name=payload.name,
cores=template.cores, memory_mb=template.memory_mb, disk_gb=template.disk_gb,
username=payload.username, password=payload.password,
)
else:
pve.provision_lxc(
source_template=template.source_template, vmid=vmid, name=payload.name,
cores=template.cores, memory_mb=template.memory_mb, disk_gb=template.disk_gb,
password=payload.password,
)
except Exception as exc:
_save_error(db, instance, exc)
raise HTTPException(status_code=502, detail="Не удалось создать инстанс в Proxmox")
instance.status = models.InstanceStatus.running
db.commit()
db.refresh(instance)
return schemas.InstanceCreateOut(
**schemas.InstanceOut.model_validate(instance).model_dump(),
initial_password=payload.password,
)
@router.delete("/{instance_id}")
def delete_instance(instance_id: int, db: Session = Depends(get_db), user: models.User = Depends(get_current_user)):
"""Удаляет принадлежащую пользователю VM/LXC и отмечает запись deleted."""
instance = db.get(models.Instance, instance_id)
if instance is None or instance.status == models.InstanceStatus.deleted:
raise HTTPException(status_code=404, detail="Инстанс не найден")
if user.role != models.UserRole.admin and instance.owner_id != user.id:
raise HTTPException(status_code=404, detail="Инстанс не найден")
if instance.vmid is None:
raise HTTPException(status_code=409, detail="У инстанса отсутствует VMID")
instance.status = models.InstanceStatus.deleting
db.commit()
try:
delete_guest(instance.guest_type.value, instance.vmid)
except Exception as exc:
instance.status = models.InstanceStatus.error
db.commit()
logger.exception("Ошибка удаления instance_id=%s: %s", instance.id, exc)
raise HTTPException(status_code=502, detail="Не удалось удалить инстанс в Proxmox")
instance.status = models.InstanceStatus.deleted
db.commit()
return {"ok": True}