Переглянути джерело

feat:环境配置热更新功能

ZhangHanJing 9 місяців тому
батько
коміт
4640f701c1

+ 4 - 0
src/main/java/cn/seecoder/paas/service/EnvironmentService.java

@@ -2,6 +2,7 @@ package cn.seecoder.paas.service;
 
 import cn.seecoder.paas.service.model.vo.EnvironmentVO;
 import cn.seecoder.paas.util.ServiceException;
+import org.springframework.transaction.annotation.Transactional;
 
 import java.util.List;
 import java.util.Map;
@@ -22,5 +23,8 @@ public interface EnvironmentService {
 
     EnvironmentVO restart(Integer id, String podName) throws ServiceException;
 
+    @Transactional
+    EnvironmentVO hotUpdateConfig(Integer id) throws ServiceException;
+
     void checkDeployStatus();
 }

+ 42 - 1
src/main/java/cn/seecoder/paas/service/impl/EnvironmentServiceImpl.java

@@ -29,7 +29,6 @@ import org.apache.commons.lang.StringUtils;
 import org.eclipse.jgit.api.Git;
 import org.eclipse.jgit.api.ResetCommand;
 import org.eclipse.jgit.api.errors.GitAPIException;
-import org.eclipse.jgit.lib.ObjectId;
 import org.eclipse.jgit.revwalk.RevCommit;
 import org.slf4j.Logger;
 import org.springframework.beans.BeanUtils;
@@ -279,6 +278,48 @@ public class EnvironmentServiceImpl implements EnvironmentService {
         return EnvironmentConverter.convertToVO(environmentDAO.save(result));
     }
 
+    @Transactional
+    @Override
+    public EnvironmentVO hotUpdateConfig(Integer id) throws ServiceException {
+        Environment env = environmentDAO.findById(id).orElse(null);
+        if (env == null) {
+            throw ServiceException.BAD_REQUEST;
+        }
+        if (env.getBuildStatus() == BuildStatus.BUILDING || env.getDeployStatus() == DeployStatus.DEPLOYING || env.getDeployStatus() == DeployStatus.RESTARTING) {
+            throw new ServiceException("101", "存在正在进行的构建或部署!");
+        }
+
+        Config config = configDAO.findByConfigBelongsAndAndEntityId(ConfigBelongsToType.ENVIRONMENT, id);
+        if (config == null) {
+            throw ServiceException.INVALID_DATA;
+        }
+
+        ConfigVO.ConfigContent cfg = ConfigConverter.convertToVO(config).getConfig();
+        String labelKey = ResourceLabel.RESOURCE.getCode();
+        String labelValue = ResourceLabel.RESOURCE.getGenerator().gen("environment", String.valueOf(env.getAppId()), String.valueOf(env.getId()));
+        String ns = applicationProperties.getDeploymentNamespace();
+        Map<String, String> labelsMap = Collections.singletonMap(labelKey, labelValue);
+
+        // 同步 ConfigMap 数据(仅基于挂载配置内容)
+        ConfigMap configMap = ConfigMap.builder().data(cfg.getMountsConfigMaps()).build();
+        configMap.setName(labelValue);
+        configMap.setNamespace(ns);
+        configMap.setLabel(labelKey, labelValue);
+        List<ConfigMap> exists = configMapApi.getByCondition(K8sObjectRequest.builder().namespace(ns).labels(labelsMap).build());
+        if (CollectionUtils.isEmpty(exists) || exists.size() != 1) {
+            configMapApi.create(configMap);
+        } else {
+            configMapApi.update(configMap);
+        }
+
+        // 删除相关 Pod,触发新 Pod 以挂载最新配置
+        deleteAllPods(id);
+
+        env.setDeployStatus(DeployStatus.RESTARTING);
+        env.setDeployStartTime(LocalDateTime.now());
+        return EnvironmentConverter.convertToVO(environmentDAO.save(env));
+    }
+
     private void deleteAllPods(Integer environmentId) throws ServiceException {
         // 查找环境
         Environment environment = environmentDAO.findById(environmentId).orElse(null);

+ 16 - 7
src/main/java/cn/seecoder/paas/web/controller/api/ConfigController.java

@@ -1,28 +1,37 @@
 package cn.seecoder.paas.web.controller.api;
 
 import cn.seecoder.paas.service.ConfigService;
+import cn.seecoder.paas.service.EnvironmentService;
 import cn.seecoder.paas.service.model.vo.ConfigVO;
 import cn.seecoder.paas.util.ServiceException;
+import cn.seecoder.paas.util.enums.ConfigBelongsToType;
 import cn.seecoder.paas.web.model.Response;
 import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.web.bind.annotation.PutMapping;
-import org.springframework.web.bind.annotation.RequestBody;
-import org.springframework.web.bind.annotation.RequestMapping;
-import org.springframework.web.bind.annotation.RestController;
+import org.springframework.web.bind.annotation.*;
 
 @RestController
 @RequestMapping("/api/config")
 public class ConfigController {
 
     private final ConfigService configService;
+    private final EnvironmentService environmentService;
 
     @Autowired
-    public ConfigController(ConfigService configService) {
+    public ConfigController(ConfigService configService, EnvironmentService environmentService) {
         this.configService = configService;
+        this.environmentService = environmentService;
     }
 
     @PutMapping("")
-    public Response update(@RequestBody ConfigVO configVO) throws ServiceException {
-        return Response.buildSuccess(configService.createOrUpdate(configVO));
+    public Response update(@RequestBody ConfigVO configVO,
+                          @RequestParam(required = false, defaultValue = "false") Boolean hotUpdate) throws ServiceException {
+        ConfigVO result = configService.createOrUpdate(configVO);
+
+        // 如果是环境配置且需要热更新
+        if (hotUpdate && result.getConfigBelongs() == ConfigBelongsToType.ENVIRONMENT) {
+            environmentService.hotUpdateConfig(result.getEntityId());
+        }
+
+        return Response.buildSuccess(result);
     }
 }

+ 1 - 1
src/main/java/cn/seecoder/paas/web/controller/api/EnvironmentController.java

@@ -62,7 +62,7 @@ public class EnvironmentController {
 
 
     @PostMapping("/restart")
-    public Response deploy(@RequestParam Integer id, @RequestParam String podName) throws ServiceException {
+    public Response restart(@RequestParam Integer id, @RequestParam String podName) throws ServiceException {
         return Response.buildSuccess(
                 environmentService.restart(id, podName));
     }