2025-12-04 10:09:04 +08:00

148 lines
4.5 KiB
Python
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# api/ecs.py
from typing import List, Dict
from fastapi import APIRouter, HTTPException, Query
from pydantic import BaseModel, Field
from services.ecs_service import (
create_ecs_instances,
get_account_credit,
list_custom_and_shared_images,
list_vpcs_and_vswitches,
)
from utils.validators import (
is_valid_customer_name,
is_valid_resource_name,
is_valid_region,
)
router = APIRouter()
class ImageItem(BaseModel):
ImageId: str = Field(..., description="镜像 ID")
ImageName: str = Field(..., description="镜像名称")
class CreateInstanceRequest(BaseModel):
customer: str
resource_name: str
region: str
access_key: str
secret_key: str
count: int = 1
account_uid: str | None = None
image_id: str
zone_id: str | None = None
vswitch_id: str | None = None
class InstanceResponse(BaseModel):
ip: str
name: str
region: str
instance_id: str
user: str
password: str
created: str
email: str | None = None
ram_user: str
ram_password: str
image_id: str
class CreateInstancesResponse(BaseModel):
instances: list[InstanceResponse]
@router.get(
"/images",
response_model=List[ImageItem],
summary="查询自建镜像和共享给您的镜像列表",
)
def get_images(
access_key: str = Query(..., description="用户的 AccessKey"),
secret_key: str = Query(..., description="用户的 SecretKey"),
ecs_region: str = Query("ap-southeast-1", description="ECS 实例所在区域,仅做展示"),
) -> List[ImageItem]:
"""
返回两类镜像:
- owner_alias='self' 用户自建镜像
- owner_alias='others' 共享给用户的镜像
"""
try:
images = list_custom_and_shared_images(
access_key, secret_key, ecs_region)
return images
except Exception as e:
raise HTTPException(status_code=500, detail=f"拉取镜像失败:{e}")
@router.get("/balance")
def balance(
access_key: str = Query(..., description="用户的 AccessKey"),
secret_key: str = Query(..., description="用户的 SecretKey"),
ecs_region: str = Query("ap-southeast-1", description="ECS 实例所在区域,仅做展示"),
) -> Dict[str, float]:
"""
查询账户可用余额AvailableAmount接口名不变仍叫 /balance
"""
try:
# 调用 get_account_credit 方法查询可用余额
available_amount = get_account_credit(
access_key, secret_key, ecs_region)
# 返回查询结果,确保返回 float 类型
return {"available_amount": float(available_amount)}
except RuntimeError as re:
# 捕获具体的运行时错误并返回 400 状态码
raise HTTPException(status_code=400, detail=f"请求失败:{str(re)}")
except Exception as e:
# 捕获所有其他异常并返回 500 状态码
raise HTTPException(status_code=500, detail=f"查询可用余额失败:{str(e)}")
@router.post("/create", response_model=CreateInstancesResponse)
def create_instances(data: CreateInstanceRequest):
if not is_valid_customer_name(data.customer):
raise HTTPException(status_code=400, detail="客户名称不能为空")
if not is_valid_resource_name(data.resource_name):
raise HTTPException(status_code=400, detail="资源账号名称非法")
if not is_valid_region(data.region):
raise HTTPException(status_code=400, detail="区域 ID 格式不合法")
try:
results = create_ecs_instances(
customer=data.customer,
resource_name=data.resource_name,
region=data.region,
access_key=data.access_key,
secret_key=data.secret_key,
count=data.count,
account_uid=data.account_uid,
image_id=data.image_id,
zone_id=data.zone_id,
vswitch_id=data.vswitch_id,
)
return CreateInstancesResponse(instances=results)
except Exception as e:
raise HTTPException(status_code=500, detail=str(e))
@router.get("/vswitches")
def list_vswitches(
access_key: str = Query(..., description="AccessKey"),
secret_key: str = Query(..., description="SecretKey"),
ecs_region: str = Query(..., description="地域 ID"),
):
"""
拉取指定地域下的 VPC 与 VSwitch 列表,供前端选择。
"""
try:
data = list_vpcs_and_vswitches(access_key, secret_key, ecs_region)
return data
except Exception as e:
raise HTTPException(status_code=500, detail=f"拉取 VPC/VSwitch 失败:{e}")