Refactor backend: Split models and proxmox_client into modules, add alembic
Some checks failed
Backend Tests / pytest (Python 3.12) (push) Failing after 2m27s

This commit is contained in:
2026-06-13 03:53:27 +05:00
parent 8a879f36fa
commit bfd92102cf
54 changed files with 6026 additions and 5137 deletions

View File

@@ -0,0 +1,145 @@
from typing import List, Dict, Optional, Union, Any
import time
import urllib3
from loguru import logger
class StorageMixin:
def get_node_isos(self, node: str) -> List[Dict]:
"""Получить список ISO-образов со всех ISO-хранилищ ноды."""
if not self.proxmox:
return []
result: List[Dict] = []
try:
storages = self.proxmox.nodes(node).storage.get()
for s in storages:
content = s.get('content', '')
if 'iso' not in content:
continue
storage_id = s.get('storage')
try:
items = self.proxmox.nodes(node).storage(storage_id).content.get(content='iso')
for it in items:
result.append({
'volid': it.get('volid'),
'storage': storage_id,
'size': it.get('size'),
'format': it.get('format'),
'name': (it.get('volid') or '').split('/')[-1],
})
except Exception as e:
logger.debug(f"Не удалось получить ISO из {storage_id}: {e}")
except Exception as e:
logger.error(f"Ошибка получения списка ISO для ноды {node}: {e}")
return result
def get_lxc_storage_templates(self, node: Optional[str] = None) -> List[Dict]:
"""
Получить список LXC CT-шаблонов из хранилищ Proxmox.
Ищет файлы типа vzdump/vztmpl на всех нодах (или на указанной).
Возвращает список объектов с полями: volid, storage, node, name, size.
"""
if not self.proxmox:
return []
result: List[Dict] = []
try:
if node:
nodes_list = [{'node': node}]
else:
nodes_list = self.get_nodes()
seen_volids: set = set()
for n in nodes_list:
node_name = n.get('node')
try:
storages = self.proxmox.nodes(node_name).storage.get()
for s in storages:
content = s.get('content', '')
if 'vztmpl' not in content:
continue
storage_id = s.get('storage')
try:
items = self.proxmox.nodes(node_name).storage(storage_id).content.get(content='vztmpl')
for it in items:
volid = it.get('volid', '')
if volid in seen_volids:
continue
seen_volids.add(volid)
filename = volid.split('/')[-1] if '/' in volid else volid
result.append({
'volid': volid,
'storage': storage_id,
'node': node_name,
'name': filename,
'size': it.get('size', 0),
})
except Exception as e:
logger.debug(f"Не удалось получить CT-шаблоны из {storage_id} на {node_name}: {e}")
except Exception as e:
logger.error(f"Ошибка получения хранилищ ноды {node_name}: {e}")
except Exception as e:
logger.error(f"Ошибка получения CT-шаблонов {self.host}: {e}")
return result
def get_node_storages(self, node: str, content: str = None) -> List[Dict]:
"""Get storages available on a specific node, optionally filtered by content type"""
if not self.proxmox:
return []
try:
params = {}
if content:
params['content'] = content
storages = self.proxmox.nodes(node).storage.get(**params)
return storages
except Exception as e:
logger.error(f"Error getting storages for node {node}: {e}")
return []
def vzdump_guest(self, node: str, vmid: int, storage: str,
compress: str = 'zstd', mode: str = 'snapshot') -> Dict:
"""
Создать резервную копию VM/LXC через vzdump.
Args:
node: Имя ноды
vmid: ID ВМ или контейнера
storage: Хранилище для бэкапа (должно поддерживать content=backup)
compress: Алгоритм сжатия (zstd, lzo, gzip, 0)
mode: Режим снятия бэкапа (snapshot, suspend, stop)
Returns:
Dict с UPID задачи
"""
if not self.proxmox:
return {'success': False, 'error': 'Not connected'}
try:
upid = self.proxmox.nodes(node).vzdump.post(
vmid=vmid,
storage=storage,
compress=compress,
mode=mode,
remove=0, # не удалять старые бэкапы автоматически
)
logger.info(f"vzdump started for vmid {vmid} on {node}, storage {storage}, UPID: {upid}")
return {'success': True, 'upid': upid, 'vmid': vmid}
except Exception as e:
logger.error(f"Ошибка vzdump vmid {vmid} на {node}: {e}")
return {'success': False, 'error': str(e), 'vmid': vmid}
def get_backup_storages(self, node: str) -> List[Dict]:
"""
Получить список хранилищ, поддерживающих content=backup на ноде.
Returns:
Список Dict с полями: storage, type, content, avail, total
"""
if not self.proxmox:
return []
try:
storages = self.proxmox.nodes(node).storage.get(content='backup', enabled=1)
return storages
except Exception as e:
logger.error(f"Ошибка получения backup-хранилищ для {node}: {e}")
return []