添加端点:获取适配器网段

This commit is contained in:
Jerry 2025-07-18 16:42:03 +08:00
parent da5743e27a
commit fcf072636e
3 changed files with 33 additions and 22 deletions

View File

@ -1,3 +1,4 @@
import socket
from datetime import datetime, timedelta from datetime import datetime, timedelta
from fastapi import (APIRouter, HTTPException, Response, WebSocket, WebSocketDisconnect) from fastapi import (APIRouter, HTTPException, Response, WebSocket, WebSocketDisconnect)
from typing import List from typing import List
@ -7,6 +8,8 @@ from fastapi.responses import HTMLResponse
import matplotlib.pyplot as plt import matplotlib.pyplot as plt
import io import io
import base64 import base64
import psutil
import ipaddress
from ..services.switch_traffic_monitor import get_switch_monitor from ..services.switch_traffic_monitor import get_switch_monitor
from ..utils import logger from ..utils import logger
@ -271,7 +274,7 @@ async def get_switch_current_traffic(switch_ip: str, interface: str = None):
try: try:
monitor = get_switch_monitor(switch_ip) monitor = get_switch_monitor(switch_ip)
# 如果没有指定接口,获取所有接口的流量
if not interface: if not interface:
traffic_data = {} traffic_data = {}
for iface in monitor.interface_oids: for iface in monitor.interface_oids:
@ -281,7 +284,6 @@ async def get_switch_current_traffic(switch_ip: str, interface: str = None):
"traffic": traffic_data "traffic": traffic_data
} }
# 获取指定接口的流量
return await get_interface_current_traffic(switch_ip, interface) return await get_interface_current_traffic(switch_ip, interface)
except Exception as e: except Exception as e:
logger.error(f"获取交换机流量失败: {str(e)}") logger.error(f"获取交换机流量失败: {str(e)}")
@ -292,7 +294,7 @@ async def get_interface_current_traffic(switch_ip: str, interface: str) -> dict:
"""获取指定交换机接口的当前流量数据""" """获取指定交换机接口的当前流量数据"""
try: try:
with SessionLocal() as session: with SessionLocal() as session:
# 获取最新记录
record = session.query(SwitchTrafficRecord).filter( record = session.query(SwitchTrafficRecord).filter(
SwitchTrafficRecord.switch_ip == switch_ip, SwitchTrafficRecord.switch_ip == switch_ip,
SwitchTrafficRecord.interface == interface SwitchTrafficRecord.interface == interface
@ -327,26 +329,21 @@ async def get_switch_traffic_history(switch_ip: str, interface: str = None, minu
try: try:
monitor = get_switch_monitor(switch_ip) monitor = get_switch_monitor(switch_ip)
# 如果没有指定接口,返回所有接口的历史数据
if not interface: if not interface:
return { return {
"switch_ip": switch_ip, "switch_ip": switch_ip,
"history": monitor.get_traffic_history() "history": monitor.get_traffic_history()
} }
# 获取指定接口的历史数据
with SessionLocal() as session: with SessionLocal() as session:
# 计算时间范围
time_threshold = datetime.now() - timedelta(minutes=minutes) time_threshold = datetime.now() - timedelta(minutes=minutes)
# 查询历史记录
records = session.query(SwitchTrafficRecord).filter( records = session.query(SwitchTrafficRecord).filter(
SwitchTrafficRecord.switch_ip == switch_ip, SwitchTrafficRecord.switch_ip == switch_ip,
SwitchTrafficRecord.interface == interface, SwitchTrafficRecord.interface == interface,
SwitchTrafficRecord.timestamp >= time_threshold SwitchTrafficRecord.timestamp >= time_threshold
).order_by(SwitchTrafficRecord.timestamp.asc()).all() ).order_by(SwitchTrafficRecord.timestamp.asc()).all()
# 提取数据
history_data = { history_data = {
"in": [record.rate_in for record in records], "in": [record.rate_in for record in records],
"out": [record.rate_out for record in records], "out": [record.rate_out for record in records],
@ -371,13 +368,10 @@ async def websocket_switch_traffic(websocket: WebSocket, switch_ip: str, interfa
monitor = get_switch_monitor(switch_ip) monitor = get_switch_monitor(switch_ip)
while True: while True:
# 获取流量数据
if interface: if interface:
# 单个接口
traffic_data = await get_interface_current_traffic(switch_ip, interface) traffic_data = await get_interface_current_traffic(switch_ip, interface)
await websocket.send_json(traffic_data) await websocket.send_json(traffic_data)
else: else:
# 所有接口
traffic_data = {} traffic_data = {}
for iface in monitor.interface_oids: for iface in monitor.interface_oids:
traffic_data[iface] = await get_interface_current_traffic(switch_ip, iface) traffic_data[iface] = await get_interface_current_traffic(switch_ip, iface)
@ -387,7 +381,6 @@ async def websocket_switch_traffic(websocket: WebSocket, switch_ip: str, interfa
"traffic": traffic_data "traffic": traffic_data
}) })
# 每秒更新一次
await asyncio.sleep(1) await asyncio.sleep(1)
except WebSocketDisconnect: except WebSocketDisconnect:
logger.info(f"客户端断开交换机流量连接: {switch_ip}") logger.info(f"客户端断开交换机流量连接: {switch_ip}")
@ -395,22 +388,17 @@ async def websocket_switch_traffic(websocket: WebSocket, switch_ip: str, interfa
logger.error(f"交换机流量WebSocket错误: {str(e)}") logger.error(f"交换机流量WebSocket错误: {str(e)}")
await websocket.close(code=1011, reason=str(e)) await websocket.close(code=1011, reason=str(e))
# 交换机流量可视化
@router.get("/traffic/switch/plot", response_class=HTMLResponse, summary="交换机流量可视化") @router.get("/traffic/switch/plot", response_class=HTMLResponse, summary="交换机流量可视化")
async def plot_switch_traffic(switch_ip: str, interface: str, minutes: int = 10): async def plot_switch_traffic(switch_ip: str, interface: str, minutes: int = 10):
"""生成交换机流量图表""" """生成交换机流量图表"""
try: try:
# 获取历史数据
history = await get_switch_traffic_history(switch_ip, interface, minutes) history = await get_switch_traffic_history(switch_ip, interface, minutes)
history_data = history["history"] history_data = history["history"]
# 提取数据点
time_points = [datetime.fromisoformat(t) for t in history_data["time"]] time_points = [datetime.fromisoformat(t) for t in history_data["time"]]
in_rates = history_data["in"] in_rates = history_data["in"]
out_rates = history_data["out"] out_rates = history_data["out"]
# 创建图表
plt.figure(figsize=(12, 6)) plt.figure(figsize=(12, 6))
plt.plot(time_points, in_rates, label="流入流量 (B/s)") plt.plot(time_points, in_rates, label="流入流量 (B/s)")
plt.plot(time_points, out_rates, label="流出流量 (B/s)") plt.plot(time_points, out_rates, label="流出流量 (B/s)")
@ -421,8 +409,6 @@ async def plot_switch_traffic(switch_ip: str, interface: str, minutes: int = 10)
plt.grid(True) plt.grid(True)
plt.xticks(rotation=45) plt.xticks(rotation=45)
plt.tight_layout() plt.tight_layout()
# 转换为HTML图像
buf = io.BytesIO() buf = io.BytesIO()
plt.savefig(buf, format="png") plt.savefig(buf, format="png")
buf.seek(0) buf.seek(0)
@ -450,3 +436,29 @@ async def plot_switch_traffic(switch_ip: str, interface: str, minutes: int = 10)
except Exception as e: except Exception as e:
logger.error(f"生成流量图表失败: {str(e)}") logger.error(f"生成流量图表失败: {str(e)}")
return HTMLResponse(content=f"<h1>错误</h1><p>{str(e)}</p>", status_code=500) return HTMLResponse(content=f"<h1>错误</h1><p>{str(e)}</p>", status_code=500)
@router.get("/network_adapters", summary="获取网络适配器网段")
async def get_network_adapters():
try:
net_if_addrs = psutil.net_if_addrs()
networks = []
for interface, addrs in net_if_addrs.items():
for addr in addrs:
if addr.family == socket.AF_INET:
ip = addr.address
netmask = addr.netmask
network = ipaddress.IPv4Network(f"{ip}/{netmask}", strict=False)
networks.append({
"adapter": interface,
"network": str(network),
"ip": ip,
"subnet_mask": netmask
})
return {"networks": networks}
except Exception as e:
return {"error": f"获取网络适配器信息失败: {str(e)}"}

View File

@ -30,9 +30,9 @@ class AIService:
2. 必须包含'commands'字段包含可直接执行的命令列表 2. 必须包含'commands'字段包含可直接执行的命令列表
3. 其他参数根据配置类型动态添加 3. 其他参数根据配置类型动态添加
4. 不要包含解释性文本步骤说明或注释 4. 不要包含解释性文本步骤说明或注释
5.要包含使用ssh连接交换机后的完整命令包括但不完全包括system-view退出保存等完整操作 5.要包含使用ssh连接交换机后的完整命令包括但不完全包括system-view退出保存等完整操作注意保存还需要输入Y和回车
示例命令'创建VLAN 100名称为TEST' 示例命令'创建VLAN 100名称为TEST'
示例返回{"type": "vlan", "vlan_id": 100, "name": "TEST", "commands": ["vlan 100", "name TEST"]} 示例返回{"type": "vlan", "vlan_id": 100, "name": "TEST", "commands": ["system-view\n","vlan 100\n", "name TEST\n","quit\n","\x1A\n","save\n","Y\n"]}
注意这里生成的commands中需包含登录交换机和保存等所有操作命令我们使ssh连接交换机你不需要给出连接ssh的命令你只需要给出使用ssh连接到交换机后所输入的全部命令 注意这里生成的commands中需包含登录交换机和保存等所有操作命令我们使ssh连接交换机你不需要给出连接ssh的命令你只需要给出使用ssh连接到交换机后所输入的全部命令
""" """

View File

@ -12,7 +12,6 @@ pysnmp==7.1.21
aiofiles==23.2.1 aiofiles==23.2.1
loguru==0.7.2 loguru==0.7.2
tenacity==8.2.3 tenacity==8.2.3
asyncio==3.4.3 asyncio==3.4.3