feat: sync httpdns sdk/platform updates without large binaries

This commit is contained in:
robin
2026-03-04 17:59:14 +08:00
parent 853897a6f8
commit 532891fad0
700 changed files with 6096 additions and 2712 deletions

View File

@@ -39,6 +39,7 @@ func (this *Helper) BeforeAction(actionPtr actions.ActionWrapper) (goNext bool)
if configloaders.AllowModule(adminId, configloaders.AdminModuleCodeSetting) {
tabbar.Add(this.Lang(actionPtr, codes.AdminSetting_TabAdminServer), "", "/settings/server", "", this.tab == "server")
tabbar.Add(this.Lang(actionPtr, codes.AdminSetting_TabAdminUI), "", "/settings/ui", "", this.tab == "ui")
tabbar.Add("升级设置", "", "/settings/upgrade", "", this.tab == "upgrade")
tabbar.Add(this.Lang(actionPtr, codes.AdminSetting_TabAdminSecuritySettings), "", "/settings/security", "", this.tab == "security")
if teaconst.IsPlus {
tabbar.Add(this.Lang(actionPtr, codes.AdminSetting_TabIPLibrary), "", "/settings/ip-library", "", this.tab == "ipLibrary")

View File

@@ -42,6 +42,7 @@ func (this *Helper) BeforeAction(actionPtr actions.ActionWrapper) (goNext bool)
if teaconst.IsPlus {
tabbar.Add(this.Lang(actionPtr, codes.AdminSetting_TabUserUI), "", "/settings/user-ui", "", this.tab == "userUI")
}
tabbar.Add("升级设置", "", "/settings/upgrade", "", this.tab == "upgrade")
tabbar.Add(this.Lang(actionPtr, codes.AdminSetting_TabAdminSecuritySettings), "", "/settings/security", "", this.tab == "security")
tabbar.Add(this.Lang(actionPtr, codes.AdminSetting_TabIPLibrary), "", "/settings/ip-library", "", this.tab == "ipLibrary")
}

View File

@@ -56,9 +56,6 @@ func (this *IndexAction) RunPost(params struct {
TimeZone string
DnsResolverType string
SupportModuleCDN bool
SupportModuleNS bool
Must *actions.Must
CSRF *actionutils.CSRF
}) {
@@ -93,13 +90,7 @@ func (this *IndexAction) RunPost(params struct {
config.DefaultPageSize = 10
}
config.Modules = []userconfigs.UserModule{}
if params.SupportModuleCDN {
config.Modules = append(config.Modules, userconfigs.UserModuleCDN)
}
if params.SupportModuleNS {
config.Modules = append(config.Modules, userconfigs.UserModuleNS)
}
config.Modules = []userconfigs.UserModule{userconfigs.UserModuleCDN, userconfigs.UserModuleNS}
// 上传Favicon文件
if params.FaviconFile != nil {

View File

@@ -0,0 +1,23 @@
//go:build !plus
package upgrade
import (
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
"github.com/iwind/TeaGo/maps"
)
// loadDNSUpgradeModules 非Plus版本不支持DNS模块
func loadDNSUpgradeModules(parent *actionutils.ParentAction) []maps.Map {
return nil
}
// upgradeDNSNode 非Plus版本不支持DNS节点升级
func upgradeDNSNode(parent *actionutils.ParentAction, nodeId int64) error {
return nil
}
// loadDNSNodeStatus 非Plus版本不支持DNS节点状态查询
func loadDNSNodeStatus(parent *actionutils.ParentAction, nodeIds []int64) []maps.Map {
return nil
}

View File

@@ -0,0 +1,100 @@
//go:build plus
package upgrade
import (
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
"github.com/iwind/TeaGo/maps"
)
// loadDNSUpgradeModules 加载DNS模块的待升级节点信息
func loadDNSUpgradeModules(parent *actionutils.ParentAction) []maps.Map {
clustersResp, err := parent.RPC().NSClusterRPC().ListNSClusters(parent.AdminContext(), &pb.ListNSClustersRequest{
Offset: 0,
Size: 10000,
})
if err != nil {
return nil
}
var clusterMaps []maps.Map
for _, cluster := range clustersResp.NsClusters {
nodesResp, err := parent.RPC().NSNodeRPC().FindAllUpgradeNSNodesWithNSClusterId(parent.AdminContext(), &pb.FindAllUpgradeNSNodesWithNSClusterIdRequest{
NsClusterId: cluster.Id,
})
if err != nil {
continue
}
var nodeMaps []maps.Map
for _, nodeUpgrade := range nodesResp.Nodes {
if nodeUpgrade.NsNode == nil {
continue
}
installStatusMap := decodeInstallStatusFromPB(nodeUpgrade.NsNode.InstallStatus)
accessIP, login, loginParams := decodeNodeAccessInfo(nodeUpgrade.NsNode.StatusJSON, nodeUpgrade.NsNode.NodeLogin, nodeUpgrade.NsNode.Name)
nodeMaps = append(nodeMaps, maps.Map{
"id": nodeUpgrade.NsNode.Id,
"name": nodeUpgrade.NsNode.Name,
"os": nodeUpgrade.Os,
"arch": nodeUpgrade.Arch,
"oldVersion": nodeUpgrade.OldVersion,
"newVersion": nodeUpgrade.NewVersion,
"isOn": nodeUpgrade.NsNode.IsOn,
"isUp": nodeUpgrade.NsNode.IsUp,
"accessIP": accessIP,
"login": login,
"loginParams": loginParams,
"installStatus": installStatusMap,
})
}
if len(nodeMaps) == 0 {
continue
}
clusterMaps = append(clusterMaps, maps.Map{
"id": cluster.Id,
"name": cluster.Name,
"nodes": nodeMaps,
"count": len(nodeMaps),
})
}
return clusterMaps
}
// upgradeDNSNode 升级DNS节点
func upgradeDNSNode(parent *actionutils.ParentAction, nodeId int64) error {
_, err := parent.RPC().NSNodeRPC().UpgradeNSNode(parent.AdminContext(), &pb.UpgradeNSNodeRequest{
NsNodeId: nodeId,
})
return err
}
// loadDNSNodeStatus 加载DNS节点安装状态
func loadDNSNodeStatus(parent *actionutils.ParentAction, nodeIds []int64) []maps.Map {
var result []maps.Map
for _, nodeId := range nodeIds {
resp, err := parent.RPC().NSNodeRPC().FindNSNode(parent.AdminContext(), &pb.FindNSNodeRequest{
NsNodeId: nodeId,
})
if err != nil || resp.NsNode == nil {
continue
}
var installStatusMap maps.Map
if resp.NsNode.InstallStatus != nil {
installStatusMap = maps.Map{
"isRunning": resp.NsNode.InstallStatus.IsRunning,
"isFinished": resp.NsNode.InstallStatus.IsFinished,
"isOk": resp.NsNode.InstallStatus.IsOk,
"error": resp.NsNode.InstallStatus.Error,
"errorCode": resp.NsNode.InstallStatus.ErrorCode,
"updatedAt": resp.NsNode.InstallStatus.UpdatedAt,
}
}
result = append(result, maps.Map{
"id": nodeId,
"installStatus": installStatusMap,
})
}
return result
}

View File

@@ -1,6 +1,15 @@
package upgrade
import "github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
import (
"encoding/json"
"strings"
"github.com/TeaOSLab/EdgeAdmin/internal/configloaders"
teaconst "github.com/TeaOSLab/EdgeAdmin/internal/const"
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
"github.com/iwind/TeaGo/maps"
)
type IndexAction struct {
actionutils.ParentAction
@@ -11,5 +20,264 @@ func (this *IndexAction) Init() {
}
func (this *IndexAction) RunGet(params struct{}) {
// 加载升级配置
config, err := configloaders.LoadUpgradeConfig()
if err != nil {
this.ErrorPage(err)
return
}
this.Data["config"] = config
// 模块列表
modules := []maps.Map{}
// 1. 边缘节点 (EdgeNode)
nodeModule := this.loadEdgeNodeModule()
if nodeModule != nil {
modules = append(modules, nodeModule)
}
// 2. DNS节点 (EdgeDNS) — 仅Plus版本
if teaconst.IsPlus {
dnsClusters := loadDNSUpgradeModules(&this.ParentAction)
if len(dnsClusters) > 0 {
totalCount := 0
for _, c := range dnsClusters {
totalCount += c.GetInt("count")
}
modules = append(modules, maps.Map{
"name": "DNS节点",
"code": "dns",
"clusters": dnsClusters,
"count": totalCount,
})
}
}
// 3. HTTPDNS节点
httpdnsModule := this.loadHTTPDNSModule()
if httpdnsModule != nil {
modules = append(modules, httpdnsModule)
}
this.Data["modules"] = modules
this.Show()
}
func (this *IndexAction) RunPost(params struct {
AutoUpgrade bool
}) {
config, err := configloaders.LoadUpgradeConfig()
if err != nil {
this.ErrorPage(err)
return
}
config.AutoUpgrade = params.AutoUpgrade
err = configloaders.UpdateUpgradeConfig(config)
if err != nil {
this.ErrorPage(err)
return
}
this.Success()
}
// loadEdgeNodeModule 加载边缘节点模块的待升级信息
func (this *IndexAction) loadEdgeNodeModule() maps.Map {
// 获取所有集群
clustersResp, err := this.RPC().NodeClusterRPC().ListEnabledNodeClusters(this.AdminContext(), &pb.ListEnabledNodeClustersRequest{
Offset: 0,
Size: 10000,
})
if err != nil {
return nil
}
var clusterMaps []maps.Map
totalCount := 0
for _, cluster := range clustersResp.NodeClusters {
resp, err := this.RPC().NodeRPC().FindAllUpgradeNodesWithNodeClusterId(this.AdminContext(), &pb.FindAllUpgradeNodesWithNodeClusterIdRequest{
NodeClusterId: cluster.Id,
})
if err != nil {
continue
}
if len(resp.Nodes) == 0 {
continue
}
var nodeMaps []maps.Map
for _, nodeUpgrade := range resp.Nodes {
if nodeUpgrade.Node == nil {
continue
}
installStatusMap := decodeInstallStatusFromPB(nodeUpgrade.Node.InstallStatus)
accessIP, login, loginParams := decodeNodeAccessInfo(nodeUpgrade.Node.StatusJSON, nodeUpgrade.Node.NodeLogin, nodeUpgrade.Node.Name)
nodeMaps = append(nodeMaps, maps.Map{
"id": nodeUpgrade.Node.Id,
"name": nodeUpgrade.Node.Name,
"os": nodeUpgrade.Os,
"arch": nodeUpgrade.Arch,
"oldVersion": nodeUpgrade.OldVersion,
"newVersion": nodeUpgrade.NewVersion,
"isOn": nodeUpgrade.Node.IsOn,
"isUp": nodeUpgrade.Node.IsUp,
"accessIP": accessIP,
"login": login,
"loginParams": loginParams,
"installStatus": installStatusMap,
})
}
totalCount += len(nodeMaps)
clusterMaps = append(clusterMaps, maps.Map{
"id": cluster.Id,
"name": cluster.Name,
"nodes": nodeMaps,
"count": len(nodeMaps),
})
}
if len(clusterMaps) == 0 {
return nil
}
return maps.Map{
"name": "边缘节点",
"code": "node",
"clusters": clusterMaps,
"count": totalCount,
}
}
// loadHTTPDNSModule 加载HTTPDNS模块的待升级信息
func (this *IndexAction) loadHTTPDNSModule() maps.Map {
clustersResp, err := this.RPC().HTTPDNSClusterRPC().ListHTTPDNSClusters(this.AdminContext(), &pb.ListHTTPDNSClustersRequest{
Offset: 0,
Size: 10000,
})
if err != nil {
return nil
}
var clusterMaps []maps.Map
totalCount := 0
for _, cluster := range clustersResp.Clusters {
resp, err := this.RPC().HTTPDNSNodeRPC().FindAllUpgradeHTTPDNSNodesWithClusterId(this.AdminContext(), &pb.FindAllUpgradeHTTPDNSNodesWithClusterIdRequest{
ClusterId: cluster.Id,
})
if err != nil {
continue
}
if len(resp.Nodes) == 0 {
continue
}
var nodeMaps []maps.Map
for _, nodeUpgrade := range resp.Nodes {
if nodeUpgrade.Node == nil {
continue
}
installStatusMap := decodeInstallStatusFromJSON(nodeUpgrade.Node.InstallStatusJSON)
accessIP, login, loginParams := decodeNodeAccessInfo(nodeUpgrade.Node.StatusJSON, nodeUpgrade.Node.NodeLogin, nodeUpgrade.Node.Name)
nodeMaps = append(nodeMaps, maps.Map{
"id": nodeUpgrade.Node.Id,
"name": nodeUpgrade.Node.Name,
"os": nodeUpgrade.Os,
"arch": nodeUpgrade.Arch,
"oldVersion": nodeUpgrade.OldVersion,
"newVersion": nodeUpgrade.NewVersion,
"isOn": nodeUpgrade.Node.IsOn,
"isUp": nodeUpgrade.Node.IsUp,
"accessIP": accessIP,
"login": login,
"loginParams": loginParams,
"installStatus": installStatusMap,
})
}
totalCount += len(nodeMaps)
clusterMaps = append(clusterMaps, maps.Map{
"id": cluster.Id,
"name": cluster.Name,
"nodes": nodeMaps,
"count": len(nodeMaps),
})
}
if len(clusterMaps) == 0 {
return nil
}
return maps.Map{
"name": "HTTPDNS节点",
"code": "httpdns",
"clusters": clusterMaps,
"count": totalCount,
}
}
// decodeInstallStatusFromPB 从 protobuf InstallStatus 解码安装状态
func decodeInstallStatusFromPB(status *pb.NodeInstallStatus) maps.Map {
if status == nil {
return nil
}
// 历史成功状态,在待升级列表中忽略
if status.IsFinished && status.IsOk {
return nil
}
return maps.Map{
"isRunning": status.IsRunning,
"isFinished": status.IsFinished,
"isOk": status.IsOk,
"error": status.Error,
"errorCode": status.ErrorCode,
"updatedAt": status.UpdatedAt,
}
}
// decodeInstallStatusFromJSON 从 JSON 字节解码安装状态
func decodeInstallStatusFromJSON(raw []byte) maps.Map {
if len(raw) == 0 {
return nil
}
result := maps.Map{}
_ = json.Unmarshal(raw, &result)
isFinished, _ := result["isFinished"].(bool)
isOk, _ := result["isOk"].(bool)
if isFinished && isOk {
return nil
}
return result
}
// decodeNodeAccessInfo 从节点状态和登录信息中提取 accessIP、login、loginParams
func decodeNodeAccessInfo(statusJSON []byte, nodeLogin *pb.NodeLogin, nodeName string) (accessIP string, login maps.Map, loginParams maps.Map) {
// 从 statusJSON 中提取 hostIP 作为 accessIP
if len(statusJSON) > 0 {
statusMap := maps.Map{}
_ = json.Unmarshal(statusJSON, &statusMap)
accessIP = strings.TrimSpace(statusMap.GetString("hostIP"))
}
if len(accessIP) == 0 {
accessIP = strings.TrimSpace(nodeName)
}
// 解码 login 信息
if nodeLogin != nil {
login = maps.Map{
"id": nodeLogin.Id,
"name": nodeLogin.Name,
"type": nodeLogin.Type,
}
if len(nodeLogin.Params) > 0 {
loginParams = maps.Map{}
_ = json.Unmarshal(nodeLogin.Params, &loginParams)
}
}
return
}

View File

@@ -13,7 +13,9 @@ func init() {
Helper(helpers.NewUserMustAuth(configloaders.AdminModuleCodeSetting)).
Helper(settingutils.NewHelper("upgrade")).
Prefix("/settings/upgrade").
Get("", new(IndexAction)).
GetPost("", new(IndexAction)).
Post("/upgradeNode", new(UpgradeNodeAction)).
Post("/status", new(StatusAction)).
EndAll()
})
}

View File

@@ -0,0 +1,80 @@
package upgrade
import (
"encoding/json"
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
"github.com/iwind/TeaGo/maps"
)
type StatusAction struct {
actionutils.ParentAction
}
func (this *StatusAction) RunPost(params struct {
NodeIdsJSON []byte // JSON: {"node": [1,2], "dns": [3], "httpdns": [4,5]}
}) {
var nodeIdsMap map[string][]int64
if len(params.NodeIdsJSON) > 0 {
_ = json.Unmarshal(params.NodeIdsJSON, &nodeIdsMap)
}
result := maps.Map{}
// EdgeNode 状态
if nodeIds, ok := nodeIdsMap["node"]; ok && len(nodeIds) > 0 {
var nodeStatuses []maps.Map
for _, nodeId := range nodeIds {
resp, err := this.RPC().NodeRPC().FindEnabledNode(this.AdminContext(), &pb.FindEnabledNodeRequest{NodeId: nodeId})
if err != nil || resp.Node == nil {
continue
}
var installStatusMap maps.Map
if resp.Node.InstallStatus != nil {
installStatusMap = maps.Map{
"isRunning": resp.Node.InstallStatus.IsRunning,
"isFinished": resp.Node.InstallStatus.IsFinished,
"isOk": resp.Node.InstallStatus.IsOk,
"error": resp.Node.InstallStatus.Error,
"errorCode": resp.Node.InstallStatus.ErrorCode,
"updatedAt": resp.Node.InstallStatus.UpdatedAt,
}
}
nodeStatuses = append(nodeStatuses, maps.Map{
"id": nodeId,
"installStatus": installStatusMap,
})
}
result["node"] = nodeStatuses
}
// DNS 状态
if nodeIds, ok := nodeIdsMap["dns"]; ok && len(nodeIds) > 0 {
result["dns"] = loadDNSNodeStatus(&this.ParentAction, nodeIds)
}
// HTTPDNS 状态
if nodeIds, ok := nodeIdsMap["httpdns"]; ok && len(nodeIds) > 0 {
var nodeStatuses []maps.Map
for _, nodeId := range nodeIds {
resp, err := this.RPC().HTTPDNSNodeRPC().FindHTTPDNSNode(this.AdminContext(), &pb.FindHTTPDNSNodeRequest{NodeId: nodeId})
if err != nil || resp.Node == nil {
continue
}
var installStatusMap maps.Map
if len(resp.Node.InstallStatusJSON) > 0 {
installStatusMap = maps.Map{}
_ = json.Unmarshal(resp.Node.InstallStatusJSON, &installStatusMap)
}
nodeStatuses = append(nodeStatuses, maps.Map{
"id": nodeId,
"installStatus": installStatusMap,
})
}
result["httpdns"] = nodeStatuses
}
this.Data["statuses"] = result
this.Success()
}

View File

@@ -0,0 +1,150 @@
package upgrade
import (
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
"github.com/iwind/TeaGo/maps"
)
type UpgradeNodeAction struct {
actionutils.ParentAction
}
func (this *UpgradeNodeAction) RunPost(params struct {
Module string // node, dns, httpdns
Scope string // all, module, cluster, node
ClusterId int64
NodeId int64
}) {
switch params.Scope {
case "node":
err := this.upgradeSingleNode(params.Module, params.NodeId)
if err != nil {
this.ErrorPage(err)
return
}
case "cluster":
err := this.upgradeCluster(params.Module, params.ClusterId)
if err != nil {
this.ErrorPage(err)
return
}
case "module":
err := this.upgradeModule(params.Module)
if err != nil {
this.ErrorPage(err)
return
}
case "all":
_ = this.upgradeModule("node")
_ = this.upgradeModule("dns")
_ = this.upgradeModule("httpdns")
}
this.Success()
}
func (this *UpgradeNodeAction) upgradeSingleNode(module string, nodeId int64) error {
switch module {
case "node":
_, err := this.RPC().NodeRPC().UpgradeNode(this.AdminContext(), &pb.UpgradeNodeRequest{NodeId: nodeId})
return err
case "dns":
return upgradeDNSNode(&this.ParentAction, nodeId)
case "httpdns":
_, err := this.RPC().HTTPDNSNodeRPC().UpgradeHTTPDNSNode(this.AdminContext(), &pb.UpgradeHTTPDNSNodeRequest{NodeId: nodeId})
return err
}
return nil
}
func (this *UpgradeNodeAction) upgradeCluster(module string, clusterId int64) error {
switch module {
case "node":
resp, err := this.RPC().NodeRPC().FindAllUpgradeNodesWithNodeClusterId(this.AdminContext(), &pb.FindAllUpgradeNodesWithNodeClusterIdRequest{
NodeClusterId: clusterId,
})
if err != nil {
return err
}
for _, nodeUpgrade := range resp.Nodes {
if nodeUpgrade.Node == nil {
continue
}
_, _ = this.RPC().NodeRPC().UpgradeNode(this.AdminContext(), &pb.UpgradeNodeRequest{NodeId: nodeUpgrade.Node.Id})
}
case "dns":
this.upgradeDNSCluster(clusterId)
case "httpdns":
resp, err := this.RPC().HTTPDNSNodeRPC().FindAllUpgradeHTTPDNSNodesWithClusterId(this.AdminContext(), &pb.FindAllUpgradeHTTPDNSNodesWithClusterIdRequest{
ClusterId: clusterId,
})
if err != nil {
return err
}
for _, nodeUpgrade := range resp.Nodes {
if nodeUpgrade.Node == nil {
continue
}
_, _ = this.RPC().HTTPDNSNodeRPC().UpgradeHTTPDNSNode(this.AdminContext(), &pb.UpgradeHTTPDNSNodeRequest{NodeId: nodeUpgrade.Node.Id})
}
}
return nil
}
func (this *UpgradeNodeAction) upgradeModule(module string) error {
switch module {
case "node":
clustersResp, err := this.RPC().NodeClusterRPC().ListEnabledNodeClusters(this.AdminContext(), &pb.ListEnabledNodeClustersRequest{
Offset: 0,
Size: 10000,
})
if err != nil {
return err
}
for _, cluster := range clustersResp.NodeClusters {
_ = this.upgradeCluster("node", cluster.Id)
}
case "dns":
dnsClusters := loadDNSUpgradeModules(&this.ParentAction)
for _, c := range dnsClusters {
this.upgradeDNSClusterFromMap(c)
}
case "httpdns":
clustersResp, err := this.RPC().HTTPDNSClusterRPC().ListHTTPDNSClusters(this.AdminContext(), &pb.ListHTTPDNSClustersRequest{
Offset: 0,
Size: 10000,
})
if err != nil {
return err
}
for _, cluster := range clustersResp.Clusters {
_ = this.upgradeCluster("httpdns", cluster.Id)
}
}
return nil
}
// upgradeDNSCluster 根据集群ID升级DNS节点
func (this *UpgradeNodeAction) upgradeDNSCluster(clusterId int64) {
dnsClusters := loadDNSUpgradeModules(&this.ParentAction)
for _, c := range dnsClusters {
if c.GetInt64("id") == clusterId {
this.upgradeDNSClusterFromMap(c)
break
}
}
}
// upgradeDNSClusterFromMap 从maps.Map中提取节点ID并升级
func (this *UpgradeNodeAction) upgradeDNSClusterFromMap(c maps.Map) {
nodesVal := c.Get("nodes")
if nodeMaps, ok := nodesVal.([]maps.Map); ok {
for _, n := range nodeMaps {
nodeId := n.GetInt64("id")
if nodeId > 0 {
_ = upgradeDNSNode(&this.ParentAction, nodeId)
}
}
}
}