Files
Proxmox-VPS-Panel/backend/app/routers/templates.py
T

123 lines
4.4 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import logging
from typing import List
from fastapi import APIRouter, Depends
from sqlalchemy.orm import Session
from .. import models, schemas, proxmox_client as pve
from ..database import get_db
from ..deps import get_current_user, require_admin
logger = logging.getLogger(__name__)
router = APIRouter(prefix="/templates", tags=["templates"])
def _normalize_lxc_source(value: str | None) -> str | None:
"""Приводит источник LXC к корректному Proxmox volid.
Принимает как полный volid:
``local:vztmpl/debian-13-standard_13.6-1_amd64.tar.zst``
так и короткое имя:
``debian-13-standard_13.6-1_amd64``.
"""
if not value:
return None
source = value.strip()
if not source:
return None
# Если уже передан полный volid, оставляем его без изменений.
if ":" in source:
return source
# Сначала пытаемся найти точный volid среди шаблонов Proxmox.
# Это позволяет корректно обработать .tar.zst, .tar.gz и .tar.xz.
try:
for item in pve.list_lxc_templates():
if item.get("name") == source:
return item["volid"]
volid_name = item.get("volid", "").split("/")[-1]
if volid_name:
for extension in (".tar.zst", ".tar.gz", ".tar.xz"):
if volid_name.removesuffix(extension) == source:
return item["volid"]
except Exception as exc:
logger.warning("Не удалось сопоставить LXC-шаблон с Proxmox: %s", exc)
# Fallback для локального storage: короткое имя превращаем в volid.
for extension in (".tar.zst", ".tar.gz", ".tar.xz"):
if source.endswith(extension):
return f"local:vztmpl/{source}"
return f"local:vztmpl/{source}.tar.zst"
@router.get("", response_model=List[schemas.TemplateOut])
def list_templates(db: Session = Depends(get_db), _=Depends(get_current_user)):
"""Возвращает активные шаблоны, сохранённые в панели."""
return db.query(models.Template).filter(models.Template.is_active == True).all() # noqa: E712
@router.post("", response_model=schemas.TemplateOut)
def create_template(
payload: schemas.TemplateCreate,
db: Session = Depends(get_db),
_=Depends(require_admin),
):
"""Добавляет шаблон в каталог панели.
Для LXC автоматически нормализует короткое имя архива в Proxmox volid.
"""
data = payload.model_dump()
if data.get("guest_type") == models.GuestType.lxc:
data["source_vmid"] = None
data["source_template"] = _normalize_lxc_source(data.get("source_template"))
if not data["source_template"]:
from fastapi import HTTPException
raise HTTPException(status_code=400, detail="Для LXC нужно указать архивный шаблон")
else:
data["source_template"] = None
tpl = models.Template(**data)
db.add(tpl)
db.commit()
db.refresh(tpl)
return tpl
@router.get("/from-proxmox")
def list_proxmox_templates(_=Depends(require_admin)):
"""Возвращает VM-шаблоны и архивные LXC-шаблоны с Proxmox."""
try:
vm_templates = pve.list_vm_templates()
except Exception as exc:
logger.warning("Ошибка получения VM-шаблонов из Proxmox: %s", exc)
vm_templates = []
try:
lxc_templates = pve.list_lxc_templates()
except Exception as exc:
logger.warning("Ошибка получения архивов LXC-шаблонов из Proxmox: %s", exc)
lxc_templates = []
for template in lxc_templates:
template["source_kind"] = "archive"
return {
"vm_templates": vm_templates,
"lxc_templates": lxc_templates,
}
@router.delete("/{template_id}")
def deactivate_template(
template_id: int, db: Session = Depends(get_db), _=Depends(require_admin)
):
"""Деактивирует шаблон в каталоге панели."""
tpl = db.query(models.Template).filter(models.Template.id == template_id).first()
if tpl:
tpl.is_active = False
db.commit()
return {"ok": True}