8ccccf8f52
主要功能: - 多主机管理: 支持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版本兼容性修复
117 라인
3.8 KiB
Python
117 라인
3.8 KiB
Python
"""主机管理路由"""
|
|
from fastapi import APIRouter, HTTPException
|
|
from app.hosts import (
|
|
list_hosts, get_host, add_host, remove_host,
|
|
test_connection, update_host_status, HostCreate,
|
|
)
|
|
from app.libvirt_conn import conn_pool
|
|
import time
|
|
|
|
router = APIRouter()
|
|
|
|
|
|
@router.get("/list")
|
|
async def api_list_hosts():
|
|
"""列出所有已注册主机"""
|
|
hosts = list_hosts()
|
|
result = []
|
|
for h in hosts:
|
|
info = h.model_dump()
|
|
# 尝试获取实时状态
|
|
try:
|
|
mgr = conn_pool.get(h.id)
|
|
conn = mgr.conn
|
|
alive = conn.isAlive()
|
|
info["status"] = "online" if alive else "offline"
|
|
if alive:
|
|
host_data = conn.getInfo()
|
|
info["cpu_cores"] = host_data[2]
|
|
info["memory_mb"] = host_data[1] # getInfo()[1] 已经是 MiB 单位
|
|
info["hostname"] = conn.getHostname()
|
|
# 虚拟机数
|
|
domains = conn.listAllDomains(0)
|
|
info["vm_total"] = len(domains)
|
|
info["vm_running"] = sum(1 for d in domains if d.isActive())
|
|
update_host_status(h.id, info["status"])
|
|
except Exception:
|
|
info["status"] = "offline"
|
|
update_host_status(h.id, "offline")
|
|
result.append(info)
|
|
return {"hosts": result, "total": len(result)}
|
|
|
|
|
|
@router.get("/detail/{host_id}")
|
|
async def api_get_host(host_id: str):
|
|
"""获取单台主机详情"""
|
|
host = get_host(host_id)
|
|
if not host:
|
|
raise HTTPException(status_code=404, detail=f"主机 '{host_id}' 不存在")
|
|
info = host.model_dump()
|
|
try:
|
|
mgr = conn_pool.get(host_id)
|
|
info["host_info"] = mgr.get_host_info()
|
|
info["status"] = "online"
|
|
# 虚拟机数
|
|
domains = mgr.conn.listAllDomains(0)
|
|
info["vm_total"] = len(domains)
|
|
info["vm_running"] = sum(1 for d in domains if d.isActive())
|
|
update_host_status(host_id, "online")
|
|
except Exception as e:
|
|
info["status"] = "offline"
|
|
info["error"] = str(e)
|
|
update_host_status(host_id, "offline")
|
|
return info
|
|
|
|
|
|
@router.post("/add")
|
|
async def api_add_host(req: HostCreate):
|
|
"""添加新主机"""
|
|
# 先测试连接
|
|
result = test_connection(req.uri)
|
|
if not result["success"]:
|
|
raise HTTPException(status_code=400, detail=f"连接测试失败: {result['error']}")
|
|
|
|
host = add_host(req)
|
|
# 更新状态为在线
|
|
update_host_status(host.id, "online")
|
|
return {"message": f"主机 '{host.name}' 添加成功", "host": host.model_dump()}
|
|
|
|
|
|
@router.delete("/delete/{host_id}")
|
|
async def api_delete_host(host_id: str):
|
|
"""删除主机"""
|
|
if host_id == "local":
|
|
raise HTTPException(status_code=400, detail="不能删除本机")
|
|
if not remove_host(host_id):
|
|
raise HTTPException(status_code=404, detail=f"主机 '{host_id}' 不存在")
|
|
conn_pool.remove(host_id)
|
|
return {"message": f"主机 '{host_id}' 已删除"}
|
|
|
|
|
|
@router.post("/test")
|
|
async def api_test_connection(req: HostCreate):
|
|
"""测试连接(不添加主机)"""
|
|
result = test_connection(req.uri)
|
|
return result
|
|
|
|
|
|
@router.post("/refresh/{host_id}")
|
|
async def api_refresh_host(host_id: str):
|
|
"""刷新主机状态"""
|
|
host = get_host(host_id)
|
|
if not host:
|
|
raise HTTPException(status_code=404, detail=f"主机 '{host_id}' 不存在")
|
|
try:
|
|
# 重新建立连接
|
|
conn_pool.remove(host_id)
|
|
mgr = conn_pool.get(host_id)
|
|
conn = mgr.conn
|
|
alive = conn.isAlive()
|
|
status = "online" if alive else "offline"
|
|
update_host_status(host_id, status)
|
|
return {"status": status, "hostname": conn.getHostname()}
|
|
except Exception as e:
|
|
update_host_status(host_id, "offline")
|
|
conn_pool.remove(host_id)
|
|
return {"status": "offline", "error": str(e)}
|