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 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) query = query.order_by(models.Instance.created_at.desc()) return list(db.scalars(query)) def _save_error(db: Session, instance: models.Instance, exc: Exception) -> None: """Помечает инстанс ошибочным, не сохраняя секреты или детали API.""" 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="Активный шаблон не найден") vmid = pve.next_vmid() 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, )