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
+10 -25
View File
@@ -1,6 +1,6 @@
"""资源监控路由"""
from fastapi import APIRouter, HTTPException
from app.libvirt_conn import libvirt_conn
from fastapi import APIRouter, HTTPException, Query
from app.libvirt_conn import conn_pool
import libvirt
import time
import threading
@@ -13,23 +13,19 @@ _cache_lock = threading.Lock()
@router.get("/overview")
async def monitor_overview():
async def monitor_overview(host_id: str = Query("local")):
"""宿主机总览监控"""
conn = libvirt_conn.conn
conn = conn_pool.get_conn(host_id)
# 宿主机信息
host_info = conn.getInfo()
hostname = conn.getHostname()
# CPU 使用率(通过 node info
cpu_stats = conn.getCPUStats(-1, 0) # 全局 CPU 统计
cpu_stats = conn.getCPUStats(-1, 0)
cpu_total = cpu_stats.get("user", 0) + cpu_stats.get("system", 0) + cpu_stats.get("idle", 0)
cpu_used = cpu_stats.get("user", 0) + cpu_stats.get("system", 0)
cpu_percent = round(cpu_used / cpu_total * 100, 1) if cpu_total > 0 else 0
# 内存
memory_total_kb = host_info[1]
# 获取可用内存
try:
with open("/proc/meminfo", "r") as f:
meminfo = {}
@@ -48,7 +44,6 @@ async def monitor_overview():
mem_available_mb = mem_total_mb
mem_percent = 0
# 虚拟机统计
domains = conn.listAllDomains(0)
running = sum(1 for d in domains if d.isActive())
stopped = len(domains) - running
@@ -75,9 +70,9 @@ async def monitor_overview():
@router.get("/vm/{name}")
async def monitor_vm(name: str):
async def monitor_vm(name: str, host_id: str = Query("local")):
"""获取虚拟机实时监控数据"""
conn = libvirt_conn.conn
conn = conn_pool.get_conn(host_id)
try:
dom = conn.lookupByName(name)
except libvirt.libvirtError:
@@ -86,10 +81,9 @@ async def monitor_vm(name: str):
if not dom.isActive():
return {"name": name, "state": "stopped", "cpu_percent": 0, "memory": {}}
# CPU 百分比
cpu_percent = _get_vm_cpu_percent(dom)
cache_key = f"{host_id}_{name}"
cpu_percent = _get_vm_cpu_percent(dom, cache_key)
# 内存
mem_stats = {}
try:
raw = dom.memoryStats()
@@ -104,10 +98,7 @@ async def monitor_vm(name: str):
except Exception:
pass
# 磁盘IO
disk_stats = _get_vm_disk_stats(dom)
# 网络IO
net_stats = _get_vm_net_stats(dom)
return {
@@ -120,17 +111,13 @@ async def monitor_vm(name: str):
}
def _get_vm_cpu_percent(dom) -> float:
def _get_vm_cpu_percent(dom, cache_key: str) -> float:
"""计算虚拟机 CPU 使用率"""
cache_key = f"cpu_{dom.name()}"
try:
# 第一次采样
info1 = dom.info()
cpu_time1 = info1[2]
t1 = time.time()
# 从缓存获取上一次数据
with _cache_lock:
prev = _stats_cache.get(cache_key)
@@ -138,13 +125,11 @@ def _get_vm_cpu_percent(dom) -> float:
cpu_time0, t0 = prev
elapsed = t1 - t0
cpu_diff = cpu_time1 - cpu_time0
# CPU时间单位是纳秒
cpu_percent = round((cpu_diff / 1e9) / elapsed * 100, 1)
cpu_percent = min(cpu_percent, 100.0)
else:
cpu_percent = 0.0
# 更新缓存
with _cache_lock:
_stats_cache[cache_key] = (cpu_time1, t1)