2025-04-02 16:57:05 +08:00
|
|
|
|
from fastapi import APIRouter, HTTPException
|
2025-04-03 12:52:37 +08:00
|
|
|
|
from ..models.schemas import PriceRequest, PriceComparison, InstanceSearchRequest, InstanceSearchRequestV2
|
2025-04-02 16:57:05 +08:00
|
|
|
|
from ..core.config import AWS_REGION_NAMES, AZURE_REGION_NAMES, ALIYUN_REGION_NAMES
|
|
|
|
|
|
from ..core.instance_data import get_instance_info
|
|
|
|
|
|
from ..services import calculate_price
|
2025-04-03 12:52:37 +08:00
|
|
|
|
from ..services.aws.pricing_v2 import search_instances_v2
|
2025-04-02 16:57:05 +08:00
|
|
|
|
from typing import Dict, List, Any
|
|
|
|
|
|
|
|
|
|
|
|
router = APIRouter(prefix="/api")
|
|
|
|
|
|
|
|
|
|
|
|
@router.get("/regions")
|
|
|
|
|
|
async def get_regions(platform: str = "aws"):
|
|
|
|
|
|
"""获取指定平台的区域列表"""
|
|
|
|
|
|
result = []
|
|
|
|
|
|
|
|
|
|
|
|
if platform == "aws":
|
|
|
|
|
|
for key in AWS_REGION_NAMES.keys():
|
|
|
|
|
|
result.append({'code': key, 'name': AWS_REGION_NAMES[key]})
|
|
|
|
|
|
elif platform == "azure":
|
|
|
|
|
|
for key in AZURE_REGION_NAMES.keys():
|
|
|
|
|
|
result.append({'code': key, 'name': AZURE_REGION_NAMES[key]})
|
|
|
|
|
|
elif platform == "aliyun":
|
|
|
|
|
|
for key in ALIYUN_REGION_NAMES.keys():
|
|
|
|
|
|
result.append({'code': key, 'name': ALIYUN_REGION_NAMES[key]})
|
|
|
|
|
|
else:
|
|
|
|
|
|
raise HTTPException(status_code=400, detail=f"不支持的平台: {platform}")
|
|
|
|
|
|
|
|
|
|
|
|
return result
|
|
|
|
|
|
|
|
|
|
|
|
@router.get("/instance-types")
|
|
|
|
|
|
async def get_instance_types(platform: str = "aws"):
|
|
|
|
|
|
"""获取指定平台的实例类型"""
|
|
|
|
|
|
try:
|
|
|
|
|
|
return get_instance_info(platform)
|
|
|
|
|
|
except ValueError as e:
|
|
|
|
|
|
raise HTTPException(status_code=400, detail=str(e))
|
|
|
|
|
|
|
|
|
|
|
|
@router.post("/search-instances")
|
|
|
|
|
|
async def search_instances(request: InstanceSearchRequest):
|
|
|
|
|
|
"""搜索符合条件的实例类型"""
|
|
|
|
|
|
try:
|
|
|
|
|
|
# 验证必填参数
|
|
|
|
|
|
if request.cpu_cores is None:
|
|
|
|
|
|
raise HTTPException(status_code=400, detail="cpu_cores是必填参数")
|
|
|
|
|
|
if request.memory_gb is None:
|
|
|
|
|
|
raise HTTPException(status_code=400, detail="memory_gb是必填参数")
|
|
|
|
|
|
if request.disk_gb is None:
|
|
|
|
|
|
raise HTTPException(status_code=400, detail="disk_gb是必填参数")
|
|
|
|
|
|
if request.region is None:
|
|
|
|
|
|
raise HTTPException(status_code=400, detail="region是必填参数")
|
|
|
|
|
|
|
|
|
|
|
|
# 获取实例信息
|
|
|
|
|
|
try:
|
|
|
|
|
|
instance_info = get_instance_info(request.platform)
|
|
|
|
|
|
except ValueError as e:
|
|
|
|
|
|
raise HTTPException(status_code=400, detail=str(e))
|
|
|
|
|
|
|
|
|
|
|
|
matching_instances = []
|
|
|
|
|
|
|
|
|
|
|
|
# 遍历所有实例类型
|
|
|
|
|
|
for instance_type, info in instance_info.items():
|
|
|
|
|
|
try:
|
|
|
|
|
|
# 检查是否满足CPU要求(严格匹配)
|
|
|
|
|
|
if request.cpu_cores and info['cpu'] != request.cpu_cores:
|
|
|
|
|
|
continue
|
|
|
|
|
|
|
|
|
|
|
|
# 检查是否满足内存要求(严格匹配)
|
|
|
|
|
|
if request.memory_gb and info['memory'] != request.memory_gb:
|
|
|
|
|
|
continue
|
|
|
|
|
|
|
|
|
|
|
|
# 计算价格
|
|
|
|
|
|
price_info = await calculate_price(
|
|
|
|
|
|
platform=request.platform,
|
|
|
|
|
|
instance_type=instance_type,
|
|
|
|
|
|
region=request.region,
|
|
|
|
|
|
disk_gb=request.disk_gb,
|
|
|
|
|
|
operating_system=request.operating_system
|
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
|
|
# 添加到匹配列表
|
|
|
|
|
|
matching_instances.append({
|
|
|
|
|
|
"instance_type": instance_type,
|
|
|
|
|
|
"description": info['description'],
|
|
|
|
|
|
"cpu": info['cpu'],
|
|
|
|
|
|
"memory": info['memory'],
|
|
|
|
|
|
"disk_gb": request.disk_gb,
|
|
|
|
|
|
"hourly_price": price_info['hourly_price'],
|
|
|
|
|
|
"monthly_price": price_info['monthly_price'],
|
|
|
|
|
|
"disk_monthly_price": price_info['disk_monthly_price'],
|
|
|
|
|
|
"total_monthly_price": price_info['total_monthly_price']
|
|
|
|
|
|
})
|
|
|
|
|
|
except Exception as e:
|
|
|
|
|
|
print(f"计算价格时出错: {str(e)}")
|
|
|
|
|
|
|
|
|
|
|
|
# 按总价格排序
|
|
|
|
|
|
matching_instances.sort(key=lambda x: x['total_monthly_price'])
|
|
|
|
|
|
|
|
|
|
|
|
return matching_instances
|
|
|
|
|
|
|
|
|
|
|
|
except Exception as e:
|
|
|
|
|
|
print(f"搜索实例时出错: {str(e)}")
|
|
|
|
|
|
raise HTTPException(status_code=500, detail=str(e))
|
2025-04-03 12:52:37 +08:00
|
|
|
|
|
|
|
|
|
|
@router.post("/search-instances-v2")
|
|
|
|
|
|
async def search_instances_v2_api(request: InstanceSearchRequestV2):
|
|
|
|
|
|
"""
|
|
|
|
|
|
第二套搜索API - 通过MySQL数据库搜索符合条件的AWS实例
|
|
|
|
|
|
"""
|
|
|
|
|
|
try:
|
|
|
|
|
|
# 调用服务层函数
|
|
|
|
|
|
instances = await search_instances_v2(
|
|
|
|
|
|
region=request.region,
|
|
|
|
|
|
cpu_cores=request.cpu_cores,
|
|
|
|
|
|
memory_gb=request.memory_gb,
|
|
|
|
|
|
disk_gb=request.disk_gb,
|
|
|
|
|
|
operating_system=request.operating_system
|
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
|
|
return instances
|
|
|
|
|
|
except Exception as e:
|
|
|
|
|
|
print(f"搜索实例时出错: {str(e)}")
|
|
|
|
|
|
raise HTTPException(status_code=500, detail=str(e))
|
2025-04-02 16:57:05 +08:00
|
|
|
|
|
|
|
|
|
|
@router.post("/compare-prices")
|
|
|
|
|
|
async def compare_prices(comparison: PriceComparison):
|
|
|
|
|
|
"""比较不同配置的价格"""
|
|
|
|
|
|
try:
|
|
|
|
|
|
results = []
|
|
|
|
|
|
for config in comparison.configurations:
|
|
|
|
|
|
# 根据请求中的平台参数调用对应的价格计算服务
|
|
|
|
|
|
# 这里假设需要扩展PriceRequest模型,添加platform字段
|
|
|
|
|
|
# 暂时默认为AWS
|
|
|
|
|
|
platform = getattr(config, 'platform', 'aws')
|
|
|
|
|
|
|
|
|
|
|
|
price = await calculate_price(
|
|
|
|
|
|
platform=platform,
|
|
|
|
|
|
instance_type=config.instance_type,
|
|
|
|
|
|
region=config.region,
|
|
|
|
|
|
operating_system=config.operating_system,
|
|
|
|
|
|
disk_gb=config.disk_gb if hasattr(config, 'disk_gb') else 0
|
|
|
|
|
|
)
|
|
|
|
|
|
results.append({
|
|
|
|
|
|
"configuration": config.dict(),
|
|
|
|
|
|
"price": price
|
|
|
|
|
|
})
|
|
|
|
|
|
return results
|
|
|
|
|
|
except Exception as e:
|
|
|
|
|
|
raise HTTPException(status_code=500, detail=str(e))
|