forked from wangqifan/calc
添加MySQL数据库配置,更新后端API以支持新的实例搜索功能,并修改前端调用接口以适应新API。
This commit is contained in:
parent
0c9cab7901
commit
d0b3ed2427
@ -1,3 +1,9 @@
|
||||
AWS_ACCESS_KEY_ID=AKIAVIOZF67K6HNCUJ5Y
|
||||
AWS_SECRET_ACCESS_KEY=BQjaaHNm5skCN/3k3r/uNdEG9xb49are+hv5fajK
|
||||
AWS_DEFAULT_REGION=us-east-1
|
||||
|
||||
# MySQL数据库配置
|
||||
MYSQL_HOST=47.76.209.7
|
||||
MYSQL_USER=aws_price
|
||||
MYSQL_PASSWORD=123456
|
||||
MYSQL_DATABASE=aws_price
|
||||
@ -5,6 +5,9 @@ WORKDIR /app
|
||||
# 安装系统依赖
|
||||
RUN apt-get update && apt-get install -y \
|
||||
curl \
|
||||
default-libmysqlclient-dev \
|
||||
gcc \
|
||||
pkg-config \
|
||||
&& rm -rf /var/lib/apt/lists/*
|
||||
|
||||
# 复制依赖文件
|
||||
|
||||
@ -1,8 +1,9 @@
|
||||
from fastapi import APIRouter, HTTPException
|
||||
from ..models.schemas import PriceRequest, PriceComparison, InstanceSearchRequest
|
||||
from ..models.schemas import PriceRequest, PriceComparison, InstanceSearchRequest, InstanceSearchRequestV2
|
||||
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
|
||||
from ..services.aws.pricing_v2 import search_instances_v2
|
||||
from typing import Dict, List, Any
|
||||
|
||||
router = APIRouter(prefix="/api")
|
||||
@ -100,6 +101,26 @@ async def search_instances(request: InstanceSearchRequest):
|
||||
print(f"搜索实例时出错: {str(e)}")
|
||||
raise HTTPException(status_code=500, detail=str(e))
|
||||
|
||||
@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))
|
||||
|
||||
@router.post("/compare-prices")
|
||||
async def compare_prices(comparison: PriceComparison):
|
||||
"""比较不同配置的价格"""
|
||||
|
||||
@ -20,3 +20,11 @@ class InstanceSearchRequest(BaseModel):
|
||||
region: Optional[str] = None
|
||||
operating_system: Optional[str] = "Linux"
|
||||
platform: Optional[str] = "aws" # 新增平台字段,默认为AWS
|
||||
|
||||
# 第二套价格计算API的数据模型
|
||||
class InstanceSearchRequestV2(BaseModel):
|
||||
cpu_cores: Optional[int] = None
|
||||
memory_gb: Optional[float] = None
|
||||
disk_gb: Optional[int] = None
|
||||
region: Optional[str] = None
|
||||
operating_system: Optional[str] = "Linux"
|
||||
136
backend/app/services/aws/pricing_v2.py
Normal file
136
backend/app/services/aws/pricing_v2.py
Normal file
@ -0,0 +1,136 @@
|
||||
import mysql.connector
|
||||
from mysql.connector import Error
|
||||
import os
|
||||
from dotenv import load_dotenv
|
||||
from typing import List, Dict, Any, Optional
|
||||
from ...core.config import AWS_REGION_NAMES_EN, AWS_PRICING_EBS
|
||||
|
||||
# 加载环境变量
|
||||
load_dotenv()
|
||||
|
||||
# 数据库连接配置
|
||||
DB_CONFIG = {
|
||||
"host": os.getenv("MYSQL_HOST", "localhost"),
|
||||
"user": os.getenv("MYSQL_USER", "root"),
|
||||
"password": os.getenv("MYSQL_PASSWORD", ""),
|
||||
"database": os.getenv("MYSQL_DATABASE", "aws_pricing")
|
||||
}
|
||||
|
||||
async def calculate_ebs_price(region: str, disk_gb: int) -> float:
|
||||
"""计算EBS存储价格"""
|
||||
# 从配置中获取价格,如果没有则使用默认价格
|
||||
if region in AWS_PRICING_EBS:
|
||||
price_dimensions = AWS_PRICING_EBS[region]
|
||||
else:
|
||||
price_dimensions = 0.1
|
||||
|
||||
return price_dimensions * disk_gb
|
||||
|
||||
async def search_instances_v2(
|
||||
region: Optional[str] = None,
|
||||
cpu_cores: Optional[int] = None,
|
||||
memory_gb: Optional[float] = None,
|
||||
disk_gb: Optional[int] = None,
|
||||
operating_system: str = "Linux"
|
||||
) -> List[Dict[str, Any]]:
|
||||
"""
|
||||
从MySQL数据库搜索符合条件的AWS实例
|
||||
"""
|
||||
try:
|
||||
# 获取区域的英文名称
|
||||
region_name = None
|
||||
if region:
|
||||
region_name = AWS_REGION_NAMES_EN.get(region)
|
||||
|
||||
# 连接到MySQL数据库
|
||||
conn = mysql.connector.connect(**DB_CONFIG)
|
||||
cursor = conn.cursor(dictionary=True)
|
||||
|
||||
# 构建SQL查询
|
||||
query = """
|
||||
SELECT
|
||||
id,
|
||||
locations,
|
||||
area_en,
|
||||
area_cn,
|
||||
instance_type,
|
||||
price,
|
||||
operating_system,
|
||||
vcpu,
|
||||
memory,
|
||||
updatetime
|
||||
FROM aws_price
|
||||
WHERE 1=1
|
||||
"""
|
||||
params = []
|
||||
|
||||
# 添加过滤条件
|
||||
if region_name:
|
||||
query += " AND area_en = %s"
|
||||
params.append(region_name)
|
||||
|
||||
if cpu_cores:
|
||||
query += " AND vcpu = %s"
|
||||
params.append(cpu_cores)
|
||||
|
||||
if memory_gb:
|
||||
query += " AND memory = %s"
|
||||
params.append(memory_gb)
|
||||
|
||||
if operating_system:
|
||||
query += " AND operating_system = %s"
|
||||
params.append(operating_system)
|
||||
|
||||
# 执行查询
|
||||
cursor.execute(query, params)
|
||||
results = cursor.fetchall()
|
||||
|
||||
# 处理结果
|
||||
instances = []
|
||||
for row in results:
|
||||
hourly_price = float(row['price'])
|
||||
monthly_price = hourly_price * 730 # 730小时/月
|
||||
|
||||
# 计算存储价格
|
||||
disk_monthly_price = 0
|
||||
if disk_gb and disk_gb > 0:
|
||||
# 从区域代码获取区域英文名称,反向查找
|
||||
region_code = None
|
||||
for code, name in AWS_REGION_NAMES_EN.items():
|
||||
if name == row['area_en']:
|
||||
region_code = code
|
||||
break
|
||||
|
||||
disk_monthly_price = await calculate_ebs_price(region_code, disk_gb) if region_code else 0
|
||||
|
||||
# 计算总价格
|
||||
total_monthly_price = monthly_price + disk_monthly_price
|
||||
|
||||
instances.append({
|
||||
"instance_type": row['instance_type'],
|
||||
"description": f"{row['vcpu']}核 {row['memory']}GB {row['instance_type']}",
|
||||
"cpu": row['vcpu'],
|
||||
"memory": row['memory'],
|
||||
"disk_gb": disk_gb if disk_gb else 0,
|
||||
"hourly_price": hourly_price,
|
||||
"monthly_price": monthly_price,
|
||||
"disk_monthly_price": disk_monthly_price,
|
||||
"total_monthly_price": total_monthly_price,
|
||||
"region": row['area_en'],
|
||||
"operating_system": row['operating_system']
|
||||
})
|
||||
|
||||
# 按总价格排序
|
||||
instances.sort(key=lambda x: x['total_monthly_price'])
|
||||
|
||||
# 关闭连接
|
||||
cursor.close()
|
||||
conn.close()
|
||||
|
||||
return instances
|
||||
except Error as e:
|
||||
print(f"MySQL数据库错误: {e}")
|
||||
raise Exception(f"数据库查询错误: {e}")
|
||||
except Exception as e:
|
||||
print(f"搜索实例时出错: {e}")
|
||||
raise Exception(f"搜索实例时出错: {e}")
|
||||
@ -7,3 +7,4 @@ pandas==2.1.3
|
||||
python-multipart==0.0.6
|
||||
requests==2.31.0
|
||||
httpx==0.25.2
|
||||
mysql-connector-python==8.2.0
|
||||
@ -63,7 +63,7 @@ const apiService = {
|
||||
// 搜索实例
|
||||
searchInstances: async (params) => {
|
||||
try {
|
||||
const response = await apiClient.post('/api/search-instances', params)
|
||||
const response = await apiClient.post('/api/search-instances-v2', params)
|
||||
return response.data
|
||||
} catch (error) {
|
||||
console.error('搜索实例失败:', error)
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user