fix(snmp): 修复异步函数同步调用导致'coroutine object is not an iterator'错误

问题原因:
- pysnmp.hlapi.asyncio 的 getCmd/bulkCmd/nextCmd 都是 async def 协程函数
- 返回的是 coroutine 对象,需要用 await 获取结果
- 原代码用 next() 或 for...in 同步迭代协程对象,报错:
  'coroutine' object is not an iterator

解决方案:
1. snmp_service.py: 所有 SNMP 操作改为 async def
   - test_connection(): getCmd 改为 await getCmd()
   - get_arp_table(): bulkCmd 改为 await bulkCmd()
   - get_mac_address_table(): bulkCmd 改为 await bulkCmd()
   - get_interfaces(): bulkCmd 改为 await bulkCmd()
   - poll_device(): 所有子调用加 await
2. api/v1/snmp.py: API 路由改为 async def + await

bulkCmd await 后返回 (errorIndication, errorStatus, errorIndex, varBindTable)
其中 varBindTable 是列表的列表(table 形式),需双层循环解析
This commit is contained in:
Your Name
2026-07-23 15:01:18 +08:00
parent 8b1df674ec
commit 094d2cc112
2 changed files with 117 additions and 118 deletions
+6 -6
View File
@@ -437,7 +437,7 @@ def delete_network_device(
# ========== SNMP 操作 ==========
@router.post("/devices/{device_id}/test", summary="测试 SNMP 连接")
def test_snmp_connection(device_id: int, db: Session = Depends(get_db)):
async def test_snmp_connection(device_id: int, db: Session = Depends(get_db)):
"""测试设备的 SNMP 连接(不写审计,避免刷屏)"""
from app.models.snmp import NetworkDevice
@@ -448,7 +448,7 @@ def test_snmp_connection(device_id: int, db: Session = Depends(get_db)):
if not device.snmp_credential:
raise HTTPException(status_code=400, detail="设备未配置 SNMP 凭据")
success, info = SNMPService.test_connection(device, device.snmp_credential)
success, info = await SNMPService.test_connection(device, device.snmp_credential)
return {
"device_id": device_id,
@@ -459,9 +459,9 @@ def test_snmp_connection(device_id: int, db: Session = Depends(get_db)):
@router.post("/devices/{device_id}/poll", summary="立即轮询设备")
def poll_device_now(device_id: int, db: Session = Depends(get_db)):
async def poll_device_now(device_id: int, db: Session = Depends(get_db)):
"""立即轮询设备,获取 ARP 表、MAC 地址表、接口信息(不写审计,常规操作)"""
result = SNMPService.poll_device(db, device_id)
result = await SNMPService.poll_device(db, device_id)
if 'error' in result:
raise HTTPException(status_code=400, detail=result['error'])
@@ -470,7 +470,7 @@ def poll_device_now(device_id: int, db: Session = Depends(get_db)):
@router.post("/devices/{device_id}/arp", summary="获取设备 ARP 表")
def get_device_arp_table(device_id: int, db: Session = Depends(get_db)):
async def get_device_arp_table(device_id: int, db: Session = Depends(get_db)):
"""获取设备的 ARP 表"""
from app.models.snmp import NetworkDevice, ARPEntry
@@ -481,7 +481,7 @@ def get_device_arp_table(device_id: int, db: Session = Depends(get_db)):
if not device.snmp_credential:
raise HTTPException(status_code=400, detail="设备未配置 SNMP 凭据")
entries = SNMPService.get_arp_table(device, device.snmp_credential, db)
entries = await SNMPService.get_arp_table(device, device.snmp_credential, db)
return {
"device_id": device_id,