This commit is contained in:
3 2025-06-18 16:18:42 +08:00
parent b3e6aa7d5c
commit 60359b54ee
5 changed files with 40 additions and 20 deletions

View File

@ -19,7 +19,8 @@ class CommandParser:
# 本地无法解析则调用AI服务
return await self.ai_service.parse_command(command)
def _try_local_parse(self, command: str) -> Dict[str, Any]:
@staticmethod
def _try_local_parse(command: str) -> dict[str, str | list[Any]] | dict[str, str] | None:
"""
尝试本地解析常见命令
"""
@ -32,7 +33,7 @@ class CommandParser:
if vlan_id:
return {
"type": "vlan",
"vlan_id": int(vlan_id),
"vlan_id": vlan_id,
"name": f"VLAN{vlan_id}",
"interfaces": []
}
@ -62,7 +63,7 @@ class CommandParser:
if "vlan" in command:
vlan_id = next((p for p in parts if p.isdigit()), None)
if vlan_id:
config["vlan"] = int(vlan_id)
config["vlan"] = vlan_id
return config

View File

@ -20,7 +20,7 @@ async def batch_apply_config(request: BatchConfigRequest):
for ip in request.switch_ips:
try:
configurator = SwitchConfigurator()
results[ip] = await configurator.apply_config(ip, request.config)
results[ip] = await configurator.safe_apply(ip, request.config)
except Exception as e:
results[ip] = str(e)
return {"results": results}
@ -80,7 +80,7 @@ async def apply_config(request: ConfigRequest):
password=settings.SWITCH_PASSWORD,
timeout=settings.SWITCH_TIMEOUT
)
result = await configurator.apply_config(request.switch_ip, request.config)
result = await configurator.safe_apply(request.switch_ip, request.config)
return {"success": True, "result": result}
except Exception as e:
raise HTTPException(

View File

@ -64,7 +64,7 @@ class SwitchConfigurator:
self.ensp_delay = ensp_command_delay
self.ssh_options = ssh_options
async def _apply_config(self, ip: str, config: Union[Dict, SwitchConfig]) -> str:
async def apply_config(self, ip: str, config: Union[Dict, SwitchConfig]) -> str:
"""实际配置逻辑"""
if isinstance(config, dict):
config = SwitchConfig(**config)
@ -127,6 +127,7 @@ class SwitchConfigurator:
# 关闭连接
writer.close()
# noinspection PyBroadException
try:
await writer.wait_closed()
except:
@ -253,7 +254,7 @@ class SwitchConfigurator:
"""安全配置应用(自动回滚)"""
backup_path = await self._backup_config(ip)
try:
result = await self._apply_config(ip, config)
result = await self.apply_config(ip, config)
if not await self._validate_config(ip, config):
raise SwitchConfigException("配置验证失败")
return {

View File

@ -1,5 +1,4 @@
from fastapi import HTTPException, status
from typing import Optional
class AICommandParseException(HTTPException):
def __init__(self, detail: str):
@ -23,9 +22,10 @@ class ConfigBackupException(SwitchConfigException):
"""配置备份失败异常"""
def __init__(self, ip: str):
super().__init__(
detail=f"无法备份设备 {ip} 的配置",
recovery_guide="检查设备存储空间或权限"
detail=f"无法备份设备 {ip} 的配置"
)
# 将恢复指南作为实例属性
self.recovery_guide = "检查设备存储空间或权限"
class ConfigRollbackException(SwitchConfigException):
"""回滚失败异常"""
@ -34,3 +34,10 @@ class ConfigRollbackException(SwitchConfigException):
detail=f"设备 {ip} 回滚失败(原始错误:{original_error}",
status_code=status.HTTP_422_UNPROCESSABLE_ENTITY
)
class SiliconFlowAPIException(HTTPException):
def __init__(self, detail: str, status_code: int = 400):
super().__init__(
status_code=status_code,
detail=f"SiliconFlow API error: {detail}"
)

View File

@ -1,33 +1,44 @@
import logging
from loguru import logger
import sys
class InterceptHandler(logging.Handler):
def emit(self, record):
# Get corresponding Loguru level if it exists
# 获取对应的Loguru日志级别
try:
level = logger.level(record.levelname).name
except ValueError:
level = record.levelno
# Find caller from where originated the logged message
# 查找日志来源
frame, depth = logging.currentframe(), 2
while frame.f_code.co_filename == logging.__file__:
while frame and frame.f_code.co_filename == logging.__file__:
frame = frame.f_back
depth += 1
# 使用Loguru记录日志
logger.opt(depth=depth, exception=record.exc_info).log(level, record.getMessage())
def setup_logging():
# 拦截标准logging
logging.basicConfig(handlers=[InterceptHandler()], level=0)
logging.basicConfig(handlers=[InterceptHandler()], level=logging.NOTSET)
# 配置loguru
logger.configure(
handlers=[
{"sink": sys.stdout,
"format": "<green>{time:YYYY-MM-DD HH:mm:ss.SSS}</green> | <level>{level: <8}</level> | <cyan>{name}</cyan>:<cyan>{function}</cyan>:<cyan>{line}</cyan> - <level>{message}</level>"}
]
# 移除所有现有处理器
logger.remove()
# 直接添加处理器避免configure方法
logger.add(
sys.stdout,
format=(
"<green>{time:YYYY-MM-DD HH:mm:ss.SSS}</green> | "
"<level>{level: <8}</level> | "
"<cyan>{name}</cyan>:<cyan>{function}</cyan>:<cyan>{line}</cyan> - "
"<level>{message}</level>"
),
level="DEBUG",
enqueue=True
)