diff --git a/internal/db/models/dns/dnsutils/dns_utils.go b/internal/db/models/dns/dnsutils/dns_utils.go new file mode 100644 index 00000000..18daaf93 --- /dev/null +++ b/internal/db/models/dns/dnsutils/dns_utils.go @@ -0,0 +1,207 @@ +// Copyright 2021 Liuxiangchao iwind.liu@gmail.com. All rights reserved. + +package dnsutils + +import ( + "github.com/TeaOSLab/EdgeAPI/internal/db/models" + "github.com/TeaOSLab/EdgeAPI/internal/db/models/dns" + "github.com/TeaOSLab/EdgeAPI/internal/dnsclients" + "github.com/TeaOSLab/EdgeAPI/internal/errors" + "github.com/TeaOSLab/EdgeAPI/internal/utils/numberutils" + "github.com/TeaOSLab/EdgeCommon/pkg/nodeconfigs" + "github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb" + "github.com/iwind/TeaGo/dbs" +) + +// CheckClusterDNS 检查集群的DNS问题 +// 藏这么深是避免package循环引用的问题 +func CheckClusterDNS(tx *dbs.Tx, cluster *models.NodeCluster) (issues []*pb.DNSIssue, err error) { + clusterId := int64(cluster.Id) + domainId := int64(cluster.DnsDomainId) + + // 检查域名 + domain, err := dns.SharedDNSDomainDAO.FindEnabledDNSDomain(tx, domainId, nil) + if err != nil { + return nil, err + } + if domain == nil { + issues = append(issues, &pb.DNSIssue{ + Target: cluster.Name, + TargetId: clusterId, + Type: "cluster", + Description: "域名选择错误,需要重新选择", + Params: nil, + MustFix: true, + }) + return + } + + // Provider + provider, err := dns.SharedDNSProviderDAO.FindEnabledDNSProvider(tx, int64(domain.ProviderId)) + if err != nil { + return nil, err + } + if provider == nil { + issues = append(issues, &pb.DNSIssue{ + Target: cluster.Name, + TargetId: clusterId, + Type: "cluster", + Description: "域名服务商不可用,需要重新选择", + Params: nil, + MustFix: true, + }) + return + } + paramsMap, err := provider.DecodeAPIParams() + if err != nil { + issues = append(issues, &pb.DNSIssue{ + Target: cluster.Name, + TargetId: clusterId, + Type: "cluster", + Description: "域名服务商参数配置错误,需要重新配置", + Params: nil, + MustFix: true, + }) + return + } + var dnsProvider = dnsclients.FindProvider(provider.Type) + if dnsProvider == nil { + issues = append(issues, &pb.DNSIssue{ + Target: cluster.Name, + TargetId: clusterId, + Type: "cluster", + Description: "目前不支持\"" + provider.Type + "\"服务商,需要重新配置", + Params: nil, + MustFix: true, + }) + return + } + err = dnsProvider.Auth(paramsMap) + if err != nil { + return + } + var defaultRoute = dnsProvider.DefaultRoute() + var hasDefaultRoute = len(defaultRoute) > 0 + + // 检查二级域名 + if len(cluster.DnsName) == 0 { + issues = append(issues, &pb.DNSIssue{ + Target: cluster.Name, + TargetId: clusterId, + Type: "cluster", + Description: "没有设置二级域名", + Params: nil, + MustFix: true, + }) + return + } + + // TODO 检查域名格式 + + // TODO 检查域名是否已解析 + + // 检查节点 + nodes, err := models.SharedNodeDAO.FindAllEnabledNodesDNSWithClusterId(tx, clusterId, true) + if err != nil { + return nil, err + } + + // TODO 检查节点数量不能为0 + + for _, node := range nodes { + nodeId := int64(node.Id) + + routeCodes, err := node.DNSRouteCodesForDomainId(domainId) + if err != nil { + return nil, err + } + if len(routeCodes) == 0 && !hasDefaultRoute { + issues = append(issues, &pb.DNSIssue{ + Target: node.Name, + TargetId: nodeId, + Type: "node", + Description: "没有选择节点所属线路", + Params: map[string]string{ + "clusterName": cluster.Name, + "clusterId": numberutils.FormatInt64(clusterId), + }, + MustFix: true, + }) + continue + } + + // 检查线路是否在已有线路中 + for _, routeCode := range routeCodes { + routeOk, err := domain.ContainsRouteCode(routeCode) + if err != nil { + return nil, err + } + if !routeOk { + issues = append(issues, &pb.DNSIssue{ + Target: node.Name, + TargetId: nodeId, + Type: "node", + Description: "线路已经失效,请重新选择", + Params: map[string]string{ + "clusterName": cluster.Name, + "clusterId": numberutils.FormatInt64(clusterId), + }, + MustFix: true, + }) + continue + } + } + + // 检查IP地址 + ipAddr, err := models.SharedNodeIPAddressDAO.FindFirstNodeAccessIPAddress(tx, nodeId, nodeconfigs.NodeRoleNode) + if err != nil { + return nil, err + } + if len(ipAddr) == 0 { + issues = append(issues, &pb.DNSIssue{ + Target: node.Name, + TargetId: nodeId, + Type: "node", + Description: "没有设置IP地址", + Params: map[string]string{ + "clusterName": cluster.Name, + "clusterId": numberutils.FormatInt64(clusterId), + }, + MustFix: true, + }) + continue + } + + // TODO 检查是否有解析记录 + } + + return +} + +// FindDefaultDomainRoute 获取域名默认的线路 +func FindDefaultDomainRoute(tx *dbs.Tx, domain *dns.DNSDomain) (string, error) { + if domain == nil { + return "", errors.New("can not find domain") + } + + provider, err := dns.SharedDNSProviderDAO.FindEnabledDNSProvider(tx, int64(domain.ProviderId)) + if err != nil { + return "", err + } + if provider == nil { + return "", errors.New("provider not found") + } + paramsMap, err := provider.DecodeAPIParams() + if err != nil { + return "", errors.New("decode provider params failed: " + err.Error()) + } + var dnsProvider = dnsclients.FindProvider(provider.Type) + if dnsProvider == nil { + return "", errors.New("not supported provider type '" + provider.Type + "'") + } + err = dnsProvider.Auth(paramsMap) + if err != nil { + return "", err + } + return dnsProvider.DefaultRoute(), nil +} diff --git a/internal/db/models/dns/dnsutils/dns_utils_test.go b/internal/db/models/dns/dnsutils/dns_utils_test.go new file mode 100644 index 00000000..a923d4a1 --- /dev/null +++ b/internal/db/models/dns/dnsutils/dns_utils_test.go @@ -0,0 +1,29 @@ +// Copyright 2021 Liuxiangchao iwind.liu@gmail.com. All rights reserved. + +package dnsutils + +import ( + "github.com/TeaOSLab/EdgeAPI/internal/db/models" + "github.com/iwind/TeaGo/dbs" + "github.com/iwind/TeaGo/logs" + "testing" +) + +func TestNodeClusterDAO_CheckClusterDNS(t *testing.T) { + dbs.NotifyReady() + + var tx *dbs.Tx + cluster, err := models.SharedNodeClusterDAO.FindEnabledNodeCluster(tx, 34) + if err != nil { + t.Fatal(err) + } + if cluster == nil { + t.Log("cluster not found, skip the test") + return + } + issues, err := CheckClusterDNS(tx, cluster) + if err != nil { + t.Fatal(err) + } + logs.PrintAsJSON(issues, t) +} diff --git a/internal/db/models/node_cluster_dao.go b/internal/db/models/node_cluster_dao.go index 36f09e39..84c74fd5 100644 --- a/internal/db/models/node_cluster_dao.go +++ b/internal/db/models/node_cluster_dao.go @@ -4,10 +4,8 @@ import ( "encoding/json" "errors" "github.com/TeaOSLab/EdgeAPI/internal/db/models/dns" - "github.com/TeaOSLab/EdgeAPI/internal/utils/numberutils" "github.com/TeaOSLab/EdgeCommon/pkg/dnsconfigs" "github.com/TeaOSLab/EdgeCommon/pkg/nodeconfigs" - "github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb" "github.com/TeaOSLab/EdgeCommon/pkg/serverconfigs" _ "github.com/go-sql-driver/mysql" "github.com/iwind/TeaGo/Tea" @@ -471,117 +469,7 @@ func (this *NodeClusterDAO) UpdateClusterDNS(tx *dbs.Tx, clusterId int64, dnsNam return this.NotifyDNSUpdate(tx, clusterId) } -// CheckClusterDNS 检查集群的DNS问题 -func (this *NodeClusterDAO) CheckClusterDNS(tx *dbs.Tx, cluster *NodeCluster) (issues []*pb.DNSIssue, err error) { - clusterId := int64(cluster.Id) - domainId := int64(cluster.DnsDomainId) - // 检查域名 - domain, err := dns.SharedDNSDomainDAO.FindEnabledDNSDomain(tx, domainId, nil) - if err != nil { - return nil, err - } - if domain == nil { - issues = append(issues, &pb.DNSIssue{ - Target: cluster.Name, - TargetId: clusterId, - Type: "cluster", - Description: "域名选择错误,需要重新选择", - Params: nil, - }) - return - } - - // 检查二级域名 - if len(cluster.DnsName) == 0 { - issues = append(issues, &pb.DNSIssue{ - Target: cluster.Name, - TargetId: clusterId, - Type: "cluster", - Description: "没有设置二级域名", - Params: nil, - }) - return - } - - // TODO 检查域名格式 - - // TODO 检查域名是否已解析 - - // 检查节点 - nodes, err := SharedNodeDAO.FindAllEnabledNodesDNSWithClusterId(tx, clusterId, true) - if err != nil { - return nil, err - } - - // TODO 检查节点数量不能为0 - - for _, node := range nodes { - nodeId := int64(node.Id) - - routeCodes, err := node.DNSRouteCodesForDomainId(domainId) - if err != nil { - return nil, err - } - if len(routeCodes) == 0 { - issues = append(issues, &pb.DNSIssue{ - Target: node.Name, - TargetId: nodeId, - Type: "node", - Description: "没有选择节点所属线路", - Params: map[string]string{ - "clusterName": cluster.Name, - "clusterId": numberutils.FormatInt64(clusterId), - }, - }) - continue - } - - // 检查线路是否在已有线路中 - for _, routeCode := range routeCodes { - routeOk, err := domain.ContainsRouteCode(routeCode) - if err != nil { - return nil, err - } - if !routeOk { - issues = append(issues, &pb.DNSIssue{ - Target: node.Name, - TargetId: nodeId, - Type: "node", - Description: "线路已经失效,请重新选择", - Params: map[string]string{ - "clusterName": cluster.Name, - "clusterId": numberutils.FormatInt64(clusterId), - }, - }) - continue - } - } - - // 检查IP地址 - ipAddr, err := SharedNodeIPAddressDAO.FindFirstNodeAccessIPAddress(tx, nodeId, nodeconfigs.NodeRoleNode) - if err != nil { - return nil, err - } - if len(ipAddr) == 0 { - issues = append(issues, &pb.DNSIssue{ - Target: node.Name, - TargetId: nodeId, - Type: "node", - Description: "没有设置IP地址", - Params: map[string]string{ - "clusterName": cluster.Name, - "clusterId": numberutils.FormatInt64(clusterId), - }, - }) - continue - } - - // TODO 检查是否有解析记录 - } - - return -} // FindClusterAdminId 查找集群所属管理员 func (this *NodeClusterDAO) FindClusterAdminId(tx *dbs.Tx, clusterId int64) (int64, error) { diff --git a/internal/rpc/services/service_dns.go b/internal/rpc/services/service_dns.go index 5dd65f72..bf223391 100644 --- a/internal/rpc/services/service_dns.go +++ b/internal/rpc/services/service_dns.go @@ -3,6 +3,7 @@ package services import ( "context" "github.com/TeaOSLab/EdgeAPI/internal/db/models" + "github.com/TeaOSLab/EdgeAPI/internal/db/models/dns/dnsutils" "github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb" ) @@ -39,7 +40,7 @@ func (this *DNSService) FindAllDNSIssues(ctx context.Context, req *pb.FindAllDNS clusters = []*models.NodeCluster{cluster} } for _, cluster := range clusters { - issues, err := models.SharedNodeClusterDAO.CheckClusterDNS(tx, cluster) + issues, err := dnsutils.CheckClusterDNS(tx, cluster) if err != nil { return nil, err } diff --git a/internal/rpc/services/service_dns_domain.go b/internal/rpc/services/service_dns_domain.go index 6cfead96..a801fec5 100644 --- a/internal/rpc/services/service_dns_domain.go +++ b/internal/rpc/services/service_dns_domain.go @@ -5,6 +5,7 @@ import ( "encoding/json" "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" @@ -12,6 +13,7 @@ import ( "github.com/TeaOSLab/EdgeAPI/internal/utils/numberutils" "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" "net" @@ -145,7 +147,7 @@ func (this *DNSDomainService) FindEnabledDNSDomain(ctx context.Context, req *pb. return &pb.FindEnabledDNSDomainResponse{DnsDomain: nil}, nil } - pbDomain, err := this.convertDomainToPB(domain) + pbDomain, err := this.convertDomainToPB(tx, domain) return &pb.FindEnabledDNSDomainResponse{DnsDomain: pbDomain}, nil } @@ -209,7 +211,7 @@ func (this *DNSDomainService) FindAllEnabledDNSDomainsWithDNSProviderId(ctx cont result := []*pb.DNSDomain{} for _, domain := range domains { - pbDomain, err := this.convertDomainToPB(domain) + pbDomain, err := this.convertDomainToPB(tx, domain) if err != nil { return nil, err } @@ -300,9 +302,14 @@ func (this *DNSDomainService) ExistAvailableDomains(ctx context.Context, req *pb } // 转换域名信息 -func (this *DNSDomainService) convertDomainToPB(domain *dns.DNSDomain) (*pb.DNSDomain, error) { +func (this *DNSDomainService) convertDomainToPB(tx *dbs.Tx, domain *dns.DNSDomain) (*pb.DNSDomain, error) { domainId := int64(domain.Id) + defaultRoute, err := dnsutils.FindDefaultDomainRoute(tx, domain) + if err != nil { + return nil, err + } + records := []*dnstypes.Record{} if len(domain.Records) > 0 && domain.Records != "null" { err := json.Unmarshal([]byte(domain.Records), &records) @@ -319,8 +326,6 @@ func (this *DNSDomainService) convertDomainToPB(domain *dns.DNSDomain) (*pb.DNSD countServerRecords := 0 serversChanged := false - tx := this.NullTx() - // 检查是否所有的集群都已经被解析 clusters, err := models.SharedNodeClusterDAO.FindAllEnabledClustersWithDNSDomainId(tx, domainId) if err != nil { @@ -330,7 +335,8 @@ func (this *DNSDomainService) convertDomainToPB(domain *dns.DNSDomain) (*pb.DNSD countAllNodes1 := int64(0) countAllServers1 := int64(0) for _, cluster := range clusters { - _, nodeRecords, serverRecords, countAllNodes, countAllServers, nodesChanged2, serversChanged2, err := this.findClusterDNSChanges(cluster, records, domain.Name) + + _, nodeRecords, serverRecords, countAllNodes, countAllServers, nodesChanged2, serversChanged2, err := this.findClusterDNSChanges(cluster, records, domain.Name, defaultRoute) if err != nil { return nil, err } @@ -389,7 +395,7 @@ func (this *DNSDomainService) convertRecordToPB(record *dnstypes.Record) *pb.DNS } // 检查集群节点变化 -func (this *DNSDomainService) findClusterDNSChanges(cluster *models.NodeCluster, records []*dnstypes.Record, domainName string) (result []maps.Map, doneNodeRecords []*dnstypes.Record, doneServerRecords []*dnstypes.Record, countAllNodes int64, countAllServers int64, nodesChanged bool, serversChanged bool, err error) { +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) { clusterId := int64(cluster.Id) clusterDnsName := cluster.DnsName clusterDomain := clusterDnsName + "." + domainName @@ -426,7 +432,12 @@ func (this *DNSDomainService) findClusterDNSChanges(cluster *models.NodeCluster, return nil, nil, nil, 0, 0, false, false, err } if len(routeCodes) == 0 { - continue + // 默认线路 + if len(defaultRoute) > 0 { + routeCodes = []string{defaultRoute} + } else { + continue + } } for _, route := range routeCodes { for _, ipAddress := range ipAddresses { @@ -617,7 +628,7 @@ func (this *DNSDomainService) syncClusterDNS(req *pb.SyncDNSDomainDataRequest) ( // 检查集群设置 for _, cluster := range clusters { - issues, err := models.SharedNodeClusterDAO.CheckClusterDNS(tx, cluster) + issues, err := dnsutils.CheckClusterDNS(tx, cluster) if err != nil { return nil, err } @@ -643,7 +654,7 @@ func (this *DNSDomainService) syncClusterDNS(req *pb.SyncDNSDomainDataRequest) ( // 对比变化 allChanges := []maps.Map{} for _, cluster := range clusters { - changes, _, _, _, _, _, _, err := this.findClusterDNSChanges(cluster, records, domainName) + changes, _, _, _, _, _, _, err := this.findClusterDNSChanges(cluster, records, domainName, manager.DefaultRoute()) if err != nil { return nil, err } diff --git a/internal/rpc/services/service_node_cluster.go b/internal/rpc/services/service_node_cluster.go index 02bc188e..7f7c9fc6 100644 --- a/internal/rpc/services/service_node_cluster.go +++ b/internal/rpc/services/service_node_cluster.go @@ -5,6 +5,7 @@ import ( "encoding/json" "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/errors" "github.com/TeaOSLab/EdgeAPI/internal/tasks" @@ -470,6 +471,8 @@ func (this *NodeClusterService) FindEnabledNodeClusterDNS(ctx context.Context, r return nil, err } + var defaultRoute = "" + var pbProvider *pb.DNSProvider = nil if provider != nil { pbProvider = &pb.DNSProvider{ @@ -478,6 +481,19 @@ func (this *NodeClusterService) FindEnabledNodeClusterDNS(ctx context.Context, r Type: provider.Type, TypeName: dnsclients.FindProviderTypeName(provider.Type), } + + manager := dnsclients.FindProvider(provider.Type) + if manager != nil { + apiParams, err := provider.DecodeAPIParams() + if err != nil { + return nil, err + } + err = manager.Auth(apiParams) + if err != nil { + return nil, err + } + defaultRoute = manager.DefaultRoute() + } } return &pb.FindEnabledNodeClusterDNSResponse{ @@ -486,6 +502,7 @@ func (this *NodeClusterService) FindEnabledNodeClusterDNS(ctx context.Context, r Provider: pbProvider, NodesAutoSync: dnsConfig.NodesAutoSync, ServersAutoSync: dnsConfig.ServersAutoSync, + DefaultRoute: defaultRoute, }, nil } @@ -617,8 +634,13 @@ func (this *NodeClusterService) CheckNodeClusterDNSChanges(ctx context.Context, return nil, err } + defaultRoute, err := dnsutils.FindDefaultDomainRoute(tx, domain) + if err != nil { + return nil, err + } + service := &DNSDomainService{} - changes, _, _, _, _, _, _, err := service.findClusterDNSChanges(cluster, records, domain.Name) + changes, _, _, _, _, _, _, err := service.findClusterDNSChanges(cluster, records, domain.Name, defaultRoute) if err != nil { return nil, err }