|
@@ -12,6 +12,12 @@ import com.css.simulation.resource.scheduler.util.MinioUtil;
|
|
import com.fasterxml.jackson.core.JsonProcessingException;
|
|
import com.fasterxml.jackson.core.JsonProcessingException;
|
|
import com.fasterxml.jackson.databind.JsonNode;
|
|
import com.fasterxml.jackson.databind.JsonNode;
|
|
import com.fasterxml.jackson.databind.ObjectMapper;
|
|
import com.fasterxml.jackson.databind.ObjectMapper;
|
|
|
|
+import io.kubernetes.client.openapi.ApiClient;
|
|
|
|
+import io.kubernetes.client.openapi.models.V1Container;
|
|
|
|
+import io.kubernetes.client.openapi.models.V1ObjectMeta;
|
|
|
|
+import io.kubernetes.client.openapi.models.V1Pod;
|
|
|
|
+import io.kubernetes.client.openapi.models.V1PodSpec;
|
|
|
|
+import io.kubernetes.client.util.Yaml;
|
|
import io.minio.MinioClient;
|
|
import io.minio.MinioClient;
|
|
import lombok.SneakyThrows;
|
|
import lombok.SneakyThrows;
|
|
import lombok.extern.slf4j.Slf4j;
|
|
import lombok.extern.slf4j.Slf4j;
|
|
@@ -24,6 +30,7 @@ import org.springframework.stereotype.Service;
|
|
import org.springframework.transaction.annotation.Transactional;
|
|
import org.springframework.transaction.annotation.Transactional;
|
|
|
|
|
|
import javax.annotation.Resource;
|
|
import javax.annotation.Resource;
|
|
|
|
+import java.io.File;
|
|
import java.io.InputStream;
|
|
import java.io.InputStream;
|
|
import java.util.*;
|
|
import java.util.*;
|
|
import java.util.stream.Collectors;
|
|
import java.util.stream.Collectors;
|
|
@@ -48,6 +55,8 @@ public class ProjectService {
|
|
String username;
|
|
String username;
|
|
@Value("${scheduler.host.password}")
|
|
@Value("${scheduler.host.password}")
|
|
String password;
|
|
String password;
|
|
|
|
+ @Value("${scheduler.kubernetes.namespace}")
|
|
|
|
+ String kubernetesNamespace;
|
|
@Resource
|
|
@Resource
|
|
StringRedisTemplate stringRedisTemplate;
|
|
StringRedisTemplate stringRedisTemplate;
|
|
@Resource
|
|
@Resource
|
|
@@ -59,10 +68,6 @@ public class ProjectService {
|
|
@Resource
|
|
@Resource
|
|
MinioClient minioClient;
|
|
MinioClient minioClient;
|
|
@Resource
|
|
@Resource
|
|
- ManualProjectMapper manualProjectMapper;
|
|
|
|
- @Resource
|
|
|
|
- AutoSubProjectMapper autoSubProjectMapper;
|
|
|
|
- @Resource
|
|
|
|
TaskMapper taskMapper;
|
|
TaskMapper taskMapper;
|
|
@Resource
|
|
@Resource
|
|
IndexTemplateMapper indexTemplateMapper;
|
|
IndexTemplateMapper indexTemplateMapper;
|
|
@@ -72,6 +77,8 @@ public class ProjectService {
|
|
SceneMapper sceneMapper;
|
|
SceneMapper sceneMapper;
|
|
@Resource
|
|
@Resource
|
|
AlgorithmMapper algorithmMapper;
|
|
AlgorithmMapper algorithmMapper;
|
|
|
|
+ @Resource
|
|
|
|
+ ApiClient apiClient;
|
|
|
|
|
|
|
|
|
|
// -------------------------------- Comment --------------------------------
|
|
// -------------------------------- Comment --------------------------------
|
|
@@ -85,11 +92,12 @@ public class ProjectService {
|
|
@Transactional
|
|
@Transactional
|
|
public void prepare(Map<String, Integer> nodeMap, ProjectMessageDTO projectMessageDTO, String clusterPrefix, String projectRunningKey) {
|
|
public void prepare(Map<String, Integer> nodeMap, ProjectMessageDTO projectMessageDTO, String clusterPrefix, String projectRunningKey) {
|
|
String projectId = projectMessageDTO.getProjectId();
|
|
String projectId = projectMessageDTO.getProjectId();
|
|
|
|
+ String projectType = projectMessageDTO.getType();
|
|
//1 将指定 node 的并行度减少
|
|
//1 将指定 node 的并行度减少
|
|
nodeMap.keySet().forEach(nodeName -> {
|
|
nodeMap.keySet().forEach(nodeName -> {
|
|
- long parallelismToUse = nodeMap.get(nodeName);
|
|
|
|
|
|
+ int parallelismToUse = nodeMap.get(nodeName);
|
|
String restParallelismKey = "node:" + nodeName + ":parallelism";
|
|
String restParallelismKey = "node:" + nodeName + ":parallelism";
|
|
- long restParallelism = Long.parseLong(Objects.requireNonNull(stringRedisTemplate.opsForValue().get(restParallelismKey)));// 剩余可用并行度
|
|
|
|
|
|
+ int restParallelism = Integer.parseInt(Objects.requireNonNull(stringRedisTemplate.opsForValue().get(restParallelismKey)));// 剩余可用并行度
|
|
stringRedisTemplate.opsForValue().set(restParallelismKey, (restParallelism - parallelismToUse) + "");
|
|
stringRedisTemplate.opsForValue().set(restParallelismKey, (restParallelism - parallelismToUse) + "");
|
|
});
|
|
});
|
|
//2 将 redis 中该项目旧的信息则直接删除(包括 waitingKey)
|
|
//2 将 redis 中该项目旧的信息则直接删除(包括 waitingKey)
|
|
@@ -102,12 +110,12 @@ public class ProjectService {
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
- //4 将项目状态修改为执行中
|
|
|
|
- if (DictConstants.PROJECT_TYPE_MANUAL.equals(projectType)) {
|
|
|
|
- manualProjectMapper.updateNowRunStateById(DictConstants.PROJECT_RUNNING, projectId); // 修改该 project 的状态为执行中,同时将已完成任务重置为 0 。
|
|
|
|
- } else if (DictConstants.PROJECT_TYPE_AUTO_SUB.equals(projectType)) {
|
|
|
|
- autoSubProjectMapper.updateNowRunStateById(DictConstants.PROJECT_RUNNING, projectId);
|
|
|
|
- }
|
|
|
|
|
|
+// //4 将项目状态修改为执行中(页面上已经改成了执行中,这里应该不需要)
|
|
|
|
+// if (DictConstants.PROJECT_TYPE_MANUAL.equals(projectType)) {
|
|
|
|
+// manualProjectMapper.updateNowRunStateById(DictConstants.PROJECT_RUNNING, projectId);
|
|
|
|
+// } else if (DictConstants.PROJECT_TYPE_AUTO_SUB.equals(projectType)) {
|
|
|
|
+// autoSubProjectMapper.updateNowRunStateById(DictConstants.PROJECT_RUNNING, projectId);
|
|
|
|
+// }
|
|
|
|
|
|
//5 将该 project 下所有旧的任务和指标得分删除。
|
|
//5 将该 project 下所有旧的任务和指标得分删除。
|
|
taskMapper.deleteByProject(projectId);
|
|
taskMapper.deleteByProject(projectId);
|
|
@@ -161,7 +169,7 @@ public class ProjectService {
|
|
* @param projectRunningPrefix
|
|
* @param projectRunningPrefix
|
|
* @param userId
|
|
* @param userId
|
|
* @param projectId
|
|
* @param projectId
|
|
- * @param maxSimulationTime
|
|
|
|
|
|
+ * @param videoTime 视频长度
|
|
* @param scenePOSet
|
|
* @param scenePOSet
|
|
* @param vehiclePO
|
|
* @param vehiclePO
|
|
* @param cameraPOList
|
|
* @param cameraPOList
|
|
@@ -374,43 +382,79 @@ public class ProjectService {
|
|
return dockerImage;
|
|
return dockerImage;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+// /**
|
|
|
|
+// * 运行
|
|
|
|
+// *
|
|
|
|
+// * @param projectId 项目id
|
|
|
|
+// * @param nodeMap 并行度
|
|
|
|
+// * @param algorithmDockerImage 算法镜像
|
|
|
|
+// */
|
|
|
|
+// @SneakyThrows
|
|
|
|
+// public void transferAndRunYaml(String projectId, Map<String, Integer> nodeMap, String algorithmDockerImage) {
|
|
|
|
+// String podTemplate = FileUtil.read(podTemplateYaml);
|
|
|
|
+// String replace0 = podTemplate.replace("vtd-container", "vtd-" + projectId);
|
|
|
|
+// String replace1 = replace0.replace("algorithm-container", "algorithm-" + projectId);
|
|
|
|
+// String replace2 = replace1.replace("algorithm-image", algorithmDockerImage);
|
|
|
|
+// String replace3 = replace2.replace("kafkaTopic", projectId); // 消息主题名称为 projectId
|
|
|
|
+// nodeMap.forEach((nodeName, parallelism) -> {
|
|
|
|
+// String tempPodNameSuffix = projectId + StringUtil.getRandomUUID();
|
|
|
|
+// String tempReplace4 = replace3.replace("pod-name", "project-" + tempPodNameSuffix); // pod 名称包括 projectId 和 随机字符串
|
|
|
|
+// String tempFinalYaml = tempReplace4.replace("node-name", nodeName); // 指定 pod 运行节点
|
|
|
|
+// log.info("ProjectConsumer--parseManualProject 在节点 " + nodeName + " 开始执行 pod:" + finalYaml);
|
|
|
|
+// String tempFinalYamlTargetPath = podYamlDirectory + tempPodNameSuffix;
|
|
|
|
+// FileUtil.writeStringToLocalFile(tempFinalYaml, tempFinalYamlTargetPath);
|
|
|
|
+// // 启动
|
|
|
|
+// KubernetesUtil.applyYaml(hostname, username, password, jobTemplateYamlPathTarget);
|
|
|
|
+// });
|
|
|
|
+// }
|
|
|
|
+
|
|
/**
|
|
/**
|
|
- * 运行
|
|
|
|
|
|
+ * 运行 pod
|
|
*
|
|
*
|
|
* @param projectId 项目id
|
|
* @param projectId 项目id
|
|
* @param nodeMap 并行度
|
|
* @param nodeMap 并行度
|
|
* @param algorithmDockerImage 算法镜像
|
|
* @param algorithmDockerImage 算法镜像
|
|
*/
|
|
*/
|
|
@SneakyThrows
|
|
@SneakyThrows
|
|
- public void transferAndRunYaml(String projectId, Map<String, Integer> nodeMap, String algorithmDockerImage) {
|
|
|
|
- String yamlSource = FileUtil.read(podTemplateYaml);
|
|
|
|
-// log.info("ProjectConsumer--transferYaml 模板文件为:" + yamlSource);
|
|
|
|
- String replace0 = yamlSource.replace("job-cloud-simulation", "project-" + projectId);
|
|
|
|
- String replace1 = replace0.replace("vtd-container", "vtd-" + projectId);
|
|
|
|
- String replace2 = replace1.replace("algorithm-container", "algorithm-" + projectId);
|
|
|
|
- String replace3 = replace2.replace("algorithm-image", algorithmDockerImage);
|
|
|
|
- String replace4 = replace3.replace("projectId", projectId);
|
|
|
|
- String replace5 = replace4.replace("completions-number", completions + "");
|
|
|
|
- String replace6 = replace5.replace("parallelism-number", parallelism + "");
|
|
|
|
- String replace7 = replace6.replace("apiVers1on", "apiVersion");
|
|
|
|
- String replace8 = replace7.replace("1atch/v1", "batch/v1");
|
|
|
|
- String finalYaml = replace8.replace("node-name", nodeName);
|
|
|
|
- log.info("ProjectConsumer--parseManualProject 在节点 " + nodeName + " 开始执行 pod:" + finalYaml);
|
|
|
|
- FileUtil.writeStringToLocalFile(finalYaml, jobTemplateYamlPathTarget);
|
|
|
|
- // 启动
|
|
|
|
- KubernetesUtil.applyYaml(hostname, username, password, jobTemplateYamlPathTarget);
|
|
|
|
|
|
+ public void createPod(String projectId, Map<String, Integer> nodeMap, String algorithmDockerImage) {
|
|
|
|
+ V1Pod v1Pod = (V1Pod) Yaml.load(new File(podTemplateYaml));
|
|
|
|
+ V1ObjectMeta metadata = v1Pod.getMetadata();
|
|
|
|
+ V1PodSpec spec = v1Pod.getSpec();
|
|
|
|
+ List<V1Container> containers = spec.getContainers();
|
|
|
|
+ containers.forEach(container -> {
|
|
|
|
+ if ("vtd-container".equals(container.getName())) {
|
|
|
|
+ container.setName("vtd-" + projectId);
|
|
|
|
+ List<String> commandList = container.getCommand();
|
|
|
|
+ for (int i = 0; i < commandList.size(); i++) {
|
|
|
|
+ if ("kafkaTopic".equals(commandList.get(i))) {
|
|
|
|
+ commandList.set(i, projectId);
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ if ("algorithm-container".equals(container.getName())) {
|
|
|
|
+ container.setName("vtd-" + projectId);
|
|
|
|
+ container.setImage(algorithmDockerImage);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ });
|
|
|
|
+
|
|
|
|
+ nodeMap.forEach((nodeName, parallelism) -> {
|
|
|
|
+ String tempPodName = "project-" + projectId + StringUtil.getRandomUUID();
|
|
|
|
+ metadata.setName(tempPodName); // pod 名称包括 projectId 和 随机字符串
|
|
|
|
+ spec.setNodeName(nodeName); // 指定 pod 运行节点
|
|
|
|
+ // 启动
|
|
|
|
+ KubernetesUtil.createPod(apiClient, kubernetesNamespace, v1Pod);
|
|
|
|
+ });
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+
|
|
@SneakyThrows
|
|
@SneakyThrows
|
|
- public void stopProject(String projectId, String type) {
|
|
|
|
|
|
+ public void stopProject(String projectId, String projectType) {
|
|
|
|
+ //2 根据 pod 前缀删除所有 pod
|
|
|
|
+ String prefix = "project-" + projectId;
|
|
|
|
+ KubernetesUtil.deleteJob(apiClient, kubernetesNamespace, prefix);
|
|
|
|
|
|
- // 需要判断项目在执行还是在等待
|
|
|
|
-// if (DictConstants.PROJECT_TYPE_MANUAL.equals(type)) {
|
|
|
|
-// manualProjectMapper.updateProjectState(projectId, DictConstants.PROJECT_TERMINATED, TimeUtil.getNowForMysql());
|
|
|
|
-// } else if (DictConstants.PROJECT_TYPE_AUTO_SUB.equals(type)) {
|
|
|
|
-// autoSubProjectMapper.updateNowRunStateAndFinishTimeById(DictConstants.PROJECT_TERMINATED, TimeUtil.getNowForMysql(), projectId);
|
|
|
|
-// }
|
|
|
|
-// KubernetesUtil.deleteJob(apiClient, "default", "project-" + projectId);
|
|
|
|
|
|
+ //3 删除所有 redis key
|
|
// PrefixTO redisPrefix = projectUtil.getRedisPrefixByProjectIdAndProjectType(projectId, type);
|
|
// PrefixTO redisPrefix = projectUtil.getRedisPrefixByProjectIdAndProjectType(projectId, type);
|
|
// Set<String> keys = stringRedisTemplate.keys(redisPrefix.getProjectRunningKey() + "*");
|
|
// Set<String> keys = stringRedisTemplate.keys(redisPrefix.getProjectRunningKey() + "*");
|
|
// if (CollectionUtil.isNotEmpty(keys)) {
|
|
// if (CollectionUtil.isNotEmpty(keys)) {
|