forked from xiaohei/taiji-AI-PAD
更新agent域名
This commit is contained in:
@@ -183,6 +183,12 @@ class AgentStatusResult:
|
||||
conditions: Optional[List[Dict[str, Any]]] = None
|
||||
# Compatible with old fields
|
||||
template: Optional[str] = None
|
||||
# ========== 访问信息字段(从 access_info 解析) ==========
|
||||
external_ip: Optional[str] = None # 外网 IP 地址
|
||||
domain: Optional[str] = None # 域名
|
||||
domain_url: Optional[str] = None # 域名访问地址
|
||||
ip_url: Optional[str] = None # IP 访问地址
|
||||
# ======================================================
|
||||
|
||||
@property
|
||||
def is_healthy(self) -> bool:
|
||||
@@ -1024,6 +1030,16 @@ class AgentManagerClient:
|
||||
# New format: list
|
||||
endpoints = endpoints_data
|
||||
|
||||
# ========== 解析 access_info(域名和外网IP) ==========
|
||||
access_info = data.get("access_info", {})
|
||||
external_ip = access_info.get("external_ip")
|
||||
domain = access_info.get("domain")
|
||||
domain_url = access_info.get("domain_url")
|
||||
ip_url = access_info.get("ip_url")
|
||||
# 优先使用 access_info 中的推荐地址,否则使用旧的 access_url
|
||||
access_url = access_info.get("recommended") or data.get("access_url")
|
||||
# ======================================================
|
||||
|
||||
return AgentStatusResult(
|
||||
name=data["name"],
|
||||
namespace=data["namespace"],
|
||||
@@ -1035,13 +1051,18 @@ class AgentManagerClient:
|
||||
node_name=data.get("node_name"),
|
||||
labels=data.get("labels"),
|
||||
service_port=data.get("service_port"),
|
||||
access_url=data.get("access_url"),
|
||||
access_url=access_url,
|
||||
containers=containers,
|
||||
resources=data.get("resources"),
|
||||
endpoints=endpoints,
|
||||
conditions=data.get("conditions"),
|
||||
# Extract template from labels (for compatibility)
|
||||
template=data.get("labels", {}).get("template") if data.get("labels") else None
|
||||
template=data.get("labels", {}).get("template") if data.get("labels") else None,
|
||||
# ========== 新增:访问信息字段 ==========
|
||||
external_ip=external_ip,
|
||||
domain=domain,
|
||||
domain_url=domain_url,
|
||||
ip_url=ip_url,
|
||||
)
|
||||
|
||||
async def get_agent_metrics(self, agent_name: str) -> AgentMetricsResult:
|
||||
|
||||
@@ -1457,7 +1457,8 @@ async def deploy_agent(
|
||||
)
|
||||
db.add(agent)
|
||||
|
||||
# 记录计费
|
||||
# 记录计费(包含访问信息)
|
||||
access_info = result.access_info or {}
|
||||
billing_record = AgentBillingRecord(
|
||||
user_id=user_id,
|
||||
channel_id=channel_id,
|
||||
@@ -1470,6 +1471,13 @@ async def deploy_agent(
|
||||
cpu_used=quota.cpu_per_pod or "100m",
|
||||
memory_used=quota.memory_per_pod or "256Mi",
|
||||
replicas=req.instances,
|
||||
# ========== 保存访问信息 ==========
|
||||
external_ip=access_info.get("external_ip"),
|
||||
domain=access_info.get("domain"),
|
||||
domain_url=access_info.get("domain_url"),
|
||||
access_url=access_info.get("recommended") or access_info.get("domain_url"),
|
||||
service_port=result.service_port,
|
||||
namespace=result.namespace,
|
||||
)
|
||||
db.add(billing_record)
|
||||
|
||||
@@ -2400,7 +2408,8 @@ async def deploy_platform_agent(
|
||||
)
|
||||
db.add(agent)
|
||||
|
||||
# 记录计费
|
||||
# 记录计费(包含访问信息)
|
||||
access_info = result.access_info or {}
|
||||
billing_record = AgentBillingRecord(
|
||||
user_id=user_id,
|
||||
channel_id=channel_id,
|
||||
@@ -2413,6 +2422,13 @@ async def deploy_platform_agent(
|
||||
cpu_used=quota.cpu_per_pod or "100m",
|
||||
memory_used=quota.memory_per_pod or "256Mi",
|
||||
replicas=1,
|
||||
# ========== 保存访问信息 ==========
|
||||
external_ip=access_info.get("external_ip"),
|
||||
domain=access_info.get("domain"),
|
||||
domain_url=access_info.get("domain_url"),
|
||||
access_url=access_info.get("recommended") or access_info.get("domain_url"),
|
||||
service_port=result.service_port,
|
||||
namespace=result.namespace,
|
||||
)
|
||||
db.add(billing_record)
|
||||
|
||||
@@ -2425,6 +2441,8 @@ async def deploy_platform_agent(
|
||||
"status": result.status,
|
||||
"servicePort": result.service_port,
|
||||
"accessInfo": result.access_info,
|
||||
"domain": access_info.get("domain"),
|
||||
"domainUrl": access_info.get("domain_url"),
|
||||
"quotaRemaining": quota.pod_quota - quota.pod_used,
|
||||
},
|
||||
message=f"平台 Agent {req.agentType} 部署成功"
|
||||
@@ -2521,7 +2539,8 @@ async def use_platform_agent(
|
||||
# 更新配额使用量
|
||||
quota.pod_used += 1
|
||||
|
||||
# 记录计费
|
||||
# 记录计费(包含访问信息)
|
||||
access_info = result.access_info or {}
|
||||
billing_record = AgentBillingRecord(
|
||||
user_id=user_id,
|
||||
channel_id=channel_id,
|
||||
@@ -2534,6 +2553,13 @@ async def use_platform_agent(
|
||||
cpu_used=quota.cpu_per_pod or "100m",
|
||||
memory_used=quota.memory_per_pod or "256Mi",
|
||||
replicas=1,
|
||||
# ========== 保存访问信息 ==========
|
||||
external_ip=access_info.get("external_ip"),
|
||||
domain=access_info.get("domain"),
|
||||
domain_url=access_info.get("domain_url"),
|
||||
access_url=access_info.get("recommended") or access_info.get("domain_url"),
|
||||
service_port=result.service_port,
|
||||
namespace=result.namespace,
|
||||
)
|
||||
db.add(billing_record)
|
||||
|
||||
@@ -2546,6 +2572,8 @@ async def use_platform_agent(
|
||||
"status": result.status,
|
||||
"servicePort": result.service_port,
|
||||
"accessInfo": result.access_info,
|
||||
"domain": access_info.get("domain"),
|
||||
"domainUrl": access_info.get("domain_url"),
|
||||
"quotaRemaining": quota.pod_quota - quota.pod_used,
|
||||
},
|
||||
message=f"平台 Agent {req.agentType} 启动成功"
|
||||
@@ -3162,7 +3190,8 @@ async def create_custom_agent(
|
||||
quota.memory_used = memory_used + memory_request
|
||||
quota.agent_count = (quota.agent_count or 0) + 1
|
||||
|
||||
# 记录计费
|
||||
# 记录计费(包含访问信息)
|
||||
access_info = result.access_info or {}
|
||||
billing_record = AgentBillingRecord(
|
||||
user_id=user_id,
|
||||
channel_id=channel_id,
|
||||
@@ -3174,6 +3203,13 @@ async def create_custom_agent(
|
||||
cpu_used=req.cpuRequest,
|
||||
memory_used=req.memoryRequest,
|
||||
tools_used=req.tools if req.tools else [],
|
||||
# ========== 保存访问信息 ==========
|
||||
external_ip=access_info.get("external_ip"),
|
||||
domain=access_info.get("domain"),
|
||||
domain_url=access_info.get("domain_url"),
|
||||
access_url=access_info.get("recommended") or access_info.get("domain_url"),
|
||||
service_port=result.service_port,
|
||||
namespace=result.namespace,
|
||||
)
|
||||
db.add(billing_record)
|
||||
|
||||
@@ -3203,6 +3239,8 @@ async def create_custom_agent(
|
||||
"status": result.status,
|
||||
"servicePort": result.service_port,
|
||||
"accessInfo": result.access_info,
|
||||
"domain": access_info.get("domain"),
|
||||
"domainUrl": access_info.get("domain_url"),
|
||||
"modelInjected": model_name is not None,
|
||||
"quotaRemaining": {
|
||||
"cpu": remaining_cpu - cpu_request,
|
||||
@@ -3951,9 +3989,16 @@ async def get_user_agents_info(
|
||||
"status": "unknown",
|
||||
"healthStatus": "unknown",
|
||||
"podIp": None,
|
||||
"accessUrl": None,
|
||||
"servicePort": None,
|
||||
"namespace": "ai-agents",
|
||||
# ========== 访问信息(优先使用数据库存储的值) ==========
|
||||
"externalIp": record.external_ip,
|
||||
"domain": record.domain,
|
||||
"domainUrl": record.domain_url,
|
||||
"accessUrl": record.access_url,
|
||||
"servicePort": record.service_port,
|
||||
"namespace": record.namespace or "ai-agents",
|
||||
# ======================================================
|
||||
"hostIp": None,
|
||||
"nodeName": None,
|
||||
"cpu": record.cpu_used,
|
||||
"memory": record.memory_used,
|
||||
"replicas": record.replicas,
|
||||
@@ -3961,30 +4006,34 @@ async def get_user_agents_info(
|
||||
"runningSeconds": int((datetime.utcnow() - record.start_time).total_seconds()) if record.start_time else 0,
|
||||
}
|
||||
|
||||
# 从 Agent Manager 获取详细状态
|
||||
# 从 Agent Manager 获取详细状态(实时更新)
|
||||
if agent_manager_available and client:
|
||||
try:
|
||||
agent_status = await client.get_agent_status(record.agent_name)
|
||||
agent_info["status"] = agent_status.status
|
||||
agent_info["healthStatus"] = agent_status.health_status
|
||||
agent_info["podIp"] = agent_status.pod_ip
|
||||
agent_info["accessUrl"] = agent_status.access_url
|
||||
agent_info["servicePort"] = agent_status.service_port
|
||||
agent_info["namespace"] = agent_status.namespace
|
||||
agent_info["hostIp"] = agent_status.host_ip
|
||||
agent_info["nodeName"] = agent_status.node_name
|
||||
|
||||
# 端点信息
|
||||
# ========== 更新访问信息(如果 Agent Manager 返回了最新值) ==========
|
||||
if agent_status.external_ip:
|
||||
agent_info["externalIp"] = agent_status.external_ip
|
||||
if agent_status.domain:
|
||||
agent_info["domain"] = agent_status.domain
|
||||
if agent_status.domain_url:
|
||||
agent_info["domainUrl"] = agent_status.domain_url
|
||||
if agent_status.access_url:
|
||||
agent_info["accessUrl"] = agent_status.access_url
|
||||
if agent_status.service_port:
|
||||
agent_info["servicePort"] = agent_status.service_port
|
||||
if agent_status.namespace:
|
||||
agent_info["namespace"] = agent_status.namespace
|
||||
# ==================================================================
|
||||
|
||||
# 端点信息(字符串列表,如 ["http://10.244.1.100:8080"])
|
||||
if agent_status.endpoints:
|
||||
agent_info["endpoints"] = [
|
||||
{
|
||||
"name": ep.name,
|
||||
"port": ep.port,
|
||||
"protocol": ep.protocol,
|
||||
"targetPort": ep.target_port,
|
||||
}
|
||||
for ep in agent_status.endpoints
|
||||
]
|
||||
agent_info["endpoints"] = agent_status.endpoints
|
||||
except Exception as e:
|
||||
logger.warning(f"获取 Agent {record.agent_name} 状态失败: {e}")
|
||||
|
||||
|
||||
@@ -0,0 +1,61 @@
|
||||
-- Migration 016: Add Agent Access Info Fields
|
||||
-- Description: 为 agent_billing_records 表添加访问信息字段(域名、外网IP等)
|
||||
-- Date: 2026-01-14
|
||||
|
||||
-- ========== 添加访问信息字段 ==========
|
||||
|
||||
-- 外网 IP 地址
|
||||
ALTER TABLE agent_billing_records
|
||||
ADD COLUMN IF NOT EXISTS external_ip VARCHAR(45);
|
||||
|
||||
-- 域名
|
||||
ALTER TABLE agent_billing_records
|
||||
ADD COLUMN IF NOT EXISTS domain VARCHAR(255);
|
||||
|
||||
-- 域名访问地址
|
||||
ALTER TABLE agent_billing_records
|
||||
ADD COLUMN IF NOT EXISTS domain_url VARCHAR(500);
|
||||
|
||||
-- 推荐访问地址
|
||||
ALTER TABLE agent_billing_records
|
||||
ADD COLUMN IF NOT EXISTS access_url VARCHAR(500);
|
||||
|
||||
-- 服务端口
|
||||
ALTER TABLE agent_billing_records
|
||||
ADD COLUMN IF NOT EXISTS service_port INTEGER;
|
||||
|
||||
-- K8s 命名空间
|
||||
ALTER TABLE agent_billing_records
|
||||
ADD COLUMN IF NOT EXISTS namespace VARCHAR(100);
|
||||
|
||||
-- ========== 添加索引 ==========
|
||||
|
||||
-- 按域名查询索引(用于根据域名查找 Agent)
|
||||
CREATE INDEX IF NOT EXISTS idx_agent_billing_domain
|
||||
ON agent_billing_records(domain);
|
||||
|
||||
-- ========== 添加注释 ==========
|
||||
|
||||
COMMENT ON COLUMN agent_billing_records.external_ip IS '外网 IP 地址(Agent Manager 分配)';
|
||||
COMMENT ON COLUMN agent_billing_records.domain IS '域名(如 my-agent.taijiagent.com)';
|
||||
COMMENT ON COLUMN agent_billing_records.domain_url IS '域名访问地址(如 http://my-agent.taijiagent.com)';
|
||||
COMMENT ON COLUMN agent_billing_records.access_url IS '推荐访问地址(域名优先)';
|
||||
COMMENT ON COLUMN agent_billing_records.service_port IS '服务端口';
|
||||
COMMENT ON COLUMN agent_billing_records.namespace IS 'Kubernetes 命名空间';
|
||||
|
||||
-- ========== 验证迁移 ==========
|
||||
|
||||
-- 检查字段是否添加成功
|
||||
DO $$
|
||||
BEGIN
|
||||
IF EXISTS (
|
||||
SELECT 1 FROM information_schema.columns
|
||||
WHERE table_name = 'agent_billing_records'
|
||||
AND column_name = 'domain'
|
||||
) THEN
|
||||
RAISE NOTICE 'Migration 016 completed successfully: domain field added';
|
||||
ELSE
|
||||
RAISE EXCEPTION 'Migration 016 failed: domain field not found';
|
||||
END IF;
|
||||
END $$;
|
||||
|
||||
@@ -0,0 +1,144 @@
|
||||
#!/usr/bin/env python3
|
||||
"""
|
||||
Migration 016: Add Agent Access Info Fields
|
||||
|
||||
为 agent_billing_records 表添加访问信息字段(域名、外网IP等)
|
||||
|
||||
Usage:
|
||||
python migrations/run_016_migration.py
|
||||
"""
|
||||
|
||||
import asyncio
|
||||
import os
|
||||
import sys
|
||||
|
||||
# 添加项目根目录到 Python 路径
|
||||
sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
|
||||
|
||||
from sqlalchemy import text
|
||||
from database import engine
|
||||
|
||||
|
||||
async def run_migration():
|
||||
"""运行迁移"""
|
||||
print("=" * 60)
|
||||
print("Migration 016: Add Agent Access Info Fields")
|
||||
print("=" * 60)
|
||||
|
||||
# 读取 SQL 文件
|
||||
sql_file = os.path.join(os.path.dirname(__file__), "016_add_agent_access_info_fields.sql")
|
||||
with open(sql_file, "r", encoding="utf-8") as f:
|
||||
sql_content = f.read()
|
||||
|
||||
# 分割 SQL 语句
|
||||
statements = []
|
||||
current_stmt = []
|
||||
in_do_block = False
|
||||
|
||||
for line in sql_content.split("\n"):
|
||||
line_stripped = line.strip()
|
||||
|
||||
# 跳过注释和空行(但保留 DO 块中的内容)
|
||||
if not in_do_block:
|
||||
if line_stripped.startswith("--") or not line_stripped:
|
||||
continue
|
||||
|
||||
# 检测 DO 块开始
|
||||
if line_stripped.upper().startswith("DO $$"):
|
||||
in_do_block = True
|
||||
current_stmt.append(line)
|
||||
continue
|
||||
|
||||
# 检测 DO 块结束
|
||||
if in_do_block and line_stripped == "END $$;":
|
||||
current_stmt.append(line)
|
||||
statements.append("\n".join(current_stmt))
|
||||
current_stmt = []
|
||||
in_do_block = False
|
||||
continue
|
||||
|
||||
if in_do_block:
|
||||
current_stmt.append(line)
|
||||
continue
|
||||
|
||||
# 普通语句处理
|
||||
current_stmt.append(line)
|
||||
if line_stripped.endswith(";"):
|
||||
stmt = "\n".join(current_stmt)
|
||||
if stmt.strip():
|
||||
statements.append(stmt)
|
||||
current_stmt = []
|
||||
|
||||
# 执行迁移
|
||||
async with engine.begin() as conn:
|
||||
for i, stmt in enumerate(statements, 1):
|
||||
try:
|
||||
# 打印语句摘要
|
||||
stmt_preview = stmt.strip()[:80].replace("\n", " ")
|
||||
if len(stmt.strip()) > 80:
|
||||
stmt_preview += "..."
|
||||
print(f"\n[{i}/{len(statements)}] Executing: {stmt_preview}")
|
||||
|
||||
await conn.execute(text(stmt))
|
||||
print(f" ✓ Success")
|
||||
except Exception as e:
|
||||
error_msg = str(e)
|
||||
# 忽略 "column already exists" 错误
|
||||
if "already exists" in error_msg.lower():
|
||||
print(f" ⚠ Skipped (already exists)")
|
||||
else:
|
||||
print(f" ✗ Error: {error_msg}")
|
||||
raise
|
||||
|
||||
print("\n" + "=" * 60)
|
||||
print("Migration 016 completed successfully!")
|
||||
print("=" * 60)
|
||||
|
||||
|
||||
async def verify_migration():
|
||||
"""验证迁移结果"""
|
||||
print("\nVerifying migration...")
|
||||
|
||||
async with engine.begin() as conn:
|
||||
# 检查新字段是否存在
|
||||
result = await conn.execute(text("""
|
||||
SELECT column_name, data_type, character_maximum_length
|
||||
FROM information_schema.columns
|
||||
WHERE table_name = 'agent_billing_records'
|
||||
AND column_name IN ('external_ip', 'domain', 'domain_url', 'access_url', 'service_port', 'namespace')
|
||||
ORDER BY column_name
|
||||
"""))
|
||||
columns = result.fetchall()
|
||||
|
||||
print(f"\nNew columns in agent_billing_records table:")
|
||||
print("-" * 50)
|
||||
for col in columns:
|
||||
col_name, data_type, max_len = col
|
||||
type_info = f"{data_type}({max_len})" if max_len else data_type
|
||||
print(f" ✓ {col_name}: {type_info}")
|
||||
|
||||
expected_columns = {'external_ip', 'domain', 'domain_url', 'access_url', 'service_port', 'namespace'}
|
||||
found_columns = {col[0] for col in columns}
|
||||
|
||||
if found_columns == expected_columns:
|
||||
print(f"\n✓ All {len(expected_columns)} columns verified successfully!")
|
||||
else:
|
||||
missing = expected_columns - found_columns
|
||||
if missing:
|
||||
print(f"\n✗ Missing columns: {missing}")
|
||||
return False
|
||||
|
||||
return True
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
try:
|
||||
asyncio.run(run_migration())
|
||||
asyncio.run(verify_migration())
|
||||
except KeyboardInterrupt:
|
||||
print("\nMigration cancelled.")
|
||||
sys.exit(1)
|
||||
except Exception as e:
|
||||
print(f"\nMigration failed: {e}")
|
||||
sys.exit(1)
|
||||
|
||||
@@ -1198,6 +1198,15 @@ class AgentBillingRecord(BaseModel, Base):
|
||||
tools_used = Column(JSON, nullable=True) # 使用的工具列表
|
||||
request_id = Column(String(100), nullable=True) # 请求 ID
|
||||
|
||||
# ========== 访问信息字段(Agent Manager 返回) ==========
|
||||
external_ip = Column(String(45), nullable=True) # 外网 IP 地址
|
||||
domain = Column(String(255), nullable=True) # 域名
|
||||
domain_url = Column(String(500), nullable=True) # 域名访问地址
|
||||
access_url = Column(String(500), nullable=True) # 推荐访问地址
|
||||
service_port = Column(Integer, nullable=True) # 服务端口
|
||||
namespace = Column(String(100), nullable=True) # K8s 命名空间
|
||||
# ======================================================
|
||||
|
||||
# 关联关系
|
||||
user = relationship("User")
|
||||
channel = relationship("Channel")
|
||||
@@ -1207,6 +1216,7 @@ class AgentBillingRecord(BaseModel, Base):
|
||||
Index("idx_agent_billing_channel", channel_id),
|
||||
Index("idx_agent_billing_period", period_start, period_end),
|
||||
Index("idx_agent_billing_type", agent_type),
|
||||
Index("idx_agent_billing_domain", domain), # 按域名查询索引
|
||||
)
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user