mirror of
https://github.com/TeaOSLab/EdgeAPI.git
synced 2025-11-05 01:20:25 +08:00
DNS节点增加在线状态通知
This commit is contained in:
@@ -4,6 +4,7 @@ import (
|
|||||||
"crypto/md5"
|
"crypto/md5"
|
||||||
"fmt"
|
"fmt"
|
||||||
"github.com/TeaOSLab/EdgeAPI/internal/errors"
|
"github.com/TeaOSLab/EdgeAPI/internal/errors"
|
||||||
|
"github.com/TeaOSLab/EdgeCommon/pkg/nodeconfigs"
|
||||||
_ "github.com/go-sql-driver/mysql"
|
_ "github.com/go-sql-driver/mysql"
|
||||||
"github.com/iwind/TeaGo/Tea"
|
"github.com/iwind/TeaGo/Tea"
|
||||||
"github.com/iwind/TeaGo/dbs"
|
"github.com/iwind/TeaGo/dbs"
|
||||||
@@ -28,8 +29,8 @@ const (
|
|||||||
MessageTypeHealthCheckFailed MessageType = "HealthCheckFailed" // 节点健康检查失败
|
MessageTypeHealthCheckFailed MessageType = "HealthCheckFailed" // 节点健康检查失败
|
||||||
MessageTypeHealthCheckNodeUp MessageType = "HealthCheckNodeUp" // 因健康检查节点上线
|
MessageTypeHealthCheckNodeUp MessageType = "HealthCheckNodeUp" // 因健康检查节点上线
|
||||||
MessageTypeHealthCheckNodeDown MessageType = "HealthCheckNodeDown" // 因健康检查节点下线
|
MessageTypeHealthCheckNodeDown MessageType = "HealthCheckNodeDown" // 因健康检查节点下线
|
||||||
MessageTypeNodeInactive MessageType = "NodeInactive" // 节点不活跃
|
MessageTypeNodeInactive MessageType = "NodeInactive" // 边缘节点不活跃
|
||||||
MessageTypeNodeActive MessageType = "NodeActive" // 节点活跃
|
MessageTypeNodeActive MessageType = "NodeActive" // 边缘节点活跃
|
||||||
MessageTypeClusterDNSSyncFailed MessageType = "ClusterDNSSyncFailed" // DNS同步失败
|
MessageTypeClusterDNSSyncFailed MessageType = "ClusterDNSSyncFailed" // DNS同步失败
|
||||||
MessageTypeSSLCertExpiring MessageType = "SSLCertExpiring" // SSL证书即将过期
|
MessageTypeSSLCertExpiring MessageType = "SSLCertExpiring" // SSL证书即将过期
|
||||||
MessageTypeSSLCertACMETaskFailed MessageType = "SSLCertACMETaskFailed" // SSL证书任务执行失败
|
MessageTypeSSLCertACMETaskFailed MessageType = "SSLCertACMETaskFailed" // SSL证书任务执行失败
|
||||||
@@ -39,6 +40,9 @@ const (
|
|||||||
MessageTypeServerNamesAuditingFailed MessageType = "ServerNamesAuditingFailed" // 服务域名审核失败
|
MessageTypeServerNamesAuditingFailed MessageType = "ServerNamesAuditingFailed" // 服务域名审核失败
|
||||||
MessageTypeThresholdSatisfied MessageType = "ThresholdSatisfied" // 满足阈值
|
MessageTypeThresholdSatisfied MessageType = "ThresholdSatisfied" // 满足阈值
|
||||||
MessageTypeFirewallEvent MessageType = "FirewallEvent" // 防火墙事件
|
MessageTypeFirewallEvent MessageType = "FirewallEvent" // 防火墙事件
|
||||||
|
|
||||||
|
MessageTypeNSNodeInactive MessageType = "NSNodeInactive" // 边缘节点不活跃
|
||||||
|
MessageTypeNSNodeActive MessageType = "NSNodeActive" // 边缘节点活跃
|
||||||
)
|
)
|
||||||
|
|
||||||
type MessageDAO dbs.DAO
|
type MessageDAO dbs.DAO
|
||||||
@@ -93,8 +97,8 @@ func (this *MessageDAO) FindEnabledMessage(tx *dbs.Tx, id int64) (*Message, erro
|
|||||||
}
|
}
|
||||||
|
|
||||||
// CreateClusterMessage 创建集群消息
|
// CreateClusterMessage 创建集群消息
|
||||||
func (this *MessageDAO) CreateClusterMessage(tx *dbs.Tx, clusterId int64, messageType MessageType, level string, subject string, body string, paramsJSON []byte) error {
|
func (this *MessageDAO) CreateClusterMessage(tx *dbs.Tx, role string, clusterId int64, messageType MessageType, level string, subject string, body string, paramsJSON []byte) error {
|
||||||
_, err := this.createMessage(tx, clusterId, 0, messageType, level, subject, body, paramsJSON)
|
_, err := this.createMessage(tx, role, clusterId, 0, messageType, level, subject, body, paramsJSON)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@@ -113,9 +117,9 @@ func (this *MessageDAO) CreateClusterMessage(tx *dbs.Tx, clusterId int64, messag
|
|||||||
}
|
}
|
||||||
|
|
||||||
// CreateNodeMessage 创建节点消息
|
// CreateNodeMessage 创建节点消息
|
||||||
func (this *MessageDAO) CreateNodeMessage(tx *dbs.Tx, clusterId int64, nodeId int64, messageType MessageType, level string, subject string, body string, paramsJSON []byte) error {
|
func (this *MessageDAO) CreateNodeMessage(tx *dbs.Tx, role string, clusterId int64, nodeId int64, messageType MessageType, level string, subject string, body string, paramsJSON []byte) error {
|
||||||
// 检查N分钟内是否已经发送过
|
// 检查N分钟内是否已经发送过
|
||||||
hash := this.calHash(subject, body, paramsJSON)
|
hash := this.calHash(role, clusterId, nodeId, subject, body, paramsJSON)
|
||||||
exists, err := this.Query(tx).
|
exists, err := this.Query(tx).
|
||||||
Attr("hash", hash).
|
Attr("hash", hash).
|
||||||
Gt("createdAt", time.Now().Unix()-10*60). // 10分钟
|
Gt("createdAt", time.Now().Unix()-10*60). // 10分钟
|
||||||
@@ -127,11 +131,13 @@ func (this *MessageDAO) CreateNodeMessage(tx *dbs.Tx, clusterId int64, nodeId in
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
_, err = this.createMessage(tx, clusterId, nodeId, messageType, level, subject, body, paramsJSON)
|
_, err = this.createMessage(tx, role, clusterId, nodeId, messageType, level, subject, body, paramsJSON)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO 目前只支持边缘节点发送消息,将来要支持NS节点
|
||||||
|
if role == nodeconfigs.NodeRoleNode {
|
||||||
// 发送给媒介接收人 - 集群
|
// 发送给媒介接收人 - 集群
|
||||||
err = SharedMessageTaskDAO.CreateMessageTasks(tx, MessageTaskTarget{
|
err = SharedMessageTaskDAO.CreateMessageTasks(tx, MessageTaskTarget{
|
||||||
ClusterId: clusterId,
|
ClusterId: clusterId,
|
||||||
@@ -153,6 +159,7 @@ func (this *MessageDAO) CreateNodeMessage(tx *dbs.Tx, clusterId int64, nodeId in
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
@@ -179,7 +186,7 @@ func (this *MessageDAO) CreateMessage(tx *dbs.Tx, adminId int64, userId int64, m
|
|||||||
op.State = MessageStateEnabled
|
op.State = MessageStateEnabled
|
||||||
op.IsRead = false
|
op.IsRead = false
|
||||||
op.Day = timeutil.Format("Ymd")
|
op.Day = timeutil.Format("Ymd")
|
||||||
op.Hash = this.calHash(subject, body, paramsJSON)
|
op.Hash = this.calHash(nodeconfigs.NodeRoleAdmin, 0, 0, subject, body, paramsJSON)
|
||||||
err := this.Save(tx, op)
|
err := this.Save(tx, op)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
@@ -287,13 +294,14 @@ func (this *MessageDAO) CheckMessageUser(tx *dbs.Tx, messageId int64, adminId in
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 创建消息
|
// 创建消息
|
||||||
func (this *MessageDAO) createMessage(tx *dbs.Tx, clusterId int64, nodeId int64, messageType MessageType, level string, subject string, body string, paramsJSON []byte) (int64, error) {
|
func (this *MessageDAO) createMessage(tx *dbs.Tx, role string, clusterId int64, nodeId int64, messageType MessageType, level string, subject string, body string, paramsJSON []byte) (int64, error) {
|
||||||
// TODO 检查同样的消息最近是否发送过
|
// TODO 检查同样的消息最近是否发送过
|
||||||
|
|
||||||
// 创建新消息
|
// 创建新消息
|
||||||
op := NewMessageOperator()
|
op := NewMessageOperator()
|
||||||
op.AdminId = 0 // TODO
|
op.AdminId = 0 // TODO
|
||||||
op.UserId = 0 // TODO
|
op.UserId = 0 // TODO
|
||||||
|
op.Role = role
|
||||||
op.ClusterId = clusterId
|
op.ClusterId = clusterId
|
||||||
op.NodeId = nodeId
|
op.NodeId = nodeId
|
||||||
op.Type = messageType
|
op.Type = messageType
|
||||||
@@ -314,7 +322,7 @@ func (this *MessageDAO) createMessage(tx *dbs.Tx, clusterId int64, nodeId int64,
|
|||||||
op.State = MessageStateEnabled
|
op.State = MessageStateEnabled
|
||||||
op.CreatedAt = time.Now().Unix()
|
op.CreatedAt = time.Now().Unix()
|
||||||
op.Day = timeutil.Format("Ymd")
|
op.Day = timeutil.Format("Ymd")
|
||||||
op.Hash = this.calHash(subject, body, paramsJSON)
|
op.Hash = this.calHash(role, clusterId, nodeId, subject, body, paramsJSON)
|
||||||
|
|
||||||
err := this.Save(tx, op)
|
err := this.Save(tx, op)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -324,10 +332,11 @@ func (this *MessageDAO) createMessage(tx *dbs.Tx, clusterId int64, nodeId int64,
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 计算Hash
|
// 计算Hash
|
||||||
func (this *MessageDAO) calHash(subject string, body string, paramsJSON []byte) string {
|
func (this *MessageDAO) calHash(role string, clusterId int64, nodeId int64, subject string, body string, paramsJSON []byte) string {
|
||||||
h := md5.New()
|
h := md5.New()
|
||||||
h.Write([]byte(subject))
|
h.Write([]byte(role + "@" + types.String(clusterId) + "@" + types.String(nodeId)))
|
||||||
h.Write([]byte(body))
|
h.Write([]byte(subject + "@"))
|
||||||
|
h.Write([]byte(body + "@"))
|
||||||
h.Write(paramsJSON)
|
h.Write(paramsJSON)
|
||||||
return fmt.Sprintf("%x", h.Sum(nil))
|
return fmt.Sprintf("%x", h.Sum(nil))
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ type Message struct {
|
|||||||
Id uint64 `field:"id"` // ID
|
Id uint64 `field:"id"` // ID
|
||||||
AdminId uint32 `field:"adminId"` // 管理员ID
|
AdminId uint32 `field:"adminId"` // 管理员ID
|
||||||
UserId uint32 `field:"userId"` // 用户ID
|
UserId uint32 `field:"userId"` // 用户ID
|
||||||
|
Role string `field:"role"` // 角色
|
||||||
ClusterId uint32 `field:"clusterId"` // 集群ID
|
ClusterId uint32 `field:"clusterId"` // 集群ID
|
||||||
NodeId uint32 `field:"nodeId"` // 节点ID
|
NodeId uint32 `field:"nodeId"` // 节点ID
|
||||||
Level string `field:"level"` // 级别
|
Level string `field:"level"` // 级别
|
||||||
@@ -23,6 +24,7 @@ type MessageOperator struct {
|
|||||||
Id interface{} // ID
|
Id interface{} // ID
|
||||||
AdminId interface{} // 管理员ID
|
AdminId interface{} // 管理员ID
|
||||||
UserId interface{} // 用户ID
|
UserId interface{} // 用户ID
|
||||||
|
Role interface{} // 角色
|
||||||
ClusterId interface{} // 集群ID
|
ClusterId interface{} // 集群ID
|
||||||
NodeId interface{} // 节点ID
|
NodeId interface{} // 节点ID
|
||||||
Level interface{} // 级别
|
Level interface{} // 级别
|
||||||
|
|||||||
@@ -134,9 +134,9 @@ func (this *NSNodeDAO) CountAllEnabledNodesMatch(tx *dbs.Tx, clusterId int64, in
|
|||||||
case configutils.BoolStateAll:
|
case configutils.BoolStateAll:
|
||||||
// 所有
|
// 所有
|
||||||
case configutils.BoolStateYes:
|
case configutils.BoolStateYes:
|
||||||
query.Where("JSON_EXTRACT(status, '$.isActive') AND UNIX_TIMESTAMP()-JSON_EXTRACT(status, '$.updatedAt')<=60")
|
query.Where("(isActive=1 AND JSON_EXTRACT(status, '$.isActive') AND UNIX_TIMESTAMP()-JSON_EXTRACT(status, '$.updatedAt')<=60)")
|
||||||
case configutils.BoolStateNo:
|
case configutils.BoolStateNo:
|
||||||
query.Where("(status IS NULL OR NOT JSON_EXTRACT(status, '$.isActive') OR UNIX_TIMESTAMP()-JSON_EXTRACT(status, '$.updatedAt')>60)")
|
query.Where("(isActive=0 OR status IS NULL OR NOT JSON_EXTRACT(status, '$.isActive') OR UNIX_TIMESTAMP()-JSON_EXTRACT(status, '$.updatedAt')>60)")
|
||||||
}
|
}
|
||||||
if len(keyword) > 0 {
|
if len(keyword) > 0 {
|
||||||
query.Where("(name LIKE :keyword)").
|
query.Where("(name LIKE :keyword)").
|
||||||
@@ -167,9 +167,9 @@ func (this *NSNodeDAO) ListAllEnabledNodesMatch(tx *dbs.Tx, clusterId int64, ins
|
|||||||
case configutils.BoolStateAll:
|
case configutils.BoolStateAll:
|
||||||
// 所有
|
// 所有
|
||||||
case configutils.BoolStateYes:
|
case configutils.BoolStateYes:
|
||||||
query.Where("JSON_EXTRACT(status, '$.isActive') AND UNIX_TIMESTAMP()-JSON_EXTRACT(status, '$.updatedAt')<=60")
|
query.Where("(isActive=1 AND JSON_EXTRACT(status, '$.isActive') AND UNIX_TIMESTAMP()-JSON_EXTRACT(status, '$.updatedAt')<=60)")
|
||||||
case configutils.BoolStateNo:
|
case configutils.BoolStateNo:
|
||||||
query.Where("(status IS NULL OR NOT JSON_EXTRACT(status, '$.isActive') OR UNIX_TIMESTAMP()-JSON_EXTRACT(status, '$.updatedAt')>60)")
|
query.Where("(isActive=0 OR status IS NULL OR NOT JSON_EXTRACT(status, '$.isActive') OR UNIX_TIMESTAMP()-JSON_EXTRACT(status, '$.updatedAt')>60)")
|
||||||
}
|
}
|
||||||
|
|
||||||
if clusterId > 0 {
|
if clusterId > 0 {
|
||||||
@@ -428,6 +428,76 @@ func (this *NSNodeDAO) FindNodeClusterId(tx *dbs.Tx, nodeId int64) (int64, error
|
|||||||
FindInt64Col(0)
|
FindInt64Col(0)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// FindNodeActive 检查节点活跃状态
|
||||||
|
func (this *NSNodeDAO) FindNodeActive(tx *dbs.Tx, nodeId int64) (bool, error) {
|
||||||
|
isActive, err := this.Query(tx).
|
||||||
|
Pk(nodeId).
|
||||||
|
Result("isActive").
|
||||||
|
FindIntCol(0)
|
||||||
|
if err != nil {
|
||||||
|
return false, err
|
||||||
|
}
|
||||||
|
return isActive == 1, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// UpdateNodeActive 修改节点活跃状态
|
||||||
|
func (this *NSNodeDAO) UpdateNodeActive(tx *dbs.Tx, nodeId int64, isActive bool) error {
|
||||||
|
if nodeId <= 0 {
|
||||||
|
return errors.New("invalid nodeId")
|
||||||
|
}
|
||||||
|
_, err := this.Query(tx).
|
||||||
|
Pk(nodeId).
|
||||||
|
Set("isActive", isActive).
|
||||||
|
Set("statusIsNotified", false).
|
||||||
|
Update()
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// UpdateNodeConnectedAPINodes 修改当前连接的API节点
|
||||||
|
func (this *NSNodeDAO) UpdateNodeConnectedAPINodes(tx *dbs.Tx, nodeId int64, apiNodeIds []int64) error {
|
||||||
|
if nodeId <= 0 {
|
||||||
|
return errors.New("invalid nodeId")
|
||||||
|
}
|
||||||
|
|
||||||
|
op := NewNSNodeOperator()
|
||||||
|
op.Id = nodeId
|
||||||
|
|
||||||
|
if len(apiNodeIds) > 0 {
|
||||||
|
apiNodeIdsJSON, err := json.Marshal(apiNodeIds)
|
||||||
|
if err != nil {
|
||||||
|
return errors.Wrap(err)
|
||||||
|
}
|
||||||
|
op.ConnectedAPINodes = apiNodeIdsJSON
|
||||||
|
} else {
|
||||||
|
op.ConnectedAPINodes = "[]"
|
||||||
|
}
|
||||||
|
err := this.Save(tx, op)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// FindAllNotifyingInactiveNodesWithClusterId 取得某个集群所有等待通知离线离线的节点
|
||||||
|
func (this *NSNodeDAO) FindAllNotifyingInactiveNodesWithClusterId(tx *dbs.Tx, clusterId int64) (result []*NSNode, err error) {
|
||||||
|
_, err = this.Query(tx).
|
||||||
|
State(NSNodeStateEnabled).
|
||||||
|
Attr("clusterId", clusterId).
|
||||||
|
Attr("isOn", true). // 只监控启用的节点
|
||||||
|
Attr("isInstalled", true). // 只监控已经安装的节点
|
||||||
|
Attr("isActive", false). // 当前已经离线的
|
||||||
|
Attr("statusIsNotified", false).
|
||||||
|
Result("id", "name").
|
||||||
|
Slice(&result).
|
||||||
|
FindAll()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// UpdateNodeStatusIsNotified 设置状态已经通知
|
||||||
|
func (this *NSNodeDAO) UpdateNodeStatusIsNotified(tx *dbs.Tx, nodeId int64) error {
|
||||||
|
return this.Query(tx).
|
||||||
|
Pk(nodeId).
|
||||||
|
Set("statusIsNotified", true).
|
||||||
|
UpdateQuickly()
|
||||||
|
}
|
||||||
|
|
||||||
// NotifyUpdate 通知更新
|
// NotifyUpdate 通知更新
|
||||||
func (this *NSNodeDAO) NotifyUpdate(tx *dbs.Tx, nodeId int64) error {
|
func (this *NSNodeDAO) NotifyUpdate(tx *dbs.Tx, nodeId int64) error {
|
||||||
// TODO 先什么都不做
|
// TODO 先什么都不做
|
||||||
|
|||||||
@@ -15,6 +15,9 @@ type NSNode struct {
|
|||||||
InstallStatus string `field:"installStatus"` // 安装状态
|
InstallStatus string `field:"installStatus"` // 安装状态
|
||||||
InstallDir string `field:"installDir"` // 安装目录
|
InstallDir string `field:"installDir"` // 安装目录
|
||||||
State uint8 `field:"state"` // 状态
|
State uint8 `field:"state"` // 状态
|
||||||
|
IsActive uint8 `field:"isActive"` // 是否活跃
|
||||||
|
StatusIsNotified uint8 `field:"statusIsNotified"` // 活跃状态已经通知
|
||||||
|
ConnectedAPINodes string `field:"connectedAPINodes"` // 当前连接的API节点
|
||||||
}
|
}
|
||||||
|
|
||||||
type NSNodeOperator struct {
|
type NSNodeOperator struct {
|
||||||
@@ -31,6 +34,9 @@ type NSNodeOperator struct {
|
|||||||
InstallStatus interface{} // 安装状态
|
InstallStatus interface{} // 安装状态
|
||||||
InstallDir interface{} // 安装目录
|
InstallDir interface{} // 安装目录
|
||||||
State interface{} // 状态
|
State interface{} // 状态
|
||||||
|
IsActive interface{} // 是否活跃
|
||||||
|
StatusIsNotified interface{} // 活跃状态已经通知
|
||||||
|
ConnectedAPINodes interface{} // 当前连接的API节点
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewNSNodeOperator() *NSNodeOperator {
|
func NewNSNodeOperator() *NSNodeOperator {
|
||||||
|
|||||||
@@ -252,7 +252,7 @@ func (this *NodeThresholdDAO) FireNodeThreshold(tx *dbs.Tx, role string, nodeId
|
|||||||
body = strings.Replace(body, "${item.name}", itemName, -1)
|
body = strings.Replace(body, "${item.name}", itemName, -1)
|
||||||
body = strings.Replace(body, "${value}", fmt.Sprintf("%.2f", paramValue), -1)
|
body = strings.Replace(body, "${value}", fmt.Sprintf("%.2f", paramValue), -1)
|
||||||
}
|
}
|
||||||
err = SharedMessageDAO.CreateNodeMessage(tx, clusterId, nodeId, MessageTypeThresholdSatisfied, MessageLevelWarning, subject, body, maps.Map{}.AsJSON())
|
err = SharedMessageDAO.CreateNodeMessage(tx, role, clusterId, nodeId, MessageTypeThresholdSatisfied, MessageLevelWarning, subject, body, maps.Map{}.AsJSON())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -119,6 +119,7 @@ func (this *NSNodeService) ListEnabledNSNodesMatch(ctx context.Context, req *pb.
|
|||||||
IsOn: node.IsOn == 1,
|
IsOn: node.IsOn == 1,
|
||||||
UniqueId: node.UniqueId,
|
UniqueId: node.UniqueId,
|
||||||
Secret: node.Secret,
|
Secret: node.Secret,
|
||||||
|
IsActive: node.IsActive == 1,
|
||||||
IsInstalled: node.IsInstalled == 1,
|
IsInstalled: node.IsInstalled == 1,
|
||||||
InstallDir: node.InstallDir,
|
InstallDir: node.InstallDir,
|
||||||
IsUp: node.IsUp == 1,
|
IsUp: node.IsUp == 1,
|
||||||
@@ -420,3 +421,21 @@ func (this *NSNodeService) DownloadNSNodeInstallationFile(ctx context.Context, r
|
|||||||
Filename: filepath.Base(file.Path),
|
Filename: filepath.Base(file.Path),
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// UpdateNSNodeConnectedAPINodes 更改节点连接的API节点信息
|
||||||
|
func (this *NSNodeService) UpdateNSNodeConnectedAPINodes(ctx context.Context, req *pb.UpdateNSNodeConnectedAPINodesRequest) (*pb.RPCSuccess, error) {
|
||||||
|
// 校验节点
|
||||||
|
_, _, nodeId, err := rpcutils.ValidateRequest(ctx, rpcutils.UserTypeDNS)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
tx := this.NullTx()
|
||||||
|
|
||||||
|
err = nameservers.SharedNSNodeDAO.UpdateNodeConnectedAPINodes(tx, nodeId, req.ApiNodeIds)
|
||||||
|
if err != nil {
|
||||||
|
return nil, errors.Wrap(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return this.Success()
|
||||||
|
}
|
||||||
|
|||||||
290
internal/rpc/services/nameservers/service_ns_node_stream.go
Normal file
290
internal/rpc/services/nameservers/service_ns_node_stream.go
Normal file
@@ -0,0 +1,290 @@
|
|||||||
|
package nameservers
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"encoding/json"
|
||||||
|
"fmt"
|
||||||
|
"github.com/TeaOSLab/EdgeAPI/internal/configs"
|
||||||
|
"github.com/TeaOSLab/EdgeAPI/internal/db/models"
|
||||||
|
"github.com/TeaOSLab/EdgeAPI/internal/db/models/nameservers"
|
||||||
|
"github.com/TeaOSLab/EdgeAPI/internal/errors"
|
||||||
|
rpcutils "github.com/TeaOSLab/EdgeAPI/internal/rpc/utils"
|
||||||
|
"github.com/TeaOSLab/EdgeCommon/pkg/messageconfigs"
|
||||||
|
"github.com/TeaOSLab/EdgeCommon/pkg/nodeconfigs"
|
||||||
|
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
|
||||||
|
"github.com/iwind/TeaGo/logs"
|
||||||
|
"strconv"
|
||||||
|
"sync"
|
||||||
|
"sync/atomic"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
// CommandRequest 命令请求相关
|
||||||
|
type CommandRequest struct {
|
||||||
|
Id int64
|
||||||
|
Code string
|
||||||
|
CommandJSON []byte
|
||||||
|
}
|
||||||
|
|
||||||
|
type CommandRequestWaiting struct {
|
||||||
|
Timestamp int64
|
||||||
|
Chan chan *pb.NSNodeStreamMessage
|
||||||
|
}
|
||||||
|
|
||||||
|
func (this *CommandRequestWaiting) Close() {
|
||||||
|
defer func() {
|
||||||
|
recover()
|
||||||
|
}()
|
||||||
|
|
||||||
|
close(this.Chan)
|
||||||
|
}
|
||||||
|
|
||||||
|
var responseChanMap = map[int64]*CommandRequestWaiting{} // request id => response
|
||||||
|
var commandRequestId = int64(0)
|
||||||
|
|
||||||
|
var nodeLocker = &sync.Mutex{}
|
||||||
|
var requestChanMap = map[int64]chan *CommandRequest{} // node id => chan
|
||||||
|
|
||||||
|
func NextCommandRequestId() int64 {
|
||||||
|
return atomic.AddInt64(&commandRequestId, 1)
|
||||||
|
}
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
// 清理WaitingChannelMap
|
||||||
|
ticker := time.NewTicker(30 * time.Second)
|
||||||
|
go func() {
|
||||||
|
for range ticker.C {
|
||||||
|
nodeLocker.Lock()
|
||||||
|
for requestId, request := range responseChanMap {
|
||||||
|
if time.Now().Unix()-request.Timestamp > 3600 {
|
||||||
|
responseChanMap[requestId].Close()
|
||||||
|
delete(responseChanMap, requestId)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
nodeLocker.Unlock()
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
}
|
||||||
|
|
||||||
|
// NsNodeStream 节点stream
|
||||||
|
func (this *NSNodeService) NsNodeStream(server pb.NSNodeService_NsNodeStreamServer) error {
|
||||||
|
// TODO 使用此stream快速通知NS节点更新
|
||||||
|
// 校验节点
|
||||||
|
_, _, nodeId, err := rpcutils.ValidateRequest(server.Context(), rpcutils.UserTypeDNS)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// 返回连接成功
|
||||||
|
{
|
||||||
|
apiConfig, err := configs.SharedAPIConfig()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
connectedMessage := &messageconfigs.NSConnectedAPINodeMessage{APINodeId: apiConfig.NumberId()}
|
||||||
|
connectedMessageJSON, err := json.Marshal(connectedMessage)
|
||||||
|
if err != nil {
|
||||||
|
return errors.Wrap(err)
|
||||||
|
}
|
||||||
|
err = server.Send(&pb.NSNodeStreamMessage{
|
||||||
|
Code: messageconfigs.NSMessageCodeConnectedAPINode,
|
||||||
|
DataJSON: connectedMessageJSON,
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//logs.Println("[RPC]accepted ns node '" + types.String(nodeId) + "' connection")
|
||||||
|
|
||||||
|
tx := this.NullTx()
|
||||||
|
|
||||||
|
// 标记为活跃状态
|
||||||
|
oldIsActive, err := nameservers.SharedNSNodeDAO.FindNodeActive(tx, nodeId)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if !oldIsActive {
|
||||||
|
err = nameservers.SharedNSNodeDAO.UpdateNodeActive(tx, nodeId, true)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// 发送恢复消息
|
||||||
|
clusterId, err := nameservers.SharedNSNodeDAO.FindNodeClusterId(tx, nodeId)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
nodeName, err := nameservers.SharedNSNodeDAO.FindEnabledNSNodeName(tx, nodeId)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
subject := "DNS节点\"" + nodeName + "\"已经恢复在线"
|
||||||
|
msg := "DNS节点\"" + nodeName + "\"已经恢复在线"
|
||||||
|
err = models.SharedMessageDAO.CreateNodeMessage(tx, nodeconfigs.NodeRoleDNS, clusterId, nodeId, models.MessageTypeNSNodeActive, models.MessageLevelSuccess, subject, msg, nil)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
nodeLocker.Lock()
|
||||||
|
requestChan, ok := requestChanMap[nodeId]
|
||||||
|
if !ok {
|
||||||
|
requestChan = make(chan *CommandRequest, 1024)
|
||||||
|
requestChanMap[nodeId] = requestChan
|
||||||
|
}
|
||||||
|
nodeLocker.Unlock()
|
||||||
|
|
||||||
|
// 发送请求
|
||||||
|
go func() {
|
||||||
|
for {
|
||||||
|
select {
|
||||||
|
case <-server.Context().Done():
|
||||||
|
return
|
||||||
|
case commandRequest := <-requestChan:
|
||||||
|
// logs.Println("[RPC]sending command '" + commandRequest.Code + "' to node '" + strconv.FormatInt(nodeId, 10) + "'")
|
||||||
|
retries := 3 // 错误重试次数
|
||||||
|
for i := 0; i < retries; i++ {
|
||||||
|
err := server.Send(&pb.NSNodeStreamMessage{
|
||||||
|
RequestId: commandRequest.Id,
|
||||||
|
Code: commandRequest.Code,
|
||||||
|
DataJSON: commandRequest.CommandJSON,
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
if i == retries-1 {
|
||||||
|
logs.Println("[RPC]send command '" + commandRequest.Code + "' failed: " + err.Error())
|
||||||
|
} else {
|
||||||
|
time.Sleep(1 * time.Second)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
|
||||||
|
// 接受请求
|
||||||
|
for {
|
||||||
|
req, err := server.Recv()
|
||||||
|
if err != nil {
|
||||||
|
// 修改节点状态
|
||||||
|
err1 := nameservers.SharedNSNodeDAO.UpdateNodeActive(tx, nodeId, false)
|
||||||
|
if err1 != nil {
|
||||||
|
logs.Println(err1.Error())
|
||||||
|
}
|
||||||
|
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
func(req *pb.NSNodeStreamMessage) {
|
||||||
|
// 因为 responseChan.Chan 有被关闭的风险,所以我们使用recover防止panic
|
||||||
|
defer func() {
|
||||||
|
recover()
|
||||||
|
}()
|
||||||
|
|
||||||
|
nodeLocker.Lock()
|
||||||
|
responseChan, ok := responseChanMap[req.RequestId]
|
||||||
|
if ok {
|
||||||
|
select {
|
||||||
|
case responseChan.Chan <- req:
|
||||||
|
default:
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
nodeLocker.Unlock()
|
||||||
|
}(req)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// SendCommandToNSNode 向节点发送命令
|
||||||
|
func (this *NSNodeService) SendCommandToNSNode(ctx context.Context, req *pb.NSNodeStreamMessage) (*pb.NSNodeStreamMessage, error) {
|
||||||
|
// 校验请求
|
||||||
|
_, _, err := this.ValidateAdminAndUser(ctx, 0, 0)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
nodeId := req.NsNodeId
|
||||||
|
if nodeId <= 0 {
|
||||||
|
return nil, errors.New("node id should not be less than 0")
|
||||||
|
}
|
||||||
|
|
||||||
|
nodeLocker.Lock()
|
||||||
|
requestChan, ok := requestChanMap[nodeId]
|
||||||
|
nodeLocker.Unlock()
|
||||||
|
|
||||||
|
if !ok {
|
||||||
|
return &pb.NSNodeStreamMessage{
|
||||||
|
RequestId: req.RequestId,
|
||||||
|
IsOk: false,
|
||||||
|
Message: "node '" + strconv.FormatInt(nodeId, 10) + "' not connected yet",
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
req.RequestId = NextCommandRequestId()
|
||||||
|
|
||||||
|
select {
|
||||||
|
case requestChan <- &CommandRequest{
|
||||||
|
Id: req.RequestId,
|
||||||
|
Code: req.Code,
|
||||||
|
CommandJSON: req.DataJSON,
|
||||||
|
}:
|
||||||
|
// 加入到等待队列中
|
||||||
|
respChan := make(chan *pb.NSNodeStreamMessage, 1)
|
||||||
|
waiting := &CommandRequestWaiting{
|
||||||
|
Timestamp: time.Now().Unix(),
|
||||||
|
Chan: respChan,
|
||||||
|
}
|
||||||
|
|
||||||
|
nodeLocker.Lock()
|
||||||
|
responseChanMap[req.RequestId] = waiting
|
||||||
|
nodeLocker.Unlock()
|
||||||
|
|
||||||
|
// 等待响应
|
||||||
|
timeoutSeconds := req.TimeoutSeconds
|
||||||
|
if timeoutSeconds <= 0 {
|
||||||
|
timeoutSeconds = 10
|
||||||
|
}
|
||||||
|
timeout := time.NewTimer(time.Duration(timeoutSeconds) * time.Second)
|
||||||
|
select {
|
||||||
|
case resp := <-respChan:
|
||||||
|
// 从队列中删除
|
||||||
|
nodeLocker.Lock()
|
||||||
|
delete(responseChanMap, req.RequestId)
|
||||||
|
waiting.Close()
|
||||||
|
nodeLocker.Unlock()
|
||||||
|
|
||||||
|
if resp == nil {
|
||||||
|
return &pb.NSNodeStreamMessage{
|
||||||
|
RequestId: req.RequestId,
|
||||||
|
Code: req.Code,
|
||||||
|
Message: "response timeout",
|
||||||
|
IsOk: false,
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
return resp, nil
|
||||||
|
case <-timeout.C:
|
||||||
|
// 从队列中删除
|
||||||
|
nodeLocker.Lock()
|
||||||
|
delete(responseChanMap, req.RequestId)
|
||||||
|
waiting.Close()
|
||||||
|
nodeLocker.Unlock()
|
||||||
|
|
||||||
|
return &pb.NSNodeStreamMessage{
|
||||||
|
RequestId: req.RequestId,
|
||||||
|
Code: req.Code,
|
||||||
|
Message: "response timeout over " + fmt.Sprintf("%d", timeoutSeconds) + " seconds",
|
||||||
|
IsOk: false,
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
return &pb.NSNodeStreamMessage{
|
||||||
|
RequestId: req.RequestId,
|
||||||
|
Code: req.Code,
|
||||||
|
Message: "command queue is full over " + strconv.Itoa(len(requestChan)),
|
||||||
|
IsOk: false,
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -3,15 +3,17 @@ package services
|
|||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"github.com/TeaOSLab/EdgeAPI/internal/db/models"
|
"github.com/TeaOSLab/EdgeAPI/internal/db/models"
|
||||||
|
"github.com/TeaOSLab/EdgeAPI/internal/db/models/nameservers"
|
||||||
|
"github.com/TeaOSLab/EdgeCommon/pkg/nodeconfigs"
|
||||||
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
|
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
|
||||||
)
|
)
|
||||||
|
|
||||||
// 消息相关服务
|
// MessageService 消息相关服务
|
||||||
type MessageService struct {
|
type MessageService struct {
|
||||||
BaseService
|
BaseService
|
||||||
}
|
}
|
||||||
|
|
||||||
// 计算未读消息数
|
// CountUnreadMessages 计算未读消息数
|
||||||
func (this *MessageService) CountUnreadMessages(ctx context.Context, req *pb.CountUnreadMessagesRequest) (*pb.RPCCountResponse, error) {
|
func (this *MessageService) CountUnreadMessages(ctx context.Context, req *pb.CountUnreadMessagesRequest) (*pb.RPCCountResponse, error) {
|
||||||
// 校验请求
|
// 校验请求
|
||||||
adminId, userId, err := this.ValidateAdminAndUser(ctx, 0, 0)
|
adminId, userId, err := this.ValidateAdminAndUser(ctx, 0, 0)
|
||||||
@@ -28,7 +30,7 @@ func (this *MessageService) CountUnreadMessages(ctx context.Context, req *pb.Cou
|
|||||||
return this.SuccessCount(count)
|
return this.SuccessCount(count)
|
||||||
}
|
}
|
||||||
|
|
||||||
// 列出单页未读消息
|
// ListUnreadMessages 列出单页未读消息
|
||||||
func (this *MessageService) ListUnreadMessages(ctx context.Context, req *pb.ListUnreadMessagesRequest) (*pb.ListUnreadMessagesResponse, error) {
|
func (this *MessageService) ListUnreadMessages(ctx context.Context, req *pb.ListUnreadMessagesRequest) (*pb.ListUnreadMessagesResponse, error) {
|
||||||
// 校验请求
|
// 校验请求
|
||||||
adminId, userId, err := this.ValidateAdminAndUser(ctx, 0, 0)
|
adminId, userId, err := this.ValidateAdminAndUser(ctx, 0, 0)
|
||||||
@@ -48,6 +50,8 @@ func (this *MessageService) ListUnreadMessages(ctx context.Context, req *pb.List
|
|||||||
var pbNode *pb.Node = nil
|
var pbNode *pb.Node = nil
|
||||||
|
|
||||||
if message.ClusterId > 0 {
|
if message.ClusterId > 0 {
|
||||||
|
switch message.Role {
|
||||||
|
case nodeconfigs.NodeRoleNode:
|
||||||
cluster, err := models.SharedNodeClusterDAO.FindEnabledNodeCluster(tx, int64(message.ClusterId))
|
cluster, err := models.SharedNodeClusterDAO.FindEnabledNodeCluster(tx, int64(message.ClusterId))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
@@ -58,9 +62,23 @@ func (this *MessageService) ListUnreadMessages(ctx context.Context, req *pb.List
|
|||||||
Name: cluster.Name,
|
Name: cluster.Name,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
case nodeconfigs.NodeRoleDNS:
|
||||||
|
cluster, err := nameservers.SharedNSClusterDAO.FindEnabledNSCluster(tx, int64(message.ClusterId))
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if cluster != nil {
|
||||||
|
pbCluster = &pb.NodeCluster{
|
||||||
|
Id: int64(cluster.Id),
|
||||||
|
Name: cluster.Name,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if message.NodeId > 0 {
|
if message.NodeId > 0 {
|
||||||
|
switch message.Role {
|
||||||
|
case nodeconfigs.NodeRoleNode:
|
||||||
node, err := models.SharedNodeDAO.FindEnabledNode(tx, int64(message.NodeId))
|
node, err := models.SharedNodeDAO.FindEnabledNode(tx, int64(message.NodeId))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
@@ -71,10 +89,23 @@ func (this *MessageService) ListUnreadMessages(ctx context.Context, req *pb.List
|
|||||||
Name: node.Name,
|
Name: node.Name,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
case nodeconfigs.NodeRoleDNS:
|
||||||
|
node, err := nameservers.SharedNSNodeDAO.FindEnabledNSNode(tx, int64(message.NodeId))
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if node != nil {
|
||||||
|
pbNode = &pb.Node{
|
||||||
|
Id: int64(node.Id),
|
||||||
|
Name: node.Name,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
result = append(result, &pb.Message{
|
result = append(result, &pb.Message{
|
||||||
Id: int64(message.Id),
|
Id: int64(message.Id),
|
||||||
|
Role: message.Role,
|
||||||
Type: message.Type,
|
Type: message.Type,
|
||||||
Body: message.Body,
|
Body: message.Body,
|
||||||
Level: message.Level,
|
Level: message.Level,
|
||||||
@@ -89,7 +120,7 @@ func (this *MessageService) ListUnreadMessages(ctx context.Context, req *pb.List
|
|||||||
return &pb.ListUnreadMessagesResponse{Messages: result}, nil
|
return &pb.ListUnreadMessagesResponse{Messages: result}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// 设置消息已读状态
|
// UpdateMessageRead 设置消息已读状态
|
||||||
func (this *MessageService) UpdateMessageRead(ctx context.Context, req *pb.UpdateMessageReadRequest) (*pb.RPCSuccess, error) {
|
func (this *MessageService) UpdateMessageRead(ctx context.Context, req *pb.UpdateMessageReadRequest) (*pb.RPCSuccess, error) {
|
||||||
// 校验请求
|
// 校验请求
|
||||||
adminId, userId, err := this.ValidateAdminAndUser(ctx, 0, 0)
|
adminId, userId, err := this.ValidateAdminAndUser(ctx, 0, 0)
|
||||||
@@ -115,7 +146,7 @@ func (this *MessageService) UpdateMessageRead(ctx context.Context, req *pb.Updat
|
|||||||
return this.Success()
|
return this.Success()
|
||||||
}
|
}
|
||||||
|
|
||||||
// 设置一组消息已读状态
|
// UpdateMessagesRead 设置一组消息已读状态
|
||||||
func (this *MessageService) UpdateMessagesRead(ctx context.Context, req *pb.UpdateMessagesReadRequest) (*pb.RPCSuccess, error) {
|
func (this *MessageService) UpdateMessagesRead(ctx context.Context, req *pb.UpdateMessagesReadRequest) (*pb.RPCSuccess, error) {
|
||||||
// 校验请求
|
// 校验请求
|
||||||
adminId, userId, err := this.ValidateAdminAndUser(ctx, 0, 0)
|
adminId, userId, err := this.ValidateAdminAndUser(ctx, 0, 0)
|
||||||
@@ -143,7 +174,7 @@ func (this *MessageService) UpdateMessagesRead(ctx context.Context, req *pb.Upda
|
|||||||
return this.Success()
|
return this.Success()
|
||||||
}
|
}
|
||||||
|
|
||||||
// 设置所有消息为已读
|
// UpdateAllMessagesRead 设置所有消息为已读
|
||||||
func (this *MessageService) UpdateAllMessagesRead(ctx context.Context, req *pb.UpdateAllMessagesReadRequest) (*pb.RPCSuccess, error) {
|
func (this *MessageService) UpdateAllMessagesRead(ctx context.Context, req *pb.UpdateAllMessagesReadRequest) (*pb.RPCSuccess, error) {
|
||||||
// 校验请求
|
// 校验请求
|
||||||
// 校验请求
|
// 校验请求
|
||||||
|
|||||||
@@ -9,6 +9,7 @@ import (
|
|||||||
"github.com/TeaOSLab/EdgeAPI/internal/errors"
|
"github.com/TeaOSLab/EdgeAPI/internal/errors"
|
||||||
rpcutils "github.com/TeaOSLab/EdgeAPI/internal/rpc/utils"
|
rpcutils "github.com/TeaOSLab/EdgeAPI/internal/rpc/utils"
|
||||||
"github.com/TeaOSLab/EdgeCommon/pkg/messageconfigs"
|
"github.com/TeaOSLab/EdgeCommon/pkg/messageconfigs"
|
||||||
|
"github.com/TeaOSLab/EdgeCommon/pkg/nodeconfigs"
|
||||||
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
|
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
|
||||||
"github.com/iwind/TeaGo/logs"
|
"github.com/iwind/TeaGo/logs"
|
||||||
"strconv"
|
"strconv"
|
||||||
@@ -119,7 +120,7 @@ func (this *NodeService) NodeStream(server pb.NodeService_NodeStreamServer) erro
|
|||||||
}
|
}
|
||||||
subject := "节点\"" + nodeName + "\"已经恢复在线"
|
subject := "节点\"" + nodeName + "\"已经恢复在线"
|
||||||
msg := "节点\"" + nodeName + "\"已经恢复在线"
|
msg := "节点\"" + nodeName + "\"已经恢复在线"
|
||||||
err = models.SharedMessageDAO.CreateNodeMessage(tx, clusterId, nodeId, models.MessageTypeNodeActive, models.MessageLevelSuccess, subject, msg, nil)
|
err = models.SharedMessageDAO.CreateNodeMessage(tx, nodeconfigs.NodeRoleNode, clusterId, nodeId, models.MessageTypeNodeActive, models.MessageLevelSuccess, subject, msg, nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|||||||
File diff suppressed because one or more lines are too long
@@ -6,6 +6,7 @@ import (
|
|||||||
"github.com/TeaOSLab/EdgeAPI/internal/db/models"
|
"github.com/TeaOSLab/EdgeAPI/internal/db/models"
|
||||||
"github.com/TeaOSLab/EdgeAPI/internal/utils"
|
"github.com/TeaOSLab/EdgeAPI/internal/utils"
|
||||||
"github.com/TeaOSLab/EdgeAPI/internal/utils/numberutils"
|
"github.com/TeaOSLab/EdgeAPI/internal/utils/numberutils"
|
||||||
|
"github.com/TeaOSLab/EdgeCommon/pkg/nodeconfigs"
|
||||||
"github.com/TeaOSLab/EdgeCommon/pkg/serverconfigs"
|
"github.com/TeaOSLab/EdgeCommon/pkg/serverconfigs"
|
||||||
"github.com/TeaOSLab/EdgeCommon/pkg/systemconfigs"
|
"github.com/TeaOSLab/EdgeCommon/pkg/systemconfigs"
|
||||||
"github.com/iwind/TeaGo/logs"
|
"github.com/iwind/TeaGo/logs"
|
||||||
@@ -132,7 +133,7 @@ func (this *HealthCheckClusterTask) loop(seconds int64) error {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
message := "有" + numberutils.FormatInt(len(failedResults)) + "个节点在健康检查中出现问题"
|
message := "有" + numberutils.FormatInt(len(failedResults)) + "个节点在健康检查中出现问题"
|
||||||
err = models.NewMessageDAO().CreateClusterMessage(nil, 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
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -139,10 +139,10 @@ func (this *HealthCheckExecutor) Run() ([]*HealthCheckResult, error) {
|
|||||||
// 通知恢复或下线
|
// 通知恢复或下线
|
||||||
if result.IsOk {
|
if result.IsOk {
|
||||||
message := "健康检查成功,节点\"" + result.Node.Name + "\"已恢复上线"
|
message := "健康检查成功,节点\"" + result.Node.Name + "\"已恢复上线"
|
||||||
err = models.NewMessageDAO().CreateNodeMessage(nil, this.clusterId, int64(result.Node.Id), models.MessageTypeHealthCheckNodeUp, models.MessageLevelSuccess, message, message, nil)
|
err = models.NewMessageDAO().CreateNodeMessage(nil, nodeconfigs.NodeRoleNode, this.clusterId, int64(result.Node.Id), models.MessageTypeHealthCheckNodeUp, models.MessageLevelSuccess, message, message, nil)
|
||||||
} else {
|
} else {
|
||||||
message := "健康检查失败,节点\"" + result.Node.Name + "\"已自动下线"
|
message := "健康检查失败,节点\"" + result.Node.Name + "\"已自动下线"
|
||||||
err = models.NewMessageDAO().CreateNodeMessage(nil, this.clusterId, int64(result.Node.Id), models.MessageTypeHealthCheckNodeDown, models.MessageLevelError, message, message, nil)
|
err = models.NewMessageDAO().CreateNodeMessage(nil, nodeconfigs.NodeRoleNode, this.clusterId, int64(result.Node.Id), models.MessageTypeHealthCheckNodeDown, models.MessageLevelError, message, message, nil)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ package tasks
|
|||||||
import (
|
import (
|
||||||
"github.com/TeaOSLab/EdgeAPI/internal/db/models"
|
"github.com/TeaOSLab/EdgeAPI/internal/db/models"
|
||||||
"github.com/TeaOSLab/EdgeAPI/internal/utils/numberutils"
|
"github.com/TeaOSLab/EdgeAPI/internal/utils/numberutils"
|
||||||
|
"github.com/TeaOSLab/EdgeCommon/pkg/nodeconfigs"
|
||||||
"github.com/TeaOSLab/EdgeCommon/pkg/systemconfigs"
|
"github.com/TeaOSLab/EdgeCommon/pkg/systemconfigs"
|
||||||
"github.com/iwind/TeaGo/dbs"
|
"github.com/iwind/TeaGo/dbs"
|
||||||
"github.com/iwind/TeaGo/logs"
|
"github.com/iwind/TeaGo/logs"
|
||||||
@@ -24,7 +25,7 @@ func init() {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
// NodeMonitorTask 健康节点任务
|
// NodeMonitorTask 边缘节点监控任务
|
||||||
type NodeMonitorTask struct {
|
type NodeMonitorTask struct {
|
||||||
intervalSeconds int
|
intervalSeconds int
|
||||||
}
|
}
|
||||||
@@ -82,7 +83,7 @@ func (this *NodeMonitorTask) monitorCluster(cluster *models.NodeCluster) error {
|
|||||||
for _, node := range inactiveNodes {
|
for _, node := range inactiveNodes {
|
||||||
subject := "节点\"" + node.Name + "\"已处于离线状态"
|
subject := "节点\"" + node.Name + "\"已处于离线状态"
|
||||||
msg := "节点\"" + node.Name + "\"已处于离线状态"
|
msg := "节点\"" + node.Name + "\"已处于离线状态"
|
||||||
err = models.SharedMessageDAO.CreateNodeMessage(nil, clusterId, int64(node.Id), models.MessageTypeNodeInactive, models.LevelError, subject, msg, nil)
|
err = models.SharedMessageDAO.CreateNodeMessage(nil, nodeconfigs.NodeRoleNode, clusterId, int64(node.Id), models.MessageTypeNodeInactive, models.LevelError, subject, msg, nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|||||||
107
internal/tasks/ns_node_monitor_task.go
Normal file
107
internal/tasks/ns_node_monitor_task.go
Normal file
@@ -0,0 +1,107 @@
|
|||||||
|
package tasks
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/TeaOSLab/EdgeAPI/internal/db/models"
|
||||||
|
"github.com/TeaOSLab/EdgeAPI/internal/db/models/nameservers"
|
||||||
|
"github.com/TeaOSLab/EdgeAPI/internal/utils/numberutils"
|
||||||
|
"github.com/TeaOSLab/EdgeCommon/pkg/nodeconfigs"
|
||||||
|
"github.com/TeaOSLab/EdgeCommon/pkg/systemconfigs"
|
||||||
|
"github.com/iwind/TeaGo/dbs"
|
||||||
|
"github.com/iwind/TeaGo/logs"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
dbs.OnReady(func() {
|
||||||
|
task := NewNSNodeMonitorTask(60)
|
||||||
|
ticker := time.NewTicker(60 * time.Second)
|
||||||
|
go func() {
|
||||||
|
for range ticker.C {
|
||||||
|
err := task.loop()
|
||||||
|
if err != nil {
|
||||||
|
logs.Println("[TASK][NS_NODE_MONITOR]" + err.Error())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// NSNodeMonitorTask 边缘节点监控任务
|
||||||
|
type NSNodeMonitorTask struct {
|
||||||
|
intervalSeconds int
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewNSNodeMonitorTask(intervalSeconds int) *NSNodeMonitorTask {
|
||||||
|
return &NSNodeMonitorTask{
|
||||||
|
intervalSeconds: intervalSeconds,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (this *NSNodeMonitorTask) Run() {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
func (this *NSNodeMonitorTask) loop() error {
|
||||||
|
// 检查上次运行时间,防止重复运行
|
||||||
|
settingKey := systemconfigs.SettingCodeNSNodeMonitor + "Loop"
|
||||||
|
timestamp := time.Now().Unix()
|
||||||
|
c, err := models.SharedSysSettingDAO.CompareInt64Setting(nil, settingKey, timestamp-int64(this.intervalSeconds))
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if c > 0 {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// 记录时间
|
||||||
|
err = models.SharedSysSettingDAO.UpdateSetting(nil, settingKey, []byte(numberutils.FormatInt64(timestamp)))
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
clusters, err := nameservers.SharedNSClusterDAO.FindAllEnabledClusters(nil)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
for _, cluster := range clusters {
|
||||||
|
err := this.monitorCluster(cluster)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (this *NSNodeMonitorTask) monitorCluster(cluster *nameservers.NSCluster) error {
|
||||||
|
clusterId := int64(cluster.Id)
|
||||||
|
|
||||||
|
// 检查离线节点
|
||||||
|
inactiveNodes, err := nameservers.SharedNSNodeDAO.FindAllNotifyingInactiveNodesWithClusterId(nil, clusterId)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
for _, node := range inactiveNodes {
|
||||||
|
subject := "DNS节点\"" + node.Name + "\"已处于离线状态"
|
||||||
|
msg := "DNS节点\"" + node.Name + "\"已处于离线状态"
|
||||||
|
err = models.SharedMessageDAO.CreateNodeMessage(nil, nodeconfigs.NodeRoleDNS, clusterId, int64(node.Id), models.MessageTypeNSNodeInactive, models.LevelError, subject, msg, nil)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// 修改在线状态
|
||||||
|
err = nameservers.SharedNSNodeDAO.UpdateNodeStatusIsNotified(nil, int64(node.Id))
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO 检查恢复连接
|
||||||
|
|
||||||
|
// 检查CPU、内存、磁盘不足节点,而且离线的节点不再重复提示
|
||||||
|
// TODO 需要实现
|
||||||
|
|
||||||
|
// TODO 检查53/tcp、53/udp是否能够访问
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user