From 3fd2925780c0f8ae63ebb33b9405cd1b57871ff9 Mon Sep 17 00:00:00 2001 From: GoEdgeLab Date: Wed, 17 May 2023 18:42:21 +0800 Subject: [PATCH] =?UTF-8?q?=E5=AE=9E=E7=8E=B0=E5=9F=BA=E7=A1=80=E7=9A=84?= =?UTF-8?q?=E6=99=BA=E8=83=BD=E8=B0=83=E5=BA=A6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- build/configs/db.template.yaml | 3 +- internal/db/models/dns/dns_task_dao.go | 3 +- internal/db/models/message_dao.go | 4 +- internal/db/models/node_action_dao.go | 63 ++++++ internal/db/models/node_action_dao_test.go | 6 + internal/db/models/node_action_model.go | 32 +++ internal/db/models/node_action_model_ext.go | 1 + internal/db/models/node_dao.go | 4 +- internal/db/models/node_dao_ext.go | 5 + internal/db/models/node_model.go | 12 ++ internal/db/models/node_model_ext.go | 16 +- internal/db/models/node_model_ext_schdule.go | 9 + .../node_traffic_daily_stat_dao.go | 6 +- .../models/node_traffic_daily_stat_dao_ext.go | 14 ++ .../node_traffic_daily_stat_dao_test.go | 2 +- .../node_traffic_daily_stat_model.go | 2 +- .../node_traffic_daily_stat_model_ext.go | 1 + internal/db/models/node_value_dao.go | 19 +- internal/db/models/node_value_dao_ext.go | 14 ++ .../node_traffic_daily_stat_model_ext.go | 1 - internal/dnsclients/types_ext.go | 5 +- internal/rpc/services/service_dns_domain.go | 26 ++- internal/rpc/services/service_dns_task.go | 2 +- internal/rpc/services/service_node.go | 27 ++- internal/rpc/services/service_node_ext.go | 21 ++ .../rpc/services/service_server_daily_stat.go | 2 +- .../rpc/services/service_server_stat_board.go | 4 +- internal/setup/sql.json | 107 +++++++++- internal/tasks/dns_task_executor.go | 198 ++++++++++-------- internal/tasks/dns_task_executor_test.go | 2 + internal/tasks/health_check_cluster_task.go | 2 +- internal/tasks/health_check_executor.go | 12 +- internal/tasks/health_check_executor_ext.go | 9 + 33 files changed, 507 insertions(+), 127 deletions(-) create mode 100644 internal/db/models/node_action_dao.go create mode 100644 internal/db/models/node_action_dao_test.go create mode 100644 internal/db/models/node_action_model.go create mode 100644 internal/db/models/node_action_model_ext.go create mode 100644 internal/db/models/node_model_ext_schdule.go rename internal/db/models/{stats => }/node_traffic_daily_stat_dao.go (98%) create mode 100644 internal/db/models/node_traffic_daily_stat_dao_ext.go rename internal/db/models/{stats => }/node_traffic_daily_stat_dao_test.go (76%) rename internal/db/models/{stats => }/node_traffic_daily_stat_model.go (99%) create mode 100644 internal/db/models/node_traffic_daily_stat_model_ext.go create mode 100644 internal/db/models/node_value_dao_ext.go delete mode 100644 internal/db/models/stats/node_traffic_daily_stat_model_ext.go create mode 100644 internal/rpc/services/service_node_ext.go create mode 100644 internal/tasks/health_check_executor_ext.go diff --git a/build/configs/db.template.yaml b/build/configs/db.template.yaml index 16c48e37..3a489cd7 100644 --- a/build/configs/db.template.yaml +++ b/build/configs/db.template.yaml @@ -12,4 +12,5 @@ dbs: fields: - bool: [ "uamIsOn", "followPort", "requestHostExcludingPort", "autoRemoteStart", "autoInstallNftables" ] + bool: [ "uamIsOn", "followPort", "requestHostExcludingPort", "autoRemoteStart", "autoInstallNftables", "enableIPLists", "detectAgents", "checkingPorts", "enableRecordHealthCheck", "offlineIsNotified" ] + diff --git a/internal/db/models/dns/dns_task_dao.go b/internal/db/models/dns/dns_task_dao.go index f599c524..b1be0522 100644 --- a/internal/db/models/dns/dns_task_dao.go +++ b/internal/db/models/dns/dns_task_dao.go @@ -12,7 +12,8 @@ import ( type DNSTaskType = string const ( - DNSTaskTypeClusterChange DNSTaskType = "clusterChange" + DNSTaskTypeClusterChange DNSTaskType = "clusterChange" // 集群节点、服务发生变化 + DNSTaskTypeClusterNodesChange DNSTaskType = "clusterNodesChange" // 集群中节点发生变化 DNSTaskTypeClusterRemoveDomain DNSTaskType = "clusterRemoveDomain" // 从集群中移除域名 DNSTaskTypeNodeChange DNSTaskType = "nodeChange" DNSTaskTypeServerChange DNSTaskType = "serverChange" diff --git a/internal/db/models/message_dao.go b/internal/db/models/message_dao.go index 0fc0604c..6b29f689 100644 --- a/internal/db/models/message_dao.go +++ b/internal/db/models/message_dao.go @@ -52,7 +52,9 @@ const ( MessageTypeReportNodeInactive MessageType = "ReportNodeInactive" // 区域监控节点节点不活跃 MessageTypeReportNodeActive MessageType = "ReportNodeActive" // 区域监控节点活跃 - MessageTypeConnectivity MessageType = "Connectivity" + MessageTypeConnectivity MessageType = "Connectivity" // 连通性 + MessageTypeNodeSchedule MessageType = "NodeSchedule" // 节点调度信息 + MessageTypeNodeOfflineDay MessageType = "NodeOfflineDay" // 节点到下线日期 ) type MessageDAO dbs.DAO diff --git a/internal/db/models/node_action_dao.go b/internal/db/models/node_action_dao.go new file mode 100644 index 00000000..8f0f3c7b --- /dev/null +++ b/internal/db/models/node_action_dao.go @@ -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 +} diff --git a/internal/db/models/node_action_dao_test.go b/internal/db/models/node_action_dao_test.go new file mode 100644 index 00000000..6595eab6 --- /dev/null +++ b/internal/db/models/node_action_dao_test.go @@ -0,0 +1,6 @@ +package models_test + +import ( + _ "github.com/go-sql-driver/mysql" + _ "github.com/iwind/TeaGo/bootstrap" +) diff --git a/internal/db/models/node_action_model.go b/internal/db/models/node_action_model.go new file mode 100644 index 00000000..25394037 --- /dev/null +++ b/internal/db/models/node_action_model.go @@ -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{} +} diff --git a/internal/db/models/node_action_model_ext.go b/internal/db/models/node_action_model_ext.go new file mode 100644 index 00000000..2640e7f9 --- /dev/null +++ b/internal/db/models/node_action_model_ext.go @@ -0,0 +1 @@ +package models diff --git a/internal/db/models/node_dao.go b/internal/db/models/node_dao.go index 606c1caa..f1620eff 100644 --- a/internal/db/models/node_dao.go +++ b/internal/db/models/node_dao.go @@ -1550,7 +1550,7 @@ func (this *NodeDAO) FindAllEnabledNodesDNSWithClusterId(tx *dbs.Tx, clusterId i Attr("isOn", true). Attr("isUp", true). Attr("isInstalled", isInstalled). - Result("id", "name", "dnsRoutes", "isOn"). + Result("id", "name", "dnsRoutes", "isOn", "offlineDay", "actionStatus", "isBackupForCluster", "isBackupForGroup", "backupIPs", "clusterId", "groupId"). DescPk(). Slice(&result). FindAll() @@ -1575,7 +1575,7 @@ func (this *NodeDAO) FindEnabledNodeDNS(tx *dbs.Tx, nodeId int64) (*Node, error) one, err := this.Query(tx). State(NodeStateEnabled). Pk(nodeId). - Result("id", "name", "dnsRoutes", "clusterId", "isOn"). + Result("id", "name", "dnsRoutes", "clusterId", "isOn", "offlineDay", "isBackupForCluster", "isBackupForGroup", "actionStatus"). Find() if one == nil { return nil, err diff --git a/internal/db/models/node_dao_ext.go b/internal/db/models/node_dao_ext.go index 1589f645..8ee85cea 100644 --- a/internal/db/models/node_dao_ext.go +++ b/internal/db/models/node_dao_ext.go @@ -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 { return nil } + +// CheckNodeIPAddresses 检查节点IP地址 +func (this *NodeDAO) CheckNodeIPAddresses(tx *dbs.Tx, node *Node) (shouldSkip bool, shouldOverwrite bool, ipAddressStrings []string, err error) { + return +} diff --git a/internal/db/models/node_model.go b/internal/db/models/node_model.go index b75da439..34614ebe 100644 --- a/internal/db/models/node_model.go +++ b/internal/db/models/node_model.go @@ -43,6 +43,12 @@ type Node struct { DnsResolver dbs.JSON `field:"dnsResolver"` // DNS解析器 EnableIPLists bool `field:"enableIPLists"` // 启用IP名单 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 { @@ -85,6 +91,12 @@ type NodeOperator struct { DnsResolver any // DNS解析器 EnableIPLists any // 启用IP名单 ApiNodeAddrs any // API节点地址 + OfflineDay any // 下线日期YYYYMMDD + OfflineIsNotified any // 下线是否已通知 + IsBackupForCluster any // 是否为集群备用节点 + IsBackupForGroup any // 是否为分组备用节点 + BackupIPs any // 备用IP + ActionStatus any // 当前动作配置 } func NewNodeOperator() *NodeOperator { diff --git a/internal/db/models/node_model_ext.go b/internal/db/models/node_model_ext.go index b776dce9..c9f19ccd 100644 --- a/internal/db/models/node_model_ext.go +++ b/internal/db/models/node_model_ext.go @@ -7,6 +7,7 @@ import ( "github.com/TeaOSLab/EdgeCommon/pkg/serverconfigs" "github.com/TeaOSLab/EdgeCommon/pkg/serverconfigs/ddosconfigs" "github.com/TeaOSLab/EdgeCommon/pkg/serverconfigs/shared" + timeutil "github.com/iwind/TeaGo/utils/time" "sort" "time" ) @@ -16,7 +17,7 @@ func (this *Node) DecodeInstallStatus() (*NodeInstallStatus, error) { if len(this.InstallStatus) == 0 { return NewNodeInstallStatus(), nil } - status := &NodeInstallStatus{} + var status = &NodeInstallStatus{} err := json.Unmarshal(this.InstallStatus, status) if err != nil { return NewNodeInstallStatus(), err @@ -37,7 +38,7 @@ func (this *Node) DecodeStatus() (*nodeconfigs.NodeStatus, error) { if len(this.Status) == 0 { return nil, nil } - status := &nodeconfigs.NodeStatus{} + var status = &nodeconfigs.NodeStatus{} err := json.Unmarshal(this.Status, status) if err != nil { return nil, err @@ -47,7 +48,7 @@ func (this *Node) DecodeStatus() (*nodeconfigs.NodeStatus, error) { // DNSRouteCodes 所有的DNS线路 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 { return routes } @@ -61,7 +62,7 @@ func (this *Node) DNSRouteCodes() map[int64][]string { // DNSRouteCodesForDomainId DNS线路 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 { return nil, nil } @@ -80,7 +81,7 @@ func (this *Node) DNSRouteCodesForDomainId(dnsDomainId int64) ([]string, error) // DecodeConnectedAPINodeIds 连接的API func (this *Node) DecodeConnectedAPINodeIds() ([]int64, error) { - apiNodeIds := []int64{} + var apiNodeIds = []int64{} if IsNotNull(this.ConnectedAPINodes) { err := json.Unmarshal(this.ConnectedAPINodes, &apiNodeIds) if err != nil { @@ -214,3 +215,8 @@ func (this *Node) DecodeAPINodeAddrs() []*serverconfigs.NetworkAddressConfig { } return result } + +// CheckIsOffline 检查是否已经离线 +func (this *Node) CheckIsOffline() bool { + return len(this.OfflineDay) > 0 && this.OfflineDay < timeutil.Format("Ymd") +} diff --git a/internal/db/models/node_model_ext_schdule.go b/internal/db/models/node_model_ext_schdule.go new file mode 100644 index 00000000..054ea2ce --- /dev/null +++ b/internal/db/models/node_model_ext_schdule.go @@ -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 +} \ No newline at end of file diff --git a/internal/db/models/stats/node_traffic_daily_stat_dao.go b/internal/db/models/node_traffic_daily_stat_dao.go similarity index 98% rename from internal/db/models/stats/node_traffic_daily_stat_dao.go rename to internal/db/models/node_traffic_daily_stat_dao.go index 07b5ebce..3d2aa41c 100644 --- a/internal/db/models/stats/node_traffic_daily_stat_dao.go +++ b/internal/db/models/node_traffic_daily_stat_dao.go @@ -1,4 +1,4 @@ -package stats +package models import ( "github.com/TeaOSLab/EdgeAPI/internal/errors" @@ -84,7 +84,9 @@ func (this *NodeTrafficDailyStatDAO) IncreaseDailyStat(tx *dbs.Tx, clusterId int if err != nil { return err } - return nil + + // 触发钩子 + return this.increaseDailyStatHook(tx, role, nodeId) } // FindDailyStats 获取日期之间统计 diff --git a/internal/db/models/node_traffic_daily_stat_dao_ext.go b/internal/db/models/node_traffic_daily_stat_dao_ext.go new file mode 100644 index 00000000..dce92f19 --- /dev/null +++ b/internal/db/models/node_traffic_daily_stat_dao_ext.go @@ -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 +} diff --git a/internal/db/models/stats/node_traffic_daily_stat_dao_test.go b/internal/db/models/node_traffic_daily_stat_dao_test.go similarity index 76% rename from internal/db/models/stats/node_traffic_daily_stat_dao_test.go rename to internal/db/models/node_traffic_daily_stat_dao_test.go index 6b0462b3..97c24b56 100644 --- a/internal/db/models/stats/node_traffic_daily_stat_dao_test.go +++ b/internal/db/models/node_traffic_daily_stat_dao_test.go @@ -1,4 +1,4 @@ -package stats +package models import ( _ "github.com/go-sql-driver/mysql" diff --git a/internal/db/models/stats/node_traffic_daily_stat_model.go b/internal/db/models/node_traffic_daily_stat_model.go similarity index 99% rename from internal/db/models/stats/node_traffic_daily_stat_model.go rename to internal/db/models/node_traffic_daily_stat_model.go index 7788f5cf..3aeca830 100644 --- a/internal/db/models/stats/node_traffic_daily_stat_model.go +++ b/internal/db/models/node_traffic_daily_stat_model.go @@ -1,4 +1,4 @@ -package stats +package models // NodeTrafficDailyStat 总的流量统计(按天) type NodeTrafficDailyStat struct { diff --git a/internal/db/models/node_traffic_daily_stat_model_ext.go b/internal/db/models/node_traffic_daily_stat_model_ext.go new file mode 100644 index 00000000..2640e7f9 --- /dev/null +++ b/internal/db/models/node_traffic_daily_stat_model_ext.go @@ -0,0 +1 @@ +package models diff --git a/internal/db/models/node_value_dao.go b/internal/db/models/node_value_dao.go index 6aef01df..c9f523de 100644 --- a/internal/db/models/node_value_dao.go +++ b/internal/db/models/node_value_dao.go @@ -37,11 +37,15 @@ func init() { // CreateValue 创建值 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 hour = timeutil.FormatTime("YmdH", createdAt) var minute = timeutil.FormatTime("YmdHi", createdAt) - return this.Query(tx). + err := this.Query(tx). InsertOrUpdateQuickly(maps.Map{ "clusterId": clusterId, "role": role, @@ -55,6 +59,17 @@ func (this *NodeValueDAO) CreateValue(tx *dbs.Tx, clusterId int64, role nodeconf }, maps.Map{ "value": valueJSON, }) + if err != nil { + return err + } + + // 触发钩子 + err = this.nodeValueHook(tx, role, nodeId, item, valueJSON) + if err != nil { + return err + } + + return nil } // Clean 清除数据 @@ -324,7 +339,7 @@ func (this *NodeValueDAO) SumNodeClusterValues(tx *dbs.Tx, role string, clusterI // FindLatestNodeValue 获取最近一条数据 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). Attr("role", role). diff --git a/internal/db/models/node_value_dao_ext.go b/internal/db/models/node_value_dao_ext.go new file mode 100644 index 00000000..e5fb75a1 --- /dev/null +++ b/internal/db/models/node_value_dao_ext.go @@ -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 +} diff --git a/internal/db/models/stats/node_traffic_daily_stat_model_ext.go b/internal/db/models/stats/node_traffic_daily_stat_model_ext.go deleted file mode 100644 index 43b4fd56..00000000 --- a/internal/db/models/stats/node_traffic_daily_stat_model_ext.go +++ /dev/null @@ -1 +0,0 @@ -package stats diff --git a/internal/dnsclients/types_ext.go b/internal/dnsclients/types_ext.go index 685ca6fc..44154b88 100644 --- a/internal/dnsclients/types_ext.go +++ b/internal/dnsclients/types_ext.go @@ -1,10 +1,11 @@ // Copyright 2022 Liuxiangchao iwind.liu@gmail.com. All rights reserved. //go:build !plus -// +build !plus package dnsclients -import "github.com/iwind/TeaGo/maps" +import ( + "github.com/iwind/TeaGo/maps" +) // FindProvider 查找服务商实例 func FindProvider(providerType ProviderType, providerId int64) ProviderInterface { diff --git a/internal/rpc/services/service_dns_domain.go b/internal/rpc/services/service_dns_domain.go index 79627b45..3161d0bd 100644 --- a/internal/rpc/services/service_dns_domain.go +++ b/internal/rpc/services/service_dns_domain.go @@ -472,13 +472,14 @@ func (this *DNSDomainService) findClusterDNSChanges(cluster *models.NodeCluster, var nodeKeys = []string{} var addingNodeRecordKeysMap = map[string]bool{} // clusterDnsName_type_ip_route 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 { return nil, nil, nil, 0, 0, false, false, err } - if len(ipAddresses) == 0 { + if shouldSkip { continue } + routeCodes, err := node.DNSRouteCodesForDomainId(int64(cluster.DnsDomainId)) if err != nil { return nil, nil, nil, 0, 0, false, false, err @@ -491,7 +492,16 @@ func (this *DNSDomainService) findClusterDNSChanges(cluster *models.NodeCluster, 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 { // 检查专属节点 if !ipAddress.IsValidInCluster(clusterId) { @@ -505,6 +515,16 @@ func (this *DNSDomainService) findClusterDNSChanges(cluster *models.NodeCluster, if net.ParseIP(ip) == nil { continue } + + ipAddressesStrings = append(ipAddressesStrings, ip) + } + } + if len(ipAddressesStrings) == 0 { + continue + } + + for _, route := range routeCodes { + for _, ip := range ipAddressesStrings { var key = ip + "_" + route nodeKeys = append(nodeKeys, key) record, ok := nodeRecordMapping[key] diff --git a/internal/rpc/services/service_dns_task.go b/internal/rpc/services/service_dns_task.go index 8496862a..4075f495 100644 --- a/internal/rpc/services/service_dns_task.go +++ b/internal/rpc/services/service_dns_task.go @@ -62,7 +62,7 @@ func (this *DNSTaskService) FindAllDoingDNSTasks(ctx context.Context, req *pb.Fi } switch task.Type { - case dns.DNSTaskTypeClusterChange, dns.DNSTaskTypeClusterRemoveDomain: + case dns.DNSTaskTypeClusterChange, dns.DNSTaskTypeClusterNodesChange, dns.DNSTaskTypeClusterRemoveDomain: clusterName, err := models.SharedNodeClusterDAO.FindNodeClusterName(tx, int64(task.ClusterId)) if err != nil { return nil, err diff --git a/internal/rpc/services/service_node.go b/internal/rpc/services/service_node.go index 3d04a06a..df23b20a 100644 --- a/internal/rpc/services/service_node.go +++ b/internal/rpc/services/service_node.go @@ -384,6 +384,9 @@ func (this *NodeService) ListEnabledNodesMatch(ctx context.Context, req *pb.List NodeRegion: pbRegion, DnsRoutes: pbRoutes, 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, EnableIPLists: node.EnableIPLists, ApiNodeAddrsJSON: node.ApiNodeAddrs, + OfflineDay: node.OfflineDay, + IsBackupForCluster: node.IsBackupForCluster, + IsBackupForGroup: node.IsBackupForGroup, }}, nil } @@ -1397,12 +1403,15 @@ func (this *NodeService) FindAllEnabledNodesDNSWithNodeClusterId(ctx context.Con continue } result = append(result, &pb.NodeDNSInfo{ - Id: int64(node.Id), - Name: node.Name, - IpAddr: ip, - NodeIPAddressId: int64(ipAddress.Id), - Routes: pbRoutes, - NodeClusterId: req.NodeClusterId, + Id: int64(node.Id), + Name: node.Name, + IpAddr: ip, + NodeIPAddressId: int64(ipAddress.Id), + Routes: pbRoutes, + 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, DnsDomainId: dnsDomainId, DnsDomainName: dnsDomainName, + IsBackupForCluster: node.IsBackupForCluster, + IsBackupForGroup: node.IsBackupForGroup, + IsOffline: node.CheckIsOffline(), }, }, nil } @@ -2097,6 +2109,9 @@ func (this *NodeService) FindEnabledNodeConfigInfo(ctx context.Context, req *pb. // ddos protection result.HasDDoSProtection = node.HasDDoSProtection() + // schedule + result.HasScheduleSettings = node.HasScheduleSettings() + return result, nil } diff --git a/internal/rpc/services/service_node_ext.go b/internal/rpc/services/service_node_ext.go new file mode 100644 index 00000000..2fb29a6c --- /dev/null +++ b/internal/rpc/services/service_node_ext.go @@ -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() +} diff --git a/internal/rpc/services/service_server_daily_stat.go b/internal/rpc/services/service_server_daily_stat.go index 51609664..70e2b2b4 100644 --- a/internal/rpc/services/service_server_daily_stat.go +++ b/internal/rpc/services/service_server_daily_stat.go @@ -68,7 +68,7 @@ func (this *ServerDailyStatService) UploadServerDailyStats(ctx context.Context, // 节点流量 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 { return nil, err } diff --git a/internal/rpc/services/service_server_stat_board.go b/internal/rpc/services/service_server_stat_board.go index 3bb6fa29..32a315e3 100644 --- a/internal/rpc/services/service_server_stat_board.go +++ b/internal/rpc/services/service_server_stat_board.go @@ -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 { 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)) - 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 { return nil, err } diff --git a/internal/setup/sql.json b/internal/setup/sql.json index 08a71ea6..2408fd99 100644 --- a/internal/setup/sql.json +++ b/internal/setup/sql.json @@ -67267,7 +67267,7 @@ "name": "edgeNSDomains", "engine": "InnoDB", "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": [ { "name": "id", @@ -67305,6 +67305,10 @@ "name": "verifyExpiresAt", "definition": "bigint(11) unsigned DEFAULT '0' COMMENT '验证TXT过期时间'" }, + { + "name": "recordsHealthCheck", + "definition": "json COMMENT '记录健康检查设置'" + }, { "name": "createdAt", "definition": "bigint(11) unsigned DEFAULT '0' COMMENT '创建时间'" @@ -67653,7 +67657,7 @@ "name": "edgeNSRecords", "engine": "InnoDB", "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": [ { "name": "id", @@ -67719,6 +67723,22 @@ "name": "routeIds", "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", "definition": "bigint(11) unsigned DEFAULT '0' COMMENT '创建时间'" @@ -67992,6 +68012,61 @@ ], "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", "engine": "InnoDB", @@ -69041,7 +69116,7 @@ "name": "edgeNodeThresholds", "engine": "InnoDB", "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": [ { "name": "id", @@ -69345,7 +69420,7 @@ "name": "edgeNodes", "engine": "InnoDB", "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": [ { "name": "id", @@ -69502,6 +69577,30 @@ { "name": "apiNodeAddrs", "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": [ diff --git a/internal/tasks/dns_task_executor.go b/internal/tasks/dns_task_executor.go index 8190b6f4..a04f884d 100644 --- a/internal/tasks/dns_task_executor.go +++ b/internal/tasks/dns_task_executor.go @@ -87,8 +87,8 @@ func (this *DNSTaskExecutor) loop() error { return err } } - case dnsmodels.DNSTaskTypeClusterChange: - err = this.doCluster(taskId, taskVersion, int64(task.ClusterId)) + case dnsmodels.DNSTaskTypeClusterChange, dnsmodels.DNSTaskTypeClusterNodesChange: + err = this.doCluster(taskId, taskVersion, int64(task.ClusterId), task.Type == dnsmodels.DNSTaskTypeClusterNodesChange) if err != nil { err = dnsmodels.SharedDNSTaskDAO.UpdateDNSTaskError(nil, taskId, err.Error()) if err != nil { @@ -300,7 +300,7 @@ func (this *DNSTaskExecutor) doNode(taskId int64, taskVersion int64, nodeCluster // 转交给cluster统一处理 if nodeClusterId > 0 { - err = dnsmodels.SharedDNSTaskDAO.CreateClusterTask(tx, nodeClusterId, dnsmodels.DNSTaskTypeClusterChange) + err = dnsmodels.SharedDNSTaskDAO.CreateClusterTask(tx, nodeClusterId, dnsmodels.DNSTaskTypeClusterNodesChange) if err != nil { return err } @@ -310,7 +310,7 @@ func (this *DNSTaskExecutor) doNode(taskId int64, taskVersion int64, nodeCluster return err } for _, clusterId := range clusterIds { - err = dnsmodels.SharedDNSTaskDAO.CreateClusterTask(tx, clusterId, dnsmodels.DNSTaskTypeClusterChange) + err = dnsmodels.SharedDNSTaskDAO.CreateClusterTask(tx, clusterId, dnsmodels.DNSTaskTypeClusterNodesChange) if err != nil { 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 { - isOk := false +func (this *DNSTaskExecutor) doCluster(taskId int64, taskVersion int64, clusterId int64, nodesOnly bool) error { + var isOk = false defer func() { if isOk { err := dnsmodels.SharedDNSTaskDAO.UpdateDNSTaskDone(nil, taskId, taskVersion) @@ -378,6 +378,14 @@ func (this *DNSTaskExecutor) doCluster(taskId int64, taskVersion int64, clusterI var isChanged = false var addingNodeRecordKeysMap = map[string]bool{} // clusterDnsName_type_ip_route 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) if err != nil { return err @@ -387,26 +395,36 @@ func (this *DNSTaskExecutor) doCluster(taskId int64, taskVersion int64, clusterI } // 所有的IP记录 - ipAddresses, err := models.SharedNodeIPAddressDAO.FindAllEnabledAddressesWithNode(tx, int64(node.Id), nodeconfigs.NodeRoleNode) - if err != nil { - return err + if !shouldOverwrite { + ipAddresses, err := models.SharedNodeIPAddressDAO.FindAllEnabledAddressesWithNode(tx, int64(node.Id), nodeconfigs.NodeRoleNode) + 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 } - 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 - } + for _, ip := range ipAddressesStrings { for _, route := range routes { var key = route + "@" + ip _, ok := oldRecordsMap[key] @@ -456,80 +474,82 @@ func (this *DNSTaskExecutor) doCluster(taskId int64, taskVersion int64, clusterI } // 服务域名 - servers, err := models.SharedServerDAO.FindAllServersDNSWithClusterId(tx, clusterId) - 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 + if !nodesOnly { + servers, err := models.SharedServerDAO.FindAllServersDNSWithClusterId(tx, clusterId) + if err != nil { + return err } - } - - // 新增的域名 - var serverDNSNames = []string{} - for _, server := range servers { - var dnsName = server.DnsName - 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 + 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 } } - } - // 自动设置的CNAME - var cnameRecords = []string{} - if dnsConfig != nil { - cnameRecords = dnsConfig.CNAMERecords - } - for _, cnameRecord := range cnameRecords { - // 如果记录已存在,则跳过 - 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 + // 新增的域名 + var serverDNSNames = []string{} + for _, server := range servers { + var dnsName = server.DnsName + 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 + } } } - } - // 多余的域名 - for _, record := range serverRecords { - if !lists.ContainsString(serverDNSNames, record.Name) { - isChanged = true - err = manager.DeleteRecord(domain, record) - if err != nil { - return err + // 自动设置的CNAME + var cnameRecords = []string{} + if dnsConfig != nil { + cnameRecords = dnsConfig.CNAMERecords + } + for _, cnameRecord := range cnameRecords { + // 如果记录已存在,则跳过 + 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 + } } } } diff --git a/internal/tasks/dns_task_executor_test.go b/internal/tasks/dns_task_executor_test.go index 7085d5a3..30fa0643 100644 --- a/internal/tasks/dns_task_executor_test.go +++ b/internal/tasks/dns_task_executor_test.go @@ -1,3 +1,5 @@ +//go:build !plus + package tasks_test import ( diff --git a/internal/tasks/health_check_cluster_task.go b/internal/tasks/health_check_cluster_task.go index 3ca24f24..f3deefd1 100644 --- a/internal/tasks/health_check_cluster_task.go +++ b/internal/tasks/health_check_cluster_task.go @@ -127,7 +127,7 @@ func (this *HealthCheckClusterTask) Loop() error { if err != nil { 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) if err != nil { return err diff --git a/internal/tasks/health_check_executor.go b/internal/tasks/health_check_executor.go index 0ef4213b..76eb16aa 100644 --- a/internal/tasks/health_check_executor.go +++ b/internal/tasks/health_check_executor.go @@ -16,6 +16,7 @@ import ( "github.com/iwind/TeaGo/lists" "github.com/iwind/TeaGo/maps" "github.com/iwind/TeaGo/types" + timeutil "github.com/iwind/TeaGo/utils/time" "net" "net/http" "strconv" @@ -66,7 +67,7 @@ func (this *HealthCheckExecutor) Run() ([]*HealthCheckResult, error) { var tx *dbs.Tx for _, node := range nodes { - if !node.IsOn { + if !node.IsOn || node.IsBackupForCluster || node.IsBackupForGroup || (len(node.OfflineDay) > 0 && node.OfflineDay < timeutil.Format("Ymd")) { continue } @@ -194,6 +195,15 @@ func (this *HealthCheckExecutor) runNode(healthCheckConfig *serverconfigs.Health this.logErr("HealthCheckExecutor", err.Error()) return } + + // 触发节点动作 + if !result.IsOk { + err := this.fireNodeActions(int64(result.Node.Id)) + if err != nil { + this.logErr("HealthCheckExecutor", err.Error()) + } + return + } } // 触发阈值 diff --git a/internal/tasks/health_check_executor_ext.go b/internal/tasks/health_check_executor_ext.go new file mode 100644 index 00000000..2642331d --- /dev/null +++ b/internal/tasks/health_check_executor_ext.go @@ -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 +}