diff --git a/src/backend/README.md b/src/backend/README.md index fbe2354..cc340a6 100644 --- a/src/backend/README.md +++ b/src/backend/README.md @@ -9,7 +9,7 @@ src/backend/ ├── app/ │ ├── __init__.py # 创建 Flask 应用实例 │ ├── api/ # API 路由模块 -│ │ ├── __init__.py # 注册 API 蓝图 +│ │ ├—── __init__.py # 注册 API 蓝图 │ │ ├── command_parser.py # /api/parse_command 接口 │ │ └── network_config.py # /api/apply_config 接口 │ └── services/ # 核心服务逻辑 diff --git a/src/backend/app/api/endpoints.py b/src/backend/app/api/endpoints.py index 8aa16bc..c5d3678 100644 --- a/src/backend/app/api/endpoints.py +++ b/src/backend/app/api/endpoints.py @@ -1,5 +1,5 @@ from fastapi import APIRouter, Depends, HTTPException -from typing import Any +from typing import List from pydantic import BaseModel from ...app.services.ai_services import AIService @@ -10,6 +10,21 @@ from ..services.network_scanner import NetworkScanner router = APIRouter(prefix="/api", tags=["API"]) scanner = NetworkScanner() +class BatchConfigRequest(BaseModel): + config: dict + switch_ips: List[str] # 支持多个IP + +@router.post("/batch_apply_config") +async def batch_apply_config(request: BatchConfigRequest): + results = {} + for ip in request.switch_ips: + try: + configurator = SwitchConfigurator() + results[ip] = await configurator.apply_config(ip, request.config) + except Exception as e: + results[ip] = str(e) + return {"results": results} + @router.get("/test") async def test_endpoint(): return {"message": "Hello World"} diff --git a/src/backend/app/api/network_config.py b/src/backend/app/api/network_config.py index e8f85e0..0898cd0 100644 --- a/src/backend/app/api/network_config.py +++ b/src/backend/app/api/network_config.py @@ -1,14 +1,26 @@ import paramiko +from tenacity import retry, stop_after_attempt import asyncio -from typing import Dict, Any +from typing import Dict, Any,List from ..utils.exceptions import SwitchConfigException class SwitchConfigurator: - def __init__(self, username: str, password: str, timeout: int = 10): + def __init__(self, username: str, password: str, timeout: int = 10,max_workers=5): self.username = username self.password = password self.timeout = timeout + self.semaphore = asyncio.Semaphore(max_workers) + + @retry(stop=stop_after_attempt(3)) + async def safe_apply(self, ip: str, config: dict): + async with self.semaphore: + return await self.apply_config(ip, config) + + async def batch_configure(self, config: dict, ips: List[str]): + """并发配置多台设备""" + tasks = [self.apply_config(ip, config) for ip in ips] + return await asyncio.gather(*tasks, return_exceptions=True) async def apply_config(self, switch_ip: str, config: Dict[str, Any]) -> str: """ diff --git a/src/backend/requirements.txt b/src/backend/requirements.txt index 7ce79b3..4ca45f3 100644 --- a/src/backend/requirements.txt +++ b/src/backend/requirements.txt @@ -1,8 +1,10 @@ -fastapi==0.95.2 -uvicorn==0.22.0 -python-dotenv==1.0.0 -requests==2.28.2 -paramiko==3.1.0 -pydantic==1.10.7 -loguru==0.7.0 -python-nmap==0.7.1 \ No newline at end of file +fastapi>=0.95.2 +uvicorn>=0.22.0 +python-dotenv>=1.0.0 +requests>=2.28.2 +paramiko>=3.1.0 +pydantic>=1.10.7 +loguru>=0.7.0 +python-nmap>=0.7.1 +tenacity>=9.1.2 +typing-extensions>=4.0.0 \ No newline at end of file