Files
EdgeAPI/internal/rpc/services/service_dns_domain.go

459 lines
13 KiB
Go
Raw 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"
"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域名相关服务
type DNSDomainService struct {
}
// 创建域名
func (this *DNSDomainService) CreateDNSDomain(ctx context.Context, req *pb.CreateDNSDomainRequest) (*pb.CreateDNSDomainResponse, error) {
// 校验请求
_, _, err := rpcutils.ValidateRequest(ctx, rpcutils.UserTypeAdmin)
if err != nil {
return nil, err
}
domainId, err := models.SharedDNSDomainDAO.CreateDomain(req.DnsProviderId, req.Name)
if err != nil {
return nil, err
}
return &pb.CreateDNSDomainResponse{DnsDomainId: domainId}, nil
}
// 修改域名
func (this *DNSDomainService) UpdateDNSDomain(ctx context.Context, req *pb.UpdateDNSDomainRequest) (*pb.RPCSuccess, error) {
// 校验请求
_, _, err := rpcutils.ValidateRequest(ctx, rpcutils.UserTypeAdmin)
if err != nil {
return nil, err
}
err = models.SharedDNSDomainDAO.UpdateDomain(req.DnsDomainId, req.Name, req.IsOn)
if err != nil {
return nil, err
}
return rpcutils.Success()
}
// 删除域名
func (this *DNSDomainService) DeleteDNSDomain(ctx context.Context, req *pb.DeleteDNSDomainRequest) (*pb.RPCSuccess, error) {
// 校验请求
_, _, err := rpcutils.ValidateRequest(ctx, rpcutils.UserTypeAdmin)
if err != nil {
return nil, err
}
err = models.SharedDNSDomainDAO.DisableDNSDomain(req.DnsDomainId)
if err != nil {
return nil, err
}
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
}
// 计算服务商下的域名数量
func (this *DNSDomainService) CountAllEnabledDNSDomainsWithDNSProviderId(ctx context.Context, req *pb.CountAllEnabledDNSDomainsWithDNSProviderIdRequest) (*pb.RPCCountResponse, error) {
// 校验请求
_, _, err := rpcutils.ValidateRequest(ctx, rpcutils.UserTypeAdmin)
if err != nil {
return nil, err
}
count, err := models.SharedDNSDomainDAO.CountAllEnabledDomainsWithProviderId(req.DnsProviderId)
if err != nil {
return nil, err
}
return &pb.RPCCountResponse{Count: count}, nil
}
// 列出服务商下的所有域名
func (this *DNSDomainService) FindAllEnabledDNSDomainsWithDNSProviderId(ctx context.Context, req *pb.FindAllEnabledDNSDomainsWithDNSProviderIdRequest) (*pb.FindAllEnabledDNSDomainsWithDNSProviderIdResponse, 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 {
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,
}
}