فهرست منبع

feat: seperate build and deploy parts

hushuyu 9 ماه پیش
والد
کامیت
9425bf2e14

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

@@ -18,6 +18,8 @@ public interface EnvironmentService {
 
 
     EnvironmentVO deploy(Integer id, Boolean useCache) throws ServiceException;
     EnvironmentVO deploy(Integer id, Boolean useCache) throws ServiceException;
 
 
+    EnvironmentVO build(Integer id) throws ServiceException;
+
     Map<String,String> getLog(Integer id, String podName) throws ServiceException;
     Map<String,String> getLog(Integer id, String podName) throws ServiceException;
 
 
     EnvironmentVO restart(Integer id, String podName) throws ServiceException;
     EnvironmentVO restart(Integer id, String podName) throws ServiceException;

+ 83 - 86
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.Git;
 import org.eclipse.jgit.api.ResetCommand;
 import org.eclipse.jgit.api.ResetCommand;
 import org.eclipse.jgit.api.errors.GitAPIException;
 import org.eclipse.jgit.api.errors.GitAPIException;
-import org.eclipse.jgit.lib.ObjectId;
 import org.eclipse.jgit.revwalk.RevCommit;
 import org.eclipse.jgit.revwalk.RevCommit;
 import org.slf4j.Logger;
 import org.slf4j.Logger;
 import org.springframework.beans.BeanUtils;
 import org.springframework.beans.BeanUtils;
@@ -214,12 +213,38 @@ public class EnvironmentServiceImpl implements EnvironmentService {
     @Override
     @Override
     @Transactional
     @Transactional
     public EnvironmentVO deploy(Integer id, Boolean useCache) throws ServiceException {
     public EnvironmentVO deploy(Integer id, Boolean useCache) throws ServiceException {
+        Environment result = getEnvironment(id);
+        TransactionSynchronizationManager.registerSynchronization(new TransactionSynchronizationAdapter() {
+            @Override
+            public void afterCommit() {
+                super.afterCommit();
+                asyncWrapper.asyncInvoke(() -> buildAndDeploy(id, useCache));
+            }
+        });
+        return EnvironmentConverter.convertToVO(environmentDAO.save(result));
+    }
+
+    @Override
+    @Transactional
+    public EnvironmentVO build(Integer id) throws ServiceException {
+        Environment result = getEnvironment(id);
+        TransactionSynchronizationManager.registerSynchronization(new TransactionSynchronizationAdapter() {
+            @Override
+            public void afterCommit() {
+                super.afterCommit();
+                asyncWrapper.asyncInvoke(() -> buildImage(id));
+            }
+        });
+        return EnvironmentConverter.convertToVO(environmentDAO.save(result));
+    }
+
+    private Environment getEnvironment(Integer id) throws ServiceException {
         Environment result = environmentDAO.findById(id).orElse(null);
         Environment result = environmentDAO.findById(id).orElse(null);
         if (result == null) {
         if (result == null) {
             throw ServiceException.BAD_REQUEST;
             throw ServiceException.BAD_REQUEST;
         }
         }
-        if (result.getBuildStatus() == BuildStatus.BUILDING || result.getDeployStatus() == DeployStatus.DEPLOYING || result.getDeployStatus() == DeployStatus.RESTARTING) {
-            throw new ServiceException("101", "存在正在进行的构建或部署!");
+        if (result.getBuildStatus() == BuildStatus.BUILDING) {
+            throw new ServiceException("101", "存在正在进行的构建!");
         }
         }
         Config config = configDAO.findByConfigBelongsAndAndEntityId(ConfigBelongsToType.ENVIRONMENT, id);
         Config config = configDAO.findByConfigBelongsAndAndEntityId(ConfigBelongsToType.ENVIRONMENT, id);
         if (config == null) {
         if (config == null) {
@@ -228,19 +253,11 @@ public class EnvironmentServiceImpl implements EnvironmentService {
         result.setBuildOutput("");
         result.setBuildOutput("");
         result.setBuildStatus(BuildStatus.BUILDING);
         result.setBuildStatus(BuildStatus.BUILDING);
         result.setBuildStartTime(LocalDateTime.now());
         result.setBuildStartTime(LocalDateTime.now());
-        result.setDeployStatus(DeployStatus.NOT_STARTED);
-        TransactionSynchronizationManager.registerSynchronization(new TransactionSynchronizationAdapter() {
-            @Override
-            public void afterCommit() {
-                super.afterCommit();
-                asyncWrapper.asyncInvoke(() -> buildAsync(id,useCache));
-            }
-        });
-        return EnvironmentConverter.convertToVO(environmentDAO.save(result));
+        return result;
     }
     }
 
 
     @Override
     @Override
-    public Map<String,String> getLog(Integer id, String podName) throws ServiceException {
+    public Map<String, String> getLog(Integer id, String podName) throws ServiceException {
         Environment result = environmentDAO.findById(id).orElse(null);
         Environment result = environmentDAO.findById(id).orElse(null);
         if (result == null) {
         if (result == null) {
             throw ServiceException.BAD_REQUEST;
             throw ServiceException.BAD_REQUEST;
@@ -345,10 +362,10 @@ public class EnvironmentServiceImpl implements EnvironmentService {
                     if (!CollectionUtils.isEmpty(pods)) {
                     if (!CollectionUtils.isEmpty(pods)) {
                         V1PodStatus status = pods.get(0).getPodStatus();
                         V1PodStatus status = pods.get(0).getPodStatus();
                         List<V1PodCondition> conditions = status.getConditions() == null ? Collections.emptyList() : status.getConditions();
                         List<V1PodCondition> conditions = status.getConditions() == null ? Collections.emptyList() : status.getConditions();
-                        Collections.sort(conditions, Comparator.comparingLong(c -> ((V1PodCondition)c).getLastTransitionTime().getMillis()).reversed());
+                        Collections.sort(conditions, Comparator.comparingLong(c -> ((V1PodCondition) c).getLastTransitionTime().getMillis()).reversed());
                         String deployOutput = "Type\tStatus\tMessage\tReason\tTime\n";
                         String deployOutput = "Type\tStatus\tMessage\tReason\tTime\n";
                         deployOutput += conditions.stream().map(condition -> {
                         deployOutput += conditions.stream().map(condition -> {
-                            return condition.getType() + "\t" + condition.getStatus() + "\t"  + condition.getMessage() + "\t" + condition.getReason() + "\t" + condition.getLastTransitionTime().toString();
+                            return condition.getType() + "\t" + condition.getStatus() + "\t" + condition.getMessage() + "\t" + condition.getReason() + "\t" + condition.getLastTransitionTime().toString();
                         }).collect(Collectors.joining("\n"));
                         }).collect(Collectors.joining("\n"));
                         switch (status.getPhase()) {
                         switch (status.getPhase()) {
                             case "Succeeded":
                             case "Succeeded":
@@ -376,8 +393,24 @@ public class EnvironmentServiceImpl implements EnvironmentService {
         }
         }
     }
     }
 
 
-    void buildAsync(Integer id, Boolean useCache) {
+    private void buildImage(Integer id) {
         Environment result = environmentDAO.findById(id).get();
         Environment result = environmentDAO.findById(id).get();
+        try {
+            String labelValue = ResourceLabel.RESOURCE.getGenerator().gen("environment", String.valueOf(result.getAppId()), String.valueOf(result.getId()));
+            // 构建镜像阶段
+            buildImageHelper(result, labelValue);
+        } catch (Exception e) {
+            result.setBuildStatus(BuildStatus.FAIL);
+            result.setBuildOutput(e.getLocalizedMessage());
+            environmentDAO.save(result);
+            LoggerUtil.error(logger, e, "构建镜像失败!");
+        }
+    }
+
+    private void deployToPod(Integer id) {
+        Environment result = environmentDAO.findById(id).get();
+        result.setDeployStatus(DeployStatus.DEPLOYING);
+        environmentDAO.save(result);
         try {
         try {
             Config config = configDAO.findByConfigBelongsAndAndEntityId(ConfigBelongsToType.ENVIRONMENT, id);
             Config config = configDAO.findByConfigBelongsAndAndEntityId(ConfigBelongsToType.ENVIRONMENT, id);
             Application application = applicationDAO.findById(result.getAppId()).get();
             Application application = applicationDAO.findById(result.getAppId()).get();
@@ -387,13 +420,8 @@ public class EnvironmentServiceImpl implements EnvironmentService {
             Map<String, String> labelsMap = Collections.singletonMap(labelKey, labelValue);
             Map<String, String> labelsMap = Collections.singletonMap(labelKey, labelValue);
             String deploymentNamespace = applicationProperties.getDeploymentNamespace();
             String deploymentNamespace = applicationProperties.getDeploymentNamespace();
             String deploymentHost = applicationProperties.getDeploymentHost();
             String deploymentHost = applicationProperties.getDeploymentHost();
-
-            // 构建镜像阶段
-            buildImage(result,useCache, labelValue);
-
             // 读取构建之后的镜像名称
             // 读取构建之后的镜像名称
             String imageName = result.getImage();
             String imageName = result.getImage();
-
             String[] ports = (configContent.getServicePort() == null ? "" : configContent.getServicePort()).split(",");
             String[] ports = (configContent.getServicePort() == null ? "" : configContent.getServicePort()).split(",");
             if (!StringUtils.isEmpty(configContent.getHostPrefix())) {
             if (!StringUtils.isEmpty(configContent.getHostPrefix())) {
                 for (String port : ports) {
                 for (String port : ports) {
@@ -572,51 +600,39 @@ public class EnvironmentServiceImpl implements EnvironmentService {
                 deleteAllPods(id);
                 deleteAllPods(id);
             }
             }
         } catch (Exception e) {
         } catch (Exception e) {
-            if (result.getBuildStatus() == BuildStatus.BUILDING) {
-                result.setBuildStatus(BuildStatus.FAIL);
-                result.setBuildOutput(e.getLocalizedMessage());
-            }
-            if (result.getDeployStatus() == DeployStatus.DEPLOYING) {
-                result.setDeployStatus(DeployStatus.FAIL);
-                result.setDeployOutput(e.getLocalizedMessage());
-            }
+            result.setDeployStatus(DeployStatus.FAIL);
+            result.setDeployOutput(e.getLocalizedMessage());
             environmentDAO.save(result);
             environmentDAO.save(result);
-            LoggerUtil.error(logger, e, "流程失败!");
-            return;
+            LoggerUtil.error(logger, e, "部署流程失败!");
+        }
+    }
+
+    private void buildAndDeploy(Integer id, Boolean useCache) {
+        if (!useCache) {
+            buildImage(id);
         }
         }
+        deployToPod(id);
     }
     }
+
     //获取当前git语境下的最后一次commit记录。
     //获取当前git语境下的最后一次commit记录。
     private static String getLatestCommitHash(Git git) throws GitAPIException {
     private static String getLatestCommitHash(Git git) throws GitAPIException {
         Iterable<RevCommit> commits = git.log().setMaxCount(1).call();
         Iterable<RevCommit> commits = git.log().setMaxCount(1).call();
         return commits.iterator().next().getId().getName();
         return commits.iterator().next().getId().getName();
     }
     }
 
 
-    // 若判断是否命中hash,若命中hash,则不需要重新构建
-    private Boolean useLastImage(Environment result, String lastCommitHash) throws GitAPIException {
-        if(lastCommitHash.equals(result.getLastSuccessCommitHash())){
-            logger.info("commitId: "+lastCommitHash+" 与上次构建成功的commitId相同,无需构建");
-            result.setBuildOutput("commitId: "+lastCommitHash+" 与上次构建成功的commitId相同,无需构建");
-
-            return true;
-        }
-        return false;
-    }
-
     /**
     /**
-     *
-     * @author   fanyanpeng
-     * @date 2023/11/14 11:34
-     * @param result 环境
-     * @param useCache 是否使用缓存
+     * @param result     环境
      * @param labelValue 标签值
      * @param labelValue 标签值
      * @return void
      * @return void
+     * @author fanyanpeng
+     * @date 2023/11/14 11:34
      */
      */
-    private void buildImage(Environment result, Boolean useCache, String labelValue) {
+    private void buildImageHelper(Environment result, String labelValue) {
         Application application = applicationDAO.findById(result.getAppId()).get();
         Application application = applicationDAO.findById(result.getAppId()).get();
         String imageName = "";
         String imageName = "";
-//         1. 有git从git拿到地址进行构建并push
         if (result.getBuildType() == BuildType.FROM_BRANCH_OR_COMMIT) {
         if (result.getBuildType() == BuildType.FROM_BRANCH_OR_COMMIT) {
             try {
             try {
+                // 有git从git拿到地址进行构建并push
                 Path directory = Files.createTempDirectory("seecoder-paas-");
                 Path directory = Files.createTempDirectory("seecoder-paas-");
                 Git git = gitApi.clone(application.getGitUrl(), directory.toString());
                 Git git = gitApi.clone(application.getGitUrl(), directory.toString());
                 try {
                 try {
@@ -630,50 +646,35 @@ public class EnvironmentServiceImpl implements EnvironmentService {
                 // 获取最新的commitId
                 // 获取最新的commitId
                 String currentCommitHash = getLatestCommitHash(git);
                 String currentCommitHash = getLatestCommitHash(git);
 
 
-                // 若成功使用上一次的镜像,就不重新构建了
-                if(useCache && useLastImage(result, currentCommitHash)){
-
-                    result.setBuildStatus(BuildStatus.SUCCESS);
-                    result.setDeployStatus(DeployStatus.DEPLOYING);
-                    result.setDeployStartTime(LocalDateTime.now());
-                    // imageName 无需修改
-                    environmentDAO.save(result);
-                    return;
-                }
-
 
 
                 if (Files.exists(Paths.get(directory.toString(), "Dockerfile"))) {
                 if (Files.exists(Paths.get(directory.toString(), "Dockerfile"))) {
                     String imageTag = String.valueOf(new Date().getTime());
                     String imageTag = String.valueOf(new Date().getTime());
                     StringBuilder sb = new StringBuilder();
                     StringBuilder sb = new StringBuilder();
                     final int DEFAULT_BUFFER_LENGTH = 200;
                     final int DEFAULT_BUFFER_LENGTH = 200;
                     final long MAX_BUFFER_SIZE = 1 << 18;
                     final long MAX_BUFFER_SIZE = 1 << 18;
-                    dockerApi.buildAndPush(directory.toString(), "seecoder-paas-" + labelValue, imageTag, new ProgressHandler() {
-                        @Override
-                        public void progress(ProgressMessage message) throws DockerException {
-                            String value = message.stream();
-                            if (value == null) {
-                                value = "";
-                            }
-                            if (!StringUtils.isEmpty(message.error())) {
-                                value += "\n" + message.error();
-                            }
-                            sb.append(value);
-                            if (sb.length() > DEFAULT_BUFFER_LENGTH) {
-                                result.setBuildOutput(result.getBuildOutput() + sb.toString());
-                                if (result.getBuildOutput().length() > MAX_BUFFER_SIZE) {
-                                    result.setBuildOutput(result.getBuildOutput().substring((int) (result.getBuildOutput().length() - MAX_BUFFER_SIZE)));
-                                }
-                                sb.setLength(0);
-                                environmentDAO.save(result);
+                    dockerApi.buildAndPush(directory.toString(), "seecoder-paas-" + labelValue, imageTag, message -> {
+                        String value = message.stream();
+                        if (value == null) {
+                            value = "";
+                        }
+                        if (!StringUtils.isEmpty(message.error())) {
+                            value += "\n" + message.error();
+                        }
+                        sb.append(value);
+                        if (sb.length() > DEFAULT_BUFFER_LENGTH) {
+                            result.setBuildOutput(result.getBuildOutput() + sb);
+                            if (result.getBuildOutput().length() > MAX_BUFFER_SIZE) {
+                                result.setBuildOutput(result.getBuildOutput().substring((int) (result.getBuildOutput().length() - MAX_BUFFER_SIZE)));
                             }
                             }
+                            sb.setLength(0);
+                            environmentDAO.save(result);
                         }
                         }
-                    },useCache);
+                    }, false);
                     if (sb.length() > 0) {
                     if (sb.length() > 0) {
-                        result.setBuildOutput(result.getBuildOutput() + sb.toString());
+                        result.setBuildOutput(result.getBuildOutput() + sb);
                     }
                     }
                     imageName = applicationProperties.getK8s().getImageRegistry() + "/seecoder-paas-" + labelValue + ":" + imageTag;
                     imageName = applicationProperties.getK8s().getImageRegistry() + "/seecoder-paas-" + labelValue + ":" + imageTag;
                     result.setBuildStatus(BuildStatus.SUCCESS);
                     result.setBuildStatus(BuildStatus.SUCCESS);
-                    result.setDeployStatus(DeployStatus.DEPLOYING);
                     result.setDeployStartTime(LocalDateTime.now());
                     result.setDeployStartTime(LocalDateTime.now());
                     result.setImage(imageName);
                     result.setImage(imageName);
                     result.setLastSuccessCommitHash(currentCommitHash);
                     result.setLastSuccessCommitHash(currentCommitHash);
@@ -691,19 +692,15 @@ public class EnvironmentServiceImpl implements EnvironmentService {
                 }
                 }
                 environmentDAO.save(result);
                 environmentDAO.save(result);
                 LoggerUtil.error(logger, e, "构建失败!gitUrl={}, branchOrCommit={}", application.getGitUrl(), result.getBuildTypeValue());
                 LoggerUtil.error(logger, e, "构建失败!gitUrl={}, branchOrCommit={}", application.getGitUrl(), result.getBuildTypeValue());
-
-
             }
             }
         } else if (result.getBuildType() == BuildType.FROM_IMAGE) {
         } else if (result.getBuildType() == BuildType.FROM_IMAGE) {
             imageName = result.getBuildTypeValue();
             imageName = result.getBuildTypeValue();
             result.setBuildStatus(BuildStatus.SUCCESS);
             result.setBuildStatus(BuildStatus.SUCCESS);
-            result.setBuildOutput("镜像构建无需部署");
-            result.setDeployStatus(DeployStatus.DEPLOYING);
+            result.setBuildOutput("已有镜像构建无需构建");
             result.setDeployStartTime(LocalDateTime.now());
             result.setDeployStartTime(LocalDateTime.now());
             result.setImage(imageName);
             result.setImage(imageName);
             environmentDAO.save(result);
             environmentDAO.save(result);
         }
         }
 
 
-
     }
     }
 }
 }

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

@@ -54,10 +54,16 @@ public class EnvironmentController {
                 environmentService.getLog(id, podName));
                 environmentService.getLog(id, podName));
     }
     }
 
 
+    @PostMapping("/build")
+    public Response build(@RequestParam Integer id) throws ServiceException {
+        return Response.buildSuccess(
+                environmentService.build(id));
+    }
+
     @PostMapping("/deploy")
     @PostMapping("/deploy")
     public Response deploy(@RequestParam Integer id, @RequestParam(required = false, defaultValue = "false") Boolean useCache) throws ServiceException {
     public Response deploy(@RequestParam Integer id, @RequestParam(required = false, defaultValue = "false") Boolean useCache) throws ServiceException {
         return Response.buildSuccess(
         return Response.buildSuccess(
-                environmentService.deploy(id,useCache));
+                environmentService.deploy(id, useCache));
     }
     }