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_ACCESS_KEY_ID=AKIAVIOZF67K6HNCUJ5Y
|
||||||
AWS_SECRET_ACCESS_KEY=BQjaaHNm5skCN/3k3r/uNdEG9xb49are+hv5fajK
|
AWS_SECRET_ACCESS_KEY=BQjaaHNm5skCN/3k3r/uNdEG9xb49are+hv5fajK
|
||||||
AWS_DEFAULT_REGION=us-east-1
|
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 \
|
RUN apt-get update && apt-get install -y \
|
||||||
curl \
|
curl \
|
||||||
|
default-libmysqlclient-dev \
|
||||||
|
gcc \
|
||||||
|
pkg-config \
|
||||||
&& rm -rf /var/lib/apt/lists/*
|
&& rm -rf /var/lib/apt/lists/*
|
||||||
|
|
||||||
# 复制依赖文件
|
# 复制依赖文件
|
||||||
|
|||||||
@ -1,8 +1,9 @@
|
|||||||
from fastapi import APIRouter, HTTPException
|
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.config import AWS_REGION_NAMES, AZURE_REGION_NAMES, ALIYUN_REGION_NAMES
|
||||||
from ..core.instance_data import get_instance_info
|
from ..core.instance_data import get_instance_info
|
||||||
from ..services import calculate_price
|
from ..services import calculate_price
|
||||||
|
from ..services.aws.pricing_v2 import search_instances_v2
|
||||||
from typing import Dict, List, Any
|
from typing import Dict, List, Any
|
||||||
|
|
||||||
router = APIRouter(prefix="/api")
|
router = APIRouter(prefix="/api")
|
||||||
@ -100,6 +101,26 @@ async def search_instances(request: InstanceSearchRequest):
|
|||||||
print(f"搜索实例时出错: {str(e)}")
|
print(f"搜索实例时出错: {str(e)}")
|
||||||
raise HTTPException(status_code=500, detail=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")
|
@router.post("/compare-prices")
|
||||||
async def compare_prices(comparison: PriceComparison):
|
async def compare_prices(comparison: PriceComparison):
|
||||||
"""比较不同配置的价格"""
|
"""比较不同配置的价格"""
|
||||||
|
|||||||
@ -19,4 +19,12 @@ class InstanceSearchRequest(BaseModel):
|
|||||||
disk_gb: Optional[int] = None
|
disk_gb: Optional[int] = None
|
||||||
region: Optional[str] = None
|
region: Optional[str] = None
|
||||||
operating_system: Optional[str] = "Linux"
|
operating_system: Optional[str] = "Linux"
|
||||||
platform: Optional[str] = "aws" # 新增平台字段,默认为AWS
|
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}")
|
||||||
@ -6,4 +6,5 @@ pydantic==2.4.2
|
|||||||
pandas==2.1.3
|
pandas==2.1.3
|
||||||
python-multipart==0.0.6
|
python-multipart==0.0.6
|
||||||
requests==2.31.0
|
requests==2.31.0
|
||||||
httpx==0.25.2
|
httpx==0.25.2
|
||||||
|
mysql-connector-python==8.2.0
|
||||||
@ -63,7 +63,7 @@ const apiService = {
|
|||||||
// 搜索实例
|
// 搜索实例
|
||||||
searchInstances: async (params) => {
|
searchInstances: async (params) => {
|
||||||
try {
|
try {
|
||||||
const response = await apiClient.post('/api/search-instances', params)
|
const response = await apiClient.post('/api/search-instances-v2', params)
|
||||||
return response.data
|
return response.data
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('搜索实例失败:', error)
|
console.error('搜索实例失败:', error)
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user