实现基本的集群DNS列表、设置、简单数据同步

This commit is contained in:
GoEdgeLab
2020-11-13 18:22:22 +08:00
parent 7f61c82c52
commit f17f987636
51 changed files with 1074 additions and 391 deletions

View File

@@ -2,9 +2,12 @@ package services
import (
"context"
"encoding/json"
"github.com/TeaOSLab/EdgeAPI/internal/db/models"
"github.com/TeaOSLab/EdgeAPI/internal/dnsclients"
rpcutils "github.com/TeaOSLab/EdgeAPI/internal/rpc/utils"
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
"github.com/iwind/TeaGo/maps"
)
// DNS域名相关服务
@@ -27,7 +30,7 @@ func (this *DNSDomainService) CreateDNSDomain(ctx context.Context, req *pb.Creat
}
// 修改域名
func (this *DNSDomainService) UpdateDNSDomain(ctx context.Context, req *pb.UpdateDNSDomainRequest) (*pb.RPCUpdateSuccess, error) {
func (this *DNSDomainService) UpdateDNSDomain(ctx context.Context, req *pb.UpdateDNSDomainRequest) (*pb.RPCSuccess, error) {
// 校验请求
_, _, err := rpcutils.ValidateRequest(ctx, rpcutils.UserTypeAdmin)
if err != nil {
@@ -38,11 +41,11 @@ func (this *DNSDomainService) UpdateDNSDomain(ctx context.Context, req *pb.Updat
if err != nil {
return nil, err
}
return rpcutils.RPCUpdateSuccess()
return rpcutils.Success()
}
// 删除域名
func (this *DNSDomainService) DeleteDNSDomain(ctx context.Context, req *pb.DeleteDNSDomainRequest) (*pb.RPCDeleteSuccess, error) {
func (this *DNSDomainService) DeleteDNSDomain(ctx context.Context, req *pb.DeleteDNSDomainRequest) (*pb.RPCSuccess, error) {
// 校验请求
_, _, err := rpcutils.ValidateRequest(ctx, rpcutils.UserTypeAdmin)
if err != nil {
@@ -53,7 +56,51 @@ func (this *DNSDomainService) DeleteDNSDomain(ctx context.Context, req *pb.Delet
if err != nil {
return nil, err
}
return rpcutils.RPCDeleteSuccess()
return rpcutils.Success()
}
// 查询单个域名完整信息
func (this *DNSDomainService) FindEnabledDNSDomain(ctx context.Context, req *pb.FindEnabledDNSDomainRequest) (*pb.FindEnabledDNSDomainResponse, error) {
// 校验请求
_, _, err := rpcutils.ValidateRequest(ctx, rpcutils.UserTypeAdmin)
if err != nil {
return nil, err
}
domain, err := models.SharedDNSDomainDAO.FindEnabledDNSDomain(req.DnsDomainId)
if err != nil {
return nil, err
}
if domain == nil {
return &pb.FindEnabledDNSDomainResponse{DnsDomain: nil}, nil
}
pbDomain, err := this.convertDomainToPB(domain)
return &pb.FindEnabledDNSDomainResponse{DnsDomain: pbDomain}, nil
}
// 查询单个域名基础信息
func (this *DNSDomainService) FindEnabledBasicDNSDomain(ctx context.Context, req *pb.FindEnabledBasicDNSDomainRequest) (*pb.FindEnabledBasicDNSDomainResponse, error) {
// 校验请求
_, _, err := rpcutils.ValidateRequest(ctx, rpcutils.UserTypeAdmin)
if err != nil {
return nil, err
}
domain, err := models.SharedDNSDomainDAO.FindEnabledDNSDomain(req.DnsDomainId)
if err != nil {
return nil, err
}
if domain == nil {
return &pb.FindEnabledBasicDNSDomainResponse{DnsDomain: nil}, nil
}
return &pb.FindEnabledBasicDNSDomainResponse{DnsDomain: &pb.DNSDomain{
Id: int64(domain.Id),
Name: domain.Name,
IsOn: domain.IsOn == 1,
ProviderId: int64(domain.ProviderId),
}}, nil
}
// 计算服务商下的域名数量
@@ -86,13 +133,326 @@ func (this *DNSDomainService) FindAllEnabledDNSDomainsWithDNSProviderId(ctx cont
result := []*pb.DNSDomain{}
for _, domain := range domains {
result = append(result, &pb.DNSDomain{
Id: int64(domain.Id),
Name: domain.Name,
IsOn: domain.IsOn == 1,
DataUpdatedAt: int64(domain.DataUpdatedAt),
})
pbDomain, err := this.convertDomainToPB(domain)
if err != nil {
return nil, err
}
result = append(result, pbDomain)
}
return &pb.FindAllEnabledDNSDomainsWithDNSProviderIdResponse{DnsDomains: result}, nil
}
// 列出服务商下的所有域名基本信息
func (this *DNSDomainService) FindAllEnabledBasicDNSDomainsWithDNSProviderId(ctx context.Context, req *pb.FindAllEnabledBasicDNSDomainsWithDNSProviderIdRequest) (*pb.FindAllEnabledBasicDNSDomainsWithDNSProviderIdResponse, error) {
// 校验请求
_, _, err := rpcutils.ValidateRequest(ctx, rpcutils.UserTypeAdmin)
if err != nil {
return nil, err
}
domains, err := models.SharedDNSDomainDAO.FindAllEnabledDomainsWithProviderId(req.DnsProviderId)
if err != nil {
return nil, err
}
result := []*pb.DNSDomain{}
for _, domain := range domains {
result = append(result, &pb.DNSDomain{
Id: int64(domain.Id),
Name: domain.Name,
IsOn: domain.IsOn == 1,
})
}
return &pb.FindAllEnabledBasicDNSDomainsWithDNSProviderIdResponse{DnsDomains: result}, nil
}
// 同步域名数据
func (this *DNSDomainService) SyncDNSDomainData(ctx context.Context, req *pb.SyncDNSDomainDataRequest) (*pb.SyncDNSDomainDataResponse, error) {
// 校验请求
_, _, err := rpcutils.ValidateRequest(ctx, rpcutils.UserTypeAdmin)
if err != nil {
return nil, err
}
// 检查集群设置完整性
clusters, err := models.SharedNodeClusterDAO.FindAllEnabledClustersWithDNSDomainId(req.DnsDomainId)
if err != nil {
return nil, err
}
for _, cluster := range clusters {
if len(cluster.DnsName) == 0 {
return &pb.SyncDNSDomainDataResponse{IsOk: false, Error: "有问题需要修复", ShouldFix: true}, nil
}
nodes, err := models.SharedNodeDAO.FindAllEnabledNodesWithClusterId(int64(cluster.Id))
if err != nil {
return nil, err
}
for _, node := range nodes {
if node.IsOn == 0 {
continue
}
ipAddress, err := models.SharedNodeIPAddressDAO.FindFirstNodeIPAddress(int64(node.Id))
if err != nil {
return nil, err
}
if len(ipAddress) == 0 {
return &pb.SyncDNSDomainDataResponse{IsOk: false, Error: "有问题需要修复", ShouldFix: true}, nil
}
route, err := node.DNSRoute(req.DnsDomainId)
if err != nil {
return nil, err
}
if len(route) == 0 {
return &pb.SyncDNSDomainDataResponse{IsOk: false, Error: "有问题需要修复", ShouldFix: true}, nil
}
}
}
// 检查服务设置完整性
servers, err := models.SharedServerDAO.FindAllServersToFixWithDNSDomainId(req.DnsDomainId)
if err != nil {
return nil, err
}
if len(servers) > 0 {
return &pb.SyncDNSDomainDataResponse{IsOk: false, Error: "有问题需要修复", ShouldFix: true}, nil
}
// 域名信息
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
}
// 所有记录
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
}
// 修正集群域名
// TODO
// 修正服务域名
// TODO
return &pb.SyncDNSDomainDataResponse{
IsOk: true,
}, nil
}
// 查看支持的线路
func (this *DNSDomainService) FindAllDNSDomainRoutes(ctx context.Context, req *pb.FindAllDNSDomainRoutesRequest) (*pb.FindAllDNSDomainRoutesResponse, error) {
// 校验请求
_, _, err := rpcutils.ValidateRequest(ctx, rpcutils.UserTypeAdmin)
if err != nil {
return nil, err
}
routes, err := models.SharedDNSDomainDAO.FindDomainRoutes(req.DnsDomainId)
if err != nil {
return nil, err
}
return &pb.FindAllDNSDomainRoutesResponse{Routes: routes}, nil
}
// 转换域名信息
func (this *DNSDomainService) convertDomainToPB(domain *models.DNSDomain) (*pb.DNSDomain, error) {
domainId := int64(domain.Id)
records := []*dnsclients.Record{}
if len(domain.Records) > 0 && domain.Records != "null" {
err := json.Unmarshal([]byte(domain.Records), &records)
if err != nil {
return nil, err
}
}
recordsMapping := map[string][]*dnsclients.Record{} // name_type => *Record
for _, record := range records {
key := record.Name + "_" + record.Type
_, ok := recordsMapping[key]
if ok {
recordsMapping[key] = append(recordsMapping[key], record)
} else {
recordsMapping[key] = []*dnsclients.Record{record}
}
}
// 集群域名
clusterRecords := []*pb.DNSRecord{}
allClusterResolved := true
{
// 检查是否所有的集群都已经被解析
clusters, err := models.SharedNodeClusterDAO.FindAllEnabledClustersWithDNSDomainId(domainId)
if err != nil {
return nil, err
}
for _, cluster := range clusters {
clusterId := int64(cluster.Id)
dnsName := cluster.DnsName
// 子节点
nodes, err := models.SharedNodeDAO.FindAllEnabledNodesWithClusterId(clusterId)
if err != nil {
return nil, err
}
nodeMapping := map[string]*models.Node{} // name_type_value_route => *Node
for _, node := range nodes {
if node.IsOn == 0 {
continue
}
ipAddr, err := models.SharedNodeIPAddressDAO.FindFirstNodeIPAddress(int64(node.Id))
if err != nil {
return nil, err
}
route, err := node.DNSRoute(domainId)
if err != nil {
return nil, err
}
nodeMapping[dnsName+"_A_"+ipAddr+"_"+route] = node
}
// 已有的记录
nodeRecordsMapping := map[string]*dnsclients.Record{} // name_type_value_route => *Record
nodeRecords, _ := recordsMapping[dnsName+"_A"]
for _, record := range nodeRecords {
key := record.Name + "_" + record.Type + "_" + record.Value + "_" + record.Route
nodeRecordsMapping[key] = record
}
// 检查有无多余的子节点
for key, record := range nodeRecordsMapping {
_, ok := nodeMapping[key]
if !ok {
allClusterResolved = false
continue
}
clusterRecords = append(clusterRecords, this.convertRecordToPB(record))
}
// 检查有无少的子节点
for key := range nodeMapping {
_, ok := nodeRecordsMapping[key]
if !ok {
allClusterResolved = false
break
}
}
}
}
// 服务域名
serverRecords := []*pb.DNSRecord{}
allServersResolved := true
// 检查是否所有的服务都已经被解析
{
dnsNames, err := models.SharedServerDAO.FindAllServerDNSNamesWithDNSDomainId(domainId)
if err != nil {
return nil, err
}
for _, dnsName := range dnsNames {
if len(dnsName) == 0 {
allServersResolved = true
continue
}
key := dnsName + "_CNAME"
recordList, ok := recordsMapping[key]
if !ok {
allServersResolved = false
continue
}
for _, record := range recordList {
serverRecords = append(serverRecords, this.convertRecordToPB(record))
}
}
}
// 线路
routes := []string{}
if len(domain.Routes) > 0 && domain.Routes != "null" {
err := json.Unmarshal([]byte(domain.Routes), &routes)
if err != nil {
return nil, err
}
}
return &pb.DNSDomain{
Id: int64(domain.Id),
ProviderId: int64(domain.ProviderId),
Name: domain.Name,
IsOn: domain.IsOn == 1,
DataUpdatedAt: int64(domain.DataUpdatedAt),
ClusterRecords: clusterRecords,
AllClustersResolved: allClusterResolved,
ServerRecords: serverRecords,
AllServersResolved: allServersResolved,
Routes: routes,
}, nil
}
// 转换域名记录信息
func (this *DNSDomainService) convertRecordToPB(record *dnsclients.Record) *pb.DNSRecord {
return &pb.DNSRecord{
Id: record.Id,
Name: record.Name,
Value: record.Value,
Type: record.Type,
Route: record.Route,
}
}