节点在线、应用在线、配置在线使用令牌查询
大石头 authored at 2021-12-16 19:49:30
4.72 KiB
Stardust
using Microsoft.AspNetCore.Mvc;
using Stardust;
using Stardust.Data.Deployment;
using Stardust.Models;
using Stardust.Web.Services;
using NewLife;
using NewLife.Cube;
using NewLife.Cube.Extensions;
using NewLife.Cube.ViewModels;
using NewLife.Log;
using NewLife.Web;
using XCode;
using XCode.Membership;

namespace Stardust.Web.Areas.Deployment.Controllers;

/// <summary>流水线。流水线配置,关联一个应用部署集与一个编译节点,监听指定分支的 webhook 触发,自动完成代码拉取、编译、上传、部署的全流程</summary>
[Menu(30, true, Icon = "fa-code-fork")]
[DeploymentArea]
public class AppPipelineController : DeploymentEntityController<AppPipeline>
{
    private readonly PipelineService _pipelineService;

    static AppPipelineController()
    {
        // 列表字段:去掉敏感字段
        ListFields.RemoveField("Id", "Token", "Secret", "DeployNodeIds", "TraceId");
        ListFields.RemoveCreateField().RemoveRemarkField();
        ListFields.TraceUrl("TraceId");

        // 表单字段:Token/Secret/TraceId 不展示,新建时后台自动生成
        AddFormFields.RemoveField("Token", "Secret", "TraceId");
        EditFormFields.RemoveField("Token", "Secret", "TraceId");
        DetailFields.RemoveField("TraceId");

        // 流水线历史列:跳转到该流水线的运行记录列表
        {
            var df = ListFields.AddListField("History", "UpdateUserId");
            df.DisplayName = "流水线历史";
            df.Url = "/Deployment/AppPipelineRun?pipelineId={Id}";
        }

        // 编译节点单选(搜索建议组件,API 版无 GroupView 部分视图,已省略)
        // 部署节点多选(级联:API 版无 GroupView 部分视图,已省略)
    }

    public AppPipelineController(PipelineService pipelineService)
    {
        _pipelineService = pipelineService;
    }

    /// <summary>高级搜索</summary>
    /// <param name="p">分页器。包含分页排序参数,以及Http请求参数</param>
    /// <returns></returns>
    /// <summary>高级搜索。按条件分页查询</summary>
    /// <param name="p">分页参数</param>
    /// <returns>实体列表</returns>
    protected override IEnumerable<AppPipeline> Search(Pager p)
    {
        var deployId = p["deployId"].ToInt(-1);
        var enable = p["enable"]?.ToBoolean();
        return AppPipeline.FindAll(
            (deployId < 0 ? null : AppPipeline._.DeployId == deployId) &
            (enable == null ? null : AppPipeline._.Enable == enable.Value) &
            AppPipeline._.UpdateTime.Between(p["dtStart"].ToDateTime(), p["dtEnd"].ToDateTime()),
            p);
    }

    /// <summary>复制 webhook URL 到剪贴板</summary>
    /// <param name="id">流水线编号</param>
    /// <returns></returns>
    [EntityAuthorize(PermissionFlags.Detail)]
    public ActionResult CopyWebhook(Int32 id)
    {
        var entity = AppPipeline.FindById(id);
        if (entity == null) return Json(500, L.T("Pipeline does not exist."));

        var serviceAddress = StarSetting.Current.ServiceAddress?.Split(",").FirstOrDefault(e => e.StartsWithIgnoreCase("http"));
        var url = $"{serviceAddress}/Pipeline/Webhook?token={entity.Token}";

        return Json(0, "ok", url);
    }

    /// <summary>手动触发流水线运行。委托 PipelineService.Trigger,参考 BatchOperate 模式通过 DeployService 下发指令</summary>
    /// <param name="id">流水线编号</param>
    /// <returns></returns>
    [EntityAuthorize(PermissionFlags.Update)]
    public async Task<ActionResult> Trigger(Int32 id)
    {
        try
        {
            var run = await _pipelineService.Trigger(id, UserHost);
            return JsonRefresh($"流水线已触发,运行编号[{run.Id}]", 1);
        }
        catch (Exception ex)
        {
            return Json(500, ex.Message);
        }
    }

    /// <summary>获取指定部署集下的可用部署节点(JSON),供前端级联下拉使用</summary>
    /// <param name="deployId">部署集编号</param>
    /// <returns></returns>
    [EntityAuthorize(PermissionFlags.Detail)]
    public ActionResult GetDeployNodes(Int32 deployId)
    {
        var nodes = AppDeployNode.FindAllByDeployId(deployId);
        var data = nodes.Where(e => e.Enable).Select(e => new { e.Id, name = $"{e.NodeName} ({e.IP})" });
        return Json(0, null, data);
    }

    /// <summary>获取指定部署集对应的项目编号(JSON),供前端级联使用</summary>
    /// <param name="deployId">部署集编号</param>
    /// <returns></returns>
    [EntityAuthorize(PermissionFlags.Detail)]
    public ActionResult GetDeployProject(Int32 deployId)
    {
        var deploy = AppDeploy.FindById(deployId);
        return Json(0, null, deploy?.ProjectId ?? 0);
    }
}