Explorar o código

web.devops 中添加构建任务页面和接口

reghao hai 1 ano
pai
achega
bff40f1e4e

+ 1 - 1
web/src/main/java/cn/reghao/bnt/web/devops/app/controller/BuildDeployController.java

@@ -72,7 +72,7 @@ public class BuildDeployController {
     public String resetState() {
         // TODO 暂不启用 web 接口, 只在应用启动时执行
         //buildStat.resetState();
-        return WebResult.successWithMsg("应用构建状态已重置");
+        return WebResult.successWithMsg("尚未实现");
     }
 
     @ApiOperation(value = "webhook 自动构建部署")

+ 34 - 0
web/src/main/java/cn/reghao/bnt/web/devops/app/controller/page/BuildDeployPageController.java

@@ -81,6 +81,40 @@ public class BuildDeployPageController {
         return "/devops/app/bd/index";
     }
 
+    @ApiOperation(value = "构建任务页面")
+    @GetMapping(value = "/task")
+    public String buildTaskPage(@RequestParam(value = "env", required = false) String env,
+                        @RequestParam(value = "type", required = false) String type,
+                        @RequestParam(value = "appName", required = false) String appName, Model model) throws Exception {
+        if (env == null) {
+            env = DefaultSetting.getDefaultAppEnv();
+        }
+
+        if (type == null) {
+            type = DefaultSetting.getDefaultAppType();
+        }
+
+        PageRequest pageRequest = PageSort.pageRequest();
+        int pageNumber = pageRequest.getPageNumber()+1;
+        int pageSize = pageRequest.getPageSize();
+        PageList<AppBuildingVO> pageList;
+        Page<AppBuildingVO> page;
+        if (appName != null) {
+            pageList = buildStat.getByName(appName, pageNumber, pageSize);
+            page = buildService.findByPage(appName, pageRequest);
+        } else {
+            pageList = buildStat.getByPage(env, type, pageNumber, pageSize);
+            page = buildService.findByPage(env, type, pageRequest);
+        }
+
+        Page<AppBuildingVO> page1 = new PageImpl<>(pageList.getList(), pageRequest, pageList.getTotalSize());
+        model.addAttribute("env", env);
+        model.addAttribute("type", type);
+        model.addAttribute("page", page);
+        model.addAttribute("list", page.getContent());
+        return "/devops/app/bd/taskindex";
+    }
+
     @ApiOperation(value = "应用部署页面")
     @GetMapping("/deploy")
     public String deployPage(@RequestParam("appId") String appId,

+ 3 - 0
web/src/main/java/cn/reghao/bnt/web/devops/app/db/repository/config/AppDeployConfigRepository.java

@@ -2,6 +2,7 @@ package cn.reghao.bnt.web.devops.app.db.repository.config;
 
 import cn.reghao.bnt.web.devops.app.model.po.config.AppConfig;
 import cn.reghao.bnt.web.devops.app.model.po.config.AppDeployConfig;
+import cn.reghao.bnt.web.devops.app.model.po.log.BuildLog;
 import cn.reghao.bnt.web.devops.machine.model.po.MachineHost;
 import org.springframework.data.jpa.repository.JpaRepository;
 import org.springframework.data.jpa.repository.JpaSpecificationExecutor;
@@ -15,6 +16,8 @@ import java.util.List;
  */
 public interface AppDeployConfigRepository 
         extends JpaRepository<AppDeployConfig, Integer>, JpaSpecificationExecutor<AppDeployConfig> {
+    void deleteByMachineHost(MachineHost machineHost);
+
     List<AppDeployConfig> findByMachineHost(MachineHost machineHost);
     List<AppDeployConfig> findByAppConfig(AppConfig appConfig);
 }

+ 26 - 5
web/src/main/java/cn/reghao/bnt/web/devops/app/service/bd/impl/BuildAppImpl.java

@@ -8,10 +8,7 @@ import cn.reghao.bnt.web.devops.app.service.bd.BuildApp;
 import cn.reghao.bnt.web.devops.app.service.bd.BuildDeployNotify;
 import cn.reghao.bnt.web.devops.app.service.bd.BuildStat;
 import cn.reghao.bnt.web.devops.app.service.bd.DeployApp;
-import cn.reghao.bnt.web.devops.build.chain.Bootstrap;
-import cn.reghao.bnt.web.devops.build.chain.BuildHandlers;
-import cn.reghao.bnt.web.devops.build.chain.BuildTools;
-import cn.reghao.bnt.web.devops.build.chain.Handler;
+import cn.reghao.bnt.web.devops.build.chain.*;
 import cn.reghao.bnt.web.devops.build.chain.impl.BuildChainParam;
 import cn.reghao.bnt.web.devops.build.chain.impl.BuildChainResult;
 import cn.reghao.bnt.web.devops.build.model.AppDto;
@@ -22,7 +19,9 @@ import cn.reghao.jutil.tool.id.IdGenerator;
 import lombok.extern.slf4j.Slf4j;
 import org.springframework.stereotype.Service;
 
+import java.util.HashMap;
 import java.util.List;
+import java.util.Map;
 import java.util.concurrent.CompletableFuture;
 import java.util.concurrent.ExecutorService;
 
@@ -35,6 +34,7 @@ import java.util.concurrent.ExecutorService;
 public class BuildAppImpl implements BuildApp {
     private final IdGenerator idGenerator = new IdGenerator(10, "build-log-id");
     private final ExecutorService threadPool = ThreadPoolWrapper.threadPool("build-pool", 10);
+    private final Map<String, CompletableFuture<HandlerResult>> buildMap = new HashMap<>(10);
     private final BuildStat buildStat;
     private final DeployApp deployApp;
     private final BuildDeployNotify buildDeployNotify;
@@ -54,6 +54,11 @@ public class BuildAppImpl implements BuildApp {
             return;
         }
 
+        if (buildMap.size() >= 10) {
+            log.info("已有 {} 个 app 正在构建中", buildMap.size());
+            return;
+        }
+
         AppConfig appConfig = buildStat.getAppConfig(appId);
         if (appConfig == null) {
             throw new Exception(appId + " 不存在");
@@ -75,12 +80,13 @@ public class BuildAppImpl implements BuildApp {
         String appId = appDto.getAppId();
         log.info("{} 开始异步构建", appId);
         buildStat.beforeBuild(appId, buildBy);
-        CompletableFuture.supplyAsync(buildChain, threadPool)
+        CompletableFuture<HandlerResult> future = CompletableFuture.supplyAsync(buildChain, threadPool)
                 .whenComplete((chainResult, throwable) -> {
                     BuildChainResult buildChainResult = (BuildChainResult) chainResult;
                     Result result = buildChainResult.getResult();
                     AppBuilding appBuilding = buildStat.afterBuild(buildChainResult);
                     log.info("{} 异步构建完成", appId);
+                    buildMap.remove(appId);
                     if (appBuilding == null) {
                         return;
                     }
@@ -91,6 +97,21 @@ public class BuildAppImpl implements BuildApp {
                         buildDeployNotify.buildNotify(appBuilding);
                     }
                 });
+        buildMap.put(appId, future);
+    }
+
+    public void getBuildStat() {
+        buildMap.forEach((appId, future) -> {
+            if (future.isDone()) {
+            }
+        });
+    }
+
+    public synchronized void cancel(String appId) {
+        CompletableFuture<HandlerResult> future = buildMap.get(appId);
+        if (future != null && !future.isDone()) {
+            future.cancel(true);
+        }
     }
 
     private void remoteBuild(AppDto appDto, String buildBy) {

+ 7 - 0
web/src/main/resources/templates/devops/app/bd/index.html

@@ -41,6 +41,13 @@
             </div>
             <div class="pull-right">
                 <div class="btn-group-right">
+                    <button class="layui-btn">
+                        <i class="fa fa-recycle">
+                            <a class="open-popup"
+                               th:attr="data-title=@{'任务列表'}, data-url=@{'/app/bd/task'}"
+                               data-size="1000,500" href="#">构建任务</a>
+                        </i>
+                    </button>
                     <button class="layui-btn">
                         <i class="fa fa-recycle"><a class="ajax-post" th:href="@{/api/app/bd/reset}">重置</a></i>
                     </button>

+ 37 - 0
web/src/main/resources/templates/devops/app/bd/taskindex.html

@@ -0,0 +1,37 @@
+<!DOCTYPE html>
+<html xmlns:th="http://www.thymeleaf.org">
+<head th:replace="/common/template :: header(~{::title},~{::link},~{::style})"></head>
+
+<body class="timo-layout-page">
+<div class="layui-card">
+    <div class="layui-card-body">
+        <div class="timo-table-wrap">
+            <table class="layui-table timo-table">
+                <thead>
+                <tr>
+                    <th class="sortable" data-field="appName">应用</th>
+                    <th class="sortable" data-field="appType">类型</th>
+                    <th>操作</th>
+                </tr>
+                </thead>
+                <tbody>
+                <tr th:each="item:${list}">
+                    <td>
+                        <a class="open-popup" data-title="应用配置详情" data-size="1200,500" href="#"
+                           th:text="${item.appName}" th:attr="data-url=@{'/app/config/app/detail/'+${item.appId}}"></a>
+                    </td>
+                    <td th:text="${item.appType}">类型</td>
+                    <td>
+                        <a class="ajax-post" th:href="@{'/api/app/bd/task/cancel'+${item.appId}}">取消</a>
+                    </td>
+                </tr>
+                </tbody>
+            </table>
+        </div>
+    </div>
+</div>
+
+<script th:replace="/common/template :: script"></script>
+<script type="text/javascript" th:src="@{/js/plugins/jquery-2.2.4.min.js}"></script>
+</body>
+</html>