feat: 多主机纳管、用户认证、noVNC控制台、深色主题

主要功能:
- 多主机管理: 支持TCP/SSH方式纳管远程KVM主机
- 用户认证: JWT token认证, 默认admin/admin123
- noVNC控制台: 前端集成noVNC, WebSocket代理VNC连接
- 深色主题: 全局Element Plus深色主题覆盖
- 虚拟机操作: 克隆、迁移、XML编辑、快照管理
- 资源监控: CPU/内存/磁盘IO/网络流量实时监控

Bug修复:
- libvirt getInfo()内存单位修正(MiB非KiB)
- 远程主机VNC 0.0.0.0监听地址连接策略修复
- Dashboard定时器内存泄漏修复
- bcrypt版本兼容性修复
This commit is contained in:
admin
2026-05-07 12:41:10 +08:00
parent fac8ab7470
commit 8ccccf8f52
30 changed files with 1972 additions and 170 deletions
+15 -16
View File
@@ -1,11 +1,11 @@
"""存储池管理路由"""
from fastapi import APIRouter, HTTPException
from fastapi import APIRouter, HTTPException, Query
from pydantic import BaseModel, Field
from typing import Optional
from lxml import etree
import os
from app.libvirt_conn import libvirt_conn
from app.libvirt_conn import conn_pool
import libvirt
router = APIRouter()
@@ -24,9 +24,9 @@ class VolCreate(BaseModel):
@router.get("/pools")
async def list_pools():
async def list_pools(host_id: str = Query("local")):
"""列出所有存储池"""
conn = libvirt_conn.conn
conn = conn_pool.get_conn(host_id)
pools = conn.listAllStoragePools(0)
result = []
for pool in pools:
@@ -47,9 +47,9 @@ async def list_pools():
@router.get("/pool/{name}")
async def get_pool(name: str):
async def get_pool(name: str, host_id: str = Query("local")):
"""获取存储池详情"""
conn = libvirt_conn.conn
conn = conn_pool.get_conn(host_id)
try:
pool = conn.storagePoolLookupByName(name)
except libvirt.libvirtError:
@@ -58,7 +58,6 @@ async def get_pool(name: str):
info = pool.info()
xml = etree.fromstring(pool.XMLDesc(0).encode())
# 获取卷列表
volumes = []
try:
for vol_name in pool.listVolumes():
@@ -89,9 +88,9 @@ async def get_pool(name: str):
@router.post("/pool/create")
async def create_pool(pool: PoolCreate):
async def create_pool(pool: PoolCreate, host_id: str = Query("local")):
"""创建存储池"""
with libvirt_conn.get_rw() as rw_conn:
with conn_pool.get_rw(host_id) as rw_conn:
xml = f"""<pool type='{pool.type}'>
<name>{pool.name}</name>
<target>
@@ -109,9 +108,9 @@ async def create_pool(pool: PoolCreate):
@router.delete("/pool/{name}")
async def delete_pool(name: str):
async def delete_pool(name: str, host_id: str = Query("local")):
"""删除存储池"""
with libvirt_conn.get_rw() as rw_conn:
with conn_pool.get_rw(host_id) as rw_conn:
try:
pool = rw_conn.storagePoolLookupByName(name)
except libvirt.libvirtError:
@@ -125,9 +124,9 @@ async def delete_pool(name: str):
@router.post("/pool/{name}/volume")
async def create_volume(name: str, vol: VolCreate):
async def create_volume(name: str, vol: VolCreate, host_id: str = Query("local")):
"""在存储池中创建卷"""
with libvirt_conn.get_rw() as rw_conn:
with conn_pool.get_rw(host_id) as rw_conn:
try:
pool = rw_conn.storagePoolLookupByName(name)
except libvirt.libvirtError:
@@ -149,9 +148,9 @@ async def create_volume(name: str, vol: VolCreate):
@router.delete("/pool/{pool_name}/volume/{vol_name}")
async def delete_volume(pool_name: str, vol_name: str):
async def delete_volume(pool_name: str, vol_name: str, host_id: str = Query("local")):
"""删除卷"""
with libvirt_conn.get_rw() as rw_conn:
with conn_pool.get_rw(host_id) as rw_conn:
try:
pool = rw_conn.storagePoolLookupByName(pool_name)
vol = pool.storageVolLookupByName(vol_name)
@@ -162,7 +161,7 @@ async def delete_volume(pool_name: str, vol_name: str):
@router.get("/isos")
async def list_isos():
async def list_isos(host_id: str = Query("local")):
"""列出可用的ISO镜像"""
iso_dirs = ["/var/lib/libvirt/iso", "/isos", "/mnt/isos"]
isos = []