mirror of
https://github.com/TeaOSLab/EdgeAPI.git
synced 2026-02-13 21:55:39 +08:00
节点根据健康检查自动上下线
This commit is contained in:
@@ -232,164 +232,7 @@ func (this *DNSDomainService) SyncDNSDomainData(ctx context.Context, req *pb.Syn
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// 查询集群信息
|
||||
clusters := []*models.NodeCluster{}
|
||||
if req.NodeClusterId > 0 {
|
||||
cluster, err := models.SharedNodeClusterDAO.FindEnabledNodeCluster(req.NodeClusterId)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if cluster == nil {
|
||||
return &pb.SyncDNSDomainDataResponse{
|
||||
IsOk: false,
|
||||
Error: "找不到要同步的集群",
|
||||
ShouldFix: false,
|
||||
}, nil
|
||||
}
|
||||
if int64(cluster.DnsDomainId) != req.DnsDomainId {
|
||||
return &pb.SyncDNSDomainDataResponse{
|
||||
IsOk: false,
|
||||
Error: "集群设置的域名和参数不符",
|
||||
ShouldFix: false,
|
||||
}, nil
|
||||
}
|
||||
clusters = append(clusters, cluster)
|
||||
} else {
|
||||
clusters, err = models.SharedNodeClusterDAO.FindAllEnabledClustersWithDNSDomainId(req.DnsDomainId)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
// 域名信息
|
||||
domain, err := models.SharedDNSDomainDAO.FindEnabledDNSDomain(req.DnsDomainId)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if domain == nil {
|
||||
return &pb.SyncDNSDomainDataResponse{IsOk: false, Error: "找不到要操作的域名"}, nil
|
||||
}
|
||||
domainId := int64(domain.Id)
|
||||
domainName := domain.Name
|
||||
|
||||
// 服务商信息
|
||||
provider, err := models.SharedDNSProviderDAO.FindEnabledDNSProvider(int64(domain.ProviderId))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if provider == nil {
|
||||
return &pb.SyncDNSDomainDataResponse{IsOk: false, Error: "域名没有设置服务商"}, nil
|
||||
}
|
||||
apiParams := maps.Map{}
|
||||
if len(provider.ApiParams) > 0 && provider.ApiParams != "null" {
|
||||
err = json.Unmarshal([]byte(provider.ApiParams), &apiParams)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
// 开始同步
|
||||
manager := dnsclients.FindProvider(provider.Type)
|
||||
if manager == nil {
|
||||
return &pb.SyncDNSDomainDataResponse{IsOk: false, Error: "目前不支持'" + provider.Type + "'"}, nil
|
||||
}
|
||||
err = manager.Auth(apiParams)
|
||||
if err != nil {
|
||||
return &pb.SyncDNSDomainDataResponse{IsOk: false, Error: "调用API认证失败:" + err.Error()}, nil
|
||||
}
|
||||
|
||||
// 更新线路
|
||||
routes, err := manager.GetRoutes(domainName)
|
||||
if err != nil {
|
||||
return &pb.SyncDNSDomainDataResponse{IsOk: false, Error: "获取线路失败:" + err.Error()}, nil
|
||||
}
|
||||
routesJSON, err := json.Marshal(routes)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
err = models.SharedDNSDomainDAO.UpdateDomainRoutes(domainId, routesJSON)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// 检查集群设置
|
||||
for _, cluster := range clusters {
|
||||
issues, err := models.SharedNodeClusterDAO.CheckClusterDNS(cluster)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if len(issues) > 0 {
|
||||
return &pb.SyncDNSDomainDataResponse{IsOk: false, Error: "发现问题需要修复", ShouldFix: true}, nil
|
||||
}
|
||||
}
|
||||
|
||||
// 所有记录
|
||||
records, err := manager.GetRecords(domainName)
|
||||
if err != nil {
|
||||
return &pb.SyncDNSDomainDataResponse{IsOk: false, Error: "获取域名解析记录失败:" + err.Error()}, nil
|
||||
}
|
||||
recordsJSON, err := json.Marshal(records)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
err = models.SharedDNSDomainDAO.UpdateDomainRecords(domainId, recordsJSON)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// 对比变化
|
||||
allChanges := []maps.Map{}
|
||||
for _, cluster := range clusters {
|
||||
changes, _, _, _, _, err := this.findClusterDNSChanges(cluster, records, domainName)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
allChanges = append(allChanges, changes...)
|
||||
}
|
||||
for _, change := range allChanges {
|
||||
action := change.GetString("action")
|
||||
record := change.Get("record").(*dnsclients.Record)
|
||||
|
||||
if len(record.Route) == 0 {
|
||||
record.Route = manager.DefaultRoute()
|
||||
}
|
||||
|
||||
switch action {
|
||||
case "create":
|
||||
err = manager.AddRecord(domainName, record)
|
||||
if err != nil {
|
||||
return &pb.SyncDNSDomainDataResponse{IsOk: false, Error: "创建域名记录失败:" + err.Error()}, nil
|
||||
}
|
||||
case "delete":
|
||||
err = manager.DeleteRecord(domainName, record)
|
||||
if err != nil {
|
||||
return &pb.SyncDNSDomainDataResponse{IsOk: false, Error: "删除域名记录失败:" + err.Error()}, nil
|
||||
}
|
||||
}
|
||||
|
||||
//logs.Println(action, record.Name, record.Type, record.Value, record.Route)
|
||||
}
|
||||
|
||||
// 重新更新记录
|
||||
if len(allChanges) > 0 {
|
||||
records, err := manager.GetRecords(domainName)
|
||||
if err != nil {
|
||||
return &pb.SyncDNSDomainDataResponse{IsOk: false, Error: "重新获取域名解析记录失败:" + err.Error()}, nil
|
||||
}
|
||||
recordsJSON, err := json.Marshal(records)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
err = models.SharedDNSDomainDAO.UpdateDomainRecords(domainId, recordsJSON)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
return &pb.SyncDNSDomainDataResponse{
|
||||
IsOk: true,
|
||||
}, nil
|
||||
return this.syncClusterDNS(req)
|
||||
}
|
||||
|
||||
// 查看支持的线路
|
||||
@@ -631,3 +474,165 @@ func (this *DNSDomainService) findClusterDNSChanges(cluster *models.NodeCluster,
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
// 执行同步
|
||||
func (this *DNSDomainService) syncClusterDNS(req *pb.SyncDNSDomainDataRequest) (*pb.SyncDNSDomainDataResponse, error) {
|
||||
// 查询集群信息
|
||||
var err error
|
||||
clusters := []*models.NodeCluster{}
|
||||
if req.NodeClusterId > 0 {
|
||||
cluster, err := models.SharedNodeClusterDAO.FindEnabledNodeCluster(req.NodeClusterId)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if cluster == nil {
|
||||
return &pb.SyncDNSDomainDataResponse{
|
||||
IsOk: false,
|
||||
Error: "找不到要同步的集群",
|
||||
ShouldFix: false,
|
||||
}, nil
|
||||
}
|
||||
if int64(cluster.DnsDomainId) != req.DnsDomainId {
|
||||
return &pb.SyncDNSDomainDataResponse{
|
||||
IsOk: false,
|
||||
Error: "集群设置的域名和参数不符",
|
||||
ShouldFix: false,
|
||||
}, nil
|
||||
}
|
||||
clusters = append(clusters, cluster)
|
||||
} else {
|
||||
clusters, err = models.SharedNodeClusterDAO.FindAllEnabledClustersWithDNSDomainId(req.DnsDomainId)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
// 域名信息
|
||||
domain, err := models.SharedDNSDomainDAO.FindEnabledDNSDomain(req.DnsDomainId)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if domain == nil {
|
||||
return &pb.SyncDNSDomainDataResponse{IsOk: false, Error: "找不到要操作的域名"}, nil
|
||||
}
|
||||
domainId := int64(domain.Id)
|
||||
domainName := domain.Name
|
||||
|
||||
// 服务商信息
|
||||
provider, err := models.SharedDNSProviderDAO.FindEnabledDNSProvider(int64(domain.ProviderId))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if provider == nil {
|
||||
return &pb.SyncDNSDomainDataResponse{IsOk: false, Error: "域名没有设置服务商"}, nil
|
||||
}
|
||||
apiParams := maps.Map{}
|
||||
if len(provider.ApiParams) > 0 && provider.ApiParams != "null" {
|
||||
err = json.Unmarshal([]byte(provider.ApiParams), &apiParams)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
// 开始同步
|
||||
manager := dnsclients.FindProvider(provider.Type)
|
||||
if manager == nil {
|
||||
return &pb.SyncDNSDomainDataResponse{IsOk: false, Error: "目前不支持'" + provider.Type + "'"}, nil
|
||||
}
|
||||
err = manager.Auth(apiParams)
|
||||
if err != nil {
|
||||
return &pb.SyncDNSDomainDataResponse{IsOk: false, Error: "调用API认证失败:" + err.Error()}, nil
|
||||
}
|
||||
|
||||
// 更新线路
|
||||
routes, err := manager.GetRoutes(domainName)
|
||||
if err != nil {
|
||||
return &pb.SyncDNSDomainDataResponse{IsOk: false, Error: "获取线路失败:" + err.Error()}, nil
|
||||
}
|
||||
routesJSON, err := json.Marshal(routes)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
err = models.SharedDNSDomainDAO.UpdateDomainRoutes(domainId, routesJSON)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// 检查集群设置
|
||||
for _, cluster := range clusters {
|
||||
issues, err := models.SharedNodeClusterDAO.CheckClusterDNS(cluster)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if len(issues) > 0 {
|
||||
return &pb.SyncDNSDomainDataResponse{IsOk: false, Error: "发现问题需要修复", ShouldFix: true}, nil
|
||||
}
|
||||
}
|
||||
|
||||
// 所有记录
|
||||
records, err := manager.GetRecords(domainName)
|
||||
if err != nil {
|
||||
return &pb.SyncDNSDomainDataResponse{IsOk: false, Error: "获取域名解析记录失败:" + err.Error()}, nil
|
||||
}
|
||||
recordsJSON, err := json.Marshal(records)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
err = models.SharedDNSDomainDAO.UpdateDomainRecords(domainId, recordsJSON)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// 对比变化
|
||||
allChanges := []maps.Map{}
|
||||
for _, cluster := range clusters {
|
||||
changes, _, _, _, _, err := this.findClusterDNSChanges(cluster, records, domainName)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
allChanges = append(allChanges, changes...)
|
||||
}
|
||||
for _, change := range allChanges {
|
||||
action := change.GetString("action")
|
||||
record := change.Get("record").(*dnsclients.Record)
|
||||
|
||||
if len(record.Route) == 0 {
|
||||
record.Route = manager.DefaultRoute()
|
||||
}
|
||||
|
||||
switch action {
|
||||
case "create":
|
||||
err = manager.AddRecord(domainName, record)
|
||||
if err != nil {
|
||||
return &pb.SyncDNSDomainDataResponse{IsOk: false, Error: "创建域名记录失败:" + err.Error()}, nil
|
||||
}
|
||||
case "delete":
|
||||
err = manager.DeleteRecord(domainName, record)
|
||||
if err != nil {
|
||||
return &pb.SyncDNSDomainDataResponse{IsOk: false, Error: "删除域名记录失败:" + err.Error()}, nil
|
||||
}
|
||||
}
|
||||
|
||||
//logs.Println(action, record.Name, record.Type, record.Value, record.Route)
|
||||
}
|
||||
|
||||
// 重新更新记录
|
||||
if len(allChanges) > 0 {
|
||||
records, err := manager.GetRecords(domainName)
|
||||
if err != nil {
|
||||
return &pb.SyncDNSDomainDataResponse{IsOk: false, Error: "重新获取域名解析记录失败:" + err.Error()}, nil
|
||||
}
|
||||
recordsJSON, err := json.Marshal(records)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
err = models.SharedDNSDomainDAO.UpdateDomainRecords(domainId, recordsJSON)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
return &pb.SyncDNSDomainDataResponse{
|
||||
IsOk: true,
|
||||
}, nil
|
||||
}
|
||||
|
||||
@@ -5,15 +5,32 @@ import (
|
||||
"encoding/json"
|
||||
"github.com/TeaOSLab/EdgeAPI/internal/db/models"
|
||||
"github.com/TeaOSLab/EdgeAPI/internal/errors"
|
||||
"github.com/TeaOSLab/EdgeAPI/internal/events"
|
||||
"github.com/TeaOSLab/EdgeAPI/internal/installers"
|
||||
rpcutils "github.com/TeaOSLab/EdgeAPI/internal/rpc/utils"
|
||||
"github.com/TeaOSLab/EdgeAPI/internal/utils/numberutils"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/configutils"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
|
||||
"github.com/iwind/TeaGo/dbs"
|
||||
"github.com/iwind/TeaGo/logs"
|
||||
"github.com/iwind/TeaGo/types"
|
||||
)
|
||||
|
||||
func init() {
|
||||
dbs.OnReady(func() {
|
||||
go func() {
|
||||
service := &NodeService{}
|
||||
for nodeId := range events.NodeDNSChanges {
|
||||
logs.Println("change dns: ", nodeId)
|
||||
err := service.notifyNodeDNSChanged(nodeId)
|
||||
if err != nil {
|
||||
logs.Println("[ERROR]change node dns: " + err.Error())
|
||||
}
|
||||
}
|
||||
}()
|
||||
})
|
||||
}
|
||||
|
||||
// 边缘节点相关服务
|
||||
type NodeService struct {
|
||||
}
|
||||
@@ -38,6 +55,24 @@ func (this *NodeService) CreateNode(ctx context.Context, req *pb.CreateNodeReque
|
||||
}
|
||||
}
|
||||
|
||||
// 保存DNS相关
|
||||
if req.DnsDomainId > 0 && len(req.DnsRoute) > 0 {
|
||||
err = models.SharedNodeDAO.UpdateNodeDNS(nodeId, map[int64]string{
|
||||
req.DnsDomainId: req.DnsRoute,
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
// 同步DNS
|
||||
go func() {
|
||||
err := this.notifyNodeDNSChanged(nodeId)
|
||||
if err != nil {
|
||||
logs.Println("sync node DNS error: " + err.Error())
|
||||
}
|
||||
}()
|
||||
|
||||
return &pb.CreateNodeResponse{
|
||||
NodeId: nodeId,
|
||||
}, nil
|
||||
@@ -173,6 +208,7 @@ func (this *NodeService) ListEnabledNodesMatch(ctx context.Context, req *pb.List
|
||||
InstallStatus: installStatusResult,
|
||||
MaxCPU: types.Int32(node.MaxCPU),
|
||||
IsOn: node.IsOn == 1,
|
||||
IsUp: node.IsUp == 1,
|
||||
Group: pbGroup,
|
||||
})
|
||||
}
|
||||
@@ -216,8 +252,8 @@ func (this *NodeService) FindAllEnabledNodesWithClusterId(ctx context.Context, r
|
||||
return &pb.FindAllEnabledNodesWithClusterIdResponse{Nodes: result}, nil
|
||||
}
|
||||
|
||||
// 禁用节点
|
||||
func (this *NodeService) DisableNode(ctx context.Context, req *pb.DisableNodeRequest) (*pb.DisableNodeResponse, error) {
|
||||
// 删除节点
|
||||
func (this *NodeService) DeleteNode(ctx context.Context, req *pb.DeleteNodeRequest) (*pb.RPCSuccess, error) {
|
||||
_, _, err := rpcutils.ValidateRequest(ctx, rpcutils.UserTypeAdmin)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@@ -228,7 +264,15 @@ func (this *NodeService) DisableNode(ctx context.Context, req *pb.DisableNodeReq
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &pb.DisableNodeResponse{}, nil
|
||||
// 同步DNS
|
||||
go func() {
|
||||
err := this.notifyNodeDNSChanged(req.NodeId)
|
||||
if err != nil {
|
||||
logs.Println("sync node DNS error: " + err.Error())
|
||||
}
|
||||
}()
|
||||
|
||||
return rpcutils.Success()
|
||||
}
|
||||
|
||||
// 修改节点
|
||||
@@ -262,6 +306,15 @@ func (this *NodeService) UpdateNode(ctx context.Context, req *pb.UpdateNodeReque
|
||||
}
|
||||
}
|
||||
|
||||
// 同步DNS
|
||||
go func() {
|
||||
// TODO 只有状态变化的时候才需要同步
|
||||
err := this.notifyNodeDNSChanged(req.NodeId)
|
||||
if err != nil {
|
||||
logs.Println("sync node DNS error: " + err.Error())
|
||||
}
|
||||
}()
|
||||
|
||||
return &pb.RPCSuccess{}, nil
|
||||
}
|
||||
|
||||
@@ -502,6 +555,15 @@ func (this *NodeService) StartNode(ctx context.Context, req *pb.StartNodeRequest
|
||||
Error: err.Error(),
|
||||
}, nil
|
||||
}
|
||||
|
||||
// 同步DNS
|
||||
go func() {
|
||||
err := this.notifyNodeDNSChanged(req.NodeId)
|
||||
if err != nil {
|
||||
logs.Println("sync node DNS error: " + err.Error())
|
||||
}
|
||||
}()
|
||||
|
||||
return &pb.StartNodeResponse{IsOk: true}, nil
|
||||
}
|
||||
|
||||
@@ -520,6 +582,15 @@ func (this *NodeService) StopNode(ctx context.Context, req *pb.StopNodeRequest)
|
||||
Error: err.Error(),
|
||||
}, nil
|
||||
}
|
||||
|
||||
// 同步DNS
|
||||
go func() {
|
||||
err := this.notifyNodeDNSChanged(req.NodeId)
|
||||
if err != nil {
|
||||
logs.Println("sync node DNS error: " + err.Error())
|
||||
}
|
||||
}()
|
||||
|
||||
return &pb.StopNodeResponse{IsOk: true}, nil
|
||||
}
|
||||
|
||||
@@ -1015,3 +1086,45 @@ func (this *NodeService) UpdateNodeDNS(ctx context.Context, req *pb.UpdateNodeDN
|
||||
|
||||
return rpcutils.Success()
|
||||
}
|
||||
|
||||
// 自动同步DNS状态
|
||||
func (this *NodeService) notifyNodeDNSChanged(nodeId int64) error {
|
||||
clusterId, err := models.SharedNodeDAO.FindNodeClusterId(nodeId)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
dnsInfo, err := models.SharedNodeClusterDAO.FindClusterDNSInfo(clusterId)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if dnsInfo == nil {
|
||||
return nil
|
||||
}
|
||||
if len(dnsInfo.DnsName) == 0 || dnsInfo.DnsDomainId == 0 {
|
||||
return nil
|
||||
}
|
||||
dnsConfig, err := dnsInfo.DecodeDNSConfig()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if !dnsConfig.NodesAutoSync {
|
||||
return nil
|
||||
}
|
||||
|
||||
// 执行同步
|
||||
domainService := &DNSDomainService{}
|
||||
resp, err := domainService.syncClusterDNS(&pb.SyncDNSDomainDataRequest{
|
||||
DnsDomainId: int64(dnsInfo.DnsDomainId),
|
||||
NodeClusterId: clusterId,
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if !resp.IsOk {
|
||||
err = models.SharedMessageDAO.CreateClusterMessage(clusterId, models.MessageTypeClusterDNSSyncFailed, models.LevelError, "集群DNS同步失败:"+resp.Error, nil)
|
||||
if err != nil {
|
||||
logs.Println("[NODE_SERVICE]" + err.Error())
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -373,11 +373,19 @@ func (this *NodeClusterService) FindEnabledNodeClusterDNS(ctx context.Context, r
|
||||
Provider: nil,
|
||||
}, nil
|
||||
}
|
||||
|
||||
dnsConfig, err := dnsInfo.DecodeDNSConfig()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if dnsInfo.DnsDomainId == 0 {
|
||||
return &pb.FindEnabledNodeClusterDNSResponse{
|
||||
Name: dnsInfo.DnsName,
|
||||
Domain: nil,
|
||||
Provider: nil,
|
||||
Name: dnsInfo.DnsName,
|
||||
Domain: nil,
|
||||
Provider: nil,
|
||||
NodesAutoSync: dnsConfig.NodesAutoSync,
|
||||
ServersAutoSync: dnsConfig.ServersAutoSync,
|
||||
}, nil
|
||||
}
|
||||
|
||||
@@ -414,9 +422,11 @@ func (this *NodeClusterService) FindEnabledNodeClusterDNS(ctx context.Context, r
|
||||
}
|
||||
|
||||
return &pb.FindEnabledNodeClusterDNSResponse{
|
||||
Name: dnsInfo.DnsName,
|
||||
Domain: pbDomain,
|
||||
Provider: pbProvider,
|
||||
Name: dnsInfo.DnsName,
|
||||
Domain: pbDomain,
|
||||
Provider: pbProvider,
|
||||
NodesAutoSync: dnsConfig.NodesAutoSync,
|
||||
ServersAutoSync: dnsConfig.ServersAutoSync,
|
||||
}, nil
|
||||
}
|
||||
|
||||
@@ -473,7 +483,7 @@ func (this *NodeClusterService) UpdateNodeClusterDNS(ctx context.Context, req *p
|
||||
return nil, err
|
||||
}
|
||||
|
||||
err = models.SharedNodeClusterDAO.UpdateClusterDNS(req.NodeClusterId, req.DnsName, req.DnsDomainId)
|
||||
err = models.SharedNodeClusterDAO.UpdateClusterDNS(req.NodeClusterId, req.DnsName, req.DnsDomainId, req.NodesAutoSync, req.ServersAutoSync)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user