570 lines
18 KiB
Python
570 lines
18 KiB
Python
"""算法服务管理路由,提供服务注册、管理等功能"""
|
||
|
||
from fastapi import APIRouter, HTTPException, status, Depends
|
||
from typing import List, Dict, Any, Optional
|
||
from pydantic import BaseModel
|
||
import uuid
|
||
import os
|
||
|
||
from app.models.models import AlgorithmService
|
||
from app.models.database import SessionLocal
|
||
from app.routes.user import get_current_active_user
|
||
from app.services.project_analyzer import ProjectAnalyzer
|
||
from app.services.service_generator import ServiceGenerator
|
||
from app.services.service_orchestrator import ServiceOrchestrator
|
||
|
||
router = APIRouter(prefix="/services", tags=["services"])
|
||
|
||
|
||
class RegisterServiceRequest(BaseModel):
|
||
"""注册服务请求"""
|
||
repository_id: str
|
||
name: str
|
||
version: str = "1.0.0"
|
||
service_type: str = "http"
|
||
host: str = "0.0.0.0"
|
||
port: int = 8000
|
||
timeout: int = 30
|
||
health_check_path: str = "/health"
|
||
environment: Dict[str, str] = {}
|
||
|
||
|
||
class ServiceResponse(BaseModel):
|
||
"""服务响应"""
|
||
id: str
|
||
service_id: str
|
||
name: str
|
||
algorithm_name: str
|
||
version: str
|
||
host: str
|
||
port: int
|
||
api_url: str
|
||
status: str
|
||
created_at: str
|
||
updated_at: str
|
||
|
||
|
||
class ServiceListResponse(BaseModel):
|
||
"""服务列表响应"""
|
||
success: bool
|
||
services: List[ServiceResponse]
|
||
|
||
|
||
class ServiceDetailResponse(BaseModel):
|
||
"""服务详情响应"""
|
||
success: bool
|
||
service: ServiceResponse
|
||
|
||
|
||
class ServiceOperationResponse(BaseModel):
|
||
"""服务操作响应"""
|
||
success: bool
|
||
message: str
|
||
service_id: str
|
||
status: str
|
||
|
||
|
||
class ServiceStatusResponse(BaseModel):
|
||
"""服务状态响应"""
|
||
success: bool
|
||
status: str
|
||
health: str
|
||
|
||
|
||
class ServiceLogsResponse(BaseModel):
|
||
"""服务日志响应"""
|
||
success: bool
|
||
logs: List[str]
|
||
|
||
|
||
class RepositoryAlgorithmsResponse(BaseModel):
|
||
"""仓库算法列表响应"""
|
||
success: bool
|
||
algorithms: List[Dict[str, Any]]
|
||
|
||
|
||
# 初始化服务组件
|
||
project_analyzer = ProjectAnalyzer()
|
||
service_generator = ServiceGenerator()
|
||
service_orchestrator = ServiceOrchestrator()
|
||
|
||
|
||
@router.post("/register", status_code=status.HTTP_201_CREATED)
|
||
async def register_service(
|
||
request: RegisterServiceRequest,
|
||
current_user: dict = Depends(get_current_active_user)
|
||
):
|
||
"""注册新服务"""
|
||
# 检查用户权限
|
||
if current_user.role != "admin":
|
||
raise HTTPException(status_code=403, detail="Insufficient permissions")
|
||
|
||
# 创建数据库会话
|
||
db = SessionLocal()
|
||
try:
|
||
# 1. 获取仓库信息
|
||
# 注意:在实际实现中,应该从数据库中获取仓库信息
|
||
# 这里简化处理,假设仓库存在
|
||
|
||
# 2. 分析项目
|
||
repo_path = f"/tmp/repository_{request.repository_id}"
|
||
# 注意:在实际实现中,应该从算法仓库中获取项目文件
|
||
# 这里简化处理,创建一个模拟的项目结构
|
||
os.makedirs(repo_path, exist_ok=True)
|
||
|
||
# 创建模拟的算法文件
|
||
with open(os.path.join(repo_path, "algorithm.py"), "w") as f:
|
||
f.write("""
|
||
def predict(data):
|
||
return {"result": "Prediction result", "input": data}
|
||
|
||
def run(data):
|
||
return {"result": "Run result", "input": data}
|
||
|
||
def main(data):
|
||
return {"result": "Main result", "input": data}
|
||
""")
|
||
|
||
# 分析项目
|
||
project_info = project_analyzer.analyze_project(repo_path)
|
||
if not project_info["success"]:
|
||
raise HTTPException(status_code=400, detail=f"项目分析失败: {project_info['error']}")
|
||
|
||
# 3. 生成服务包装器
|
||
service_config = {
|
||
"name": request.name,
|
||
"version": request.version,
|
||
"service_type": request.service_type,
|
||
"host": request.host,
|
||
"port": request.port,
|
||
"timeout": request.timeout,
|
||
"health_check_path": request.health_check_path,
|
||
"environment": request.environment
|
||
}
|
||
|
||
generate_result = service_generator.generate_service(project_info, service_config)
|
||
if not generate_result["success"]:
|
||
raise HTTPException(status_code=400, detail=f"服务生成失败: {generate_result['error']}")
|
||
|
||
# 4. 部署服务
|
||
service_id = str(uuid.uuid4())
|
||
deploy_result = service_orchestrator.deploy_service(service_id, service_config, project_info)
|
||
if not deploy_result["success"]:
|
||
raise HTTPException(status_code=400, detail=f"服务部署失败: {deploy_result['error']}")
|
||
|
||
# 5. 保存服务信息到数据库
|
||
new_service = AlgorithmService(
|
||
id=str(uuid.uuid4()),
|
||
service_id=service_id,
|
||
name=request.name,
|
||
algorithm_name="algorithm", # 注意:在实际实现中,应该从仓库信息中获取
|
||
version=request.version,
|
||
host=request.host,
|
||
port=request.port,
|
||
api_url=deploy_result["api_url"],
|
||
status=deploy_result["status"],
|
||
config={
|
||
"service_type": request.service_type,
|
||
"timeout": request.timeout,
|
||
"health_check_path": request.health_check_path,
|
||
"environment": request.environment,
|
||
"container_id": deploy_result["container_id"]
|
||
}
|
||
)
|
||
|
||
db.add(new_service)
|
||
db.commit()
|
||
db.refresh(new_service)
|
||
|
||
# 6. 返回响应
|
||
return {
|
||
"success": True,
|
||
"message": "服务注册成功",
|
||
"service": {
|
||
"id": new_service.id,
|
||
"service_id": new_service.service_id,
|
||
"name": new_service.name,
|
||
"algorithm_name": new_service.algorithm_name,
|
||
"version": new_service.version,
|
||
"host": new_service.host,
|
||
"port": new_service.port,
|
||
"api_url": new_service.api_url,
|
||
"status": new_service.status,
|
||
"created_at": new_service.created_at.isoformat(),
|
||
"updated_at": new_service.updated_at.isoformat()
|
||
}
|
||
}
|
||
finally:
|
||
db.close()
|
||
|
||
|
||
@router.get("", response_model=ServiceListResponse)
|
||
async def list_services(
|
||
current_user: dict = Depends(get_current_active_user)
|
||
):
|
||
"""获取服务列表"""
|
||
# 检查用户权限
|
||
if current_user.role != "admin":
|
||
raise HTTPException(status_code=403, detail="Insufficient permissions")
|
||
|
||
# 创建数据库会话
|
||
db = SessionLocal()
|
||
try:
|
||
# 查询服务列表
|
||
services = db.query(AlgorithmService).all()
|
||
|
||
# 转换为响应格式
|
||
service_list = []
|
||
for service in services:
|
||
service_list.append(ServiceResponse(
|
||
id=service.id,
|
||
service_id=service.service_id,
|
||
name=service.name,
|
||
algorithm_name=service.algorithm_name,
|
||
version=service.version,
|
||
host=service.host,
|
||
port=service.port,
|
||
api_url=service.api_url,
|
||
status=service.status,
|
||
created_at=service.created_at.isoformat(),
|
||
updated_at=service.updated_at.isoformat()
|
||
))
|
||
|
||
return ServiceListResponse(
|
||
success=True,
|
||
services=service_list
|
||
)
|
||
finally:
|
||
db.close()
|
||
|
||
|
||
@router.get("/{service_id}", response_model=ServiceDetailResponse)
|
||
async def get_service(
|
||
service_id: str,
|
||
current_user: dict = Depends(get_current_active_user)
|
||
):
|
||
"""获取服务详情"""
|
||
# 检查用户权限
|
||
if current_user.role != "admin":
|
||
raise HTTPException(status_code=403, detail="Insufficient permissions")
|
||
|
||
# 创建数据库会话
|
||
db = SessionLocal()
|
||
try:
|
||
# 查询服务
|
||
service = db.query(AlgorithmService).filter(AlgorithmService.service_id == service_id).first()
|
||
|
||
if not service:
|
||
raise HTTPException(status_code=404, detail="Service not found")
|
||
|
||
# 返回响应
|
||
return ServiceDetailResponse(
|
||
success=True,
|
||
service=ServiceResponse(
|
||
id=service.id,
|
||
service_id=service.service_id,
|
||
name=service.name,
|
||
algorithm_name=service.algorithm_name,
|
||
version=service.version,
|
||
host=service.host,
|
||
port=service.port,
|
||
api_url=service.api_url,
|
||
status=service.status,
|
||
created_at=service.created_at.isoformat(),
|
||
updated_at=service.updated_at.isoformat()
|
||
)
|
||
)
|
||
finally:
|
||
db.close()
|
||
|
||
|
||
@router.post("/{service_id}/start")
|
||
async def start_service(
|
||
service_id: str,
|
||
current_user: dict = Depends(get_current_active_user)
|
||
):
|
||
"""启动服务"""
|
||
# 检查用户权限
|
||
if current_user.role != "admin":
|
||
raise HTTPException(status_code=403, detail="Insufficient permissions")
|
||
|
||
# 创建数据库会话
|
||
db = SessionLocal()
|
||
try:
|
||
# 查询服务
|
||
service = db.query(AlgorithmService).filter(AlgorithmService.service_id == service_id).first()
|
||
|
||
if not service:
|
||
raise HTTPException(status_code=404, detail="Service not found")
|
||
|
||
# 获取容器ID
|
||
container_id = service.config.get("container_id")
|
||
if not container_id:
|
||
raise HTTPException(status_code=400, detail="Container ID not found")
|
||
|
||
# 启动服务
|
||
start_result = service_orchestrator.start_service(service_id, container_id)
|
||
if not start_result["success"]:
|
||
raise HTTPException(status_code=400, detail=f"服务启动失败: {start_result['error']}")
|
||
|
||
# 更新服务状态
|
||
service.status = start_result["status"]
|
||
db.commit()
|
||
|
||
# 返回响应
|
||
return ServiceOperationResponse(
|
||
success=True,
|
||
message="服务启动成功",
|
||
service_id=service_id,
|
||
status=start_result["status"]
|
||
)
|
||
finally:
|
||
db.close()
|
||
|
||
|
||
@router.post("/{service_id}/stop")
|
||
async def stop_service(
|
||
service_id: str,
|
||
current_user: dict = Depends(get_current_active_user)
|
||
):
|
||
"""停止服务"""
|
||
# 检查用户权限
|
||
if current_user.role != "admin":
|
||
raise HTTPException(status_code=403, detail="Insufficient permissions")
|
||
|
||
# 创建数据库会话
|
||
db = SessionLocal()
|
||
try:
|
||
# 查询服务
|
||
service = db.query(AlgorithmService).filter(AlgorithmService.service_id == service_id).first()
|
||
|
||
if not service:
|
||
raise HTTPException(status_code=404, detail="Service not found")
|
||
|
||
# 获取容器ID
|
||
container_id = service.config.get("container_id")
|
||
if not container_id:
|
||
raise HTTPException(status_code=400, detail="Container ID not found")
|
||
|
||
# 停止服务
|
||
stop_result = service_orchestrator.stop_service(service_id, container_id)
|
||
if not stop_result["success"]:
|
||
raise HTTPException(status_code=400, detail=f"服务停止失败: {stop_result['error']}")
|
||
|
||
# 更新服务状态
|
||
service.status = stop_result["status"]
|
||
db.commit()
|
||
|
||
# 返回响应
|
||
return ServiceOperationResponse(
|
||
success=True,
|
||
message="服务停止成功",
|
||
service_id=service_id,
|
||
status=stop_result["status"]
|
||
)
|
||
finally:
|
||
db.close()
|
||
|
||
|
||
@router.post("/{service_id}/restart")
|
||
async def restart_service(
|
||
service_id: str,
|
||
current_user: dict = Depends(get_current_active_user)
|
||
):
|
||
"""重启服务"""
|
||
# 检查用户权限
|
||
if current_user.role != "admin":
|
||
raise HTTPException(status_code=403, detail="Insufficient permissions")
|
||
|
||
# 创建数据库会话
|
||
db = SessionLocal()
|
||
try:
|
||
# 查询服务
|
||
service = db.query(AlgorithmService).filter(AlgorithmService.service_id == service_id).first()
|
||
|
||
if not service:
|
||
raise HTTPException(status_code=404, detail="Service not found")
|
||
|
||
# 获取容器ID
|
||
container_id = service.config.get("container_id")
|
||
if not container_id:
|
||
raise HTTPException(status_code=400, detail="Container ID not found")
|
||
|
||
# 重启服务
|
||
restart_result = service_orchestrator.restart_service(service_id, container_id)
|
||
if not restart_result["success"]:
|
||
raise HTTPException(status_code=400, detail=f"服务重启失败: {restart_result['error']}")
|
||
|
||
# 更新服务状态
|
||
service.status = restart_result["status"]
|
||
db.commit()
|
||
|
||
# 返回响应
|
||
return ServiceOperationResponse(
|
||
success=True,
|
||
message="服务重启成功",
|
||
service_id=service_id,
|
||
status=restart_result["status"]
|
||
)
|
||
finally:
|
||
db.close()
|
||
|
||
|
||
@router.delete("/{service_id}")
|
||
async def delete_service(
|
||
service_id: str,
|
||
current_user: dict = Depends(get_current_active_user)
|
||
):
|
||
"""删除服务"""
|
||
# 检查用户权限
|
||
if current_user.role != "admin":
|
||
raise HTTPException(status_code=403, detail="Insufficient permissions")
|
||
|
||
# 创建数据库会话
|
||
db = SessionLocal()
|
||
try:
|
||
# 查询服务
|
||
service = db.query(AlgorithmService).filter(AlgorithmService.service_id == service_id).first()
|
||
|
||
if not service:
|
||
raise HTTPException(status_code=404, detail="Service not found")
|
||
|
||
# 获取容器ID和镜像名称
|
||
container_id = service.config.get("container_id")
|
||
image_name = f"algorithm-service-{service_id}:{service.version}"
|
||
|
||
# 删除服务
|
||
delete_result = service_orchestrator.delete_service(service_id, container_id, image_name)
|
||
if not delete_result["success"]:
|
||
# 继续执行,即使Docker操作失败
|
||
pass
|
||
|
||
# 删除数据库记录
|
||
db.delete(service)
|
||
db.commit()
|
||
|
||
# 返回响应
|
||
return {
|
||
"success": True,
|
||
"message": "服务删除成功",
|
||
"service_id": service_id
|
||
}
|
||
finally:
|
||
db.close()
|
||
|
||
|
||
@router.get("/{service_id}/status")
|
||
async def get_service_status(
|
||
service_id: str,
|
||
current_user: dict = Depends(get_current_active_user)
|
||
):
|
||
"""获取服务状态"""
|
||
# 检查用户权限
|
||
if current_user.role != "admin":
|
||
raise HTTPException(status_code=403, detail="Insufficient permissions")
|
||
|
||
# 创建数据库会话
|
||
db = SessionLocal()
|
||
try:
|
||
# 查询服务
|
||
service = db.query(AlgorithmService).filter(AlgorithmService.service_id == service_id).first()
|
||
|
||
if not service:
|
||
raise HTTPException(status_code=404, detail="Service not found")
|
||
|
||
# 获取容器ID
|
||
container_id = service.config.get("container_id")
|
||
if not container_id:
|
||
raise HTTPException(status_code=400, detail="Container ID not found")
|
||
|
||
# 获取服务状态
|
||
status_result = service_orchestrator.get_service_status(container_id)
|
||
if not status_result["success"]:
|
||
raise HTTPException(status_code=400, detail=f"获取服务状态失败: {status_result['error']}")
|
||
|
||
# 返回响应
|
||
return ServiceStatusResponse(
|
||
success=True,
|
||
status=status_result["status"],
|
||
health=status_result["health"]
|
||
)
|
||
finally:
|
||
db.close()
|
||
|
||
|
||
@router.get("/{service_id}/logs")
|
||
async def get_service_logs(
|
||
service_id: str,
|
||
lines: int = 100,
|
||
current_user: dict = Depends(get_current_active_user)
|
||
):
|
||
"""获取服务日志"""
|
||
# 检查用户权限
|
||
if current_user.role != "admin":
|
||
raise HTTPException(status_code=403, detail="Insufficient permissions")
|
||
|
||
# 创建数据库会话
|
||
db = SessionLocal()
|
||
try:
|
||
# 查询服务
|
||
service = db.query(AlgorithmService).filter(AlgorithmService.service_id == service_id).first()
|
||
|
||
if not service:
|
||
raise HTTPException(status_code=404, detail="Service not found")
|
||
|
||
# 获取容器ID
|
||
container_id = service.config.get("container_id")
|
||
if not container_id:
|
||
raise HTTPException(status_code=400, detail="Container ID not found")
|
||
|
||
# 获取服务日志
|
||
logs_result = service_orchestrator.get_service_logs(container_id, lines)
|
||
if not logs_result["success"]:
|
||
raise HTTPException(status_code=400, detail=f"获取服务日志失败: {logs_result['error']}")
|
||
|
||
# 返回响应
|
||
return ServiceLogsResponse(
|
||
success=True,
|
||
logs=logs_result["logs"]
|
||
)
|
||
finally:
|
||
db.close()
|
||
|
||
|
||
@router.get("/repository/algorithms")
|
||
async def get_repository_algorithms(
|
||
repository_id: str,
|
||
current_user: dict = Depends(get_current_active_user)
|
||
):
|
||
"""获取仓库中的算法列表"""
|
||
# 检查用户权限
|
||
if current_user.role != "admin":
|
||
raise HTTPException(status_code=403, detail="Insufficient permissions")
|
||
|
||
try:
|
||
# 模拟获取仓库中的算法列表
|
||
# 注意:在实际实现中,应该从算法仓库中获取真实的算法列表
|
||
algorithms = [
|
||
{
|
||
"id": "alg-001",
|
||
"name": "图像分类算法",
|
||
"description": "基于深度学习的图像分类算法",
|
||
"type": "computer_vision",
|
||
"entry_point": "algorithm.py"
|
||
},
|
||
{
|
||
"id": "alg-002",
|
||
"name": "文本分类算法",
|
||
"description": "基于BERT的文本分类算法",
|
||
"type": "nlp",
|
||
"entry_point": "text_algorithm.py"
|
||
}
|
||
]
|
||
|
||
return RepositoryAlgorithmsResponse(
|
||
success=True,
|
||
algorithms=algorithms
|
||
)
|
||
except Exception as e:
|
||
raise HTTPException(status_code=500, detail=str(e))
|