SchedulingSimulator/task/cloud_task_submit.py

243 lines
9.8 KiB
Python
Raw 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.

import random
import string
from typing import Optional, Dict, Any, List
import requests
import json
from config.db_manager import load_config_from_db
from config.config import logger
from config.auth import get_token
class CloudTaskSubmitter:
"""云算任务提交器,提供完整的云算任务管理功能"""
def __init__(self):
"""初始化云算任务提交器"""
self.config = load_config_from_db()
self.token = None
def authenticate(self) -> bool:
"""获取认证Token"""
self.token = get_token()
return self.token is not None
def query_adapter_list(self) -> Optional[List[Dict]]:
"""查询适配器列表"""
if not self.token:
logger.error("未获取到认证Token请先调用authenticate()")
return None
headers = {'Content-Type': 'application/json', 'Authorization': f'Bearer {self.token}'}
# 检查配置中是否有adapter_list配置
if "adapter_list" not in self.config["api_config"]:
logger.error("API配置中缺少adapter_list配置")
return None
api_url = self.config["api_config"]["adapter_list"]["url"]
try:
response = requests.get(api_url, headers=headers)
response.raise_for_status()
result = response.json()
if result.get("code") == "OK" and "data" in result:
logger.info("查询适配器列表成功")
return result["data"]
else:
logger.error(f"查询适配器列表失败 | 响应: {result}")
return None
except requests.exceptions.RequestException as e:
logger.error(f"查询适配器列表时发生异常: {str(e)}", exc_info=True)
return None
def query_cluster_list(self, adapter_id: str) -> Optional[List[Dict]]:
"""查询集群列表"""
if not self.token:
logger.error("未获取到认证Token请先调用authenticate()")
return None
headers = {'Content-Type': 'application/json', 'Authorization': f'Bearer {self.token}'}
# 检查配置中是否有cluster_list配置
if "cluster_list" not in self.config["api_config"]:
logger.error("API配置中缺少cluster_list配置")
return None
api_url = self.config["api_config"]["cluster_list"]["url"].format(adapter_id=adapter_id)
try:
response = requests.get(api_url, headers=headers)
response.raise_for_status()
result = response.json()
if result.get("code") == "OK" and "data" in result:
logger.info("查询集群列表成功")
return result["data"]
else:
logger.error(f"查询集群列表失败 | 响应: {result}")
return None
except requests.exceptions.RequestException as e:
logger.error(f"查询集群列表时发生异常: {str(e)}", exc_info=True)
return None
def generate_random_string(self, length: int = 7) -> str:
"""生成随机字符串作为任务名称后缀"""
characters = string.ascii_lowercase # 只使用小写字母
random_string = ''.join(random.choice(characters) for _ in range(length))
return random_string
def create_task(self, cluster_id: str, task_name: str, replicas: int = 1, cpu: int = 1, memory: int = 1, port: int = 80, image: str = "nginx:latest", strategy: str = "replication") -> Optional[str]:
"""创建云算任务,返回 jobSetID 或 None"""
if not self.token:
logger.error("未获取到认证Token请先调用authenticate()")
return None
# 生成带随机后缀的任务名称
task_name = f"{task_name}-{self.generate_random_string()}"
# 根据策略创建不同的任务负载
if strategy == "replication":
# 使用标准Deployment方式创建任务
payload = {
"userID": 5,
"jobSetInfo": {
"jobs": [{
"localJobID": "1",
"name": task_name,
"type": "PCM_Container",
"clusterId": cluster_id,
"containerGroupName": task_name,
"image": image,
"cpu": str(cpu),
"memory": str(memory),
"port": port,
"capacity": replicas,
"mountPath": "/models"
}]
}
}
else:
# 其他策略可以在此扩展
payload = {
"userID": 5,
"jobSetInfo": {
"jobs": [{
"localJobID": "1",
"name": task_name,
"type": "PCM_Container",
"clusterId": cluster_id,
"containerGroupName": task_name,
"image": image,
"cpu": str(cpu),
"memory": str(memory),
"port": port,
"capacity": replicas,
"mountPath": "/models"
}]
}
}
headers = {
'Content-Type': 'application/json',
'Authorization': f'Bearer {self.token}'
}
# 尝试从配置中获取create_task的URL如果不存在则使用默认URL
if "submit_task" not in self.config["api_config"]:
# 尝试使用其他可能的键名
possible_keys = ["create_task", "task_create", "submit_task", "create"]
api_url = None
for key in possible_keys:
if key in self.config["api_config"]:
api_url = self.config["api_config"][key]["url"]
break
# 如果仍然没有找到使用默认URL
if api_url is None:
logger.warning("API配置中缺少create_task配置使用默认URL")
api_url = "https://jcc.jointcloud.net/jsm/jobSet/submit" # 默认URL
else:
api_url = self.config["api_config"]["submit_task"]["url"]
try:
response = requests.post(api_url, headers=headers, json=payload)
response.raise_for_status()
result = response.json()
# 提取并返回 jobSetID
if result.get("code") == "OK" and "data" in result:
job_set_id = result["data"].get("jobSetID")
logger.info(f"任务创建成功 | 任务名称: {task_name} | JobSetID: {job_set_id}")
return job_set_id
else:
logger.error(f"任务创建失败 | 响应: {result}")
return None
except requests.exceptions.RequestException as e:
logger.error(f"创建任务时发生异常: {str(e)}", exc_info=True)
return None
def submit_cloud_task(self, task_name: str, cluster_id: str, replicas: int = 1, cpu: int = 1, memory: int = 1, port: int = 80, image: str = "nginx:latest", strategy: str = "replication") -> Optional[str]:
"""提交云算任务的主方法"""
# 首先进行身份验证
if not self.authenticate():
logger.error("认证失败,无法提交任务")
return None
# 创建任务并返回JobSetID
return self.create_task(cluster_id, task_name, replicas, cpu, memory, port, image, strategy)
def get_available_clusters(self) -> List[Dict]:
"""获取所有可用的云集群"""
available_clusters = []
for cluster_id, cluster_info in self.config["cluster_resources"].items():
if cluster_info["cluster_type"] == "Cloud":
available_clusters.append({
"cluster_id": cluster_id,
"cluster_info": cluster_info
})
return available_clusters
def get_cluster_resources(self, cluster_id: str) -> Optional[Dict]:
"""获取指定集群的资源信息"""
return self.config["cluster_resources"].get(cluster_id)
def query_task_status(self, job_set_id: str) -> Optional[Dict]:
"""查询任务状态"""
if not self.token:
logger.error("未获取到认证Token请先调用authenticate()")
return None
headers = {'Authorization': f'Bearer {self.token}'}
# 检查配置中是否有task_status配置
if "task_status" not in self.config["api_config"]:
logger.error("API配置中缺少task_status配置")
return None
api_url = self.config["api_config"]["task_status"]["url"]
try:
params = {
"jobSetID": job_set_id,
"localJobID": 1
}
response = requests.get(api_url, headers=headers, params=params)
response.raise_for_status()
result = response.json()
if result.get("code") == "OK" and "data" in result:
logger.info(f"任务状态查询成功 | JobSetID: {job_set_id}")
return result["data"]
else:
logger.error(f"任务状态查询失败 | 响应: {result}")
return None
except requests.exceptions.RequestException as e:
logger.error(f"查询任务状态时发生异常: {str(e)}", exc_info=True)
return None
# 便捷函数,兼容原有接口
def submit_cloud_task(task_name: str, cluster_id: str, replicas: int = 1, cpu: int = 1, memory: int = 1, port: int = 80) -> Optional[str]:
"""便捷函数:提交云算任务"""
submitter = CloudTaskSubmitter()
return submitter.submit_cloud_task(task_name, cluster_id, replicas, cpu, memory, port)