Files
EdgeAPI/internal/rpc/services/service_dns_domain.go
GoEdgeLab 5a17ae9d79 v1.4.1
2024-07-27 14:15:25 +08:00

934 lines
26 KiB
Go
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

package services
import (
"context"
"encoding/json"
"net"
"github.com/TeaOSLab/EdgeAPI/internal/db/models"
"github.com/TeaOSLab/EdgeAPI/internal/db/models/dns"
"github.com/TeaOSLab/EdgeAPI/internal/db/models/dns/dnsutils"
"github.com/TeaOSLab/EdgeAPI/internal/dnsclients"
"github.com/TeaOSLab/EdgeAPI/internal/dnsclients/dnstypes"
"github.com/TeaOSLab/EdgeAPI/internal/errors"
"github.com/TeaOSLab/EdgeAPI/internal/goman"
"github.com/TeaOSLab/EdgeAPI/internal/utils/numberutils"
"github.com/TeaOSLab/EdgeCommon/pkg/dnsconfigs"
"github.com/TeaOSLab/EdgeCommon/pkg/iputils"
"github.com/TeaOSLab/EdgeCommon/pkg/nodeconfigs"
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
"github.com/iwind/TeaGo/dbs"
"github.com/iwind/TeaGo/lists"
"github.com/iwind/TeaGo/maps"
)
// DNSDomainService DNS域名相关服务
type DNSDomainService struct {
BaseService
}
// CreateDNSDomain 创建域名
func (this *DNSDomainService) CreateDNSDomain(ctx context.Context, req *pb.CreateDNSDomainRequest) (*pb.CreateDNSDomainResponse, error) {
// 校验请求
adminId, userId, err := this.ValidateAdminAndUser(ctx, false)
if err != nil {
return nil, err
}
var tx = this.NullTx()
// 查询Provider
provider, err := dns.SharedDNSProviderDAO.FindEnabledDNSProvider(tx, req.DnsProviderId)
if err != nil {
return nil, err
}
if provider == nil {
return nil, errors.New("can not find provider")
}
apiParams, err := provider.DecodeAPIParams()
if err != nil {
return nil, err
}
domainId, err := dns.SharedDNSDomainDAO.CreateDomain(tx, adminId, userId, req.DnsProviderId, req.Name)
if err != nil {
return nil, err
}
// 更新数据,且不提示错误
goman.New(func() {
domainName := req.Name
providerInterface := dnsclients.FindProvider(provider.Type, int64(provider.Id))
if providerInterface == nil {
return
}
err = providerInterface.Auth(apiParams)
if err != nil {
// 这里我们刻意不提示错误
return
}
routes, err := providerInterface.GetRoutes(domainName)
if err != nil {
return
}
routesJSON, err := json.Marshal(routes)
if err != nil {
return
}
err = dns.SharedDNSDomainDAO.UpdateDomainRoutes(tx, domainId, routesJSON)
if err != nil {
return
}
records, err := providerInterface.GetRecords(domainName)
if err != nil {
return
}
recordsJSON, err := json.Marshal(records)
if err != nil {
return
}
err = dns.SharedDNSDomainDAO.UpdateDomainRecords(tx, domainId, recordsJSON)
if err != nil {
return
}
})
return &pb.CreateDNSDomainResponse{DnsDomainId: domainId}, nil
}
// UpdateDNSDomain 修改域名
func (this *DNSDomainService) UpdateDNSDomain(ctx context.Context, req *pb.UpdateDNSDomainRequest) (*pb.RPCSuccess, error) {
// 校验请求
_, err := this.ValidateAdmin(ctx)
if err != nil {
return nil, err
}
var tx = this.NullTx()
err = dns.SharedDNSDomainDAO.UpdateDomain(tx, req.DnsDomainId, req.Name, req.IsOn)
if err != nil {
return nil, err
}
return this.Success()
}
// DeleteDNSDomain 删除域名
func (this *DNSDomainService) DeleteDNSDomain(ctx context.Context, req *pb.DeleteDNSDomainRequest) (*pb.RPCSuccess, error) {
// 校验请求
_, err := this.ValidateAdmin(ctx)
if err != nil {
return nil, err
}
var tx = this.NullTx()
err = dns.SharedDNSDomainDAO.UpdateDomainIsDeleted(tx, req.DnsDomainId, true)
if err != nil {
return nil, err
}
return this.Success()
}
// RecoverDNSDomain 恢复删除的域名
func (this *DNSDomainService) RecoverDNSDomain(ctx context.Context, req *pb.RecoverDNSDomainRequest) (*pb.RPCSuccess, error) {
// 校验请求
_, err := this.ValidateAdmin(ctx)
if err != nil {
return nil, err
}
var tx = this.NullTx()
err = dns.SharedDNSDomainDAO.UpdateDomainIsDeleted(tx, req.DnsDomainId, false)
if err != nil {
return nil, err
}
return this.Success()
}
// FindDNSDomain 查询单个域名完整信息
func (this *DNSDomainService) FindDNSDomain(ctx context.Context, req *pb.FindDNSDomainRequest) (*pb.FindDNSDomainResponse, error) {
// 校验请求
_, err := this.ValidateAdmin(ctx)
if err != nil {
return nil, err
}
var tx = this.NullTx()
domain, err := dns.SharedDNSDomainDAO.FindEnabledDNSDomain(tx, req.DnsDomainId, nil)
if err != nil {
return nil, err
}
if domain == nil {
return &pb.FindDNSDomainResponse{DnsDomain: nil}, nil
}
pbDomain, err := this.convertDomainToPB(tx, domain)
return &pb.FindDNSDomainResponse{DnsDomain: pbDomain}, nil
}
// FindBasicDNSDomain 查询单个域名基础信息
func (this *DNSDomainService) FindBasicDNSDomain(ctx context.Context, req *pb.FindBasicDNSDomainRequest) (*pb.FindBasicDNSDomainResponse, error) {
// 校验请求
_, err := this.ValidateAdmin(ctx)
if err != nil {
return nil, err
}
var tx = this.NullTx()
domain, err := dns.SharedDNSDomainDAO.FindEnabledDNSDomain(tx, req.DnsDomainId, nil)
if err != nil {
return nil, err
}
if domain == nil {
return &pb.FindBasicDNSDomainResponse{DnsDomain: nil}, nil
}
return &pb.FindBasicDNSDomainResponse{DnsDomain: &pb.DNSDomain{
Id: int64(domain.Id),
Name: domain.Name,
IsOn: domain.IsOn,
ProviderId: int64(domain.ProviderId),
}}, nil
}
// CountAllDNSDomainsWithDNSProviderId 计算服务商下的域名数量
func (this *DNSDomainService) CountAllDNSDomainsWithDNSProviderId(ctx context.Context, req *pb.CountAllDNSDomainsWithDNSProviderIdRequest) (*pb.RPCCountResponse, error) {
// 校验请求
_, err := this.ValidateAdmin(ctx)
if err != nil {
return nil, err
}
var tx = this.NullTx()
count, err := dns.SharedDNSDomainDAO.CountAllEnabledDomainsWithProviderId(tx, req.DnsProviderId, req.IsDeleted, !req.IsDown)
if err != nil {
return nil, err
}
return this.SuccessCount(count)
}
// FindAllDNSDomainsWithDNSProviderId 列出服务商下的所有域名
func (this *DNSDomainService) FindAllDNSDomainsWithDNSProviderId(ctx context.Context, req *pb.FindAllDNSDomainsWithDNSProviderIdRequest) (*pb.FindAllDNSDomainsWithDNSProviderIdResponse, error) {
// 校验请求
_, err := this.ValidateAdmin(ctx)
if err != nil {
return nil, err
}
var tx = this.NullTx()
domains, err := dns.SharedDNSDomainDAO.FindAllEnabledDomainsWithProviderId(tx, req.DnsProviderId)
if err != nil {
return nil, err
}
result := []*pb.DNSDomain{}
for _, domain := range domains {
pbDomain, err := this.convertDomainToPB(tx, domain)
if err != nil {
return nil, err
}
result = append(result, pbDomain)
}
return &pb.FindAllDNSDomainsWithDNSProviderIdResponse{DnsDomains: result}, nil
}
// FindAllBasicDNSDomainsWithDNSProviderId 列出服务商下的所有域名基本信息
func (this *DNSDomainService) FindAllBasicDNSDomainsWithDNSProviderId(ctx context.Context, req *pb.FindAllBasicDNSDomainsWithDNSProviderIdRequest) (*pb.FindAllBasicDNSDomainsWithDNSProviderIdResponse, error) {
// 校验请求
_, err := this.ValidateAdmin(ctx)
if err != nil {
return nil, err
}
var tx = this.NullTx()
domains, err := dns.SharedDNSDomainDAO.FindAllEnabledDomainsWithProviderId(tx, req.DnsProviderId)
if err != nil {
return nil, err
}
var result = []*pb.DNSDomain{}
for _, domain := range domains {
result = append(result, &pb.DNSDomain{
Id: int64(domain.Id),
Name: domain.Name,
IsOn: domain.IsOn,
IsUp: domain.IsUp,
IsDeleted: domain.IsDeleted,
})
}
return &pb.FindAllBasicDNSDomainsWithDNSProviderIdResponse{DnsDomains: result}, nil
}
// ListBasicDNSDomainsWithDNSProviderId 列出服务商下的单页域名信息
func (this *DNSDomainService) ListBasicDNSDomainsWithDNSProviderId(ctx context.Context, req *pb.ListBasicDNSDomainsWithDNSProviderIdRequest) (*pb.ListDNSDomainsWithDNSProviderIdResponse, error) {
// 校验请求
_, err := this.ValidateAdmin(ctx)
if err != nil {
return nil, err
}
var tx = this.NullTx()
domains, err := dns.SharedDNSDomainDAO.ListDomains(tx, req.DnsProviderId, req.IsDeleted, !req.IsDown, req.Offset, req.Size)
if err != nil {
return nil, err
}
var result = []*pb.DNSDomain{}
for _, domain := range domains {
pbDomain, err := this.convertDomainToPB(tx, domain)
if err != nil {
return nil, err
}
result = append(result, pbDomain)
}
return &pb.ListDNSDomainsWithDNSProviderIdResponse{DnsDomains: result}, nil
}
// SyncDNSDomainData 同步域名数据
func (this *DNSDomainService) SyncDNSDomainData(ctx context.Context, req *pb.SyncDNSDomainDataRequest) (*pb.SyncDNSDomainDataResponse, error) {
// 校验请求
_, err := this.ValidateAdmin(ctx)
if err != nil {
return nil, err
}
var latestVersion = dns.SharedDNSTaskDAO.GenerateVersion()
resp, err := this.syncClusterDNS(req)
if err != nil {
return resp, err
}
// 标记集群所有任务已完成
if req.NodeClusterId > 0 && resp != nil && resp.IsOk {
var tx = this.NullTx()
err = dns.SharedDNSTaskDAO.UpdateClusterDNSTasksDone(tx, req.NodeClusterId, latestVersion)
if err != nil {
return resp, err
}
}
return resp, err
}
// FindAllDNSDomainRoutes 查看支持的线路
func (this *DNSDomainService) FindAllDNSDomainRoutes(ctx context.Context, req *pb.FindAllDNSDomainRoutesRequest) (*pb.FindAllDNSDomainRoutesResponse, error) {
// 校验请求
_, err := this.ValidateAdmin(ctx)
if err != nil {
return nil, err
}
var tx = this.NullTx()
routes, err := dns.SharedDNSDomainDAO.FindDomainRoutes(tx, req.DnsDomainId)
if err != nil {
return nil, err
}
pbRoutes := []*pb.DNSRoute{}
for _, route := range routes {
pbRoutes = append(pbRoutes, &pb.DNSRoute{
Name: route.Name,
Code: route.Code,
})
}
return &pb.FindAllDNSDomainRoutesResponse{Routes: pbRoutes}, nil
}
// ExistAvailableDomains 判断是否有域名可选
func (this *DNSDomainService) ExistAvailableDomains(ctx context.Context, req *pb.ExistAvailableDomainsRequest) (*pb.ExistAvailableDomainsResponse, error) {
// 校验请求
_, err := this.ValidateAdmin(ctx)
if err != nil {
return nil, err
}
var tx = this.NullTx()
exist, err := dns.SharedDNSDomainDAO.ExistAvailableDomains(tx)
if err != nil {
return nil, err
}
return &pb.ExistAvailableDomainsResponse{Exist: exist}, nil
}
// 转换域名信息
func (this *DNSDomainService) convertDomainToPB(tx *dbs.Tx, domain *dns.DNSDomain) (*pb.DNSDomain, error) {
var domainId = int64(domain.Id)
defaultRoute, err := dnsutils.FindDefaultDomainRoute(tx, domain)
if err != nil {
return nil, err
}
records := []*dnstypes.Record{}
if models.IsNotNull(domain.Records) {
err := json.Unmarshal(domain.Records, &records)
if err != nil {
return nil, err
}
}
// 集群域名
countNodeRecords := 0
nodesChanged := false
// 服务域名
countServerRecords := 0
serversChanged := false
// 检查是否所有的集群都已经被解析
clusters, err := models.SharedNodeClusterDAO.FindAllEnabledClustersWithDNSDomainId(tx, domainId)
if err != nil {
return nil, err
}
countClusters := len(clusters)
countAllNodes1 := int64(0)
countAllServers1 := int64(0)
for _, cluster := range clusters {
_, nodeRecords, serverRecords, countAllNodes, countAllServers, nodesChanged2, serversChanged2, err := this.findClusterDNSChanges(cluster, records, domain.Name, defaultRoute)
if err != nil {
return nil, err
}
countNodeRecords += len(nodeRecords)
countServerRecords += len(serverRecords)
countAllNodes1 += countAllNodes
countAllServers1 += countAllServers
if nodesChanged2 {
nodesChanged = true
}
if serversChanged2 {
serversChanged = true
}
}
// 线路
routes, err := domain.DecodeRoutes()
if err != nil {
return nil, err
}
pbRoutes := []*pb.DNSRoute{}
for _, route := range routes {
pbRoutes = append(pbRoutes, &pb.DNSRoute{
Name: route.Name,
Code: route.Code,
})
}
return &pb.DNSDomain{
Id: int64(domain.Id),
ProviderId: int64(domain.ProviderId),
Name: domain.Name,
IsOn: domain.IsOn,
IsUp: domain.IsUp,
IsDeleted: domain.IsDeleted,
DataUpdatedAt: int64(domain.DataUpdatedAt),
CountNodeRecords: int64(countNodeRecords),
NodesChanged: nodesChanged,
CountServerRecords: int64(countServerRecords),
ServersChanged: serversChanged,
Routes: pbRoutes,
CountNodeClusters: int64(countClusters),
CountAllNodes: countAllNodes1,
CountAllServers: countAllServers1,
}, nil
}
// 检查集群节点变化
func (this *DNSDomainService) findClusterDNSChanges(cluster *models.NodeCluster, records []*dnstypes.Record, domainName string, defaultRoute string) (result []maps.Map, doneNodeRecords []*dnstypes.Record, doneServerRecords []*dnstypes.Record, countAllNodes int64, countAllServers int64, nodesChanged bool, serversChanged bool, err error) {
var clusterId = int64(cluster.Id)
var clusterDnsName = cluster.DnsName
var clusterDomain = clusterDnsName + "." + domainName
dnsConfig, err := cluster.DecodeDNSConfig()
if err != nil {
return nil, nil, nil, 0, 0, false, false, err
}
if dnsConfig == nil {
dnsConfig = dnsconfigs.DefaultClusterDNSConfig()
}
var tx = this.NullTx()
// 自动设置的cname记录
var ttl int32
var cnameRecords = dnsConfig.CNAMERecords
if dnsConfig.TTL > 0 {
ttl = dnsConfig.TTL
}
// 节点域名
nodes, err := models.SharedNodeDAO.FindAllEnabledNodesDNSWithClusterId(tx, clusterId, true, dnsConfig != nil && dnsConfig.IncludingLnNodes, true)
if err != nil {
return nil, nil, nil, 0, 0, false, false, err
}
countAllNodes = int64(len(nodes))
var nodeRecords = []*dnstypes.Record{} // 之所以用数组再存一遍是因为dnsName可能会重复
var nodeRecordMapping = map[string]*dnstypes.Record{} // value_route => *Record
for _, record := range records {
if (record.Type == dnstypes.RecordTypeA || record.Type == dnstypes.RecordTypeAAAA) && record.Name == clusterDnsName {
nodeRecords = append(nodeRecords, record)
nodeRecordMapping[record.Value+"_"+record.Route] = record
}
}
// 新增的节点域名
var nodeKeys = []string{}
var addingNodeRecordKeysMap = map[string]bool{} // clusterDnsName_type_ip_route
for _, node := range nodes {
shouldSkip, shouldOverwrite, ipAddressesStrings, err := models.SharedNodeDAO.CheckNodeIPAddresses(tx, node)
if err != nil {
return nil, nil, nil, 0, 0, false, false, err
}
if shouldSkip {
continue
}
routeCodes, err := node.DNSRouteCodesForDomainId(int64(cluster.DnsDomainId))
if err != nil {
return nil, nil, nil, 0, 0, false, false, err
}
if len(routeCodes) == 0 {
// 默认线路
if len(defaultRoute) > 0 {
routeCodes = []string{defaultRoute}
} else {
continue
}
}
if !shouldOverwrite {
ipAddresses, err := models.SharedNodeIPAddressDAO.FindNodeAccessAndUpIPAddresses(tx, int64(node.Id), nodeconfigs.NodeRoleNode)
if err != nil {
return nil, nil, nil, 0, 0, false, false, err
}
if len(ipAddresses) == 0 {
continue
}
for _, ipAddress := range ipAddresses {
// 检查专属节点
if !ipAddress.IsValidInCluster(clusterId) {
continue
}
var ip = ipAddress.DNSIP()
if len(ip) == 0 {
continue
}
if net.ParseIP(ip) == nil {
continue
}
ipAddressesStrings = append(ipAddressesStrings, ip)
}
}
if len(ipAddressesStrings) == 0 {
continue
}
for _, route := range routeCodes {
for _, ip := range ipAddressesStrings {
var key = ip + "_" + route
nodeKeys = append(nodeKeys, key)
record, ok := nodeRecordMapping[key]
if !ok {
var recordType = dnstypes.RecordTypeA
if iputils.IsIPv6(ip) {
recordType = dnstypes.RecordTypeAAAA
}
// 避免添加重复的记录
var fullKey = clusterDnsName + "_" + recordType + "_" + ip + "_" + route
if addingNodeRecordKeysMap[fullKey] {
continue
}
addingNodeRecordKeysMap[fullKey] = true
result = append(result, maps.Map{
"action": "create",
"record": &dnstypes.Record{
Id: "",
Name: clusterDnsName,
Type: recordType,
Value: ip,
Route: route,
TTL: ttl,
},
})
nodesChanged = true
} else {
doneNodeRecords = append(doneNodeRecords, record)
}
}
}
}
// 多余的节点域名
for _, record := range nodeRecords {
key := record.Value + "_" + record.Route
if !lists.ContainsString(nodeKeys, key) {
nodesChanged = true
result = append(result, maps.Map{
"action": "delete",
"record": record,
})
}
}
// 服务域名
servers, err := models.SharedServerDAO.FindAllServersDNSWithClusterId(tx, clusterId)
if err != nil {
return nil, nil, nil, 0, 0, false, false, err
}
countAllServers = int64(len(servers))
var serverRecords = []*dnstypes.Record{} // 之所以用数组再存一遍是因为dnsName可能会重复
var serverRecordsMap = map[string]*dnstypes.Record{} // dnsName => *Record
for _, record := range records {
if record.Type == dnstypes.RecordTypeCNAME && record.Value == clusterDomain+"." {
serverRecords = append(serverRecords, record)
serverRecordsMap[record.Name] = record
}
}
// 新增的域名
var serverDNSNames = []string{}
for _, server := range servers {
var dnsName = server.DnsName
if len(dnsName) == 0 {
return nil, nil, nil, 0, 0, false, false, errors.New("server '" + numberutils.FormatInt64(int64(server.Id)) + "' 'dnsName' should not empty")
}
serverDNSNames = append(serverDNSNames, dnsName)
record, ok := serverRecordsMap[dnsName]
if !ok {
serversChanged = true
result = append(result, maps.Map{
"action": "create",
"record": &dnstypes.Record{
Id: "",
Name: dnsName,
Type: dnstypes.RecordTypeCNAME,
Value: clusterDomain + ".",
Route: "", // 注意这里为空,需要在执行过程中获取默认值
TTL: ttl,
},
})
} else {
doneServerRecords = append(doneServerRecords, record)
}
}
// 自动设置的CNAME
for _, cnameRecord := range cnameRecords {
// 如果记录已存在,则跳过
if lists.ContainsString(serverDNSNames, cnameRecord) {
continue
}
serverDNSNames = append(serverDNSNames, cnameRecord)
record, ok := serverRecordsMap[cnameRecord]
if !ok {
serversChanged = true
result = append(result, maps.Map{
"action": "create",
"record": &dnstypes.Record{
Id: "",
Name: cnameRecord,
Type: dnstypes.RecordTypeCNAME,
Value: clusterDomain + ".",
Route: "", // 注意这里为空,需要在执行过程中获取默认值
TTL: ttl,
},
})
} else {
doneServerRecords = append(doneServerRecords, record)
}
}
// 多余的域名
for _, record := range serverRecords {
if !lists.ContainsString(serverDNSNames, record.Name) {
serversChanged = true
result = append(result, maps.Map{
"action": "delete",
"record": record,
})
}
}
return
}
// 执行同步
func (this *DNSDomainService) syncClusterDNS(req *pb.SyncDNSDomainDataRequest) (*pb.SyncDNSDomainDataResponse, error) {
var tx = this.NullTx()
// 查询集群信息
var err error
var clusters = []*models.NodeCluster{}
if req.NodeClusterId > 0 {
cluster, err := models.SharedNodeClusterDAO.FindEnabledNodeCluster(tx, 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(tx, req.DnsDomainId)
if err != nil {
return nil, err
}
}
// 域名信息
domain, err := dns.SharedDNSDomainDAO.FindEnabledDNSDomain(tx, req.DnsDomainId, nil)
if err != nil {
return nil, err
}
if domain == nil {
return &pb.SyncDNSDomainDataResponse{IsOk: false, Error: "找不到要操作的域名"}, nil
}
var domainId = int64(domain.Id)
var domainName = domain.Name
// 服务商信息
provider, err := dns.SharedDNSProviderDAO.FindEnabledDNSProvider(tx, int64(domain.ProviderId))
if err != nil {
return nil, err
}
if provider == nil {
return &pb.SyncDNSDomainDataResponse{IsOk: false, Error: "域名没有设置服务商"}, nil
}
var apiParams = maps.Map{}
if models.IsNotNull(provider.ApiParams) {
err = json.Unmarshal(provider.ApiParams, &apiParams)
if err != nil {
return nil, err
}
}
// 开始同步
var manager = dnsclients.FindProvider(provider.Type, int64(provider.Id))
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 = dns.SharedDNSDomainDAO.UpdateDomainRoutes(tx, domainId, routesJSON)
if err != nil {
return nil, err
}
// 检查集群设置
for _, cluster := range clusters {
issues, err := dnsutils.CheckClusterDNS(tx, cluster, req.CheckNodeIssues)
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 = dns.SharedDNSDomainDAO.UpdateDomainRecords(tx, domainId, recordsJSON)
if err != nil {
return nil, err
}
// 对比变化
var allChanges = []maps.Map{}
for _, cluster := range clusters {
changes, _, _, _, _, _, _, err := this.findClusterDNSChanges(cluster, records, domainName, manager.DefaultRoute())
if err != nil {
return nil, err
}
allChanges = append(allChanges, changes...)
}
for _, change := range allChanges {
action := change.GetString("action")
record := change.Get("record").(*dnstypes.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
}
}
}
// 重新更新记录
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 = dns.SharedDNSDomainDAO.UpdateDomainRecords(tx, domainId, recordsJSON)
if err != nil {
return nil, err
}
}
return &pb.SyncDNSDomainDataResponse{
IsOk: true,
}, nil
}
// ExistDNSDomainRecord 检查域名是否在记录中
func (this *DNSDomainService) ExistDNSDomainRecord(ctx context.Context, req *pb.ExistDNSDomainRecordRequest) (*pb.ExistDNSDomainRecordResponse, error) {
_, _, err := this.ValidateAdminAndUser(ctx, false)
if err != nil {
return nil, err
}
var tx = this.NullTx()
isOk, err := dns.SharedDNSDomainDAO.ExistDomainRecord(tx, req.DnsDomainId, req.Name, req.Type, req.Route, req.Value)
if err != nil {
return nil, err
}
return &pb.ExistDNSDomainRecordResponse{IsOk: isOk}, nil
}
// SyncDNSDomainsFromProvider 从服务商同步域名
func (this *DNSDomainService) SyncDNSDomainsFromProvider(ctx context.Context, req *pb.SyncDNSDomainsFromProviderRequest) (*pb.SyncDNSDomainsFromProviderResponse, error) {
_, _, err := this.ValidateAdminAndUser(ctx, false)
if err != nil {
return nil, err
}
var tx = this.NullTx()
provider, err := dns.SharedDNSProviderDAO.FindEnabledDNSProvider(tx, req.DnsProviderId)
if err != nil {
return nil, err
}
if provider == nil {
return nil, errors.New("can not find provider")
}
// 下线不存在的域名
oldDomains, err := dns.SharedDNSDomainDAO.FindAllEnabledDomainsWithProviderId(tx, req.DnsProviderId)
if err != nil {
return nil, err
}
dnsProvider := dnsclients.FindProvider(provider.Type, int64(provider.Id))
if dnsProvider == nil {
return nil, errors.New("provider type '" + provider.Type + "' is not supported yet")
}
params, err := provider.DecodeAPIParams()
if err != nil {
return nil, errors.New("decode params failed: " + err.Error())
}
err = dnsProvider.Auth(params)
if err != nil {
return nil, errors.New("auth failed: " + err.Error())
}
domainNames, err := dnsProvider.GetDomains()
if err != nil {
return nil, err
}
var hasChanges = false
// 创建或上线域名
for _, domainName := range domainNames {
domain, err := dns.SharedDNSDomainDAO.FindEnabledDomainWithName(tx, req.DnsProviderId, domainName)
if err != nil {
return nil, err
}
if domain == nil {
_, err = dns.SharedDNSDomainDAO.CreateDomain(tx, 0, 0, req.DnsProviderId, domainName)
if err != nil {
return nil, err
}
hasChanges = true
} else if !domain.IsUp {
err = dns.SharedDNSDomainDAO.UpdateDomainIsUp(tx, int64(domain.Id), true)
if err != nil {
return nil, err
}
hasChanges = true
}
}
// 将老的域名置为下线
for _, oldDomain := range oldDomains {
var domainName = oldDomain.Name
if oldDomain.IsUp && !lists.ContainsString(domainNames, domainName) {
err = dns.SharedDNSDomainDAO.UpdateDomainIsUp(tx, int64(oldDomain.Id), false)
if err != nil {
return nil, err
}
hasChanges = true
}
}
return &pb.SyncDNSDomainsFromProviderResponse{
HasChanges: hasChanges,
}, nil
}