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:
+88
-13
@@ -1,38 +1,40 @@
|
||||
"""libvirt 连接管理 - 使用连接池模式"""
|
||||
"""libvirt 多主机连接管理器"""
|
||||
import libvirt
|
||||
from contextlib import contextmanager
|
||||
from app.config import settings
|
||||
import logging
|
||||
from app.hosts import get_host, update_host_status, list_hosts
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class LibvirtConnection:
|
||||
"""libvirt 连接管理器(只读连接保持,写操作用短连接)"""
|
||||
"""单个 libvirt 连接管理器(只读保持,读写短连接)"""
|
||||
|
||||
def __init__(self):
|
||||
def __init__(self, uri: str, host_id: str = "local"):
|
||||
self._uri = uri
|
||||
self._host_id = host_id
|
||||
self._conn = None
|
||||
|
||||
def _connect(self):
|
||||
"""建立新的 libvirt 连接"""
|
||||
"""建立只读连接"""
|
||||
try:
|
||||
conn = libvirt.openReadOnly(settings.LIBVIRT_URI)
|
||||
conn = libvirt.openReadOnly(self._uri)
|
||||
if conn is None:
|
||||
raise ConnectionError(f"无法连接到 libvirt: {settings.LIBVIRT_URI}")
|
||||
raise ConnectionError(f"无法连接到 libvirt: {self._uri}")
|
||||
return conn
|
||||
except libvirt.libvirtError as e:
|
||||
logger.error(f"libvirt 连接错误: {e}")
|
||||
logger.error(f"libvirt 连接错误 ({self._host_id}): {e}")
|
||||
raise
|
||||
|
||||
def _connect_rw(self):
|
||||
"""建立可读写连接"""
|
||||
try:
|
||||
conn = libvirt.open(settings.LIBVIRT_URI)
|
||||
conn = libvirt.open(self._uri)
|
||||
if conn is None:
|
||||
raise ConnectionError(f"无法连接到 libvirt (RW): {settings.LIBVIRT_URI}")
|
||||
raise ConnectionError(f"无法连接到 libvirt (RW): {self._uri}")
|
||||
return conn
|
||||
except libvirt.libvirtError as e:
|
||||
logger.error(f"libvirt RW 连接错误: {e}")
|
||||
logger.error(f"libvirt RW 连接错误 ({self._host_id}): {e}")
|
||||
raise
|
||||
|
||||
@property
|
||||
@@ -73,6 +75,79 @@ class LibvirtConnection:
|
||||
"cpu_speed": c.getInfo()[3], # MHz
|
||||
}
|
||||
|
||||
def close(self):
|
||||
"""关闭连接"""
|
||||
if self._conn is not None:
|
||||
try:
|
||||
self._conn.close()
|
||||
except Exception:
|
||||
pass
|
||||
self._conn = None
|
||||
|
||||
# 全局单例
|
||||
libvirt_conn = LibvirtConnection()
|
||||
|
||||
class ConnectionPool:
|
||||
"""多主机连接池"""
|
||||
|
||||
def __init__(self):
|
||||
self._pool: dict[str, LibvirtConnection] = {}
|
||||
|
||||
def get(self, host_id: str = "local") -> LibvirtConnection:
|
||||
"""获取指定主机的连接管理器"""
|
||||
if host_id not in self._pool:
|
||||
host = get_host(host_id)
|
||||
if not host:
|
||||
raise ValueError(f"主机 '{host_id}' 不存在")
|
||||
self._pool[host_id] = LibvirtConnection(host.uri, host_id)
|
||||
return self._pool[host_id]
|
||||
|
||||
def remove(self, host_id: str):
|
||||
"""移除并关闭指定主机的连接"""
|
||||
if host_id in self._pool:
|
||||
self._pool[host_id].close()
|
||||
del self._pool[host_id]
|
||||
|
||||
def get_conn(self, host_id: str = "local"):
|
||||
"""快捷获取 libvirt 只读连接"""
|
||||
return self.get(host_id).conn
|
||||
|
||||
@contextmanager
|
||||
def get_rw(self, host_id: str = "local"):
|
||||
"""快捷获取 libvirt 读写连接"""
|
||||
mgr = self.get(host_id)
|
||||
with mgr.get_rw() as conn:
|
||||
yield conn
|
||||
|
||||
def refresh_all(self):
|
||||
"""刷新所有连接状态"""
|
||||
for host_id, mgr in list(self._pool.items()):
|
||||
try:
|
||||
alive = mgr.conn.isAlive()
|
||||
update_host_status(host_id, "online" if alive else "offline")
|
||||
except Exception:
|
||||
update_host_status(host_id, "offline")
|
||||
mgr.close()
|
||||
|
||||
|
||||
# 全局连接池单例
|
||||
conn_pool = ConnectionPool()
|
||||
|
||||
# 保持向后兼容:本机连接的直接引用
|
||||
libvirt_conn = property(lambda self: conn_pool.get("local"))
|
||||
|
||||
|
||||
class _CompatConn:
|
||||
"""向后兼容包装,让现有 `libvirt_conn.conn` 等调用继续工作"""
|
||||
|
||||
@property
|
||||
def conn(self):
|
||||
return conn_pool.get_conn("local")
|
||||
|
||||
def get_rw(self):
|
||||
return conn_pool.get_rw("local")
|
||||
|
||||
def get_host_info(self):
|
||||
return conn_pool.get("local").get_host_info()
|
||||
|
||||
|
||||
# 全局兼容单例
|
||||
libvirt_conn = _CompatConn()
|
||||
|
||||
Reference in New Issue
Block a user