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:
@@ -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)
|
||||
|
||||
|
||||
Reference in New Issue
Block a user