1.4.5.2
This commit is contained in:
879
EdgeAPI/internal/db/models/node_dao_ext_plus.go
Normal file
879
EdgeAPI/internal/db/models/node_dao_ext_plus.go
Normal file
@@ -0,0 +1,879 @@
|
||||
// Copyright 2022 Liuxiangchao iwind.liu@gmail.com. All rights reserved.
|
||||
//go:build plus
|
||||
|
||||
package models
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"errors"
|
||||
teaconst "github.com/TeaOSLab/EdgeAPI/internal/const"
|
||||
"github.com/TeaOSLab/EdgeAPI/internal/db/models/dns"
|
||||
"github.com/TeaOSLab/EdgeAPI/internal/utils"
|
||||
"github.com/TeaOSLab/EdgeAPI/internal/utils/regexputils"
|
||||
"github.com/TeaOSLab/EdgeAPI/internal/zero"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/nodeconfigs"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/serverconfigs"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/serverconfigs/shared"
|
||||
"github.com/iwind/TeaGo/dbs"
|
||||
"github.com/iwind/TeaGo/lists"
|
||||
"github.com/iwind/TeaGo/maps"
|
||||
"github.com/iwind/TeaGo/types"
|
||||
timeutil "github.com/iwind/TeaGo/utils/time"
|
||||
"net/http"
|
||||
"strings"
|
||||
"sync"
|
||||
"time"
|
||||
)
|
||||
|
||||
// 从集群加载其他服务
|
||||
func (this *NodeDAO) loadServersFromCluster(tx *dbs.Tx, clusterId int64, serverIdMap map[int64]zero.Zero) ([]*Server, error) {
|
||||
// 高防实例
|
||||
// TODO 将来支持部署到具体节点
|
||||
objectCodes, err := SharedADPackageInstanceDAO.FindAvailableObjectCodesInCluster(tx, clusterId)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
var resultServers = []*Server{}
|
||||
for _, objectCode := range objectCodes {
|
||||
objectType, objectValue := SharedUserADInstanceDAO.SplitObjectCode(objectCode)
|
||||
if objectType == ADObjectTypeServer && len(objectValue) > 0 {
|
||||
var serverId = types.Int64(objectValue)
|
||||
if serverId > 0 {
|
||||
_, ok := serverIdMap[serverId]
|
||||
if !ok {
|
||||
serverIdMap[serverId] = zero.Zero{}
|
||||
|
||||
// TODO 将来支持一次性读取一批server
|
||||
server, err := SharedServerDAO.FindEnabledServer(tx, serverId)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if server != nil && server.IsOn {
|
||||
resultServers = append(resultServers, server)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return resultServers, nil
|
||||
}
|
||||
|
||||
// 组合扩展配置
|
||||
func (this *NodeDAO) composeExtConfig(tx *dbs.Tx, config *nodeconfigs.NodeConfig, clusterIds []int64, cacheMap *utils.CacheMap) error {
|
||||
// 脚本
|
||||
// scripts
|
||||
scriptConfigs, err := SharedScriptHistoryDAO.ComposeScriptConfigs(tx, 0, cacheMap)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
config.CommonScripts = scriptConfigs
|
||||
|
||||
// 套餐
|
||||
// plan
|
||||
plans, err := SharedPlanDAO.FindAllAvailableBasicPlans(tx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
var planMap = map[int64]*serverconfigs.PlanConfig{}
|
||||
for _, plan := range plans {
|
||||
planMap[int64(plan.Id)] = &serverconfigs.PlanConfig{
|
||||
Id: int64(plan.Id),
|
||||
Name: plan.Name,
|
||||
BandwidthLimitPerNode: plan.DecodeBandwidthLimitPerNode(),
|
||||
TrafficLimit: plan.DecodeTrafficLimit(),
|
||||
MaxUploadSize: plan.DecodeMaxUploadSize(),
|
||||
}
|
||||
}
|
||||
config.Plans = planMap
|
||||
|
||||
// 父节点
|
||||
// 这里不需要进行 teaconst.IsPlus 判断,是为了防止在API节点升级过程中或者用户授权过期又激活时,节点无法正常更新
|
||||
if config.Level == 1 {
|
||||
parentNodes, err := SharedNodeDAO.FindParentNodeConfigs(tx, config.Id, config.GroupId, clusterIds, types.Int(config.Level))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
config.ParentNodes = parentNodes
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// UpdateNodeSchedule 修改智能调度信息
|
||||
// offlineDay YYYYMMDD
|
||||
func (this *NodeDAO) UpdateNodeSchedule(tx *dbs.Tx, nodeId int64, offlineDay string, isBackupForCluster bool, isBackupForGroup bool, backupIPs []string) error {
|
||||
if nodeId <= 0 {
|
||||
return errors.New("invalid nodeId")
|
||||
}
|
||||
|
||||
var op = NewNodeOperator()
|
||||
op.Id = nodeId
|
||||
|
||||
if len(offlineDay) > 0 && !regexputils.YYYYMMDD.MatchString(offlineDay) {
|
||||
return errors.New("invalid 'offlineDay' value: " + offlineDay)
|
||||
}
|
||||
op.OfflineDay = offlineDay
|
||||
if offlineDay >= timeutil.Format("Ymd") {
|
||||
op.OfflineIsNotified = false
|
||||
}
|
||||
|
||||
op.IsBackupForCluster = isBackupForCluster
|
||||
op.IsBackupForGroup = isBackupForGroup
|
||||
|
||||
if backupIPs == nil {
|
||||
backupIPs = []string{}
|
||||
}
|
||||
backupIPsJSON, err := json.Marshal(backupIPs)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
op.BackupIPs = backupIPsJSON
|
||||
err = this.Save(tx, op)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return this.NotifyDNSUpdate(tx, nodeId)
|
||||
}
|
||||
|
||||
// FindAllNodeScheduleWithClusterId 查找集群下的节点
|
||||
func (this *NodeDAO) FindAllNodeScheduleWithClusterId(tx *dbs.Tx, clusterId int64) (result []*Node, err error) {
|
||||
if clusterId <= 0 {
|
||||
return
|
||||
}
|
||||
_, err = this.Query(tx).
|
||||
Result("id", "name", "groupId", "offlineDay", "backupIPs", "isBackupForCluster", "isBackupForGroup", "actionStatus").
|
||||
Attr("clusterId", clusterId).
|
||||
State(NodeStateEnabled).
|
||||
Slice(&result).
|
||||
FindAll()
|
||||
return
|
||||
}
|
||||
|
||||
// FindNodeSchedule 查找智能调度信息
|
||||
func (this *NodeDAO) FindNodeSchedule(tx *dbs.Tx, nodeId int64) (node *Node, err error) {
|
||||
if nodeId <= 0 {
|
||||
err = errors.New("invalid nodeId")
|
||||
return
|
||||
}
|
||||
|
||||
one, err := this.Query(tx).
|
||||
Result("id", "offlineDay", "isBackupForCluster", "isBackupForGroup", "backupIPs", "actionStatus").
|
||||
Pk(nodeId).
|
||||
Find()
|
||||
if err != nil || one == nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return one.(*Node), nil
|
||||
}
|
||||
|
||||
// NotifyNodesWithOfflineDay 通知租期到期的节点
|
||||
var notifiedOfflineDayMap = map[string]bool{} // DAY_{END|00}
|
||||
var notifiedOfflineDayLocker = &sync.Mutex{}
|
||||
|
||||
func (this *NodeDAO) NotifyNodesWithOfflineDay(tx *dbs.Tx) error {
|
||||
// 每天最多两次
|
||||
var cacheKey = timeutil.Format("Ymd")
|
||||
var endHour = 23
|
||||
if time.Now().Hour() == endHour {
|
||||
cacheKey += "_END"
|
||||
} else {
|
||||
cacheKey += "_00"
|
||||
}
|
||||
|
||||
notifiedOfflineDayLocker.Lock()
|
||||
if notifiedOfflineDayMap[cacheKey] {
|
||||
notifiedOfflineDayLocker.Unlock()
|
||||
return nil
|
||||
}
|
||||
notifiedOfflineDayLocker.Unlock()
|
||||
|
||||
var query = this.Query(tx).
|
||||
State(NodeStateEnabled).
|
||||
Result("id", "clusterId", "offlineDay").
|
||||
Attr("offlineIsNotified", false)
|
||||
|
||||
if time.Now().Hour() == endHour {
|
||||
// 提前将今天到期的也下线
|
||||
query.
|
||||
Where("(LENGTH(offlineDay) > 0 AND offlineDay<=:offlineDay)").
|
||||
Param("offlineDay", timeutil.Format("Ymd"))
|
||||
} else {
|
||||
// 将以往的下线
|
||||
query.
|
||||
Where("(LENGTH(offlineDay) > 0 AND offlineDay<:offlineDay)").
|
||||
Param("offlineDay", timeutil.Format("Ymd"))
|
||||
}
|
||||
|
||||
nodeOnes, err := query.
|
||||
FindAll()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
var clusterIdMap = map[int64]bool{} // clusterId => bool
|
||||
for _, nodeOne := range nodeOnes {
|
||||
var node = nodeOne.(*Node)
|
||||
var offlineDay = node.OfflineDay
|
||||
if len(offlineDay) != 8 {
|
||||
continue
|
||||
}
|
||||
var realOfflineDay = offlineDay[:4] + "-" + offlineDay[4:6] + "-" + offlineDay[6:]
|
||||
|
||||
var nodeId = int64(node.Id)
|
||||
var clusterId = int64(node.ClusterId)
|
||||
if clusterId > 0 && !clusterIdMap[clusterId] {
|
||||
err = dns.SharedDNSTaskDAO.CreateClusterTask(tx, clusterId, dns.DNSTaskTypeClusterNodesChange)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
clusterIdMap[clusterId] = true
|
||||
}
|
||||
|
||||
// 设置为已通知
|
||||
err = this.Query(tx).
|
||||
Pk(nodeId).
|
||||
Set("offlineIsNotified", true).
|
||||
UpdateQuickly()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// 发送消息
|
||||
err = SharedMessageDAO.CreateNodeMessage(tx, nodeconfigs.NodeRoleNode, clusterId, nodeId, MessageTypeNodeOfflineDay, MessageLevelError, "节点租期已结束("+realOfflineDay+")", "节点租期已结束("+realOfflineDay+")", nil, true)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
notifiedOfflineDayLocker.Lock()
|
||||
notifiedOfflineDayMap[cacheKey] = true
|
||||
notifiedOfflineDayLocker.Unlock()
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// ResetNodeActionStatus 重置节点动作状态
|
||||
// checkConds 是否检查条件
|
||||
func (this *NodeDAO) ResetNodeActionStatus(tx *dbs.Tx, nodeId int64, checkConds bool) error {
|
||||
if nodeId <= 0 {
|
||||
return errors.New("invalid 'nodeId'")
|
||||
}
|
||||
|
||||
nodeOne, err := this.Query(tx).
|
||||
Pk(nodeId).
|
||||
Result("clusterId", "actionStatus").
|
||||
Find()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if nodeOne == nil {
|
||||
return nil
|
||||
}
|
||||
var node = nodeOne.(*Node)
|
||||
var clusterId = int64(node.ClusterId)
|
||||
if clusterId <= 0 {
|
||||
return nil
|
||||
}
|
||||
|
||||
if len(node.ActionStatus) == 0 {
|
||||
return nil
|
||||
}
|
||||
|
||||
if checkConds {
|
||||
var actionStatus = &nodeconfigs.NodeActionStatus{}
|
||||
err = json.Unmarshal(node.ActionStatus, actionStatus)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// 处理健康检查的特殊情况
|
||||
if actionStatus.ActionId > 0 {
|
||||
upAddressId, err := SharedNodeIPAddressDAO.FindFirstNodeAccessIPAddressId(tx, nodeId, true, nodeconfigs.NodeRoleNode)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if upAddressId <= 0 {
|
||||
if actionStatus.DurationSeconds <= 0 || actionStatus.DurationSeconds > 3600 {
|
||||
actionStatus.DurationSeconds = 3600
|
||||
}
|
||||
actionStatus.ExpiresAt += actionStatus.DurationSeconds
|
||||
actionStatusJSON, err := json.Marshal(actionStatus)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
err = this.Query(tx).
|
||||
Pk(nodeId).
|
||||
Set("actionStatus", actionStatusJSON).
|
||||
UpdateQuickly()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// 发送通知
|
||||
return SharedMessageDAO.CreateNodeMessage(tx, nodeconfigs.NodeRoleNode, clusterId, nodeId, MessageTypeNodeSchedule, MessageLevelError, "节点未能从智能调度状态中恢复", "节点由于没有可以正常访问的IP,所以未能从智能调度状态中恢复,将在下次循环中再次尝试。", nil, true)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
err = this.Query(tx).
|
||||
Pk(nodeId).
|
||||
Set("actionStatus", dbs.SQL("NULL")).
|
||||
UpdateQuickly()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
err = dns.SharedDNSTaskDAO.CreateClusterTask(tx, clusterId, dns.DNSTaskTypeClusterNodesChange)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// 发送通知
|
||||
return SharedMessageDAO.CreateNodeMessage(tx, nodeconfigs.NodeRoleNode, clusterId, nodeId, MessageTypeNodeSchedule, MessageLevelSuccess, "节点已从智能调度状态中恢复", "节点已从智能调度状态中恢复。", nil, true)
|
||||
}
|
||||
|
||||
// FindNodeIdsWithExpiredActions 查找动作状态已过期的节点ID
|
||||
func (this *NodeDAO) FindNodeIdsWithExpiredActions(tx *dbs.Tx) (nodeIds []int64, err error) {
|
||||
ones, err := this.Query(tx).
|
||||
Result("id").
|
||||
State(NodeStateEnabled).
|
||||
Where("(actionStatus IS NOT NULL AND JSON_EXTRACT(actionStatus, '$.expiresAt')<:currentTime)").
|
||||
Param("currentTime", time.Now().Unix()).
|
||||
FindAll()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
for _, one := range ones {
|
||||
nodeIds = append(nodeIds, int64(one.(*Node).Id))
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
// CopyNodeActionsToGroup 复制动作设置到分组
|
||||
func (this *NodeDAO) CopyNodeActionsToGroup(tx *dbs.Tx, nodeId int64) error {
|
||||
groupId, err := this.Query(tx).
|
||||
Pk(nodeId).
|
||||
Result("groupId").
|
||||
FindInt64Col(0)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if groupId <= 0 {
|
||||
return nil
|
||||
}
|
||||
|
||||
const nodeRole = nodeconfigs.NodeRoleNode
|
||||
|
||||
actions, err := SharedNodeActionDAO.FindAllNodeActions(tx, nodeRole, nodeId)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
nodeOnes, err := this.Query(tx).
|
||||
ResultPk().
|
||||
Attr("groupId", groupId).
|
||||
Neq("id", nodeId).
|
||||
State(NodeStateEnabled).
|
||||
FindAll()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
for _, nodeOne := range nodeOnes {
|
||||
var targetNodeId = int64(nodeOne.(*Node).Id)
|
||||
err = SharedNodeActionDAO.DisableAllNodeActions(tx, nodeRole, targetNodeId)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
for _, action := range actions {
|
||||
err = SharedNodeActionDAO.DuplicateNodeAction(tx, action, nodeRole, targetNodeId)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// CopyNodeActionsToCluster 复制动作设置到集群
|
||||
func (this *NodeDAO) CopyNodeActionsToCluster(tx *dbs.Tx, nodeId int64) error {
|
||||
clusterId, err := this.Query(tx).
|
||||
Pk(nodeId).
|
||||
Result("clusterId").
|
||||
FindInt64Col(0)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if clusterId <= 0 {
|
||||
return nil
|
||||
}
|
||||
|
||||
const nodeRole = nodeconfigs.NodeRoleNode
|
||||
|
||||
actions, err := SharedNodeActionDAO.FindAllNodeActions(tx, nodeRole, nodeId)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
nodeOnes, err := this.Query(tx).
|
||||
ResultPk().
|
||||
Attr("clusterId", clusterId).
|
||||
Neq("id", nodeId).
|
||||
State(NodeStateEnabled).
|
||||
FindAll()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
for _, nodeOne := range nodeOnes {
|
||||
var targetNodeId = int64(nodeOne.(*Node).Id)
|
||||
|
||||
err = SharedNodeActionDAO.DisableAllNodeActions(tx, nodeRole, targetNodeId)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
for _, action := range actions {
|
||||
err = SharedNodeActionDAO.DuplicateNodeAction(tx, action, nodeRole, targetNodeId)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// FireNodeActions 触发动作
|
||||
func (this *NodeDAO) FireNodeActions(tx *dbs.Tx, nodeId int64, paramCode nodeconfigs.NodeActionParam, paramValue any) error {
|
||||
// 只有Plus会员才会触发
|
||||
if !teaconst.IsPlus {
|
||||
return nil
|
||||
}
|
||||
|
||||
nodeOne, err := this.Query(tx).
|
||||
Pk(nodeId).
|
||||
Result("isBackupForCluster", "isBackupForGroup", "actionStatus", "offlineDay").
|
||||
State(NodeStateEnabled).
|
||||
Find()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if nodeOne == nil {
|
||||
return nil
|
||||
}
|
||||
var node = nodeOne.(*Node)
|
||||
|
||||
// 备用节点不处理
|
||||
if node.IsBackupForCluster || node.IsBackupForGroup {
|
||||
return nil
|
||||
}
|
||||
|
||||
// 是否已下线
|
||||
if node.CheckIsOffline() {
|
||||
return nil
|
||||
}
|
||||
|
||||
// 当前节点是否已经在动作状态中
|
||||
var statusJSON = node.ActionStatus
|
||||
if len(statusJSON) == 0 {
|
||||
return this.fireNodeActions(tx, nodeId, paramCode, paramValue)
|
||||
}
|
||||
|
||||
var status = &nodeconfigs.NodeActionStatus{}
|
||||
err = json.Unmarshal(statusJSON, status)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if status.ActionId <= 0 {
|
||||
return this.fireNodeActions(tx, nodeId, paramCode, paramValue)
|
||||
}
|
||||
|
||||
// 如果现在已经处于切换状态,则不做任何处理(使用任务来处理)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// 触发某个参数相关的动作
|
||||
func (this *NodeDAO) fireNodeActions(tx *dbs.Tx, nodeId int64, paramCode nodeconfigs.NodeActionParam, paramValue any) error {
|
||||
actions, err := SharedNodeActionDAO.FindAllAvailableNodeActionsWithParam(tx, nodeconfigs.NodeRoleNode, nodeId, paramCode)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if len(actions) == 0 {
|
||||
return nil
|
||||
}
|
||||
|
||||
for _, action := range actions {
|
||||
var condsConfig = action.DecodeCondsConfig()
|
||||
b, err := condsConfig.Match(func(param nodeconfigs.NodeActionParam) (value any, err error) {
|
||||
if paramCode == param && paramValue != nil {
|
||||
return paramValue, nil
|
||||
}
|
||||
|
||||
switch param {
|
||||
case nodeconfigs.NodeActionParamDailyTrafficOut:
|
||||
var today = timeutil.Format("Ymd")
|
||||
stat, err := SharedNodeTrafficDailyStatDAO.SumDailyStat(tx, nodeconfigs.NodeRoleNode, nodeId, today, today)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if stat != nil {
|
||||
value = stat.Bytes
|
||||
} else {
|
||||
value = 0
|
||||
}
|
||||
case nodeconfigs.NodeActionParamMonthlyTrafficOut:
|
||||
var monthBegin = timeutil.Format("Ym01")
|
||||
var today = timeutil.Format("Ymd")
|
||||
stat, err := SharedNodeTrafficDailyStatDAO.SumDailyStat(tx, nodeconfigs.NodeRoleNode, nodeId, monthBegin, today)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if stat != nil {
|
||||
value = stat.Bytes
|
||||
} else {
|
||||
value = 0
|
||||
}
|
||||
case nodeconfigs.NodeActionParamBandwidthIn:
|
||||
itemValue, err := SharedNodeValueDAO.FindLatestNodeValue(tx, nodeconfigs.NodeRoleNode, nodeId, nodeconfigs.NodeValueItemAllTraffic)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if itemValue == nil {
|
||||
return 0, nil
|
||||
}
|
||||
var mapValue = itemValue.DecodeMapValue()
|
||||
if mapValue != nil {
|
||||
value = mapValue.GetInt64("avgInBytes") * 8
|
||||
} else {
|
||||
value = 0
|
||||
}
|
||||
case nodeconfigs.NodeActionParamBandwidthOut:
|
||||
itemValue, err := SharedNodeValueDAO.FindLatestNodeValue(tx, nodeconfigs.NodeRoleNode, nodeId, nodeconfigs.NodeValueItemAllTraffic)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if itemValue == nil {
|
||||
return 0, nil
|
||||
}
|
||||
var mapValue = itemValue.DecodeMapValue()
|
||||
if mapValue != nil {
|
||||
value = mapValue.GetInt64("avgOutBytes") * 8
|
||||
} else {
|
||||
value = 0
|
||||
}
|
||||
case nodeconfigs.NodeActionParamUDPDPSIn:
|
||||
itemValue, err := SharedNodeValueDAO.FindLatestNodeValue(tx, nodeconfigs.NodeRoleNode, nodeId, nodeconfigs.NodeValueItemAllTraffic)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if itemValue == nil {
|
||||
return 0, nil
|
||||
}
|
||||
var mapValue = itemValue.DecodeMapValue()
|
||||
if mapValue != nil {
|
||||
value = mapValue.GetInt64("avgUDPInDatagrams")
|
||||
} else {
|
||||
value = 0
|
||||
}
|
||||
case nodeconfigs.NodeActionParamUDPDPSOut:
|
||||
itemValue, err := SharedNodeValueDAO.FindLatestNodeValue(tx, nodeconfigs.NodeRoleNode, nodeId, nodeconfigs.NodeValueItemAllTraffic)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if itemValue == nil {
|
||||
return 0, nil
|
||||
}
|
||||
var mapValue = itemValue.DecodeMapValue()
|
||||
if mapValue != nil {
|
||||
value = mapValue.GetInt64("avgUDPOutDatagrams")
|
||||
} else {
|
||||
value = 0
|
||||
}
|
||||
case nodeconfigs.NodeActionParamCPUUsage:
|
||||
itemValue, err := SharedNodeValueDAO.FindLatestNodeValue(tx, nodeconfigs.NodeRoleNode, nodeId, nodeconfigs.NodeValueItemCPU)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if itemValue == nil {
|
||||
return 0, nil
|
||||
}
|
||||
var mapValue = itemValue.DecodeMapValue()
|
||||
if mapValue != nil {
|
||||
value = mapValue.GetFloat64("usage") * 100
|
||||
} else {
|
||||
value = 0
|
||||
}
|
||||
case nodeconfigs.NodeActionParamMemoryUsage:
|
||||
itemValue, err := SharedNodeValueDAO.FindLatestNodeValue(tx, nodeconfigs.NodeRoleNode, nodeId, nodeconfigs.NodeValueItemMemory)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if itemValue == nil {
|
||||
return 0, nil
|
||||
}
|
||||
var mapValue = itemValue.DecodeMapValue()
|
||||
if mapValue != nil {
|
||||
value = mapValue.GetFloat64("usage") * 100
|
||||
} else {
|
||||
value = 0
|
||||
}
|
||||
case nodeconfigs.NodeActionParamLoad:
|
||||
itemValue, err := SharedNodeValueDAO.FindLatestNodeValue(tx, nodeconfigs.NodeRoleNode, nodeId, nodeconfigs.NodeValueItemLoad)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if itemValue == nil {
|
||||
return 0, nil
|
||||
}
|
||||
var mapValue = itemValue.DecodeMapValue()
|
||||
if mapValue != nil {
|
||||
value = mapValue.GetInt64("load5m")
|
||||
} else {
|
||||
value = 0
|
||||
}
|
||||
case nodeconfigs.NodeActionParamHealthCheckFailure:
|
||||
// 不需要返回值
|
||||
|
||||
}
|
||||
return
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if b {
|
||||
return this.runAction(tx, nodeId, int64(action.Id), condsConfig, action.DecodeAction(), action.DecodeDuration())
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// 执行动作
|
||||
func (this *NodeDAO) runAction(tx *dbs.Tx, nodeId int64, actionId int64, condsConfig *nodeconfigs.NodeActionCondsConfig, actionConfig *nodeconfigs.NodeActionConfig, duration *shared.TimeDuration) error {
|
||||
if actionConfig == nil {
|
||||
return errors.New("'actionConfig' should not be nil")
|
||||
}
|
||||
|
||||
// 暂时不处理secondary clusters
|
||||
clusterId, err := this.Query(tx).
|
||||
Result("clusterId").
|
||||
Pk(nodeId).
|
||||
FindInt64Col(0)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if clusterId == 0 {
|
||||
return nil
|
||||
}
|
||||
|
||||
var status = &nodeconfigs.NodeActionStatus{
|
||||
ActionId: actionId,
|
||||
Conds: condsConfig,
|
||||
Action: actionConfig,
|
||||
CreatedAt: time.Now().Unix(),
|
||||
}
|
||||
|
||||
if duration != nil {
|
||||
var seconds = duration.Seconds()
|
||||
if seconds > 0 {
|
||||
status.ExpiresAt = time.Now().Unix() + seconds
|
||||
status.DurationSeconds = seconds
|
||||
}
|
||||
}
|
||||
if status.ExpiresAt <= 0 {
|
||||
status.ExpiresAt = time.Now().Unix() + 3600 // 默认1个小时
|
||||
}
|
||||
if status.DurationSeconds <= 0 {
|
||||
status.DurationSeconds = 3600
|
||||
}
|
||||
|
||||
// 特殊情况下的过期时间
|
||||
if condsConfig != nil {
|
||||
var now = time.Now()
|
||||
for _, cond := range condsConfig.Conds {
|
||||
if cond.Param == nodeconfigs.NodeActionParamDailyTrafficOut {
|
||||
// 当天结束
|
||||
var expiresAt = now.Unix() - int64(now.Hour()*3600) - int64(now.Minute()*60) - int64(now.Second()) + 86400
|
||||
if expiresAt > status.ExpiresAt {
|
||||
status.ExpiresAt = expiresAt
|
||||
}
|
||||
} else if cond.Param == nodeconfigs.NodeActionParamMonthlyTrafficOut {
|
||||
// 当月结束
|
||||
var endDay = 32 - time.Date(now.Year(), now.Month(), 32, 0, 0, 0, 0, time.Local).Day()
|
||||
|
||||
var expiresAt = now.Unix() - int64(now.Hour()*3600) - int64(now.Minute()*60) - int64(now.Second()) + int64((endDay-now.Day()+1)*86400)
|
||||
if expiresAt > status.ExpiresAt {
|
||||
status.ExpiresAt = expiresAt
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
statusJSON, err := json.Marshal(status)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
err = this.Query(tx).
|
||||
Pk(nodeId).
|
||||
Set("actionStatus", statusJSON).
|
||||
UpdateQuickly()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
switch actionConfig.Code {
|
||||
case nodeconfigs.NodeActionCodeWebHook:
|
||||
var url = maps.NewMap(actionConfig.Params).GetString("url")
|
||||
if len(url) > 0 {
|
||||
if strings.Contains(url, "?") {
|
||||
url += "&"
|
||||
} else {
|
||||
url += "?"
|
||||
}
|
||||
url += "role=node&clusterId=" + types.String(clusterId) + "&nodeId=" + types.String(nodeId)
|
||||
req, err := http.NewRequest(http.MethodGet, url, nil)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
var httpClient = utils.SharedHttpClient(5 * time.Second)
|
||||
httpResp, httpErr := httpClient.Do(req)
|
||||
if httpErr == nil {
|
||||
_ = httpResp.Body.Close()
|
||||
}
|
||||
}
|
||||
default:
|
||||
// 通知更新
|
||||
err = dns.SharedDNSTaskDAO.CreateClusterTask(tx, clusterId, dns.DNSTaskTypeClusterNodesChange)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
// 发送消息
|
||||
return SharedMessageDAO.CreateNodeMessage(tx, nodeconfigs.NodeRoleNode, clusterId, nodeId, MessageTypeNodeSchedule, MessageLevelError, "节点已满足调度条件", "节点已满足调度条件,并执行动作:"+nodeconfigs.FindNodeActionName(actionConfig.Code), nil, true)
|
||||
}
|
||||
|
||||
// CheckNodeIPAddresses 检查节点IP地址
|
||||
func (this *NodeDAO) CheckNodeIPAddresses(tx *dbs.Tx, node *Node) (shouldSkip bool, shouldOverwrite bool, ipAddressStrings []string, err error) {
|
||||
// 是否到期
|
||||
if len(node.OfflineDay) > 0 && node.OfflineDay < timeutil.Format("Ymd") {
|
||||
// 到期后直接跳过
|
||||
shouldSkip = true
|
||||
return
|
||||
}
|
||||
|
||||
// 是否为备用
|
||||
if node.IsBackupForCluster || node.IsBackupForGroup {
|
||||
shouldSkip = true
|
||||
return
|
||||
}
|
||||
|
||||
// 当前状态
|
||||
if len(node.ActionStatus) > 0 {
|
||||
var actionStatus = node.DecodeActionStatus()
|
||||
if actionStatus.ActionId > 0 && actionStatus.Action != nil {
|
||||
switch actionStatus.Action.Code {
|
||||
case nodeconfigs.NodeActionCodeUp:
|
||||
// do nothing
|
||||
return
|
||||
case nodeconfigs.NodeActionCodeDown:
|
||||
shouldSkip = true
|
||||
return
|
||||
case nodeconfigs.NodeActionCodeSwitchToBackupNodesInCluster:
|
||||
if node.ClusterId <= 0 {
|
||||
shouldSkip = true
|
||||
return
|
||||
}
|
||||
addresses, addressesErr := SharedNodeIPAddressDAO.FindAllBackupNodeAccessAndUpIPAddresses(tx, int64(node.ClusterId), 0, nodeconfigs.NodeRoleNode)
|
||||
if addressesErr != nil {
|
||||
return false, false, nil, addressesErr
|
||||
}
|
||||
for _, address := range addresses {
|
||||
var ip = address.DNSIP()
|
||||
if !lists.ContainsString(ipAddressStrings, ip) {
|
||||
ipAddressStrings = append(ipAddressStrings, ip)
|
||||
}
|
||||
}
|
||||
if len(ipAddressStrings) > 0 {
|
||||
shouldOverwrite = true
|
||||
}
|
||||
return
|
||||
case nodeconfigs.NodeActionCodeSwitchToBackupNodesInGroup:
|
||||
if node.GroupId <= 0 {
|
||||
shouldSkip = true
|
||||
return
|
||||
}
|
||||
addresses, addressesErr := SharedNodeIPAddressDAO.FindAllBackupNodeAccessAndUpIPAddresses(tx, 0, int64(node.GroupId), nodeconfigs.NodeRoleNode)
|
||||
if addressesErr != nil {
|
||||
return false, false, nil, addressesErr
|
||||
}
|
||||
for _, address := range addresses {
|
||||
var ip = address.DNSIP()
|
||||
if !lists.ContainsString(ipAddressStrings, ip) {
|
||||
ipAddressStrings = append(ipAddressStrings, ip)
|
||||
}
|
||||
}
|
||||
if len(ipAddressStrings) > 0 {
|
||||
shouldOverwrite = true
|
||||
}
|
||||
return
|
||||
case nodeconfigs.NodeActionCodeSwitchToBackupIP:
|
||||
ipAddressStrings = node.DecodeBackupIPs()
|
||||
shouldOverwrite = true
|
||||
return
|
||||
case nodeconfigs.NodeActionCodeEnableBackupNodesInCluster:
|
||||
if node.ClusterId <= 0 {
|
||||
shouldSkip = true
|
||||
return
|
||||
}
|
||||
addresses, addressesErr := SharedNodeIPAddressDAO.FindAllBackupNodeAccessAndUpIPAddresses(tx, int64(node.ClusterId), 0, nodeconfigs.NodeRoleNode)
|
||||
if addressesErr != nil {
|
||||
return false, false, nil, addressesErr
|
||||
}
|
||||
for _, address := range addresses {
|
||||
var ip = address.DNSIP()
|
||||
if !lists.ContainsString(ipAddressStrings, ip) {
|
||||
ipAddressStrings = append(ipAddressStrings, ip)
|
||||
}
|
||||
}
|
||||
return
|
||||
case nodeconfigs.NodeActionCodeEnableBackupNodesInGroup:
|
||||
if node.GroupId <= 0 {
|
||||
// 不能跳过
|
||||
return
|
||||
}
|
||||
addresses, addressesErr := SharedNodeIPAddressDAO.FindAllBackupNodeAccessAndUpIPAddresses(tx, 0, int64(node.GroupId), nodeconfigs.NodeRoleNode)
|
||||
if addressesErr != nil {
|
||||
return false, false, nil, addressesErr
|
||||
}
|
||||
for _, address := range addresses {
|
||||
var ip = address.DNSIP()
|
||||
if !lists.ContainsString(ipAddressStrings, ip) {
|
||||
ipAddressStrings = append(ipAddressStrings, ip)
|
||||
}
|
||||
}
|
||||
return
|
||||
case nodeconfigs.NodeActionCodeEnableBackupIP:
|
||||
ipAddressStrings = node.DecodeBackupIPs()
|
||||
return
|
||||
case nodeconfigs.NodeActionCodeWebHook:
|
||||
// do nothing
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
Reference in New Issue
Block a user