148 lines
4.5 KiB
Python
148 lines
4.5 KiB
Python
# 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}")
|