[feat]支持多运行时版本部署,例如上传win-x64/osx-arm64/linux-musl-arm等不同包,各节点根据需要拉取满足自己系统类型和芯片架构的包。https://github.com/NewLifeX/Stardust/pull/57
大石头 authored at 2024-05-23 14:36:12
5.20 KiB
Stardust
using NewLife;
using Stardust.Data;
using Stardust.Data.Deployment;
using Stardust.Data.Nodes;
using Stardust.Models;

namespace Stardust.Server.Services;

public class DeployService
{
    private readonly RegistryService _registryService;

    public DeployService(RegistryService registryService)
    {
        _registryService = registryService;
    }

    public AppDeployVersion GetDeployVersion(AppDeploy app, Node node)
    {
        if (app.MultiVersion)
        {
            // 查找最新的一批版本,挑选符合目标节点的最新版本
            var vers = AppDeployVersion.FindAllByDeployId(app.Id, 100);
            vers = vers.Where(e => e.Enable).OrderByDescending(e => e.Id).ToList();

            // 目标节点所支持的运行时标识符。一般有两个,如 win-x64/win
            var rids = OSKindHelper.GetRID(node.OSKind, node.Architecture?.ToLower() + "");

            return vers.FirstOrDefault(e => rids.Contains(e.Runtime));
        }

        return AppDeployVersion.FindByDeployIdAndVersion(app.Id, app.Version);
    }

    /// <summary>更新应用部署的节点信息</summary>
    /// <param name="online"></param>
    public void UpdateDeployNode(AppOnline online)
    {
        if (online == null || online.AppId == 0 || online.NodeId == 0) return;

        // 提出StarAgent
        if (online.AppName == "StarAgent") return;

        // 找应用部署。此时只有应用标识和节点标识,可能对应多个部署集
        var list = AppDeploy.FindAllByAppId(online.AppId);
        if (list.Count == 0)
        {
            // 根据应用名查找
            var deploy = AppDeploy.FindByName(online.AppName);
            if (deploy != null)
            {
                // 部署名绑定到别的应用,退出
                if (deploy.AppId != 0 && deploy.AppId != online.AppId) return;

                // 当顶当前应用
                deploy.AppId = online.AppId;
                deploy.Update();
            }
            else
            {
                // 新增部署集,禁用状态,信息不完整
                //deploy = new AppDeploy
                //{
                //    AppId = online.AppId,
                //    Name = online.AppName,
                //    Category = online.App?.Category
                //};
                //deploy.Insert();

                deploy = AppDeploy.GetOrAdd(online.Name);
                deploy.AppId = online.AppId;
                deploy.Category = online.App?.Category;
                deploy.Save();
            }
            list.Add(deploy);
        }

        // 查找节点。借助缓存找到启用的那一个部署节点,去更新它的信息。如果有多个无法识别,则都更新一遍
        //var nodes = AppDeployNode.Search(list.Select(e => e.Id).ToArray(), online.NodeId, null, null);
        var nodes = list.SelectMany(e => e.DeployNodes).Where(e => e.NodeId == online.NodeId).ToList();
        var node = nodes.FirstOrDefault(e => e.Enable);

        // 自动创建部署节点,更新信息
        if (node != null)
        {
            node.Fill(online);
            node.Update();
        }
        else
        {
            // 由于无法确定发布集,所以创建所有发布集的节点。此时不能启用,否则下一次应用启动时,将会拉取到该部署信息,而此时部署信息还不完整
            foreach (var deploy in list)
            {
                node = nodes.FirstOrDefault(e => e.DeployId == deploy.Id);
                node ??= new AppDeployNode { DeployId = deploy.Id, NodeId = online.NodeId, Enable = false };
                node.Fill(online);
                node.Save();
            }
        }
        {
            // 定时更新部署信息
            foreach (var deploy in list)
            {
                if (deploy.UpdateTime.AddHours(1) < DateTime.Now) deploy.Fix();
            }
        }
    }

    public void WriteHistory(Int32 appId, Int32 nodeId, String action, Boolean success, String remark, String ip)
    {
        var hi = AppDeployHistory.Create(appId, nodeId, action, success, remark, ip);
        hi.Insert();
    }

    public Int32 Ping(Node node, AppInfo inf, String ip)
    {
        var name = !inf.AppName.IsNullOrEmpty() ? inf.AppName : inf.Name;
        if (name.IsNullOrEmpty()) return -1;

        // 应用
        var ap = App.FindByName(name);
        if (ap == null)
        {
            ap = new App { Name = name };
            ap.Insert();
        }
        {
            var clientId = $"{inf.IP?.Split(',').FirstOrDefault()}@{inf.Id}";
            _registryService.Ping(ap, inf, ip, clientId, null);
            AppMeter.WriteData(ap, inf, "Deploy", clientId, ip);
        }

        // 部署集
        var app = AppDeploy.FindByName(name);
        app ??= new AppDeploy { Name = name };
        app.AppId = ap.Id;
        if (!ap.Category.IsNullOrEmpty()) app.Category = ap.Category;
        app.Save();

        // 本节点所有发布
        var list = AppDeployNode.FindAllByNodeId(node.ID);
        var dn = list.FirstOrDefault(e => e.DeployId == app.Id);
        dn ??= new AppDeployNode { DeployId = app.Id, NodeId = node.ID };

        dn.Fill(inf);
        dn.LastActive = DateTime.Now;

        return dn.Update();
    }
}