mirror of
				https://github.com/TeaOSLab/EdgeAPI.git
				synced 2025-11-04 07:50:25 +08:00 
			
		
		
		
	实现基础的智能调度
This commit is contained in:
		@@ -12,4 +12,5 @@ dbs:
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
fields:
 | 
					fields:
 | 
				
			||||||
  bool: [ "uamIsOn", "followPort", "requestHostExcludingPort", "autoRemoteStart", "autoInstallNftables" ]
 | 
					  bool: [ "uamIsOn", "followPort", "requestHostExcludingPort", "autoRemoteStart", "autoInstallNftables", "enableIPLists", "detectAgents", "checkingPorts", "enableRecordHealthCheck", "offlineIsNotified" ]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -12,7 +12,8 @@ import (
 | 
				
			|||||||
type DNSTaskType = string
 | 
					type DNSTaskType = string
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const (
 | 
					const (
 | 
				
			||||||
	DNSTaskTypeClusterChange       DNSTaskType = "clusterChange"
 | 
						DNSTaskTypeClusterChange       DNSTaskType = "clusterChange"       // 集群节点、服务发生变化
 | 
				
			||||||
 | 
						DNSTaskTypeClusterNodesChange  DNSTaskType = "clusterNodesChange"  // 集群中节点发生变化
 | 
				
			||||||
	DNSTaskTypeClusterRemoveDomain DNSTaskType = "clusterRemoveDomain" // 从集群中移除域名
 | 
						DNSTaskTypeClusterRemoveDomain DNSTaskType = "clusterRemoveDomain" // 从集群中移除域名
 | 
				
			||||||
	DNSTaskTypeNodeChange          DNSTaskType = "nodeChange"
 | 
						DNSTaskTypeNodeChange          DNSTaskType = "nodeChange"
 | 
				
			||||||
	DNSTaskTypeServerChange        DNSTaskType = "serverChange"
 | 
						DNSTaskTypeServerChange        DNSTaskType = "serverChange"
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -52,7 +52,9 @@ const (
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
	MessageTypeReportNodeInactive MessageType = "ReportNodeInactive" // 区域监控节点节点不活跃
 | 
						MessageTypeReportNodeInactive MessageType = "ReportNodeInactive" // 区域监控节点节点不活跃
 | 
				
			||||||
	MessageTypeReportNodeActive   MessageType = "ReportNodeActive"   // 区域监控节点活跃
 | 
						MessageTypeReportNodeActive   MessageType = "ReportNodeActive"   // 区域监控节点活跃
 | 
				
			||||||
	MessageTypeConnectivity       MessageType = "Connectivity"
 | 
						MessageTypeConnectivity       MessageType = "Connectivity"       // 连通性
 | 
				
			||||||
 | 
						MessageTypeNodeSchedule       MessageType = "NodeSchedule"       // 节点调度信息
 | 
				
			||||||
 | 
						MessageTypeNodeOfflineDay     MessageType = "NodeOfflineDay"     // 节点到下线日期
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
type MessageDAO dbs.DAO
 | 
					type MessageDAO dbs.DAO
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										63
									
								
								internal/db/models/node_action_dao.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										63
									
								
								internal/db/models/node_action_dao.go
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,63 @@
 | 
				
			|||||||
 | 
					package models
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import (
 | 
				
			||||||
 | 
						_ "github.com/go-sql-driver/mysql"
 | 
				
			||||||
 | 
						"github.com/iwind/TeaGo/Tea"
 | 
				
			||||||
 | 
						"github.com/iwind/TeaGo/dbs"
 | 
				
			||||||
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const (
 | 
				
			||||||
 | 
						NodeActionStateEnabled  = 1 // 已启用
 | 
				
			||||||
 | 
						NodeActionStateDisabled = 0 // 已禁用
 | 
				
			||||||
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					type NodeActionDAO dbs.DAO
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func NewNodeActionDAO() *NodeActionDAO {
 | 
				
			||||||
 | 
						return dbs.NewDAO(&NodeActionDAO{
 | 
				
			||||||
 | 
							DAOObject: dbs.DAOObject{
 | 
				
			||||||
 | 
								DB:     Tea.Env,
 | 
				
			||||||
 | 
								Table:  "edgeNodeActions",
 | 
				
			||||||
 | 
								Model:  new(NodeAction),
 | 
				
			||||||
 | 
								PkName: "id",
 | 
				
			||||||
 | 
							},
 | 
				
			||||||
 | 
						}).(*NodeActionDAO)
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					var SharedNodeActionDAO *NodeActionDAO
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func init() {
 | 
				
			||||||
 | 
						dbs.OnReady(func() {
 | 
				
			||||||
 | 
							SharedNodeActionDAO = NewNodeActionDAO()
 | 
				
			||||||
 | 
						})
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// EnableNodeAction 启用条目
 | 
				
			||||||
 | 
					func (this *NodeActionDAO) EnableNodeAction(tx *dbs.Tx, id uint64) error {
 | 
				
			||||||
 | 
						_, err := this.Query(tx).
 | 
				
			||||||
 | 
							Pk(id).
 | 
				
			||||||
 | 
							Set("state", NodeActionStateEnabled).
 | 
				
			||||||
 | 
							Update()
 | 
				
			||||||
 | 
						return err
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// DisableNodeAction 禁用条目
 | 
				
			||||||
 | 
					func (this *NodeActionDAO) DisableNodeAction(tx *dbs.Tx, id int64) error {
 | 
				
			||||||
 | 
						_, err := this.Query(tx).
 | 
				
			||||||
 | 
							Pk(id).
 | 
				
			||||||
 | 
							Set("state", NodeActionStateDisabled).
 | 
				
			||||||
 | 
							Update()
 | 
				
			||||||
 | 
						return err
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// FindEnabledNodeAction 查找启用中的条目
 | 
				
			||||||
 | 
					func (this *NodeActionDAO) FindEnabledNodeAction(tx *dbs.Tx, id int64) (*NodeAction, error) {
 | 
				
			||||||
 | 
						result, err := this.Query(tx).
 | 
				
			||||||
 | 
							Pk(id).
 | 
				
			||||||
 | 
							State(NodeActionStateEnabled).
 | 
				
			||||||
 | 
							Find()
 | 
				
			||||||
 | 
						if result == nil {
 | 
				
			||||||
 | 
							return nil, err
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return result.(*NodeAction), err
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										6
									
								
								internal/db/models/node_action_dao_test.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										6
									
								
								internal/db/models/node_action_dao_test.go
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,6 @@
 | 
				
			|||||||
 | 
					package models_test
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import (
 | 
				
			||||||
 | 
						_ "github.com/go-sql-driver/mysql"
 | 
				
			||||||
 | 
						_ "github.com/iwind/TeaGo/bootstrap"
 | 
				
			||||||
 | 
					)
 | 
				
			||||||
							
								
								
									
										32
									
								
								internal/db/models/node_action_model.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										32
									
								
								internal/db/models/node_action_model.go
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,32 @@
 | 
				
			|||||||
 | 
					package models
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import "github.com/iwind/TeaGo/dbs"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// NodeAction 节点智能调度设置
 | 
				
			||||||
 | 
					type NodeAction struct {
 | 
				
			||||||
 | 
						Id       uint64   `field:"id"`       // ID
 | 
				
			||||||
 | 
						NodeId   uint64   `field:"nodeId"`   // 节点ID
 | 
				
			||||||
 | 
						Role     string   `field:"role"`     // 角色
 | 
				
			||||||
 | 
						IsOn     bool     `field:"isOn"`     // 是否启用
 | 
				
			||||||
 | 
						Conds    dbs.JSON `field:"conds"`    // 条件
 | 
				
			||||||
 | 
						Action   dbs.JSON `field:"action"`   // 动作
 | 
				
			||||||
 | 
						Duration dbs.JSON `field:"duration"` // 持续时间
 | 
				
			||||||
 | 
						Order    uint32   `field:"order"`    // 排序
 | 
				
			||||||
 | 
						State    uint8    `field:"state"`    // 状态
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					type NodeActionOperator struct {
 | 
				
			||||||
 | 
						Id       any // ID
 | 
				
			||||||
 | 
						NodeId   any // 节点ID
 | 
				
			||||||
 | 
						Role     any // 角色
 | 
				
			||||||
 | 
						IsOn     any // 是否启用
 | 
				
			||||||
 | 
						Conds    any // 条件
 | 
				
			||||||
 | 
						Action   any // 动作
 | 
				
			||||||
 | 
						Duration any // 持续时间
 | 
				
			||||||
 | 
						Order    any // 排序
 | 
				
			||||||
 | 
						State    any // 状态
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func NewNodeActionOperator() *NodeActionOperator {
 | 
				
			||||||
 | 
						return &NodeActionOperator{}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										1
									
								
								internal/db/models/node_action_model_ext.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1
									
								
								internal/db/models/node_action_model_ext.go
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1 @@
 | 
				
			|||||||
 | 
					package models
 | 
				
			||||||
@@ -1550,7 +1550,7 @@ func (this *NodeDAO) FindAllEnabledNodesDNSWithClusterId(tx *dbs.Tx, clusterId i
 | 
				
			|||||||
		Attr("isOn", true).
 | 
							Attr("isOn", true).
 | 
				
			||||||
		Attr("isUp", true).
 | 
							Attr("isUp", true).
 | 
				
			||||||
		Attr("isInstalled", isInstalled).
 | 
							Attr("isInstalled", isInstalled).
 | 
				
			||||||
		Result("id", "name", "dnsRoutes", "isOn").
 | 
							Result("id", "name", "dnsRoutes", "isOn", "offlineDay", "actionStatus", "isBackupForCluster", "isBackupForGroup", "backupIPs", "clusterId", "groupId").
 | 
				
			||||||
		DescPk().
 | 
							DescPk().
 | 
				
			||||||
		Slice(&result).
 | 
							Slice(&result).
 | 
				
			||||||
		FindAll()
 | 
							FindAll()
 | 
				
			||||||
@@ -1575,7 +1575,7 @@ func (this *NodeDAO) FindEnabledNodeDNS(tx *dbs.Tx, nodeId int64) (*Node, error)
 | 
				
			|||||||
	one, err := this.Query(tx).
 | 
						one, err := this.Query(tx).
 | 
				
			||||||
		State(NodeStateEnabled).
 | 
							State(NodeStateEnabled).
 | 
				
			||||||
		Pk(nodeId).
 | 
							Pk(nodeId).
 | 
				
			||||||
		Result("id", "name", "dnsRoutes", "clusterId", "isOn").
 | 
							Result("id", "name", "dnsRoutes", "clusterId", "isOn", "offlineDay", "isBackupForCluster", "isBackupForGroup", "actionStatus").
 | 
				
			||||||
		Find()
 | 
							Find()
 | 
				
			||||||
	if one == nil {
 | 
						if one == nil {
 | 
				
			||||||
		return nil, err
 | 
							return nil, err
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -18,3 +18,8 @@ func (this *NodeDAO) loadServersFromCluster(tx *dbs.Tx, clusterId int64, serverI
 | 
				
			|||||||
func (this *NodeDAO) composeExtConfig(tx *dbs.Tx, config *nodeconfigs.NodeConfig, clusterIds []int64, cacheMap *utils.CacheMap) error {
 | 
					func (this *NodeDAO) composeExtConfig(tx *dbs.Tx, config *nodeconfigs.NodeConfig, clusterIds []int64, cacheMap *utils.CacheMap) error {
 | 
				
			||||||
	return nil
 | 
						return nil
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// CheckNodeIPAddresses 检查节点IP地址
 | 
				
			||||||
 | 
					func (this *NodeDAO) CheckNodeIPAddresses(tx *dbs.Tx, node *Node) (shouldSkip bool, shouldOverwrite bool, ipAddressStrings []string, err error) {
 | 
				
			||||||
 | 
						return
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -43,6 +43,12 @@ type Node struct {
 | 
				
			|||||||
	DnsResolver            dbs.JSON `field:"dnsResolver"`            // DNS解析器
 | 
						DnsResolver            dbs.JSON `field:"dnsResolver"`            // DNS解析器
 | 
				
			||||||
	EnableIPLists          bool     `field:"enableIPLists"`          // 启用IP名单
 | 
						EnableIPLists          bool     `field:"enableIPLists"`          // 启用IP名单
 | 
				
			||||||
	ApiNodeAddrs           dbs.JSON `field:"apiNodeAddrs"`           // API节点地址
 | 
						ApiNodeAddrs           dbs.JSON `field:"apiNodeAddrs"`           // API节点地址
 | 
				
			||||||
 | 
						OfflineDay             string   `field:"offlineDay"`             // 下线日期YYYYMMDD
 | 
				
			||||||
 | 
						OfflineIsNotified      bool     `field:"offlineIsNotified"`      // 下线是否已通知
 | 
				
			||||||
 | 
						IsBackupForCluster     bool     `field:"isBackupForCluster"`     // 是否为集群备用节点
 | 
				
			||||||
 | 
						IsBackupForGroup       bool     `field:"isBackupForGroup"`       // 是否为分组备用节点
 | 
				
			||||||
 | 
						BackupIPs              dbs.JSON `field:"backupIPs"`              // 备用IP
 | 
				
			||||||
 | 
						ActionStatus           dbs.JSON `field:"actionStatus"`           // 当前动作配置
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
type NodeOperator struct {
 | 
					type NodeOperator struct {
 | 
				
			||||||
@@ -85,6 +91,12 @@ type NodeOperator struct {
 | 
				
			|||||||
	DnsResolver            any // DNS解析器
 | 
						DnsResolver            any // DNS解析器
 | 
				
			||||||
	EnableIPLists          any // 启用IP名单
 | 
						EnableIPLists          any // 启用IP名单
 | 
				
			||||||
	ApiNodeAddrs           any // API节点地址
 | 
						ApiNodeAddrs           any // API节点地址
 | 
				
			||||||
 | 
						OfflineDay             any // 下线日期YYYYMMDD
 | 
				
			||||||
 | 
						OfflineIsNotified      any // 下线是否已通知
 | 
				
			||||||
 | 
						IsBackupForCluster     any // 是否为集群备用节点
 | 
				
			||||||
 | 
						IsBackupForGroup       any // 是否为分组备用节点
 | 
				
			||||||
 | 
						BackupIPs              any // 备用IP
 | 
				
			||||||
 | 
						ActionStatus           any // 当前动作配置
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func NewNodeOperator() *NodeOperator {
 | 
					func NewNodeOperator() *NodeOperator {
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -7,6 +7,7 @@ import (
 | 
				
			|||||||
	"github.com/TeaOSLab/EdgeCommon/pkg/serverconfigs"
 | 
						"github.com/TeaOSLab/EdgeCommon/pkg/serverconfigs"
 | 
				
			||||||
	"github.com/TeaOSLab/EdgeCommon/pkg/serverconfigs/ddosconfigs"
 | 
						"github.com/TeaOSLab/EdgeCommon/pkg/serverconfigs/ddosconfigs"
 | 
				
			||||||
	"github.com/TeaOSLab/EdgeCommon/pkg/serverconfigs/shared"
 | 
						"github.com/TeaOSLab/EdgeCommon/pkg/serverconfigs/shared"
 | 
				
			||||||
 | 
						timeutil "github.com/iwind/TeaGo/utils/time"
 | 
				
			||||||
	"sort"
 | 
						"sort"
 | 
				
			||||||
	"time"
 | 
						"time"
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
@@ -16,7 +17,7 @@ func (this *Node) DecodeInstallStatus() (*NodeInstallStatus, error) {
 | 
				
			|||||||
	if len(this.InstallStatus) == 0 {
 | 
						if len(this.InstallStatus) == 0 {
 | 
				
			||||||
		return NewNodeInstallStatus(), nil
 | 
							return NewNodeInstallStatus(), nil
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	status := &NodeInstallStatus{}
 | 
						var status = &NodeInstallStatus{}
 | 
				
			||||||
	err := json.Unmarshal(this.InstallStatus, status)
 | 
						err := json.Unmarshal(this.InstallStatus, status)
 | 
				
			||||||
	if err != nil {
 | 
						if err != nil {
 | 
				
			||||||
		return NewNodeInstallStatus(), err
 | 
							return NewNodeInstallStatus(), err
 | 
				
			||||||
@@ -37,7 +38,7 @@ func (this *Node) DecodeStatus() (*nodeconfigs.NodeStatus, error) {
 | 
				
			|||||||
	if len(this.Status) == 0 {
 | 
						if len(this.Status) == 0 {
 | 
				
			||||||
		return nil, nil
 | 
							return nil, nil
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	status := &nodeconfigs.NodeStatus{}
 | 
						var status = &nodeconfigs.NodeStatus{}
 | 
				
			||||||
	err := json.Unmarshal(this.Status, status)
 | 
						err := json.Unmarshal(this.Status, status)
 | 
				
			||||||
	if err != nil {
 | 
						if err != nil {
 | 
				
			||||||
		return nil, err
 | 
							return nil, err
 | 
				
			||||||
@@ -47,7 +48,7 @@ func (this *Node) DecodeStatus() (*nodeconfigs.NodeStatus, error) {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
// DNSRouteCodes 所有的DNS线路
 | 
					// DNSRouteCodes 所有的DNS线路
 | 
				
			||||||
func (this *Node) DNSRouteCodes() map[int64][]string {
 | 
					func (this *Node) DNSRouteCodes() map[int64][]string {
 | 
				
			||||||
	routes := map[int64][]string{} // domainId => routes
 | 
						var routes = map[int64][]string{} // domainId => routes
 | 
				
			||||||
	if len(this.DnsRoutes) == 0 {
 | 
						if len(this.DnsRoutes) == 0 {
 | 
				
			||||||
		return routes
 | 
							return routes
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
@@ -61,7 +62,7 @@ func (this *Node) DNSRouteCodes() map[int64][]string {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
// DNSRouteCodesForDomainId DNS线路
 | 
					// DNSRouteCodesForDomainId DNS线路
 | 
				
			||||||
func (this *Node) DNSRouteCodesForDomainId(dnsDomainId int64) ([]string, error) {
 | 
					func (this *Node) DNSRouteCodesForDomainId(dnsDomainId int64) ([]string, error) {
 | 
				
			||||||
	routes := map[int64][]string{} // domainId => routes
 | 
						var routes = map[int64][]string{} // domainId => routes
 | 
				
			||||||
	if len(this.DnsRoutes) == 0 {
 | 
						if len(this.DnsRoutes) == 0 {
 | 
				
			||||||
		return nil, nil
 | 
							return nil, nil
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
@@ -80,7 +81,7 @@ func (this *Node) DNSRouteCodesForDomainId(dnsDomainId int64) ([]string, error)
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
// DecodeConnectedAPINodeIds 连接的API
 | 
					// DecodeConnectedAPINodeIds 连接的API
 | 
				
			||||||
func (this *Node) DecodeConnectedAPINodeIds() ([]int64, error) {
 | 
					func (this *Node) DecodeConnectedAPINodeIds() ([]int64, error) {
 | 
				
			||||||
	apiNodeIds := []int64{}
 | 
						var apiNodeIds = []int64{}
 | 
				
			||||||
	if IsNotNull(this.ConnectedAPINodes) {
 | 
						if IsNotNull(this.ConnectedAPINodes) {
 | 
				
			||||||
		err := json.Unmarshal(this.ConnectedAPINodes, &apiNodeIds)
 | 
							err := json.Unmarshal(this.ConnectedAPINodes, &apiNodeIds)
 | 
				
			||||||
		if err != nil {
 | 
							if err != nil {
 | 
				
			||||||
@@ -214,3 +215,8 @@ func (this *Node) DecodeAPINodeAddrs() []*serverconfigs.NetworkAddressConfig {
 | 
				
			|||||||
	}
 | 
						}
 | 
				
			||||||
	return result
 | 
						return result
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// CheckIsOffline 检查是否已经离线
 | 
				
			||||||
 | 
					func (this *Node) CheckIsOffline() bool {
 | 
				
			||||||
 | 
						return len(this.OfflineDay) > 0 && this.OfflineDay < timeutil.Format("Ymd")
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										9
									
								
								internal/db/models/node_model_ext_schdule.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										9
									
								
								internal/db/models/node_model_ext_schdule.go
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,9 @@
 | 
				
			|||||||
 | 
					// Copyright 2023 Liuxiangchao iwind.liu@gmail.com. All rights reserved. Official site: https://goedge.cn .
 | 
				
			||||||
 | 
					//go:build !plus
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					package models
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// HasScheduleSettings 检查是否设置了调度
 | 
				
			||||||
 | 
					func (this *Node) HasScheduleSettings() bool {
 | 
				
			||||||
 | 
						return false
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@@ -1,4 +1,4 @@
 | 
				
			|||||||
package stats
 | 
					package models
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import (
 | 
					import (
 | 
				
			||||||
	"github.com/TeaOSLab/EdgeAPI/internal/errors"
 | 
						"github.com/TeaOSLab/EdgeAPI/internal/errors"
 | 
				
			||||||
@@ -84,7 +84,9 @@ func (this *NodeTrafficDailyStatDAO) IncreaseDailyStat(tx *dbs.Tx, clusterId int
 | 
				
			|||||||
	if err != nil {
 | 
						if err != nil {
 | 
				
			||||||
		return err
 | 
							return err
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	return nil
 | 
					
 | 
				
			||||||
 | 
						// 触发钩子
 | 
				
			||||||
 | 
						return this.increaseDailyStatHook(tx, role, nodeId)
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// FindDailyStats 获取日期之间统计
 | 
					// FindDailyStats 获取日期之间统计
 | 
				
			||||||
							
								
								
									
										14
									
								
								internal/db/models/node_traffic_daily_stat_dao_ext.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										14
									
								
								internal/db/models/node_traffic_daily_stat_dao_ext.go
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,14 @@
 | 
				
			|||||||
 | 
					// Copyright 2023 Liuxiangchao iwind.liu@gmail.com. All rights reserved. Official site: https://goedge.cn .
 | 
				
			||||||
 | 
					//go:build !plus
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					package models
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import (
 | 
				
			||||||
 | 
						"github.com/TeaOSLab/EdgeCommon/pkg/nodeconfigs"
 | 
				
			||||||
 | 
						"github.com/iwind/TeaGo/dbs"
 | 
				
			||||||
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// 增加日统计Hook
 | 
				
			||||||
 | 
					func (this *NodeTrafficDailyStatDAO) increaseDailyStatHook(tx *dbs.Tx, role nodeconfigs.NodeRole, nodeId int64) error {
 | 
				
			||||||
 | 
						return nil
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@@ -1,4 +1,4 @@
 | 
				
			|||||||
package stats
 | 
					package models
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import (
 | 
					import (
 | 
				
			||||||
	_ "github.com/go-sql-driver/mysql"
 | 
						_ "github.com/go-sql-driver/mysql"
 | 
				
			||||||
@@ -1,4 +1,4 @@
 | 
				
			|||||||
package stats
 | 
					package models
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// NodeTrafficDailyStat 总的流量统计(按天)
 | 
					// NodeTrafficDailyStat 总的流量统计(按天)
 | 
				
			||||||
type NodeTrafficDailyStat struct {
 | 
					type NodeTrafficDailyStat struct {
 | 
				
			||||||
							
								
								
									
										1
									
								
								internal/db/models/node_traffic_daily_stat_model_ext.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1
									
								
								internal/db/models/node_traffic_daily_stat_model_ext.go
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1 @@
 | 
				
			|||||||
 | 
					package models
 | 
				
			||||||
@@ -37,11 +37,15 @@ func init() {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
// CreateValue 创建值
 | 
					// CreateValue 创建值
 | 
				
			||||||
func (this *NodeValueDAO) CreateValue(tx *dbs.Tx, clusterId int64, role nodeconfigs.NodeRole, nodeId int64, item string, valueJSON []byte, createdAt int64) error {
 | 
					func (this *NodeValueDAO) CreateValue(tx *dbs.Tx, clusterId int64, role nodeconfigs.NodeRole, nodeId int64, item string, valueJSON []byte, createdAt int64) error {
 | 
				
			||||||
 | 
						if len(valueJSON) == 0 {
 | 
				
			||||||
 | 
							return errors.New("'valueJSON' should not be nil")
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	var day = timeutil.FormatTime("Ymd", createdAt)
 | 
						var day = timeutil.FormatTime("Ymd", createdAt)
 | 
				
			||||||
	var hour = timeutil.FormatTime("YmdH", createdAt)
 | 
						var hour = timeutil.FormatTime("YmdH", createdAt)
 | 
				
			||||||
	var minute = timeutil.FormatTime("YmdHi", createdAt)
 | 
						var minute = timeutil.FormatTime("YmdHi", createdAt)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return this.Query(tx).
 | 
						err := this.Query(tx).
 | 
				
			||||||
		InsertOrUpdateQuickly(maps.Map{
 | 
							InsertOrUpdateQuickly(maps.Map{
 | 
				
			||||||
			"clusterId": clusterId,
 | 
								"clusterId": clusterId,
 | 
				
			||||||
			"role":      role,
 | 
								"role":      role,
 | 
				
			||||||
@@ -55,6 +59,17 @@ func (this *NodeValueDAO) CreateValue(tx *dbs.Tx, clusterId int64, role nodeconf
 | 
				
			|||||||
		}, maps.Map{
 | 
							}, maps.Map{
 | 
				
			||||||
			"value": valueJSON,
 | 
								"value": valueJSON,
 | 
				
			||||||
		})
 | 
							})
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							return err
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// 触发钩子
 | 
				
			||||||
 | 
						err = this.nodeValueHook(tx, role, nodeId, item, valueJSON)
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							return err
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return nil
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// Clean 清除数据
 | 
					// Clean 清除数据
 | 
				
			||||||
@@ -324,7 +339,7 @@ func (this *NodeValueDAO) SumNodeClusterValues(tx *dbs.Tx, role string, clusterI
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
// FindLatestNodeValue 获取最近一条数据
 | 
					// FindLatestNodeValue 获取最近一条数据
 | 
				
			||||||
func (this *NodeValueDAO) FindLatestNodeValue(tx *dbs.Tx, role string, nodeId int64, item string) (*NodeValue, error) {
 | 
					func (this *NodeValueDAO) FindLatestNodeValue(tx *dbs.Tx, role string, nodeId int64, item string) (*NodeValue, error) {
 | 
				
			||||||
	fromMinute := timeutil.FormatTime("YmdHi", time.Now().Unix()-int64(60))
 | 
						var fromMinute = timeutil.FormatTime("YmdHi", time.Now().Unix()-int64(60))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	one, err := this.Query(tx).
 | 
						one, err := this.Query(tx).
 | 
				
			||||||
		Attr("role", role).
 | 
							Attr("role", role).
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										14
									
								
								internal/db/models/node_value_dao_ext.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										14
									
								
								internal/db/models/node_value_dao_ext.go
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,14 @@
 | 
				
			|||||||
 | 
					// Copyright 2023 Liuxiangchao iwind.liu@gmail.com. All rights reserved. Official site: https://goedge.cn .
 | 
				
			||||||
 | 
					//go:build !plus
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					package models
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import (
 | 
				
			||||||
 | 
						"github.com/TeaOSLab/EdgeCommon/pkg/nodeconfigs"
 | 
				
			||||||
 | 
						"github.com/iwind/TeaGo/dbs"
 | 
				
			||||||
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// 节点值变更Hook
 | 
				
			||||||
 | 
					func (this *NodeValueDAO) nodeValueHook(tx *dbs.Tx, role nodeconfigs.NodeRole, nodeId int64, item nodeconfigs.NodeValueItem, valueJSON []byte) error {
 | 
				
			||||||
 | 
						return nil
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@@ -1 +0,0 @@
 | 
				
			|||||||
package stats
 | 
					 | 
				
			||||||
@@ -1,10 +1,11 @@
 | 
				
			|||||||
// Copyright 2022 Liuxiangchao iwind.liu@gmail.com. All rights reserved.
 | 
					// Copyright 2022 Liuxiangchao iwind.liu@gmail.com. All rights reserved.
 | 
				
			||||||
//go:build !plus
 | 
					//go:build !plus
 | 
				
			||||||
// +build !plus
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
package dnsclients
 | 
					package dnsclients
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import "github.com/iwind/TeaGo/maps"
 | 
					import (
 | 
				
			||||||
 | 
						"github.com/iwind/TeaGo/maps"
 | 
				
			||||||
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// FindProvider 查找服务商实例
 | 
					// FindProvider 查找服务商实例
 | 
				
			||||||
func FindProvider(providerType ProviderType, providerId int64) ProviderInterface {
 | 
					func FindProvider(providerType ProviderType, providerId int64) ProviderInterface {
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -472,13 +472,14 @@ func (this *DNSDomainService) findClusterDNSChanges(cluster *models.NodeCluster,
 | 
				
			|||||||
	var nodeKeys = []string{}
 | 
						var nodeKeys = []string{}
 | 
				
			||||||
	var addingNodeRecordKeysMap = map[string]bool{} // clusterDnsName_type_ip_route
 | 
						var addingNodeRecordKeysMap = map[string]bool{} // clusterDnsName_type_ip_route
 | 
				
			||||||
	for _, node := range nodes {
 | 
						for _, node := range nodes {
 | 
				
			||||||
		ipAddresses, err := models.SharedNodeIPAddressDAO.FindNodeAccessAndUpIPAddresses(tx, int64(node.Id), nodeconfigs.NodeRoleNode)
 | 
							shouldSkip, shouldOverwrite, ipAddressesStrings, err := models.SharedNodeDAO.CheckNodeIPAddresses(tx, node)
 | 
				
			||||||
		if err != nil {
 | 
							if err != nil {
 | 
				
			||||||
			return nil, nil, nil, 0, 0, false, false, err
 | 
								return nil, nil, nil, 0, 0, false, false, err
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		if len(ipAddresses) == 0 {
 | 
							if shouldSkip {
 | 
				
			||||||
			continue
 | 
								continue
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		routeCodes, err := node.DNSRouteCodesForDomainId(int64(cluster.DnsDomainId))
 | 
							routeCodes, err := node.DNSRouteCodesForDomainId(int64(cluster.DnsDomainId))
 | 
				
			||||||
		if err != nil {
 | 
							if err != nil {
 | 
				
			||||||
			return nil, nil, nil, 0, 0, false, false, err
 | 
								return nil, nil, nil, 0, 0, false, false, err
 | 
				
			||||||
@@ -491,7 +492,16 @@ func (this *DNSDomainService) findClusterDNSChanges(cluster *models.NodeCluster,
 | 
				
			|||||||
				continue
 | 
									continue
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		for _, route := range routeCodes {
 | 
					
 | 
				
			||||||
 | 
							if !shouldOverwrite {
 | 
				
			||||||
 | 
								ipAddresses, err := models.SharedNodeIPAddressDAO.FindNodeAccessAndUpIPAddresses(tx, int64(node.Id), nodeconfigs.NodeRoleNode)
 | 
				
			||||||
 | 
								if err != nil {
 | 
				
			||||||
 | 
									return nil, nil, nil, 0, 0, false, false, err
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
								if len(ipAddresses) == 0 {
 | 
				
			||||||
 | 
									continue
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			for _, ipAddress := range ipAddresses {
 | 
								for _, ipAddress := range ipAddresses {
 | 
				
			||||||
				// 检查专属节点
 | 
									// 检查专属节点
 | 
				
			||||||
				if !ipAddress.IsValidInCluster(clusterId) {
 | 
									if !ipAddress.IsValidInCluster(clusterId) {
 | 
				
			||||||
@@ -505,6 +515,16 @@ func (this *DNSDomainService) findClusterDNSChanges(cluster *models.NodeCluster,
 | 
				
			|||||||
				if net.ParseIP(ip) == nil {
 | 
									if net.ParseIP(ip) == nil {
 | 
				
			||||||
					continue
 | 
										continue
 | 
				
			||||||
				}
 | 
									}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
									ipAddressesStrings = append(ipAddressesStrings, ip)
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							if len(ipAddressesStrings) == 0 {
 | 
				
			||||||
 | 
								continue
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							for _, route := range routeCodes {
 | 
				
			||||||
 | 
								for _, ip := range ipAddressesStrings {
 | 
				
			||||||
				var key = ip + "_" + route
 | 
									var key = ip + "_" + route
 | 
				
			||||||
				nodeKeys = append(nodeKeys, key)
 | 
									nodeKeys = append(nodeKeys, key)
 | 
				
			||||||
				record, ok := nodeRecordMapping[key]
 | 
									record, ok := nodeRecordMapping[key]
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -62,7 +62,7 @@ func (this *DNSTaskService) FindAllDoingDNSTasks(ctx context.Context, req *pb.Fi
 | 
				
			|||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		switch task.Type {
 | 
							switch task.Type {
 | 
				
			||||||
		case dns.DNSTaskTypeClusterChange, dns.DNSTaskTypeClusterRemoveDomain:
 | 
							case dns.DNSTaskTypeClusterChange, dns.DNSTaskTypeClusterNodesChange, dns.DNSTaskTypeClusterRemoveDomain:
 | 
				
			||||||
			clusterName, err := models.SharedNodeClusterDAO.FindNodeClusterName(tx, int64(task.ClusterId))
 | 
								clusterName, err := models.SharedNodeClusterDAO.FindNodeClusterName(tx, int64(task.ClusterId))
 | 
				
			||||||
			if err != nil {
 | 
								if err != nil {
 | 
				
			||||||
				return nil, err
 | 
									return nil, err
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -384,6 +384,9 @@ func (this *NodeService) ListEnabledNodesMatch(ctx context.Context, req *pb.List
 | 
				
			|||||||
			NodeRegion:            pbRegion,
 | 
								NodeRegion:            pbRegion,
 | 
				
			||||||
			DnsRoutes:             pbRoutes,
 | 
								DnsRoutes:             pbRoutes,
 | 
				
			||||||
			Level:                 int32(node.Level),
 | 
								Level:                 int32(node.Level),
 | 
				
			||||||
 | 
								OfflineDay:            node.OfflineDay,
 | 
				
			||||||
 | 
								IsBackupForCluster:    node.IsBackupForCluster,
 | 
				
			||||||
 | 
								IsBackupForGroup:      node.IsBackupForGroup,
 | 
				
			||||||
		})
 | 
							})
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -683,6 +686,9 @@ func (this *NodeService) FindEnabledNode(ctx context.Context, req *pb.FindEnable
 | 
				
			|||||||
		DnsRoutes:              pbRoutes,
 | 
							DnsRoutes:              pbRoutes,
 | 
				
			||||||
		EnableIPLists:          node.EnableIPLists,
 | 
							EnableIPLists:          node.EnableIPLists,
 | 
				
			||||||
		ApiNodeAddrsJSON:       node.ApiNodeAddrs,
 | 
							ApiNodeAddrsJSON:       node.ApiNodeAddrs,
 | 
				
			||||||
 | 
							OfflineDay:             node.OfflineDay,
 | 
				
			||||||
 | 
							IsBackupForCluster:     node.IsBackupForCluster,
 | 
				
			||||||
 | 
							IsBackupForGroup:       node.IsBackupForGroup,
 | 
				
			||||||
	}}, nil
 | 
						}}, nil
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -1397,12 +1403,15 @@ func (this *NodeService) FindAllEnabledNodesDNSWithNodeClusterId(ctx context.Con
 | 
				
			|||||||
				continue
 | 
									continue
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
			result = append(result, &pb.NodeDNSInfo{
 | 
								result = append(result, &pb.NodeDNSInfo{
 | 
				
			||||||
				Id:              int64(node.Id),
 | 
									Id:                 int64(node.Id),
 | 
				
			||||||
				Name:            node.Name,
 | 
									Name:               node.Name,
 | 
				
			||||||
				IpAddr:          ip,
 | 
									IpAddr:             ip,
 | 
				
			||||||
				NodeIPAddressId: int64(ipAddress.Id),
 | 
									NodeIPAddressId:    int64(ipAddress.Id),
 | 
				
			||||||
				Routes:          pbRoutes,
 | 
									Routes:             pbRoutes,
 | 
				
			||||||
				NodeClusterId:   req.NodeClusterId,
 | 
									NodeClusterId:      req.NodeClusterId,
 | 
				
			||||||
 | 
									IsBackupForCluster: node.IsBackupForCluster,
 | 
				
			||||||
 | 
									IsBackupForGroup:   node.IsBackupForGroup,
 | 
				
			||||||
 | 
									IsOffline:          node.CheckIsOffline(),
 | 
				
			||||||
			})
 | 
								})
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
@@ -1497,6 +1506,9 @@ func (this *NodeService) FindEnabledNodeDNS(ctx context.Context, req *pb.FindEna
 | 
				
			|||||||
			NodeClusterDNSName: clusterDNS.DnsName,
 | 
								NodeClusterDNSName: clusterDNS.DnsName,
 | 
				
			||||||
			DnsDomainId:        dnsDomainId,
 | 
								DnsDomainId:        dnsDomainId,
 | 
				
			||||||
			DnsDomainName:      dnsDomainName,
 | 
								DnsDomainName:      dnsDomainName,
 | 
				
			||||||
 | 
								IsBackupForCluster: node.IsBackupForCluster,
 | 
				
			||||||
 | 
								IsBackupForGroup:   node.IsBackupForGroup,
 | 
				
			||||||
 | 
								IsOffline:          node.CheckIsOffline(),
 | 
				
			||||||
		},
 | 
							},
 | 
				
			||||||
	}, nil
 | 
						}, nil
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
@@ -2097,6 +2109,9 @@ func (this *NodeService) FindEnabledNodeConfigInfo(ctx context.Context, req *pb.
 | 
				
			|||||||
	// ddos protection
 | 
						// ddos protection
 | 
				
			||||||
	result.HasDDoSProtection = node.HasDDoSProtection()
 | 
						result.HasDDoSProtection = node.HasDDoSProtection()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// schedule
 | 
				
			||||||
 | 
						result.HasScheduleSettings = node.HasScheduleSettings()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return result, nil
 | 
						return result, nil
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										21
									
								
								internal/rpc/services/service_node_ext.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										21
									
								
								internal/rpc/services/service_node_ext.go
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,21 @@
 | 
				
			|||||||
 | 
					// Copyright 2023 Liuxiangchao iwind.liu@gmail.com. All rights reserved. Official site: https://goedge.cn .
 | 
				
			||||||
 | 
					//go:build !plus
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					package services
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import (
 | 
				
			||||||
 | 
						"context"
 | 
				
			||||||
 | 
						"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
 | 
				
			||||||
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func (this *NodeService) FindNodeScheduleInfo(ctx context.Context, req *pb.FindNodeScheduleInfoRequest) (*pb.FindNodeScheduleInfoResponse, error) {
 | 
				
			||||||
 | 
						return nil, this.NotImplementedYet()
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func (this *NodeService) UpdateNodeScheduleInfo(ctx context.Context, req *pb.UpdateNodeScheduleInfoRequest) (*pb.RPCSuccess, error) {
 | 
				
			||||||
 | 
						return nil, this.NotImplementedYet()
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func (this *NodeService) ResetNodeActionStatus(ctx context.Context, req *pb.ResetNodeActionStatusRequest) (*pb.RPCSuccess, error) {
 | 
				
			||||||
 | 
						return nil, this.NotImplementedYet()
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@@ -68,7 +68,7 @@ func (this *ServerDailyStatService) UploadServerDailyStats(ctx context.Context,
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
		// 节点流量
 | 
							// 节点流量
 | 
				
			||||||
		if nodeId > 0 {
 | 
							if nodeId > 0 {
 | 
				
			||||||
			err = stats.SharedNodeTrafficDailyStatDAO.IncreaseDailyStat(tx, clusterId, role, nodeId, timeutil.FormatTime("Ymd", stat.CreatedAt), stat.Bytes, stat.CachedBytes, stat.CountRequests, stat.CountCachedRequests, stat.CountAttackRequests, stat.AttackBytes)
 | 
								err = models.SharedNodeTrafficDailyStatDAO.IncreaseDailyStat(tx, clusterId, role, nodeId, timeutil.FormatTime("Ymd", stat.CreatedAt), stat.Bytes, stat.CachedBytes, stat.CountRequests, stat.CountCachedRequests, stat.CountAttackRequests, stat.AttackBytes)
 | 
				
			||||||
			if err != nil {
 | 
								if err != nil {
 | 
				
			||||||
				return nil, err
 | 
									return nil, err
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -325,7 +325,7 @@ func (this *ServerStatBoardService) ComposeServerStatNodeBoard(ctx context.Conte
 | 
				
			|||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// 当月总流量
 | 
						// 当月总流量
 | 
				
			||||||
	monthlyTrafficStat, err := stats.SharedNodeTrafficDailyStatDAO.SumDailyStat(tx, nodeconfigs.NodeRoleNode, req.NodeId, timeutil.Format("Ym01"), timeutil.Format("Ym31"))
 | 
						monthlyTrafficStat, err := models.SharedNodeTrafficDailyStatDAO.SumDailyStat(tx, nodeconfigs.NodeRoleNode, req.NodeId, timeutil.Format("Ym01"), timeutil.Format("Ym31"))
 | 
				
			||||||
	if err != nil {
 | 
						if err != nil {
 | 
				
			||||||
		return nil, err
 | 
							return nil, err
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
@@ -335,7 +335,7 @@ func (this *ServerStatBoardService) ComposeServerStatNodeBoard(ctx context.Conte
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
	// 按日流量统计
 | 
						// 按日流量统计
 | 
				
			||||||
	var dayFrom = timeutil.Format("Ymd", time.Now().AddDate(0, 0, -14))
 | 
						var dayFrom = timeutil.Format("Ymd", time.Now().AddDate(0, 0, -14))
 | 
				
			||||||
	dailyTrafficStats, err := stats.SharedNodeTrafficDailyStatDAO.FindDailyStats(tx, "node", req.NodeId, dayFrom, timeutil.Format("Ymd"))
 | 
						dailyTrafficStats, err := models.SharedNodeTrafficDailyStatDAO.FindDailyStats(tx, "node", req.NodeId, dayFrom, timeutil.Format("Ymd"))
 | 
				
			||||||
	if err != nil {
 | 
						if err != nil {
 | 
				
			||||||
		return nil, err
 | 
							return nil, err
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -67267,7 +67267,7 @@
 | 
				
			|||||||
      "name": "edgeNSDomains",
 | 
					      "name": "edgeNSDomains",
 | 
				
			||||||
      "engine": "InnoDB",
 | 
					      "engine": "InnoDB",
 | 
				
			||||||
      "charset": "utf8mb4_general_ci",
 | 
					      "charset": "utf8mb4_general_ci",
 | 
				
			||||||
      "definition": "CREATE TABLE `edgeNSDomains` (\n  `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT COMMENT 'ID',\n  `clusterId` int(11) unsigned DEFAULT '0' COMMENT '集群ID',\n  `userId` int(11) unsigned DEFAULT '0' COMMENT '用户ID',\n  `isOn` tinyint(1) unsigned DEFAULT '1' COMMENT '是否启用',\n  `name` varchar(255) DEFAULT NULL COMMENT '域名',\n  `groupIds` json DEFAULT NULL COMMENT '分组ID',\n  `tsig` json DEFAULT NULL COMMENT 'TSIG配置',\n  `verifyTXT` varchar(64) DEFAULT NULL COMMENT '验证用的TXT',\n  `verifyExpiresAt` bigint(11) unsigned DEFAULT '0' COMMENT '验证TXT过期时间',\n  `createdAt` bigint(11) unsigned DEFAULT '0' COMMENT '创建时间',\n  `version` bigint(20) unsigned DEFAULT '0' COMMENT '版本号',\n  `status` varchar(64) DEFAULT 'none' COMMENT '状态:none|verified',\n  `state` tinyint(1) unsigned DEFAULT '1' COMMENT '状态',\n  PRIMARY KEY (`id`),\n  KEY `userId` (`userId`),\n  KEY `name` (`name`),\n  KEY `version` (`version`) USING BTREE,\n  KEY `status` (`status`)\n) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='DNS域名'",
 | 
					      "definition": "CREATE TABLE `edgeNSDomains` (\n  `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT COMMENT 'ID',\n  `clusterId` int(11) unsigned DEFAULT '0' COMMENT '集群ID',\n  `userId` int(11) unsigned DEFAULT '0' COMMENT '用户ID',\n  `isOn` tinyint(1) unsigned DEFAULT '1' COMMENT '是否启用',\n  `name` varchar(255) DEFAULT NULL COMMENT '域名',\n  `groupIds` json DEFAULT NULL COMMENT '分组ID',\n  `tsig` json DEFAULT NULL COMMENT 'TSIG配置',\n  `verifyTXT` varchar(64) DEFAULT NULL COMMENT '验证用的TXT',\n  `verifyExpiresAt` bigint(11) unsigned DEFAULT '0' COMMENT '验证TXT过期时间',\n  `recordsHealthCheck` json DEFAULT NULL COMMENT '记录健康检查设置',\n  `createdAt` bigint(11) unsigned DEFAULT '0' COMMENT '创建时间',\n  `version` bigint(20) unsigned DEFAULT '0' COMMENT '版本号',\n  `status` varchar(64) DEFAULT 'none' COMMENT '状态:none|verified',\n  `state` tinyint(1) unsigned DEFAULT '1' COMMENT '状态',\n  PRIMARY KEY (`id`),\n  KEY `userId` (`userId`),\n  KEY `name` (`name`),\n  KEY `version` (`version`) USING BTREE,\n  KEY `status` (`status`)\n) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='DNS域名'",
 | 
				
			||||||
      "fields": [
 | 
					      "fields": [
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
          "name": "id",
 | 
					          "name": "id",
 | 
				
			||||||
@@ -67305,6 +67305,10 @@
 | 
				
			|||||||
          "name": "verifyExpiresAt",
 | 
					          "name": "verifyExpiresAt",
 | 
				
			||||||
          "definition": "bigint(11) unsigned DEFAULT '0' COMMENT '验证TXT过期时间'"
 | 
					          "definition": "bigint(11) unsigned DEFAULT '0' COMMENT '验证TXT过期时间'"
 | 
				
			||||||
        },
 | 
					        },
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					          "name": "recordsHealthCheck",
 | 
				
			||||||
 | 
					          "definition": "json COMMENT '记录健康检查设置'"
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
          "name": "createdAt",
 | 
					          "name": "createdAt",
 | 
				
			||||||
          "definition": "bigint(11) unsigned DEFAULT '0' COMMENT '创建时间'"
 | 
					          "definition": "bigint(11) unsigned DEFAULT '0' COMMENT '创建时间'"
 | 
				
			||||||
@@ -67653,7 +67657,7 @@
 | 
				
			|||||||
      "name": "edgeNSRecords",
 | 
					      "name": "edgeNSRecords",
 | 
				
			||||||
      "engine": "InnoDB",
 | 
					      "engine": "InnoDB",
 | 
				
			||||||
      "charset": "utf8mb4_general_ci",
 | 
					      "charset": "utf8mb4_general_ci",
 | 
				
			||||||
      "definition": "CREATE TABLE `edgeNSRecords` (\n  `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT COMMENT 'ID',\n  `domainId` int(11) unsigned DEFAULT '0' COMMENT '域名ID',\n  `isOn` tinyint(1) unsigned DEFAULT '1' COMMENT '是否启用',\n  `description` varchar(512) DEFAULT NULL COMMENT '备注',\n  `name` varchar(255) DEFAULT NULL COMMENT '记录名',\n  `type` varchar(32) DEFAULT NULL COMMENT '类型',\n  `value` varchar(4096) DEFAULT NULL COMMENT '值',\n  `mxPriority` int(11) unsigned DEFAULT '0' COMMENT 'MX优先级',\n  `srvPriority` int(11) unsigned DEFAULT '0' COMMENT 'SRV优先级',\n  `srvWeight` int(11) unsigned DEFAULT '0' COMMENT 'SRV权重',\n  `srvPort` int(11) unsigned DEFAULT '0' COMMENT 'SRV端口',\n  `caaFlag` tinyint(1) unsigned DEFAULT '0' COMMENT 'CAA Flag',\n  `caaTag` varchar(32) DEFAULT NULL COMMENT 'CAA TAG',\n  `ttl` int(11) unsigned DEFAULT '0' COMMENT 'TTL(秒)',\n  `weight` int(11) unsigned DEFAULT '0' COMMENT '权重',\n  `routeIds` json DEFAULT NULL COMMENT '线路',\n  `createdAt` bigint(11) unsigned DEFAULT '0' COMMENT '创建时间',\n  `version` bigint(20) unsigned DEFAULT '0' COMMENT '版本号',\n  `state` tinyint(1) unsigned DEFAULT '1' COMMENT '状态',\n  PRIMARY KEY (`id`),\n  KEY `domainId` (`domainId`),\n  KEY `version` (`version`)\n) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='DNS记录'",
 | 
					      "definition": "CREATE TABLE `edgeNSRecords` (\n  `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT COMMENT 'ID',\n  `domainId` int(11) unsigned DEFAULT '0' COMMENT '域名ID',\n  `isOn` tinyint(1) unsigned DEFAULT '1' COMMENT '是否启用',\n  `description` varchar(512) DEFAULT NULL COMMENT '备注',\n  `name` varchar(255) DEFAULT NULL COMMENT '记录名',\n  `type` varchar(32) DEFAULT NULL COMMENT '类型',\n  `value` varchar(4096) DEFAULT NULL COMMENT '值',\n  `mxPriority` int(11) unsigned DEFAULT '0' COMMENT 'MX优先级',\n  `srvPriority` int(11) unsigned DEFAULT '0' COMMENT 'SRV优先级',\n  `srvWeight` int(11) unsigned DEFAULT '0' COMMENT 'SRV权重',\n  `srvPort` int(11) unsigned DEFAULT '0' COMMENT 'SRV端口',\n  `caaFlag` tinyint(1) unsigned DEFAULT '0' COMMENT 'CAA Flag',\n  `caaTag` varchar(32) DEFAULT NULL COMMENT 'CAA TAG',\n  `ttl` int(11) unsigned DEFAULT '0' COMMENT 'TTL(秒)',\n  `weight` int(11) unsigned DEFAULT '0' COMMENT '权重',\n  `routeIds` json DEFAULT NULL COMMENT '线路',\n  `healthCheck` json DEFAULT NULL COMMENT '健康检查配置',\n  `countUp` int(11) unsigned DEFAULT '0' COMMENT '连续上线次数',\n  `countDown` int(11) unsigned DEFAULT '0' COMMENT '连续离线次数',\n  `isUp` tinyint(1) unsigned DEFAULT '1' COMMENT '是否在线',\n  `createdAt` bigint(11) unsigned DEFAULT '0' COMMENT '创建时间',\n  `version` bigint(20) unsigned DEFAULT '0' COMMENT '版本号',\n  `state` tinyint(1) unsigned DEFAULT '1' COMMENT '状态',\n  PRIMARY KEY (`id`),\n  KEY `domainId` (`domainId`),\n  KEY `version` (`version`)\n) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='DNS记录'",
 | 
				
			||||||
      "fields": [
 | 
					      "fields": [
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
          "name": "id",
 | 
					          "name": "id",
 | 
				
			||||||
@@ -67719,6 +67723,22 @@
 | 
				
			|||||||
          "name": "routeIds",
 | 
					          "name": "routeIds",
 | 
				
			||||||
          "definition": "json COMMENT '线路'"
 | 
					          "definition": "json COMMENT '线路'"
 | 
				
			||||||
        },
 | 
					        },
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					          "name": "healthCheck",
 | 
				
			||||||
 | 
					          "definition": "json COMMENT '健康检查配置'"
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					          "name": "countUp",
 | 
				
			||||||
 | 
					          "definition": "int(11) unsigned DEFAULT '0' COMMENT '连续上线次数'"
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					          "name": "countDown",
 | 
				
			||||||
 | 
					          "definition": "int(11) unsigned DEFAULT '0' COMMENT '连续离线次数'"
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					          "name": "isUp",
 | 
				
			||||||
 | 
					          "definition": "tinyint(1) unsigned DEFAULT '1' COMMENT '是否在线'"
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
          "name": "createdAt",
 | 
					          "name": "createdAt",
 | 
				
			||||||
          "definition": "bigint(11) unsigned DEFAULT '0' COMMENT '创建时间'"
 | 
					          "definition": "bigint(11) unsigned DEFAULT '0' COMMENT '创建时间'"
 | 
				
			||||||
@@ -67992,6 +68012,61 @@
 | 
				
			|||||||
      ],
 | 
					      ],
 | 
				
			||||||
      "records": []
 | 
					      "records": []
 | 
				
			||||||
    },
 | 
					    },
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					      "name": "edgeNodeActions",
 | 
				
			||||||
 | 
					      "engine": "InnoDB",
 | 
				
			||||||
 | 
					      "charset": "utf8mb4_general_ci",
 | 
				
			||||||
 | 
					      "definition": "CREATE TABLE `edgeNodeActions` (\n  `id` bigint(11) unsigned NOT NULL AUTO_INCREMENT COMMENT 'ID',\n  `nodeId` bigint(11) unsigned DEFAULT '0' COMMENT '节点ID',\n  `role` varchar(16) DEFAULT NULL COMMENT '角色',\n  `isOn` tinyint(1) unsigned DEFAULT '1' COMMENT '是否启用',\n  `conds` json DEFAULT NULL COMMENT '条件',\n  `action` json DEFAULT NULL COMMENT '动作',\n  `duration` json DEFAULT NULL COMMENT '持续时间',\n  `order` int(11) unsigned DEFAULT '0' COMMENT '排序',\n  `state` tinyint(1) unsigned DEFAULT '1' COMMENT '状态',\n  PRIMARY KEY (`id`),\n  KEY `nodeId` (`nodeId`)\n) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='节点智能调度设置'",
 | 
				
			||||||
 | 
					      "fields": [
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					          "name": "id",
 | 
				
			||||||
 | 
					          "definition": "bigint(11) unsigned auto_increment COMMENT 'ID'"
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					          "name": "nodeId",
 | 
				
			||||||
 | 
					          "definition": "bigint(11) unsigned DEFAULT '0' COMMENT '节点ID'"
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					          "name": "role",
 | 
				
			||||||
 | 
					          "definition": "varchar(16) COMMENT '角色'"
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					          "name": "isOn",
 | 
				
			||||||
 | 
					          "definition": "tinyint(1) unsigned DEFAULT '1' COMMENT '是否启用'"
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					          "name": "conds",
 | 
				
			||||||
 | 
					          "definition": "json COMMENT '条件'"
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					          "name": "action",
 | 
				
			||||||
 | 
					          "definition": "json COMMENT '动作'"
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					          "name": "duration",
 | 
				
			||||||
 | 
					          "definition": "json COMMENT '持续时间'"
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					          "name": "order",
 | 
				
			||||||
 | 
					          "definition": "int(11) unsigned DEFAULT '0' COMMENT '排序'"
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					          "name": "state",
 | 
				
			||||||
 | 
					          "definition": "tinyint(1) unsigned DEFAULT '1' COMMENT '状态'"
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					      ],
 | 
				
			||||||
 | 
					      "indexes": [
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					          "name": "PRIMARY",
 | 
				
			||||||
 | 
					          "definition": "UNIQUE KEY `PRIMARY` (`id`) USING BTREE"
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					          "name": "nodeId",
 | 
				
			||||||
 | 
					          "definition": "KEY `nodeId` (`nodeId`) USING BTREE"
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					      ],
 | 
				
			||||||
 | 
					      "records": []
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
      "name": "edgeNodeClusterFirewallActions",
 | 
					      "name": "edgeNodeClusterFirewallActions",
 | 
				
			||||||
      "engine": "InnoDB",
 | 
					      "engine": "InnoDB",
 | 
				
			||||||
@@ -69041,7 +69116,7 @@
 | 
				
			|||||||
      "name": "edgeNodeThresholds",
 | 
					      "name": "edgeNodeThresholds",
 | 
				
			||||||
      "engine": "InnoDB",
 | 
					      "engine": "InnoDB",
 | 
				
			||||||
      "charset": "utf8mb4_general_ci",
 | 
					      "charset": "utf8mb4_general_ci",
 | 
				
			||||||
      "definition": "CREATE TABLE `edgeNodeThresholds` (\n  `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT COMMENT 'ID',\n  `role` varchar(32) DEFAULT NULL COMMENT '节点角色',\n  `clusterId` int(11) unsigned DEFAULT '0' COMMENT '集群ID',\n  `nodeId` int(11) unsigned DEFAULT '0' COMMENT '节点ID',\n  `isOn` tinyint(1) unsigned DEFAULT '1' COMMENT '是否启用',\n  `item` varchar(255) DEFAULT NULL COMMENT '监控项',\n  `param` varchar(255) DEFAULT NULL COMMENT '参数',\n  `operator` varchar(255) DEFAULT NULL COMMENT '操作符',\n  `value` json DEFAULT NULL COMMENT '对比值',\n  `message` varchar(512) DEFAULT NULL COMMENT '消息内容',\n  `notifyDuration` int(11) unsigned DEFAULT '0' COMMENT '通知间隔(单位分钟)',\n  `notifiedAt` int(11) unsigned DEFAULT '0' COMMENT '上次通知时间',\n  `duration` int(11) unsigned DEFAULT '0' COMMENT '时间段',\n  `durationUnit` varchar(16) DEFAULT NULL COMMENT '时间段单位',\n  `sumMethod` varchar(32) DEFAULT NULL COMMENT '聚合方法',\n  `order` int(11) unsigned DEFAULT '0' COMMENT '排序',\n  `state` tinyint(1) unsigned DEFAULT '1' COMMENT '状态',\n  PRIMARY KEY (`id`),\n  KEY `nodeId` (`nodeId`),\n  KEY `clusterId` (`clusterId`)\n) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='集群阈值设置'",
 | 
					      "definition": "CREATE TABLE `edgeNodeThresholds` (\n  `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT COMMENT 'ID',\n  `role` varchar(32) DEFAULT NULL COMMENT '节点角色',\n  `clusterId` int(11) unsigned DEFAULT '0' COMMENT '集群ID',\n  `nodeId` int(11) unsigned DEFAULT '0' COMMENT '节点ID',\n  `isOn` tinyint(1) unsigned DEFAULT '1' COMMENT '是否启用',\n  `item` varchar(255) DEFAULT NULL COMMENT '监控项',\n  `param` varchar(255) DEFAULT NULL COMMENT '参数',\n  `operator` varchar(255) DEFAULT NULL COMMENT '操作符',\n  `value` json DEFAULT NULL COMMENT '对比值',\n  `message` varchar(512) DEFAULT NULL COMMENT '消息内容',\n  `notifyDuration` int(11) unsigned DEFAULT '0' COMMENT '通知间隔(单位分钟)',\n  `notifiedAt` int(11) unsigned DEFAULT '0' COMMENT '上次通知时间',\n  `duration` int(11) unsigned DEFAULT '0' COMMENT '时间段',\n  `durationUnit` varchar(16) DEFAULT NULL COMMENT '时间段单位',\n  `sumMethod` varchar(32) DEFAULT NULL COMMENT '聚合方法',\n  `order` int(11) unsigned DEFAULT '0' COMMENT '排序',\n  `state` tinyint(1) unsigned DEFAULT '1' COMMENT '状态',\n  PRIMARY KEY (`id`),\n  KEY `nodeId` (`nodeId`),\n  KEY `clusterId` (`clusterId`)\n) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='节点监控阈值设置'",
 | 
				
			||||||
      "fields": [
 | 
					      "fields": [
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
          "name": "id",
 | 
					          "name": "id",
 | 
				
			||||||
@@ -69345,7 +69420,7 @@
 | 
				
			|||||||
      "name": "edgeNodes",
 | 
					      "name": "edgeNodes",
 | 
				
			||||||
      "engine": "InnoDB",
 | 
					      "engine": "InnoDB",
 | 
				
			||||||
      "charset": "utf8mb4_general_ci",
 | 
					      "charset": "utf8mb4_general_ci",
 | 
				
			||||||
      "definition": "CREATE TABLE `edgeNodes` (\n  `id` int(11) unsigned NOT NULL AUTO_INCREMENT COMMENT 'ID',\n  `adminId` int(11) unsigned DEFAULT '0' COMMENT '管理员ID',\n  `userId` int(11) unsigned DEFAULT '0' COMMENT '用户ID',\n  `level` tinyint(1) unsigned DEFAULT '1' COMMENT '级别',\n  `lnAddrs` json DEFAULT NULL COMMENT 'Ln级别访问地址',\n  `isOn` tinyint(1) unsigned DEFAULT '1' COMMENT '是否启用',\n  `isUp` tinyint(1) unsigned DEFAULT '1' COMMENT '是否在线',\n  `countUp` int(11) unsigned DEFAULT '0' COMMENT '连续在线次数',\n  `countDown` int(11) unsigned DEFAULT '0' COMMENT '连续下线次数',\n  `isActive` tinyint(1) unsigned DEFAULT '1' COMMENT '是否活跃',\n  `inactiveNotifiedAt` bigint(11) unsigned DEFAULT '0' COMMENT '离线通知时间',\n  `uniqueId` varchar(32) DEFAULT NULL COMMENT '节点ID',\n  `secret` varchar(32) DEFAULT NULL COMMENT '密钥',\n  `name` varchar(255) DEFAULT NULL COMMENT '节点名',\n  `code` varchar(255) DEFAULT NULL COMMENT '代号',\n  `clusterId` int(11) unsigned DEFAULT '0' COMMENT '主集群ID',\n  `secondaryClusterIds` json DEFAULT NULL COMMENT '从集群ID',\n  `regionId` int(11) unsigned DEFAULT '0' COMMENT '区域ID',\n  `groupId` int(11) unsigned DEFAULT '0' COMMENT '分组ID',\n  `createdAt` bigint(11) unsigned DEFAULT '0' COMMENT '创建时间',\n  `status` json DEFAULT NULL COMMENT '最新的状态',\n  `version` int(11) unsigned DEFAULT '0' COMMENT '当前版本号',\n  `latestVersion` int(11) unsigned DEFAULT '0' COMMENT '最后版本号',\n  `installDir` varchar(512) DEFAULT NULL COMMENT '安装目录',\n  `isInstalled` tinyint(1) unsigned DEFAULT '0' COMMENT '是否已安装',\n  `installStatus` json DEFAULT NULL COMMENT '安装状态',\n  `state` tinyint(1) unsigned DEFAULT '1' COMMENT '状态',\n  `connectedAPINodes` json DEFAULT NULL COMMENT '当前连接的API节点',\n  `maxCPU` int(4) unsigned DEFAULT '0' COMMENT '可以使用的最多CPU',\n  `maxThreads` int(11) unsigned DEFAULT '0' COMMENT '最大线程数',\n  `ddosProtection` json DEFAULT NULL COMMENT 'DDOS配置',\n  `dnsRoutes` json DEFAULT NULL COMMENT 'DNS线路设置',\n  `maxCacheDiskCapacity` json DEFAULT NULL COMMENT '硬盘缓存容量',\n  `maxCacheMemoryCapacity` json DEFAULT NULL COMMENT '内存缓存容量',\n  `cacheDiskDir` varchar(255) DEFAULT NULL COMMENT '主缓存目录',\n  `cacheDiskSubDirs` json DEFAULT NULL COMMENT '其他缓存目录',\n  `dnsResolver` json DEFAULT NULL COMMENT 'DNS解析器',\n  `enableIPLists` tinyint(1) unsigned DEFAULT '1' COMMENT '启用IP名单',\n  `apiNodeAddrs` json DEFAULT NULL COMMENT 'API节点地址',\n  PRIMARY KEY (`id`),\n  KEY `uniqueId` (`uniqueId`),\n  KEY `clusterId` (`clusterId`),\n  KEY `groupId` (`groupId`),\n  KEY `regionId` (`regionId`)\n) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='节点'",
 | 
					      "definition": "CREATE TABLE `edgeNodes` (\n  `id` int(11) unsigned NOT NULL AUTO_INCREMENT COMMENT 'ID',\n  `adminId` int(11) unsigned DEFAULT '0' COMMENT '管理员ID',\n  `userId` int(11) unsigned DEFAULT '0' COMMENT '用户ID',\n  `level` tinyint(1) unsigned DEFAULT '1' COMMENT '级别',\n  `lnAddrs` json DEFAULT NULL COMMENT 'Ln级别访问地址',\n  `isOn` tinyint(1) unsigned DEFAULT '1' COMMENT '是否启用',\n  `isUp` tinyint(1) unsigned DEFAULT '1' COMMENT '是否在线',\n  `countUp` int(11) unsigned DEFAULT '0' COMMENT '连续在线次数',\n  `countDown` int(11) unsigned DEFAULT '0' COMMENT '连续下线次数',\n  `isActive` tinyint(1) unsigned DEFAULT '1' COMMENT '是否活跃',\n  `inactiveNotifiedAt` bigint(11) unsigned DEFAULT '0' COMMENT '离线通知时间',\n  `uniqueId` varchar(32) DEFAULT NULL COMMENT '节点ID',\n  `secret` varchar(32) DEFAULT NULL COMMENT '密钥',\n  `name` varchar(255) DEFAULT NULL COMMENT '节点名',\n  `code` varchar(255) DEFAULT NULL COMMENT '代号',\n  `clusterId` int(11) unsigned DEFAULT '0' COMMENT '主集群ID',\n  `secondaryClusterIds` json DEFAULT NULL COMMENT '从集群ID',\n  `regionId` int(11) unsigned DEFAULT '0' COMMENT '区域ID',\n  `groupId` int(11) unsigned DEFAULT '0' COMMENT '分组ID',\n  `createdAt` bigint(11) unsigned DEFAULT '0' COMMENT '创建时间',\n  `status` json DEFAULT NULL COMMENT '最新的状态',\n  `version` int(11) unsigned DEFAULT '0' COMMENT '当前版本号',\n  `latestVersion` int(11) unsigned DEFAULT '0' COMMENT '最后版本号',\n  `installDir` varchar(512) DEFAULT NULL COMMENT '安装目录',\n  `isInstalled` tinyint(1) unsigned DEFAULT '0' COMMENT '是否已安装',\n  `installStatus` json DEFAULT NULL COMMENT '安装状态',\n  `state` tinyint(1) unsigned DEFAULT '1' COMMENT '状态',\n  `connectedAPINodes` json DEFAULT NULL COMMENT '当前连接的API节点',\n  `maxCPU` int(4) unsigned DEFAULT '0' COMMENT '可以使用的最多CPU',\n  `maxThreads` int(11) unsigned DEFAULT '0' COMMENT '最大线程数',\n  `ddosProtection` json DEFAULT NULL COMMENT 'DDOS配置',\n  `dnsRoutes` json DEFAULT NULL COMMENT 'DNS线路设置',\n  `maxCacheDiskCapacity` json DEFAULT NULL COMMENT '硬盘缓存容量',\n  `maxCacheMemoryCapacity` json DEFAULT NULL COMMENT '内存缓存容量',\n  `cacheDiskDir` varchar(255) DEFAULT NULL COMMENT '主缓存目录',\n  `cacheDiskSubDirs` json DEFAULT NULL COMMENT '其他缓存目录',\n  `dnsResolver` json DEFAULT NULL COMMENT 'DNS解析器',\n  `enableIPLists` tinyint(1) unsigned DEFAULT '1' COMMENT '启用IP名单',\n  `apiNodeAddrs` json DEFAULT NULL COMMENT 'API节点地址',\n  `offlineDay` varchar(8) DEFAULT NULL COMMENT '下线日期YYYYMMDD',\n  `offlineIsNotified` tinyint(1) unsigned DEFAULT '0' COMMENT '下线是否已通知',\n  `isBackupForCluster` tinyint(1) unsigned DEFAULT '0' COMMENT '是否为集群备用节点',\n  `isBackupForGroup` tinyint(1) unsigned DEFAULT '0' COMMENT '是否为分组备用节点',\n  `backupIPs` json DEFAULT NULL COMMENT '备用IP',\n  `actionStatus` json DEFAULT NULL COMMENT '当前动作配置',\n  PRIMARY KEY (`id`),\n  KEY `uniqueId` (`uniqueId`),\n  KEY `clusterId` (`clusterId`),\n  KEY `groupId` (`groupId`),\n  KEY `regionId` (`regionId`)\n) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='节点'",
 | 
				
			||||||
      "fields": [
 | 
					      "fields": [
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
          "name": "id",
 | 
					          "name": "id",
 | 
				
			||||||
@@ -69502,6 +69577,30 @@
 | 
				
			|||||||
        {
 | 
					        {
 | 
				
			||||||
          "name": "apiNodeAddrs",
 | 
					          "name": "apiNodeAddrs",
 | 
				
			||||||
          "definition": "json COMMENT 'API节点地址'"
 | 
					          "definition": "json COMMENT 'API节点地址'"
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					          "name": "offlineDay",
 | 
				
			||||||
 | 
					          "definition": "varchar(8) COMMENT '下线日期YYYYMMDD'"
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					          "name": "offlineIsNotified",
 | 
				
			||||||
 | 
					          "definition": "tinyint(1) unsigned DEFAULT '0' COMMENT '下线是否已通知'"
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					          "name": "isBackupForCluster",
 | 
				
			||||||
 | 
					          "definition": "tinyint(1) unsigned DEFAULT '0' COMMENT '是否为集群备用节点'"
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					          "name": "isBackupForGroup",
 | 
				
			||||||
 | 
					          "definition": "tinyint(1) unsigned DEFAULT '0' COMMENT '是否为分组备用节点'"
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					          "name": "backupIPs",
 | 
				
			||||||
 | 
					          "definition": "json COMMENT '备用IP'"
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					          "name": "actionStatus",
 | 
				
			||||||
 | 
					          "definition": "json COMMENT '当前动作配置'"
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
      ],
 | 
					      ],
 | 
				
			||||||
      "indexes": [
 | 
					      "indexes": [
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -87,8 +87,8 @@ func (this *DNSTaskExecutor) loop() error {
 | 
				
			|||||||
					return err
 | 
										return err
 | 
				
			||||||
				}
 | 
									}
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
		case dnsmodels.DNSTaskTypeClusterChange:
 | 
							case dnsmodels.DNSTaskTypeClusterChange, dnsmodels.DNSTaskTypeClusterNodesChange:
 | 
				
			||||||
			err = this.doCluster(taskId, taskVersion, int64(task.ClusterId))
 | 
								err = this.doCluster(taskId, taskVersion, int64(task.ClusterId), task.Type == dnsmodels.DNSTaskTypeClusterNodesChange)
 | 
				
			||||||
			if err != nil {
 | 
								if err != nil {
 | 
				
			||||||
				err = dnsmodels.SharedDNSTaskDAO.UpdateDNSTaskError(nil, taskId, err.Error())
 | 
									err = dnsmodels.SharedDNSTaskDAO.UpdateDNSTaskError(nil, taskId, err.Error())
 | 
				
			||||||
				if err != nil {
 | 
									if err != nil {
 | 
				
			||||||
@@ -300,7 +300,7 @@ func (this *DNSTaskExecutor) doNode(taskId int64, taskVersion int64, nodeCluster
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
	// 转交给cluster统一处理
 | 
						// 转交给cluster统一处理
 | 
				
			||||||
	if nodeClusterId > 0 {
 | 
						if nodeClusterId > 0 {
 | 
				
			||||||
		err = dnsmodels.SharedDNSTaskDAO.CreateClusterTask(tx, nodeClusterId, dnsmodels.DNSTaskTypeClusterChange)
 | 
							err = dnsmodels.SharedDNSTaskDAO.CreateClusterTask(tx, nodeClusterId, dnsmodels.DNSTaskTypeClusterNodesChange)
 | 
				
			||||||
		if err != nil {
 | 
							if err != nil {
 | 
				
			||||||
			return err
 | 
								return err
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
@@ -310,7 +310,7 @@ func (this *DNSTaskExecutor) doNode(taskId int64, taskVersion int64, nodeCluster
 | 
				
			|||||||
			return err
 | 
								return err
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		for _, clusterId := range clusterIds {
 | 
							for _, clusterId := range clusterIds {
 | 
				
			||||||
			err = dnsmodels.SharedDNSTaskDAO.CreateClusterTask(tx, clusterId, dnsmodels.DNSTaskTypeClusterChange)
 | 
								err = dnsmodels.SharedDNSTaskDAO.CreateClusterTask(tx, clusterId, dnsmodels.DNSTaskTypeClusterNodesChange)
 | 
				
			||||||
			if err != nil {
 | 
								if err != nil {
 | 
				
			||||||
				return err
 | 
									return err
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
@@ -323,8 +323,8 @@ func (this *DNSTaskExecutor) doNode(taskId int64, taskVersion int64, nodeCluster
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// 修改集群相关记录
 | 
					// 修改集群相关记录
 | 
				
			||||||
func (this *DNSTaskExecutor) doCluster(taskId int64, taskVersion int64, clusterId int64) error {
 | 
					func (this *DNSTaskExecutor) doCluster(taskId int64, taskVersion int64, clusterId int64, nodesOnly bool) error {
 | 
				
			||||||
	isOk := false
 | 
						var isOk = false
 | 
				
			||||||
	defer func() {
 | 
						defer func() {
 | 
				
			||||||
		if isOk {
 | 
							if isOk {
 | 
				
			||||||
			err := dnsmodels.SharedDNSTaskDAO.UpdateDNSTaskDone(nil, taskId, taskVersion)
 | 
								err := dnsmodels.SharedDNSTaskDAO.UpdateDNSTaskDone(nil, taskId, taskVersion)
 | 
				
			||||||
@@ -378,6 +378,14 @@ func (this *DNSTaskExecutor) doCluster(taskId int64, taskVersion int64, clusterI
 | 
				
			|||||||
	var isChanged = false
 | 
						var isChanged = false
 | 
				
			||||||
	var addingNodeRecordKeysMap = map[string]bool{} // clusterDnsName_type_ip_route
 | 
						var addingNodeRecordKeysMap = map[string]bool{} // clusterDnsName_type_ip_route
 | 
				
			||||||
	for _, node := range nodes {
 | 
						for _, node := range nodes {
 | 
				
			||||||
 | 
							shouldSkip, shouldOverwrite, ipAddressesStrings, err := models.SharedNodeDAO.CheckNodeIPAddresses(tx, node)
 | 
				
			||||||
 | 
							if err != nil {
 | 
				
			||||||
 | 
								return err
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							if shouldSkip {
 | 
				
			||||||
 | 
								continue
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		routes, err := node.DNSRouteCodesForDomainId(domainId)
 | 
							routes, err := node.DNSRouteCodesForDomainId(domainId)
 | 
				
			||||||
		if err != nil {
 | 
							if err != nil {
 | 
				
			||||||
			return err
 | 
								return err
 | 
				
			||||||
@@ -387,26 +395,36 @@ func (this *DNSTaskExecutor) doCluster(taskId int64, taskVersion int64, clusterI
 | 
				
			|||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		// 所有的IP记录
 | 
							// 所有的IP记录
 | 
				
			||||||
		ipAddresses, err := models.SharedNodeIPAddressDAO.FindAllEnabledAddressesWithNode(tx, int64(node.Id), nodeconfigs.NodeRoleNode)
 | 
							if !shouldOverwrite {
 | 
				
			||||||
		if err != nil {
 | 
								ipAddresses, err := models.SharedNodeIPAddressDAO.FindAllEnabledAddressesWithNode(tx, int64(node.Id), nodeconfigs.NodeRoleNode)
 | 
				
			||||||
			return err
 | 
								if err != nil {
 | 
				
			||||||
 | 
									return err
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
								if len(ipAddresses) == 0 {
 | 
				
			||||||
 | 
									continue
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
								for _, ipAddress := range ipAddresses {
 | 
				
			||||||
 | 
									// 检查专属节点
 | 
				
			||||||
 | 
									if !ipAddress.IsValidInCluster(clusterId) {
 | 
				
			||||||
 | 
										continue
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
									var ip = ipAddress.DNSIP()
 | 
				
			||||||
 | 
									if len(ip) == 0 || !ipAddress.CanAccess || !ipAddress.IsUp || !ipAddress.IsOn {
 | 
				
			||||||
 | 
										continue
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
									if net.ParseIP(ip) == nil {
 | 
				
			||||||
 | 
										continue
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
									ipAddressesStrings = append(ipAddressesStrings, ip)
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		if len(ipAddresses) == 0 {
 | 
					
 | 
				
			||||||
 | 
							if len(ipAddressesStrings) == 0 {
 | 
				
			||||||
			continue
 | 
								continue
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		for _, ipAddress := range ipAddresses {
 | 
					 | 
				
			||||||
			// 检查专属节点
 | 
					 | 
				
			||||||
			if !ipAddress.IsValidInCluster(clusterId) {
 | 
					 | 
				
			||||||
				continue
 | 
					 | 
				
			||||||
			}
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
			var ip = ipAddress.DNSIP()
 | 
							for _, ip := range ipAddressesStrings {
 | 
				
			||||||
			if len(ip) == 0 || !ipAddress.CanAccess || !ipAddress.IsUp || !ipAddress.IsOn {
 | 
					 | 
				
			||||||
				continue
 | 
					 | 
				
			||||||
			}
 | 
					 | 
				
			||||||
			if net.ParseIP(ip) == nil {
 | 
					 | 
				
			||||||
				continue
 | 
					 | 
				
			||||||
			}
 | 
					 | 
				
			||||||
			for _, route := range routes {
 | 
								for _, route := range routes {
 | 
				
			||||||
				var key = route + "@" + ip
 | 
									var key = route + "@" + ip
 | 
				
			||||||
				_, ok := oldRecordsMap[key]
 | 
									_, ok := oldRecordsMap[key]
 | 
				
			||||||
@@ -456,80 +474,82 @@ func (this *DNSTaskExecutor) doCluster(taskId int64, taskVersion int64, clusterI
 | 
				
			|||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// 服务域名
 | 
						// 服务域名
 | 
				
			||||||
	servers, err := models.SharedServerDAO.FindAllServersDNSWithClusterId(tx, clusterId)
 | 
						if !nodesOnly {
 | 
				
			||||||
	if err != nil {
 | 
							servers, err := models.SharedServerDAO.FindAllServersDNSWithClusterId(tx, clusterId)
 | 
				
			||||||
		return err
 | 
							if err != nil {
 | 
				
			||||||
	}
 | 
								return err
 | 
				
			||||||
	serverRecords := []*dnstypes.Record{}             // 之所以用数组再存一遍,是因为dnsName可能会重复
 | 
					 | 
				
			||||||
	serverRecordsMap := map[string]*dnstypes.Record{} // dnsName => *Record
 | 
					 | 
				
			||||||
	for _, record := range records {
 | 
					 | 
				
			||||||
		if record.Type == dnstypes.RecordTypeCNAME && record.Value == clusterDomain+"." {
 | 
					 | 
				
			||||||
			serverRecords = append(serverRecords, record)
 | 
					 | 
				
			||||||
			serverRecordsMap[record.Name] = record
 | 
					 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	}
 | 
							serverRecords := []*dnstypes.Record{}             // 之所以用数组再存一遍,是因为dnsName可能会重复
 | 
				
			||||||
 | 
							serverRecordsMap := map[string]*dnstypes.Record{} // dnsName => *Record
 | 
				
			||||||
	// 新增的域名
 | 
							for _, record := range records {
 | 
				
			||||||
	var serverDNSNames = []string{}
 | 
								if record.Type == dnstypes.RecordTypeCNAME && record.Value == clusterDomain+"." {
 | 
				
			||||||
	for _, server := range servers {
 | 
									serverRecords = append(serverRecords, record)
 | 
				
			||||||
		var dnsName = server.DnsName
 | 
									serverRecordsMap[record.Name] = record
 | 
				
			||||||
		if len(dnsName) == 0 {
 | 
					 | 
				
			||||||
			continue
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
		serverDNSNames = append(serverDNSNames, dnsName)
 | 
					 | 
				
			||||||
		_, ok := serverRecordsMap[dnsName]
 | 
					 | 
				
			||||||
		if !ok {
 | 
					 | 
				
			||||||
			isChanged = true
 | 
					 | 
				
			||||||
			err = manager.AddRecord(domain, &dnstypes.Record{
 | 
					 | 
				
			||||||
				Id:    "",
 | 
					 | 
				
			||||||
				Name:  dnsName,
 | 
					 | 
				
			||||||
				Type:  dnstypes.RecordTypeCNAME,
 | 
					 | 
				
			||||||
				Value: clusterDomain + ".",
 | 
					 | 
				
			||||||
				Route: "", // 注意这里为空,需要在执行过程中获取默认值
 | 
					 | 
				
			||||||
				TTL:   ttl,
 | 
					 | 
				
			||||||
			})
 | 
					 | 
				
			||||||
			if err != nil {
 | 
					 | 
				
			||||||
				return err
 | 
					 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// 自动设置的CNAME
 | 
							// 新增的域名
 | 
				
			||||||
	var cnameRecords = []string{}
 | 
							var serverDNSNames = []string{}
 | 
				
			||||||
	if dnsConfig != nil {
 | 
							for _, server := range servers {
 | 
				
			||||||
		cnameRecords = dnsConfig.CNAMERecords
 | 
								var dnsName = server.DnsName
 | 
				
			||||||
	}
 | 
								if len(dnsName) == 0 {
 | 
				
			||||||
	for _, cnameRecord := range cnameRecords {
 | 
									continue
 | 
				
			||||||
		// 如果记录已存在,则跳过
 | 
								}
 | 
				
			||||||
		if lists.ContainsString(serverDNSNames, cnameRecord) {
 | 
								serverDNSNames = append(serverDNSNames, dnsName)
 | 
				
			||||||
			continue
 | 
								_, ok := serverRecordsMap[dnsName]
 | 
				
			||||||
		}
 | 
								if !ok {
 | 
				
			||||||
 | 
									isChanged = true
 | 
				
			||||||
		serverDNSNames = append(serverDNSNames, cnameRecord)
 | 
									err = manager.AddRecord(domain, &dnstypes.Record{
 | 
				
			||||||
		_, ok := serverRecordsMap[cnameRecord]
 | 
										Id:    "",
 | 
				
			||||||
		if !ok {
 | 
										Name:  dnsName,
 | 
				
			||||||
			isChanged = true
 | 
										Type:  dnstypes.RecordTypeCNAME,
 | 
				
			||||||
			err = manager.AddRecord(domain, &dnstypes.Record{
 | 
										Value: clusterDomain + ".",
 | 
				
			||||||
				Id:    "",
 | 
										Route: "", // 注意这里为空,需要在执行过程中获取默认值
 | 
				
			||||||
				Name:  cnameRecord,
 | 
										TTL:   ttl,
 | 
				
			||||||
				Type:  dnstypes.RecordTypeCNAME,
 | 
									})
 | 
				
			||||||
				Value: clusterDomain + ".",
 | 
									if err != nil {
 | 
				
			||||||
				Route: "", // 注意这里为空,需要在执行过程中获取默认值
 | 
										return err
 | 
				
			||||||
				TTL:   ttl,
 | 
									}
 | 
				
			||||||
			})
 | 
					 | 
				
			||||||
			if err != nil {
 | 
					 | 
				
			||||||
				return err
 | 
					 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// 多余的域名
 | 
							// 自动设置的CNAME
 | 
				
			||||||
	for _, record := range serverRecords {
 | 
							var cnameRecords = []string{}
 | 
				
			||||||
		if !lists.ContainsString(serverDNSNames, record.Name) {
 | 
							if dnsConfig != nil {
 | 
				
			||||||
			isChanged = true
 | 
								cnameRecords = dnsConfig.CNAMERecords
 | 
				
			||||||
			err = manager.DeleteRecord(domain, record)
 | 
							}
 | 
				
			||||||
			if err != nil {
 | 
							for _, cnameRecord := range cnameRecords {
 | 
				
			||||||
				return err
 | 
								// 如果记录已存在,则跳过
 | 
				
			||||||
 | 
								if lists.ContainsString(serverDNSNames, cnameRecord) {
 | 
				
			||||||
 | 
									continue
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								serverDNSNames = append(serverDNSNames, cnameRecord)
 | 
				
			||||||
 | 
								_, ok := serverRecordsMap[cnameRecord]
 | 
				
			||||||
 | 
								if !ok {
 | 
				
			||||||
 | 
									isChanged = true
 | 
				
			||||||
 | 
									err = manager.AddRecord(domain, &dnstypes.Record{
 | 
				
			||||||
 | 
										Id:    "",
 | 
				
			||||||
 | 
										Name:  cnameRecord,
 | 
				
			||||||
 | 
										Type:  dnstypes.RecordTypeCNAME,
 | 
				
			||||||
 | 
										Value: clusterDomain + ".",
 | 
				
			||||||
 | 
										Route: "", // 注意这里为空,需要在执行过程中获取默认值
 | 
				
			||||||
 | 
										TTL:   ttl,
 | 
				
			||||||
 | 
									})
 | 
				
			||||||
 | 
									if err != nil {
 | 
				
			||||||
 | 
										return err
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							// 多余的域名
 | 
				
			||||||
 | 
							for _, record := range serverRecords {
 | 
				
			||||||
 | 
								if !lists.ContainsString(serverDNSNames, record.Name) {
 | 
				
			||||||
 | 
									isChanged = true
 | 
				
			||||||
 | 
									err = manager.DeleteRecord(domain, record)
 | 
				
			||||||
 | 
									if err != nil {
 | 
				
			||||||
 | 
										return err
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,3 +1,5 @@
 | 
				
			|||||||
 | 
					//go:build !plus
 | 
				
			||||||
 | 
					
 | 
				
			||||||
package tasks_test
 | 
					package tasks_test
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import (
 | 
					import (
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -127,7 +127,7 @@ func (this *HealthCheckClusterTask) Loop() error {
 | 
				
			|||||||
			if err != nil {
 | 
								if err != nil {
 | 
				
			||||||
				return err
 | 
									return err
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
			var message = "有" + numberutils.FormatInt(len(failedResults)) + "个节点在健康检查中出现问题"
 | 
								var message = "有" + numberutils.FormatInt(len(failedResults)) + "个节点IP在健康检查中出现问题"
 | 
				
			||||||
			err = models.NewMessageDAO().CreateClusterMessage(nil, nodeconfigs.NodeRoleNode, this.clusterId, models.MessageTypeHealthCheckFailed, models.MessageLevelError, message, message, failedResultsJSON)
 | 
								err = models.NewMessageDAO().CreateClusterMessage(nil, nodeconfigs.NodeRoleNode, this.clusterId, models.MessageTypeHealthCheckFailed, models.MessageLevelError, message, message, failedResultsJSON)
 | 
				
			||||||
			if err != nil {
 | 
								if err != nil {
 | 
				
			||||||
				return err
 | 
									return err
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -16,6 +16,7 @@ import (
 | 
				
			|||||||
	"github.com/iwind/TeaGo/lists"
 | 
						"github.com/iwind/TeaGo/lists"
 | 
				
			||||||
	"github.com/iwind/TeaGo/maps"
 | 
						"github.com/iwind/TeaGo/maps"
 | 
				
			||||||
	"github.com/iwind/TeaGo/types"
 | 
						"github.com/iwind/TeaGo/types"
 | 
				
			||||||
 | 
						timeutil "github.com/iwind/TeaGo/utils/time"
 | 
				
			||||||
	"net"
 | 
						"net"
 | 
				
			||||||
	"net/http"
 | 
						"net/http"
 | 
				
			||||||
	"strconv"
 | 
						"strconv"
 | 
				
			||||||
@@ -66,7 +67,7 @@ func (this *HealthCheckExecutor) Run() ([]*HealthCheckResult, error) {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
	var tx *dbs.Tx
 | 
						var tx *dbs.Tx
 | 
				
			||||||
	for _, node := range nodes {
 | 
						for _, node := range nodes {
 | 
				
			||||||
		if !node.IsOn {
 | 
							if !node.IsOn || node.IsBackupForCluster || node.IsBackupForGroup || (len(node.OfflineDay) > 0 && node.OfflineDay < timeutil.Format("Ymd")) {
 | 
				
			||||||
			continue
 | 
								continue
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -194,6 +195,15 @@ func (this *HealthCheckExecutor) runNode(healthCheckConfig *serverconfigs.Health
 | 
				
			|||||||
					this.logErr("HealthCheckExecutor", err.Error())
 | 
										this.logErr("HealthCheckExecutor", err.Error())
 | 
				
			||||||
					return
 | 
										return
 | 
				
			||||||
				}
 | 
									}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
									// 触发节点动作
 | 
				
			||||||
 | 
									if !result.IsOk {
 | 
				
			||||||
 | 
										err := this.fireNodeActions(int64(result.Node.Id))
 | 
				
			||||||
 | 
										if err != nil {
 | 
				
			||||||
 | 
											this.logErr("HealthCheckExecutor", err.Error())
 | 
				
			||||||
 | 
										}
 | 
				
			||||||
 | 
										return
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			// 触发阈值
 | 
								// 触发阈值
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										9
									
								
								internal/tasks/health_check_executor_ext.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										9
									
								
								internal/tasks/health_check_executor_ext.go
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,9 @@
 | 
				
			|||||||
 | 
					// Copyright 2023 Liuxiangchao iwind.liu@gmail.com. All rights reserved. Official site: https://goedge.cn .
 | 
				
			||||||
 | 
					//go:build !plus
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					package tasks
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// 触发节点动作
 | 
				
			||||||
 | 
					func (this *HealthCheckExecutor) fireNodeActions(nodeId int64) error {
 | 
				
			||||||
 | 
						return nil
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
		Reference in New Issue
	
	Block a user