浏览代码

走通应用部署流程

reghao 5 年之前
父节点
当前提交
df70af9ad7
共有 26 个文件被更改,包括 264 次插入234 次删除
  1. 0 29
      common/src/main/java/cn/reghao/autodop/common/config/BuildDeployResult.java
  2. 3 1
      common/src/main/java/cn/reghao/autodop/common/deploy/DeployConfig.java
  3. 23 0
      common/src/main/java/cn/reghao/autodop/common/deploy/DeployResult.java
  4. 1 1
      common/src/main/java/cn/reghao/autodop/common/deploy/PackerType.java
  5. 0 8
      common/src/main/java/cn/reghao/autodop/common/notification/DingNotify.java
  6. 2 2
      dagent/src/main/java/cn/reghao/autodop/dagent/deploy/Deploy.java
  7. 3 6
      dagent/src/main/java/cn/reghao/autodop/dagent/deploy/DockerDeploy.java
  8. 3 8
      dagent/src/main/java/cn/reghao/autodop/dagent/deploy/ZipDeploy.java
  9. 3 5
      dagent/src/main/java/cn/reghao/autodop/dagent/deploy/ZipRemoteDeploy.java
  10. 24 20
      dagent/src/main/java/cn/reghao/autodop/dagent/service/DeployServiceImpl.java
  11. 0 7
      dmaster/pom.xml
  12. 11 11
      dmaster/src/main/java/cn/reghao/autodop/dmaster/app/controller/BuildController.java
  13. 1 1
      dmaster/src/main/java/cn/reghao/autodop/dmaster/app/entity/constant/AppStage.java
  14. 18 6
      dmaster/src/main/java/cn/reghao/autodop/dmaster/app/service/build/AppBuildPipeline.java
  15. 11 2
      dmaster/src/main/java/cn/reghao/autodop/dmaster/app/service/build/AppIntegrate.java
  16. 6 4
      dmaster/src/main/java/cn/reghao/autodop/dmaster/app/service/build/BuildDispatcher.java
  17. 0 71
      dmaster/src/main/java/cn/reghao/autodop/dmaster/app/service/deploy/AppDeploy.java
  18. 35 0
      dmaster/src/main/java/cn/reghao/autodop/dmaster/app/service/deploy/AppDeployTask.java
  19. 53 40
      dmaster/src/main/java/cn/reghao/autodop/dmaster/app/service/deploy/Deployer.java
  20. 39 0
      dmaster/src/main/java/cn/reghao/autodop/dmaster/app/service/log/LogConsumer.java
  21. 2 5
      dmaster/src/main/java/cn/reghao/autodop/dmaster/app/service/tools/updater/ChangedFile.java
  22. 1 1
      dmaster/src/main/java/cn/reghao/autodop/dmaster/app/service/tools/updater/CommitInfo.java
  23. 16 0
      dmaster/src/test/java/cn/reghao/autodop/common/notification/DingNotifyTest.java
  24. 1 3
      dmaster/src/test/java/cn/reghao/autodop/dmaster/app/entity/orchestration/AppOrchestrationTest.java
  25. 1 3
      dmaster/src/test/java/cn/reghao/autodop/dmaster/app/entity/orchestration/ProjOrchestrationTest.java
  26. 7 0
      pom.xml

+ 0 - 29
common/src/main/java/cn/reghao/autodop/common/config/BuildDeployResult.java

@@ -1,29 +0,0 @@
-package cn.reghao.autodop.common.config;
-
-import lombok.Data;
-import lombok.NoArgsConstructor;
-
-/**
- * 构建部署结果
- *
- * @author reghao
- * @date 2020-03-10 11:22:05
- */
-@NoArgsConstructor
-@Data
-public class BuildDeployResult {
-    private String appId;
-    private String description;
-    private String version;
-    private String stage;
-    private int code;
-    private String msg;
-    private String host;
-
-    public BuildDeployResult(String appId, String stage, int code, String msg) {
-        this.appId = appId;
-        this.appId = stage;
-        this.code = code;
-        this.msg = msg;
-    }
-}

+ 3 - 1
common/src/main/java/cn/reghao/autodop/common/config/DeployConfig.java → common/src/main/java/cn/reghao/autodop/common/deploy/DeployConfig.java

@@ -1,8 +1,10 @@
-package cn.reghao.autodop.common.config;
+package cn.reghao.autodop.common.deploy;
 
 import lombok.Data;
 
 /**
+ * 部署配置
+ *
  * @author reghao
  * @date 2020-01-03 08:43:03
  */

+ 23 - 0
common/src/main/java/cn/reghao/autodop/common/deploy/DeployResult.java

@@ -0,0 +1,23 @@
+package cn.reghao.autodop.common.deploy;
+
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+/**
+ * 部署结果
+ *
+ * @author reghao
+ * @date 2020-03-10 11:22:05
+ */
+@NoArgsConstructor
+@Data
+public class DeployResult {
+    private String host;
+    private int code;
+    private String msg;
+
+    public DeployResult(int code, String msg) {
+        this.code = code;
+        this.msg = msg;
+    }
+}

+ 1 - 1
dmaster/src/main/java/cn/reghao/autodop/dmaster/app/entity/constant/PackerType.java → common/src/main/java/cn/reghao/autodop/common/deploy/PackerType.java

@@ -1,4 +1,4 @@
-package cn.reghao.autodop.dmaster.app.entity.constant;
+package cn.reghao.autodop.common.deploy;
 
 /**
  * 打包工具

+ 0 - 8
common/src/main/java/cn/reghao/autodop/common/notification/DingNotify.java

@@ -26,12 +26,4 @@ public class DingNotify implements Notify {
         }
         return false;
     }
-
-    public static void main(String[] args) throws Exception {
-        String webhook = "https://oapi.dingtalk.com/robot/send?access_token=ba9cf0d846cff8c471168e0d2f91ec0c44645a086cf5e4e421697c9b0c606bd2";
-        DingNotify dingNotify = new DingNotify();
-
-        String content = "打发时间咯";
-        dingNotify.send(webhook, content);
-    }
 }

+ 2 - 2
dagent/src/main/java/cn/reghao/autodop/dagent/deploy/Deploy.java

@@ -1,6 +1,6 @@
 package cn.reghao.autodop.dagent.deploy;
 
-import cn.reghao.autodop.common.config.BuildDeployResult;
+import cn.reghao.autodop.common.deploy.DeployResult;
 
 /**
  * 应用部署
@@ -19,5 +19,5 @@ public interface Deploy {
      * @return 0 - 部署成功,1 - 部署失败
      * @date 2019-10-15 下午4:57
      */
-    BuildDeployResult deploy(String appId, String appPath, String runningDir);
+    DeployResult deploy(String appId, String appPath, String runningDir);
 }

+ 3 - 6
dagent/src/main/java/cn/reghao/autodop/dagent/deploy/DockerDeploy.java

@@ -1,6 +1,6 @@
 package cn.reghao.autodop.dagent.deploy;
 
-import cn.reghao.autodop.common.config.BuildDeployResult;
+import cn.reghao.autodop.common.deploy.DeployResult;
 import cn.reghao.autodop.common.dockerc.DockerClient;
 import lombok.extern.slf4j.Slf4j;
 
@@ -15,13 +15,10 @@ public class DockerDeploy implements Deploy {
     private DockerClient docker = new DockerClient();
 
     @Override
-    public BuildDeployResult deploy(String appId, String appPath, String runningDir) {
-        BuildDeployResult result = new BuildDeployResult();
-        result.setAppId(appId);
-        result.setStage("部署");
+    public DeployResult deploy(String appId, String appPath, String runningDir) {
+        DeployResult result = new DeployResult();
         try {
             docker.pull(appPath);
-            result.setStage("运行");
             docker.run(appId, appPath);
 
             result.setCode(0);

+ 3 - 8
dagent/src/main/java/cn/reghao/autodop/dagent/deploy/ZipDeploy.java

@@ -1,12 +1,10 @@
 package cn.reghao.autodop.dagent.deploy;
 
-import cn.reghao.autodop.common.config.BuildDeployResult;
+import cn.reghao.autodop.common.deploy.DeployResult;
 import cn.reghao.autodop.common.http.DefaultWebRequest;
 import cn.reghao.autodop.common.http.WebRequest;
 import cn.reghao.autodop.common.utils.FileUtil;
 import cn.reghao.autodop.common.utils.compression.ZipUtil;
-import cn.reghao.autodop.dagent.config.DmasterProperties;
-import org.springframework.stereotype.Service;
 
 import java.io.File;
 
@@ -18,12 +16,10 @@ import java.io.File;
  */
 public class ZipDeploy implements Deploy {
     @Override
-    public BuildDeployResult deploy(String appId, String appPath, String runningDir) {
+    public DeployResult deploy(String appId, String appPath, String runningDir) {
         WebRequest request = new DefaultWebRequest();
 
-        BuildDeployResult result = new BuildDeployResult();
-        result.setAppId(appId);
-        result.setStage("部署");
+        DeployResult result = new DeployResult();
         try {
             String appDir = runningDir + "/" + appId;
             String appRunningDir = appDir + "/app";
@@ -36,7 +32,6 @@ public class ZipDeploy implements Deploy {
             }
 
             // TODO 前端静态文件并不存在运行的概念,它与二进制运行文件和 Python 之类的应用不同
-            result.setStage("运行");
             FileUtil.eraseDir(new File(appRunningDir));
             ZipUtil.unzip(filepath, appRunningDir);
 

+ 3 - 5
dagent/src/main/java/cn/reghao/autodop/dagent/deploy/ZipRemoteDeploy.java

@@ -1,6 +1,6 @@
 package cn.reghao.autodop.dagent.deploy;
 
-import cn.reghao.autodop.common.config.BuildDeployResult;
+import cn.reghao.autodop.common.deploy.DeployResult;
 import cn.reghao.autodop.common.http.DefaultWebRequest;
 import cn.reghao.autodop.common.http.WebRequest;
 import cn.reghao.autodop.common.utils.FileUtil;
@@ -16,12 +16,10 @@ import java.io.File;
  */
 public class ZipRemoteDeploy implements Deploy {
     @Override
-    public BuildDeployResult deploy(String appId, String appPath, String runningDir) {
+    public DeployResult deploy(String appId, String appPath, String runningDir) {
         WebRequest request = new DefaultWebRequest();
 
-        BuildDeployResult result = new BuildDeployResult();
-        result.setAppId(appId);
-        result.setStage("部署");
+        DeployResult result = new DeployResult();
         try {
             String appDir = runningDir + "/" + appId;
             String appRunningDir = appDir + "/app";

+ 24 - 20
dagent/src/main/java/cn/reghao/autodop/dagent/service/DeployServiceImpl.java

@@ -1,29 +1,27 @@
 package cn.reghao.autodop.dagent.service;
 
-import cn.reghao.autodop.common.config.BuildDeployResult;
-import cn.reghao.autodop.common.config.DeployConfig;
+import cn.reghao.autodop.common.deploy.DeployResult;
+import cn.reghao.autodop.common.deploy.DeployConfig;
+import cn.reghao.autodop.common.deploy.PackerType;
 import cn.reghao.autodop.dagent.deploy.Deploy;
 import cn.reghao.autodop.dagent.deploy.DockerDeploy;
 import cn.reghao.autodop.dagent.deploy.ZipDeploy;
-import cn.reghao.autodop.dagent.deploy.ZipRemoteDeploy;
 import cn.reghao.autodop.common.grpc.facade.DeployService;
 import cn.reghao.autodop.common.utils.NetworkUtil;
 import com.alibaba.fastjson.JSONObject;
-import lombok.extern.slf4j.Slf4j;
 import org.springframework.stereotype.Service;
 
 /**
  * @author reghao
  * @date 2019-11-07 10:54:01
  */
-@Slf4j
 @Service
 public class DeployServiceImpl implements DeployService {
     public DeployServiceImpl() {
     }
 
     @Override
-    public BuildDeployResult deploy(Object object) {
+    public DeployResult deploy(Object object) {
         JSONObject jsonObject = (JSONObject) object;
         DeployConfig deployConfig = jsonObject.toJavaObject(DeployConfig.class);
 
@@ -31,21 +29,27 @@ public class DeployServiceImpl implements DeployService {
         String appPath = deployConfig.getAppPath();
         String runningDir = deployConfig.getRunningDir();
         String packerType = deployConfig.getPackerType();
-        //boolean isRun = deployConfig.isRun();
 
-        // result 中只有 version 不需要设置
-        BuildDeployResult result;
-        if ("docker".equalsIgnoreCase(packerType)) {
-            Deploy deployApp = new DockerDeploy();
-            result = deployApp.deploy(appId, appPath, null);
-        } else if ("zip".equalsIgnoreCase(packerType)) {
-            Deploy deployApp = new ZipDeploy();
-            result = deployApp.deploy(appId, appPath, runningDir);
-        } else if ("zip-remote".equalsIgnoreCase(packerType)) {
-            Deploy deployApp = new ZipRemoteDeploy();
-            result = deployApp.deploy(appId, appPath, runningDir);
-        } else {
-            result = new BuildDeployResult(appId, "部署", 1, "打包类型不正确");
+        Deploy deployApp;
+        DeployResult result;
+        switch (PackerType.valueOf(packerType)) {
+            case docker:
+                deployApp = new DockerDeploy();
+                result = deployApp.deploy(appId, appPath, null);
+                break;
+            /*case maven:
+                break;
+            case jar:
+                break;
+            case dotnetBinary:
+                break;*/
+            case zip:
+                deployApp = new ZipDeploy();
+                result = deployApp.deploy(appId, appPath, runningDir);
+                break;
+            default:
+                result = new DeployResult(1, "打包类型不正确");
+                break;
         }
 
         // TODO 指定主机 IP 地址的前缀,后期通过配置指定,不动态获取

+ 0 - 7
dmaster/pom.xml

@@ -39,13 +39,6 @@
             <artifactId>spring-boot-starter-actuator</artifactId>
         </dependency>
 
-        <dependency>
-            <groupId>org.springframework.boot</groupId>
-            <artifactId>spring-boot-devtools</artifactId>
-            <optional>true</optional>
-            <scope>true</scope>
-        </dependency>
-
         <dependency>
             <groupId>mysql</groupId>
             <artifactId>mysql-connector-java</artifactId>

+ 11 - 11
dmaster/src/main/java/cn/reghao/autodop/dmaster/app/controller/BuildController.java

@@ -71,6 +71,17 @@ public class BuildController {
         }
     }
 
+    @ApiOperation(value = "部署应用")
+    @ApiImplicitParams({
+            @ApiImplicitParam(name="appId", value="应用标识", paramType="query", dataType = "String"),
+            @ApiImplicitParam(name="appPath", value="应用地址", paramType="query", dataType = "String")
+    })
+    @PostMapping("/deploy")
+    public String deployApp(@RequestParam("appId") String appId, @RequestParam("appPath") String appPath)
+            throws Exception {
+        return null;
+    }
+
     @ApiOperation(value = "构建部署应用")
     @ApiImplicitParams(
             @ApiImplicitParam(name="appId", value="一个或多个应用(多个应用间使用 , 分隔)",
@@ -88,17 +99,6 @@ public class BuildController {
         }
     }
 
-    @ApiOperation(value = "部署应用")
-    @ApiImplicitParams({
-            @ApiImplicitParam(name="appId", value="应用标识", paramType="query", dataType = "String"),
-            @ApiImplicitParam(name="appPath", value="应用地址", paramType="query", dataType = "String")
-    })
-    @PostMapping("/deploy")
-    public String deployApp(@RequestParam("appId") String appId, @RequestParam("appPath") String appPath)
-            throws Exception {
-        return null;
-    }
-
     @ApiOperation(value = "部署 OSS 资源")
     @ApiImplicitParams(
             @ApiImplicitParam(name="appId", value="一个或多个应用(多个应用间使用 , 分隔)",

+ 1 - 1
dmaster/src/main/java/cn/reghao/autodop/dmaster/app/entity/constant/AppStage.java

@@ -8,5 +8,5 @@ package cn.reghao.autodop.dmaster.app.entity.constant;
  * @date 2019-10-18 14:31:29
  */
 public enum AppStage {
-    update, compile, pack, deploy;
+    update, compile, pack, build, deploy;
 }

+ 18 - 6
dmaster/src/main/java/cn/reghao/autodop/dmaster/app/service/build/AppBuildPipeline.java

@@ -1,9 +1,10 @@
 package cn.reghao.autodop.dmaster.app.service.build;
 
+import cn.reghao.autodop.dmaster.app.entity.constant.AppStage;
 import cn.reghao.autodop.dmaster.app.entity.log.BuildLog;
 import cn.reghao.autodop.dmaster.app.entity.log.BuildResult;
+import cn.reghao.autodop.dmaster.app.service.log.LogConsumer;
 import cn.reghao.autodop.dmaster.app.service.tools.updater.CommitInfo;
-import lombok.extern.slf4j.Slf4j;
 
 import java.util.concurrent.Callable;
 
@@ -14,14 +15,15 @@ import java.util.concurrent.Callable;
  * @author reghao
  * @date 2019-11-16 21:39:53
  */
-@Slf4j
 public class AppBuildPipeline implements Callable<BuildResult> {
     private AppIntegrate appIntegrate;
     private boolean isDeploy;
+    private LogConsumer logConsumer;
 
-    public AppBuildPipeline(AppIntegrate appIntegrate, boolean isDeploy) {
+    public AppBuildPipeline(AppIntegrate appIntegrate, boolean isDeploy, LogConsumer logConsumer) {
         this.appIntegrate = appIntegrate;
         this.isDeploy = isDeploy;
+        this.logConsumer = logConsumer;
         // TODO 暂时不使用动态代理
         /*this.appIntegrate = ProxyUtils.createProxyObject(AppIntegrate.class);
         this.appIntegrate.setApp(app);*/
@@ -52,12 +54,22 @@ public class AppBuildPipeline implements Callable<BuildResult> {
             return buildResult(appIntegrate.buildLog());
         }
 
-        return buildResult(appIntegrate.buildLog());
+        BuildLog buildLog = appIntegrate.buildLog();
+        if (!isDeploy) {
+            buildLog.setStage(AppStage.build.name());
+            buildLog.setCode(0);
+            buildLog.setMsg("构建成功");
+        } else {
+            buildLog.setStage(AppStage.deploy.name());
+            buildLog.setCode(0);
+            buildLog.setMsg("部署成功");
+        }
+        // 使用一个单独的线程来持久化构建过程产生的日志,有一定的延时
+        logConsumer.addLog(buildLog);
+        return buildResult(buildLog);
     }
 
     private BuildResult buildResult(BuildLog buildLog) {
-        // TODO 使用一个单独的线程来持久化构建过程产生的日志
-
         BuildResult buildResult = new BuildResult();
         buildResult.setAppId(buildLog.getAppId());
         buildResult.setDescription(buildLog.getDescription());

+ 11 - 2
dmaster/src/main/java/cn/reghao/autodop/dmaster/app/service/build/AppIntegrate.java

@@ -6,11 +6,12 @@ import cn.reghao.autodop.dmaster.app.entity.build.pack.AppPack;
 import cn.reghao.autodop.dmaster.app.entity.build.update.AppUpdate;
 import cn.reghao.autodop.dmaster.app.entity.constant.AppStage;
 import cn.reghao.autodop.dmaster.app.entity.constant.CompilerType;
-import cn.reghao.autodop.dmaster.app.entity.constant.PackerType;
+import cn.reghao.autodop.common.deploy.PackerType;
 import cn.reghao.autodop.dmaster.app.entity.constant.RepoType;
 import cn.reghao.autodop.dmaster.app.entity.deploy.AppDeploy;
 import cn.reghao.autodop.dmaster.app.entity.log.BuildLog;
 import cn.reghao.autodop.dmaster.app.entity.orchestration.AppOrchestration;
+import cn.reghao.autodop.dmaster.app.service.deploy.Deployer;
 import cn.reghao.autodop.dmaster.app.service.tools.compiler.*;
 import cn.reghao.autodop.dmaster.app.service.tools.packer.*;
 import cn.reghao.autodop.dmaster.app.service.tools.updater.CodeUpdater;
@@ -211,6 +212,14 @@ public class AppIntegrate {
     }
 
     public boolean deploy() {
-        return false;
+        try {
+            Deployer.deploy(app, buildLog);
+            return true;
+        } catch (Exception e) {
+            buildLog.setStage(AppStage.deploy.name());
+            buildLog.setCode(1);
+            buildLog.setMsg(e.getMessage());
+            return false;
+        }
     }
 }

+ 6 - 4
dmaster/src/main/java/cn/reghao/autodop/dmaster/app/service/build/BuildDispatcher.java

@@ -6,6 +6,7 @@ import cn.reghao.autodop.dmaster.app.entity.log.BuildResult;
 import cn.reghao.autodop.dmaster.app.entity.orchestration.AppOrchestration;
 import cn.reghao.autodop.dmaster.app.entity.orchestration.ProjOrchestration;
 import cn.reghao.autodop.dmaster.app.repository.log.CommitInfoRepository;
+import cn.reghao.autodop.dmaster.app.service.log.LogConsumer;
 import cn.reghao.autodop.dmaster.app.thread.ThreadPoolWrapper;
 import lombok.extern.slf4j.Slf4j;
 import org.springframework.stereotype.Service;
@@ -24,11 +25,12 @@ import java.util.concurrent.*;
 public class BuildDispatcher {
     private final String STANDALONE_APP = "standaloneApp";
     private OrchestrationCaching caching;
-    private CommitInfoRepository commitInfoRepository;
+    private LogConsumer logConsumer;
 
     public BuildDispatcher(OrchestrationCaching caching, CommitInfoRepository commitInfoRepository) {
         this.caching = caching;
-        this.commitInfoRepository = commitInfoRepository;
+        this.logConsumer = new LogConsumer(commitInfoRepository);
+        ThreadPoolWrapper.threadPool("log").submit(logConsumer);
     }
 
     /**
@@ -75,7 +77,7 @@ public class BuildDispatcher {
                 // 更新,编译,打包独立的应用
                 apps.forEach(app -> {
                     AppIntegrate appIntegrate = new AppIntegrate(app);
-                    appFutures.add(threadPool.submit(new AppBuildPipeline(appIntegrate, isDeploy)));
+                    appFutures.add(threadPool.submit(new AppBuildPipeline(appIntegrate, isDeploy, logConsumer)));
                 });
             }
         }
@@ -95,7 +97,7 @@ public class BuildDispatcher {
                 appStatusList.forEach(appStatus -> {
                     if (appStatus.isUpdated()) {
                         AppIntegrate appIntegrate = new AppIntegrate(appStatus.getApp(), appStatus.getLastCommitInfo());
-                        appFutures.add(threadPool.submit(new AppBuildPipeline(appIntegrate, isDeploy)));
+                        appFutures.add(threadPool.submit(new AppBuildPipeline(appIntegrate, isDeploy, logConsumer)));
                     } else {
                         BuildResult buildResult = new BuildResult();
                         buildResult.setAppId(appStatus.getApp().getAppId());

+ 0 - 71
dmaster/src/main/java/cn/reghao/autodop/dmaster/app/service/deploy/AppDeploy.java

@@ -1,71 +0,0 @@
-package cn.reghao.autodop.dmaster.app.service.deploy;
-
-import cn.reghao.autodop.common.config.BuildDeployResult;
-import cn.reghao.autodop.dmaster.app.entity.orchestration.AppOrchestration;
-import lombok.extern.slf4j.Slf4j;
-
-import java.util.List;
-
-/**
- * @author reghao
- * @date 2020-03-13 10:26:22
- */
-@Slf4j
-public class AppDeploy {
-    /**
-     * 部署和/或运行应用
-     *
-     * @param
-     * @return
-     * @date 2020-03-13 下午1:00
-     */
-    public static List<BuildDeployResult> deploy(AppOrchestration app, String version) throws Exception {
-        /*Notifier notifier = app.getBuild().getNotifier();
-
-        Notify notify = null;
-        if ("ding".equalsIgnoreCase(notifier.getNotifierType())) {
-            notify = new DingNotify();
-        }
-
-        AppPacker appPacker = app.getBuild().getAppPacker();
-        String packerType = appPacker.getPackerType();
-        String appPath = "";
-        // 根据不同的打包类型,确定应用的地址
-        if ("docker".equalsIgnoreCase(packerType)) {
-            appPath = appPacker.getAppRootPath() + "/" + app.getIdentifier() + ":" + version;
-        } else if ("zip".equalsIgnoreCase(packerType)) {
-            String env = app.getEnv();
-            // 根据应用环境确定 autodop 的地址和端口
-            if ("test".equals(env)) {
-                appPath = HttpApi.url("192.168.0.50", 4000,
-                        "/api/app/file/dl/" + app.getIdentifier() + "_" + version + ".zip");
-            } else if ("prod".equals(env)) {
-                appPath = HttpApi.url("static.iquizoo.com", 80,
-                        "/api/app/file/dl/" + app.getIdentifier() + "_" + version + ".zip");
-            } else {
-                appPath = HttpApi.url("localhost", 4000,
-                        "/api/app/file/dl/" + app.getIdentifier() + "_" + version + ".zip");
-            }
-        } else if ("zip-remote".equalsIgnoreCase(packerType)) {
-            // TODO zip-remote 使用 zip 打包,并将应用包上传到远程服务器,appRootPath 是一个 HTTP 链接
-            appPath = appPacker.getAppRootPath() + "/" + app.getIdentifier() + "_" + version;
-        }
-
-        List<BuildDeployResult> results = Deployer.deploy(app, appPath);
-        for (BuildDeployResult result : results) {
-            result.setVersion(version);
-            result.setDescription(app.getDescription());
-            if ("运行".equals(result.getStage()) && result.getCode() == 0) {
-                log.info("{} 已运行", app.getIdentifier());
-                BuildLog buildLog =
-                        new BuildLog(app.getIdentifier(), app.getDescription(), version, app.getEnv());
-                // TODO 异步通知
-                assert notify != null;
-                //notify.sendJson(JsonUtil.objectToJson(buildMsg));
-            }
-        }
-
-        return results;*/
-        return null;
-    }
-}

+ 35 - 0
dmaster/src/main/java/cn/reghao/autodop/dmaster/app/service/deploy/AppDeployTask.java

@@ -0,0 +1,35 @@
+package cn.reghao.autodop.dmaster.app.service.deploy;
+
+import cn.reghao.autodop.common.deploy.DeployConfig;
+import cn.reghao.autodop.common.deploy.DeployResult;
+import cn.reghao.autodop.common.grpc.client.GrpcClientProxy;
+import cn.reghao.autodop.common.grpc.facade.DeployService;
+import com.alibaba.fastjson.JSONObject;
+
+import java.util.concurrent.Callable;
+
+/**
+ * @author reghao
+ * @date 2019-11-16 21:39:53
+ */
+public class AppDeployTask implements Callable<DeployResult> {
+    // TODO 配置文件中指定 gRPC 服务器端口
+    private static final int GRPC_PORT = 4001;
+    private DeployConfig deployConfig;
+
+    public AppDeployTask(DeployConfig deployConfig) {
+        this.deployConfig = deployConfig;
+    }
+
+    @Override
+    public DeployResult call() {
+        // TODO 公共网络下,gRPC 调用需要经过认证
+        DeployService deployService = (DeployService)new GrpcClientProxy<DeployService>()
+                .getProxy(deployConfig.getHost(), GRPC_PORT, DeployService.class);
+
+        // TODO 处理超时未返回的情况
+        Object object = deployService.deploy(deployConfig);
+        JSONObject jsonObject = (JSONObject) object;
+        return jsonObject.toJavaObject(DeployResult.class);
+    }
+}

+ 53 - 40
dmaster/src/main/java/cn/reghao/autodop/dmaster/app/service/deploy/Deployer.java

@@ -1,61 +1,74 @@
 package cn.reghao.autodop.dmaster.app.service.deploy;
 
-import cn.reghao.autodop.common.config.BuildDeployResult;
-import cn.reghao.autodop.common.grpc.client.GrpcClientProxy;
-import cn.reghao.autodop.common.grpc.facade.DeployService;
-import cn.reghao.autodop.common.config.DeployConfig;
-import cn.reghao.autodop.common.http.HttpApi;
+import cn.reghao.autodop.common.deploy.DeployResult;
+import cn.reghao.autodop.common.deploy.DeployConfig;
+import cn.reghao.autodop.common.notification.DingNotify;
+import cn.reghao.autodop.common.notification.Notify;
+import cn.reghao.autodop.common.utils.JsonUtil;
+import cn.reghao.autodop.dmaster.app.entity.build.pack.AppPack;
+import cn.reghao.autodop.dmaster.app.entity.constant.NotifyType;
+import cn.reghao.autodop.dmaster.app.entity.deploy.AppDeploy;
+import cn.reghao.autodop.dmaster.app.entity.log.BuildLog;
 import cn.reghao.autodop.dmaster.app.entity.orchestration.AppOrchestration;
-import com.alibaba.fastjson.JSONObject;
-import lombok.extern.slf4j.Slf4j;
+import cn.reghao.autodop.dmaster.app.entity.orchestration.Notification;
+import cn.reghao.autodop.dmaster.app.thread.ThreadPoolWrapper;
 
 import java.util.ArrayList;
+import java.util.Iterator;
 import java.util.List;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Future;
 
 /**
- * 部署应用到远程主机
- *
  * @author reghao
- * @date 2019-11-11 17:33:56
+ * @date 2020-03-13 10:26:22
  */
-@Slf4j
 public class Deployer {
-    private static final int GRPC_PORT = 4001;
+    private static ExecutorService threadPool = ThreadPoolWrapper.threadPool("deploy");
 
     /**
-     * @return 返回 List 是因为可能是集群部署
-     * @date 2020-03-12 下午3:18
+     * 部署应用
+     *
+     * @param
+     * @return
+     * @date 2020-03-13 下午1:00
      */
-    public static List<BuildDeployResult> deploy(AppOrchestration app, String appPath) {
-        DeployConfig deployConfig = new DeployConfig();
-        deployConfig.setAppId(app.getAppId());
-        deployConfig.setAppPath(appPath);
-        /*deployConfig.setPackerType(app.getBuild().getAppPacker().getPackerType());
-        deployConfig.setRunningDir(app.getRunning().getRunningDir());*/
-
-        List<BuildDeployResult> results = new ArrayList<>();
-       /* String[] hosts = app.getDeploy().getHosts().split(",");
-        // TODO 异步调用
-        for (String host : hosts) {
-            // TODO 公共网络下,gRPC 调用需要经过认证
-            DeployService deployService = (DeployService)new GrpcClientProxy<DeployService>()
-                    .getProxy(host, GRPC_PORT, DeployService.class);
+    public static List<DeployResult> deploy(AppOrchestration app, BuildLog buildLog) throws Exception {
+        Notification notification = app.getNotification();
+        String notifyType = notification.getNotifyType();
+        String dest = notification.getDestination();
+        Notify notify = null;
+        if (notifyType.equals(NotifyType.ding.name())) {
+            notify = new DingNotify();
+        }
 
-            Object object = deployService.deploy(deployConfig);
-            JSONObject jsonObject = (JSONObject) object;
-            BuildDeployResult result = jsonObject.toJavaObject(BuildDeployResult.class);
+        AppPack appPack = app.getAppBuild().getAppPack();
+        AppDeploy appDeploy = app.getAppDeploy();
+        String[] hosts = appDeploy.getHosts().split(",");
+        List<Future<DeployResult>> futures = new ArrayList<>();
+        for (String host : hosts) {
+            DeployConfig deployConfig = new DeployConfig();
+            deployConfig.setAppId(app.getAppId());
+            deployConfig.setAppPath(buildLog.getAppPath());
+            deployConfig.setPackerType(appPack.getPackerType());
+            deployConfig.setHost(host);
+            deployConfig.setRunningDir(appDeploy.getRunningDir());
+            futures.add(threadPool.submit(new AppDeployTask(deployConfig)));
+        }
 
-            // TODO 检查应用是否成功运行,若启动失败,则回退到上一个版本。若上一个版本仍失败,则返回错误并发出紧急通知
-            if ("运行".equals(result.getStage()) && result.getCode() == 1) {
-                String healthCheck = app.getRunning().getHealthCheck();
-                int port = app.getRunning().getPort();
-                // 健康检查 URL
-                String url = HttpApi.url(host, port, healthCheck);
+        Iterator<Future<DeployResult>> iterator = futures.iterator();
+        while (iterator.hasNext()) {
+            Future<DeployResult> future = iterator.next();
+            iterator.remove();
+            while (!future.isDone() && !future.isCancelled()) {
+                Thread.sleep(1_000);
             }
 
-            results.add(result);
-        }*/
+            // TODO 检查应用是否成功运行,若启动失败,则回退到上一个版本。若上一个版本仍失败,则返回错误并发出紧急通知
+            DeployResult deployResult = future.get();
+            notify.send(dest, JsonUtil.objectToJson(deployResult));
+        }
 
-        return results;
+        return null;
     }
 }

+ 39 - 0
dmaster/src/main/java/cn/reghao/autodop/dmaster/app/service/log/LogConsumer.java

@@ -0,0 +1,39 @@
+package cn.reghao.autodop.dmaster.app.service.log;
+
+import cn.reghao.autodop.dmaster.app.entity.log.BuildLog;
+import cn.reghao.autodop.dmaster.app.repository.log.CommitInfoRepository;
+import cn.reghao.autodop.dmaster.app.service.tools.updater.CommitInfo;
+
+import java.util.concurrent.BlockingQueue;
+import java.util.concurrent.LinkedBlockingQueue;
+
+/**
+ * @author reghao
+ * @date 2020-05-15 21:29:32
+ */
+public class LogConsumer implements Runnable {
+    private BlockingQueue<BuildLog> queue = new LinkedBlockingQueue<>();
+    private CommitInfoRepository commitInfoRepository;
+
+    public LogConsumer(CommitInfoRepository commitInfoRepository) {
+        this.commitInfoRepository = commitInfoRepository;
+    }
+
+    public void addLog(BuildLog log) {
+        queue.add(log);
+    }
+
+    @Override
+    public void run() {
+        while (!Thread.interrupted()) {
+            try {
+                BuildLog log = queue.take();
+                CommitInfo commitInfo = log.getCommitInfo();
+                commitInfoRepository.save(commitInfo);
+            } catch (InterruptedException e) {
+                // 中断线程
+                Thread.currentThread().interrupt();
+            }
+        }
+    }
+}

+ 2 - 5
dmaster/src/main/java/cn/reghao/autodop/dmaster/app/service/tools/updater/ChangedFile.java

@@ -4,10 +4,7 @@ import cn.reghao.autodop.dmaster.app.entity.BaseEntity;
 import lombok.Data;
 import lombok.EqualsAndHashCode;
 
-import javax.persistence.CascadeType;
-import javax.persistence.Entity;
-import javax.persistence.JoinColumn;
-import javax.persistence.ManyToOne;
+import javax.persistence.*;
 
 /**
  * @author reghao
@@ -17,8 +14,8 @@ import javax.persistence.ManyToOne;
 @EqualsAndHashCode(callSuper = false)
 @Entity
 public class ChangedFile extends BaseEntity {
+    // TODO 没有关联到 commit_info 表
     @ManyToOne(cascade = CascadeType.ALL)
-    @JoinColumn(name="commit_id")
     private CommitInfo commitInfo;
     private String changeType;
     private String oldFilePath;

+ 1 - 1
dmaster/src/main/java/cn/reghao/autodop/dmaster/app/service/tools/updater/CommitInfo.java

@@ -17,7 +17,7 @@ import java.util.List;
 @EqualsAndHashCode(callSuper = false)
 @Entity
 public class CommitInfo extends BaseEntity {
-    @Column(nullable = false, unique = true)
+
     private String commitId;
     private String commitAuthor;
     private String remoteRepoUrl;

+ 16 - 0
dmaster/src/test/java/cn/reghao/autodop/common/notification/DingNotifyTest.java

@@ -0,0 +1,16 @@
+package cn.reghao.autodop.common.notification;
+
+import org.junit.jupiter.api.Test;
+
+import static org.junit.jupiter.api.Assertions.*;
+
+class DingNotifyTest {
+    @Test
+    void main() {
+        String webhook = "https://oapi.dingtalk.com/robot/send?access_token=ba9cf0d846cff8c471168e0d2f91ec0c44645a086cf5e4e421697c9b0c606bd2";
+        DingNotify dingNotify = new DingNotify();
+
+        String content = "打发时间咯";
+        dingNotify.send(webhook, content);
+    }
+}

+ 1 - 3
dmaster/src/test/java/cn/reghao/autodop/dmaster/app/entity/orchestration/AppOrchestrationTest.java

@@ -7,13 +7,11 @@ import cn.reghao.autodop.dmaster.app.entity.build.pack.AppPack;
 import cn.reghao.autodop.dmaster.app.entity.build.update.AppUpdate;
 import cn.reghao.autodop.dmaster.app.entity.constant.CompilerType;
 import cn.reghao.autodop.dmaster.app.entity.constant.NotifyType;
-import cn.reghao.autodop.dmaster.app.entity.constant.PackerType;
+import cn.reghao.autodop.common.deploy.PackerType;
 import cn.reghao.autodop.dmaster.app.entity.constant.RepoType;
 import cn.reghao.autodop.dmaster.app.entity.deploy.AppDeploy;
 import org.junit.jupiter.api.Test;
 
-import static org.junit.jupiter.api.Assertions.*;
-
 class AppOrchestrationTest {
 
     @Test

+ 1 - 3
dmaster/src/test/java/cn/reghao/autodop/dmaster/app/entity/orchestration/ProjOrchestrationTest.java

@@ -6,12 +6,10 @@ import cn.reghao.autodop.dmaster.app.entity.build.compile.AppCompile;
 import cn.reghao.autodop.dmaster.app.entity.build.pack.AppPack;
 import cn.reghao.autodop.dmaster.app.entity.build.update.AppUpdate;
 import cn.reghao.autodop.dmaster.app.entity.constant.CompilerType;
-import cn.reghao.autodop.dmaster.app.entity.constant.PackerType;
+import cn.reghao.autodop.common.deploy.PackerType;
 import cn.reghao.autodop.dmaster.app.entity.constant.RepoType;
 import org.junit.jupiter.api.Test;
 
-import static org.junit.jupiter.api.Assertions.*;
-
 class ProjOrchestrationTest {
 
     @Test

+ 7 - 0
pom.xml

@@ -31,6 +31,13 @@
     </properties>
 
     <dependencies>
+        <dependency>
+            <groupId>org.springframework.boot</groupId>
+            <artifactId>spring-boot-devtools</artifactId>
+            <optional>true</optional>
+            <scope>true</scope>
+        </dependency>
+
         <dependency>
             <groupId>org.springframework.boot</groupId>
             <artifactId>spring-boot-configuration-processor</artifactId>