实现最基本的域名服务节点管理

This commit is contained in:
刘祥超
2021-05-26 14:40:05 +08:00
parent 725692ce94
commit a71bf9ed79
28 changed files with 790 additions and 117 deletions

View File

@@ -63,6 +63,15 @@ func (this *NSClusterDAO) FindEnabledNSCluster(tx *dbs.Tx, id int64) (*NSCluster
return result.(*NSCluster), err
}
// FindEnabledNSClusterName 查找启用中的条目名称
func (this *NSClusterDAO) FindEnabledNSClusterName(tx *dbs.Tx, id int64) (string, error) {
return this.Query(tx).
Pk(id).
State(NSClusterStateEnabled).
Result("name").
FindStringCol("")
}
// CreateCluster 创建集群
func (this *NSClusterDAO) CreateCluster(tx *dbs.Tx, name string) (int64, error) {
op := NewNSClusterOperator()

View File

@@ -2,17 +2,19 @@ package nameservers
// NSCluster 域名服务器集群
type NSCluster struct {
Id uint32 `field:"id"` // ID
IsOn uint8 `field:"isOn"` // 是否启用
Name string `field:"name"` // 集群名
State uint8 `field:"state"` // 状态
Id uint32 `field:"id"` // ID
IsOn uint8 `field:"isOn"` // 是否启用
Name string `field:"name"` // 集群名
InstallDir string `field:"installDir"` // 安装目录
State uint8 `field:"state"` // 状态
}
type NSClusterOperator struct {
Id interface{} // ID
IsOn interface{} // 是否启用
Name interface{} // 集群名
State interface{} // 状态
Id interface{} // ID
IsOn interface{} // 是否启用
Name interface{} // 集群名
InstallDir interface{} // 安装目录
State interface{} // 状态
}
func NewNSClusterOperator() *NSClusterOperator {

View File

@@ -1,9 +1,17 @@
package nameservers
import (
"encoding/json"
"github.com/TeaOSLab/EdgeAPI/internal/db/models"
"github.com/TeaOSLab/EdgeAPI/internal/errors"
"github.com/TeaOSLab/EdgeAPI/internal/utils"
"github.com/TeaOSLab/EdgeCommon/pkg/configutils"
"github.com/TeaOSLab/EdgeCommon/pkg/nodeconfigs"
_ "github.com/go-sql-driver/mysql"
"github.com/iwind/TeaGo/Tea"
"github.com/iwind/TeaGo/dbs"
"github.com/iwind/TeaGo/rands"
"github.com/iwind/TeaGo/types"
)
const (
@@ -33,7 +41,7 @@ func init() {
}
// EnableNSNode 启用条目
func (this *NSNodeDAO) EnableNSNode(tx *dbs.Tx, id uint32) error {
func (this *NSNodeDAO) EnableNSNode(tx *dbs.Tx, id int64) error {
_, err := this.Query(tx).
Pk(id).
Set("state", NSNodeStateEnabled).
@@ -42,16 +50,20 @@ func (this *NSNodeDAO) EnableNSNode(tx *dbs.Tx, id uint32) error {
}
// DisableNSNode 禁用条目
func (this *NSNodeDAO) DisableNSNode(tx *dbs.Tx, id uint32) error {
func (this *NSNodeDAO) DisableNSNode(tx *dbs.Tx, id int64) error {
_, err := this.Query(tx).
Pk(id).
Set("state", NSNodeStateDisabled).
Update()
return err
if err != nil {
return err
}
return this.NotifyUpdate(tx, id)
}
// FindEnabledNSNode 查找启用中的条目
func (this *NSNodeDAO) FindEnabledNSNode(tx *dbs.Tx, id uint32) (*NSNode, error) {
func (this *NSNodeDAO) FindEnabledNSNode(tx *dbs.Tx, id int64) (*NSNode, error) {
result, err := this.Query(tx).
Pk(id).
Attr("state", NSNodeStateEnabled).
@@ -61,3 +73,259 @@ func (this *NSNodeDAO) FindEnabledNSNode(tx *dbs.Tx, id uint32) (*NSNode, error)
}
return result.(*NSNode), err
}
// FindAllEnabledNodesWithClusterId 查找一个集群下的所有节点
func (this *NSNodeDAO) FindAllEnabledNodesWithClusterId(tx *dbs.Tx, clusterId int64) (result []*NSNode, err error) {
_, err = this.Query(tx).
Attr("clusterId", clusterId).
State(NSNodeStateEnabled).
DescPk().
Slice(&result).
FindAll()
return
}
// CountAllEnabledNodes 所有集群的可用的节点数量
func (this *NSNodeDAO) CountAllEnabledNodes(tx *dbs.Tx) (int64, error) {
return this.Query(tx).
State(NSNodeStateEnabled).
Where("clusterId IN (SELECT id FROM " + SharedNSClusterDAO.Table + " WHERE state=1)").
Count()
}
// CountAllEnabledNodesMatch 计算满足条件的节点数量
func (this *NSNodeDAO) CountAllEnabledNodesMatch(tx *dbs.Tx, clusterId int64, installState configutils.BoolState, activeState configutils.BoolState, keyword string) (int64, error) {
query := this.Query(tx)
if clusterId > 0 {
query.Attr("clusterId", clusterId)
}
// 安装状态
switch installState {
case configutils.BoolStateAll:
// 所有
case configutils.BoolStateYes:
query.Attr("isInstalled", 1)
case configutils.BoolStateNo:
query.Attr("isInstalled", 0)
}
// 在线状态
switch activeState {
case configutils.BoolStateAll:
// 所有
case configutils.BoolStateYes:
query.Where("JSON_EXTRACT(status, '$.isActive') AND UNIX_TIMESTAMP()-JSON_EXTRACT(status, '$.updatedAt')<=60")
case configutils.BoolStateNo:
query.Where("(status IS NULL OR NOT JSON_EXTRACT(status, '$.isActive') OR UNIX_TIMESTAMP()-JSON_EXTRACT(status, '$.updatedAt')>60)")
}
if len(keyword) > 0 {
query.Where("(name LIKE :keyword)").
Param("keyword", "%"+keyword+"%")
}
return query.
State(NSNodeStateEnabled).
Count()
}
// ListAllEnabledNodesMatch 列出单页匹配的节点
func (this *NSNodeDAO) ListAllEnabledNodesMatch(tx *dbs.Tx, clusterId int64, installState configutils.BoolState, activeState configutils.BoolState, keyword string, offset int64, size int64) (result []*NSNode, err error) {
query := this.Query(tx)
// 安装状态
switch installState {
case configutils.BoolStateAll:
// 所有
case configutils.BoolStateYes:
query.Attr("isInstalled", 1)
case configutils.BoolStateNo:
query.Attr("isInstalled", 0)
}
// 在线状态
switch activeState {
case configutils.BoolStateAll:
// 所有
case configutils.BoolStateYes:
query.Where("JSON_EXTRACT(status, '$.isActive') AND UNIX_TIMESTAMP()-JSON_EXTRACT(status, '$.updatedAt')<=60")
case configutils.BoolStateNo:
query.Where("(status IS NULL OR NOT JSON_EXTRACT(status, '$.isActive') OR UNIX_TIMESTAMP()-JSON_EXTRACT(status, '$.updatedAt')>60)")
}
if clusterId > 0 {
query.Attr("clusterId", clusterId)
}
if len(keyword) > 0 {
query.Where("(name LIKE :keyword)").
Param("keyword", "%"+keyword+"%")
}
_, err = query.
State(NSNodeStateEnabled).
Offset(offset).
Limit(size).
Slice(&result).
DescPk().
FindAll()
return
}
// CountAllLowerVersionNodesWithClusterId 计算单个集群中所有低于某个版本的节点数量
func (this *NSNodeDAO) CountAllLowerVersionNodesWithClusterId(tx *dbs.Tx, clusterId int64, os string, arch string, version string) (int64, error) {
return this.Query(tx).
State(NSNodeStateEnabled).
Attr("clusterId", clusterId).
Where("status IS NOT NULL").
Where("JSON_EXTRACT(status, '$.os')=:os").
Where("JSON_EXTRACT(status, '$.arch')=:arch").
Where("(JSON_EXTRACT(status, '$.buildVersionCode') IS NULL OR JSON_EXTRACT(status, '$.buildVersionCode')<:version)").
Param("os", os).
Param("arch", arch).
Param("version", utils.VersionToLong(version)).
Count()
}
// CreateNode 创建节点
func (this *NSNodeDAO) CreateNode(tx *dbs.Tx, adminId int64, name string, clusterId int64) (nodeId int64, err error) {
uniqueId, err := this.GenUniqueId(tx)
if err != nil {
return 0, err
}
secret := rands.String(32)
// 保存API Token
err = models.SharedApiTokenDAO.CreateAPIToken(tx, uniqueId, secret, nodeconfigs.NodeRoleDNS)
if err != nil {
return
}
op := NewNSNodeOperator()
op.AdminId = adminId
op.Name = name
op.UniqueId = uniqueId
op.Secret = secret
op.ClusterId = clusterId
op.IsOn = 1
op.State = NSNodeStateEnabled
err = this.Save(tx, op)
if err != nil {
return 0, err
}
// 通知节点更新
nodeId = types.Int64(op.Id)
err = this.NotifyUpdate(tx, nodeId)
if err != nil {
return 0, err
}
// 通知DNS更新
err = this.NotifyDNSUpdate(tx, nodeId)
if err != nil {
return 0, err
}
return nodeId, nil
}
// UpdateNode 修改节点
func (this *NSNodeDAO) UpdateNode(tx *dbs.Tx, nodeId int64, name string, clusterId int64, isOn bool) error {
if nodeId <= 0 {
return errors.New("invalid nodeId")
}
op := NewNSNodeOperator()
op.Id = nodeId
op.Name = name
op.ClusterId = clusterId
op.IsOn = isOn
err := this.Save(tx, op)
if err != nil {
return err
}
err = this.NotifyUpdate(tx, nodeId)
if err != nil {
return err
}
return this.NotifyDNSUpdate(tx, nodeId)
}
// FindEnabledNodeIdWithUniqueId 根据唯一ID获取节点ID
func (this *NSNodeDAO) FindEnabledNodeIdWithUniqueId(tx *dbs.Tx, uniqueId string) (int64, error) {
return this.Query(tx).
Attr("uniqueId", uniqueId).
Attr("state", NSNodeStateEnabled).
ResultPk().
FindInt64Col(0)
}
// FindNodeInstallStatus 查询节点的安装状态
func (this *NSNodeDAO) FindNodeInstallStatus(tx *dbs.Tx, nodeId int64) (*models.NodeInstallStatus, error) {
node, err := this.Query(tx).
Pk(nodeId).
Result("installStatus", "isInstalled").
Find()
if err != nil {
return nil, err
}
if node == nil {
return nil, errors.New("not found")
}
installStatus := node.(*NSNode).InstallStatus
isInstalled := node.(*NSNode).IsInstalled == 1
if len(installStatus) == 0 {
return models.NewNodeInstallStatus(), nil
}
status := &models.NodeInstallStatus{}
err = json.Unmarshal([]byte(installStatus), status)
if err != nil {
return nil, err
}
if isInstalled {
status.IsFinished = true
status.IsOk = true
}
return status, nil
}
// GenUniqueId 生成唯一ID
func (this *NSNodeDAO) GenUniqueId(tx *dbs.Tx) (string, error) {
for {
uniqueId := rands.HexString(32)
ok, err := this.Query(tx).
Attr("uniqueId", uniqueId).
Exist()
if err != nil {
return "", err
}
if ok {
continue
}
return uniqueId, nil
}
}
// UpdateNodeIsInstalled 设置节点安装状态
func (this *NSNodeDAO) UpdateNodeIsInstalled(tx *dbs.Tx, nodeId int64, isInstalled bool) error {
_, err := this.Query(tx).
Pk(nodeId).
Set("isInstalled", isInstalled).
Set("installStatus", "null"). // 重置安装状态
Update()
return err
}
// NotifyUpdate 通知更新
func (this *NSNodeDAO) NotifyUpdate(tx *dbs.Tx, nodeId int64) error {
// TODO 先什么都不做
return nil
}
// NotifyDNSUpdate 通知DNS更新
func (this *NSNodeDAO) NotifyDNSUpdate(tx *dbs.Tx, nodeId int64) error {
// TODO 先什么都不做
return nil
}

View File

@@ -2,25 +2,35 @@ package nameservers
// NSNode 域名服务器节点
type NSNode struct {
Id uint32 `field:"id"` // ID
ClusterId uint32 `field:"clusterId"` // 集群ID
Name string `field:"name"` // 节点名称
IsOn uint8 `field:"isOn"` // 是否启用
Status string `field:"status"` // 运行状态
UniqueId string `field:"uniqueId"` // 节点ID
Secret string `field:"secret"` // 密钥
State uint8 `field:"state"` // 状态
Id uint32 `field:"id"` // ID
AdminId uint32 `field:"adminId"` // 管理员ID
ClusterId uint32 `field:"clusterId"` // 集群ID
Name string `field:"name"` // 节点名称
IsOn uint8 `field:"isOn"` // 是否启用
Status string `field:"status"` // 运行状态
UniqueId string `field:"uniqueId"` // 节点ID
Secret string `field:"secret"` // 密钥
IsUp uint8 `field:"isUp"` // 是否运行
IsInstalled uint8 `field:"isInstalled"` // 是否已安装
InstallStatus string `field:"installStatus"` // 安装状态
InstallDir string `field:"installDir"` // 安装目录
State uint8 `field:"state"` // 状态
}
type NSNodeOperator struct {
Id interface{} // ID
ClusterId interface{} // 集群ID
Name interface{} // 节点名称
IsOn interface{} // 是否启用
Status interface{} // 运行状态
UniqueId interface{} // 节点ID
Secret interface{} // 密钥
State interface{} // 状态
Id interface{} // ID
AdminId interface{} // 管理员ID
ClusterId interface{} // 集群ID
Name interface{} // 节点名称
IsOn interface{} // 是否启用
Status interface{} // 运行状态
UniqueId interface{} // 节点ID
Secret interface{} // 密钥
IsUp interface{} // 是否运行
IsInstalled interface{} // 是否已安装
InstallStatus interface{} // 安装状态
InstallDir interface{} // 安装目录
State interface{} // 状态
}
func NewNSNodeOperator() *NSNodeOperator {

View File

@@ -1 +1,42 @@
package nameservers
import (
"encoding/json"
"github.com/TeaOSLab/EdgeAPI/internal/db/models"
"github.com/TeaOSLab/EdgeCommon/pkg/nodeconfigs"
"time"
)
// DecodeInstallStatus 安装状态
func (this *NSNode) DecodeInstallStatus() (*models.NodeInstallStatus, error) {
if len(this.InstallStatus) == 0 || this.InstallStatus == "null" {
return models.NewNodeInstallStatus(), nil
}
status := &models.NodeInstallStatus{}
err := json.Unmarshal([]byte(this.InstallStatus), status)
if err != nil {
return models.NewNodeInstallStatus(), err
}
// 如果N秒钟没有更新状态则认为不在运行
if status.IsRunning && status.UpdatedAt < time.Now().Unix()-10 {
status.IsRunning = false
status.IsFinished = true
status.Error = "timeout"
}
return status, nil
}
// DecodeStatus 节点状态
func (this *NSNode) DecodeStatus() (*nodeconfigs.NodeStatus, error) {
if len(this.Status) == 0 || this.Status == "null" {
return nil, nil
}
status := &nodeconfigs.NodeStatus{}
err := json.Unmarshal([]byte(this.Status), status)
if err != nil {
return nil, err
}
return status, nil
}