DNSPod改名为腾讯云DNSPod/DNSPod 支持腾讯云API密钥

This commit is contained in:
GoEdgeLab
2023-11-23 15:15:11 +08:00
parent 2dae39d097
commit 24a3399f9c
4 changed files with 469 additions and 11 deletions

View File

@@ -32,8 +32,6 @@ var dnsPodHTTPClient = &http.Client{
}
// DNSPodProvider DNSPod服务商
// TODO 考虑支持线路ID
// TODO 支持自定义线路
type DNSPodProvider struct {
BaseProvider
@@ -42,19 +40,30 @@ type DNSPodProvider struct {
region string
apiId string
apiToken string
tencentDNSProvider *TencentDNSProvider
}
// Auth 认证
func (this *DNSPodProvider) Auth(params maps.Map) error {
this.apiId = params.GetString("id")
this.apiToken = params.GetString("token")
this.region = params.GetString("region")
// 兼容腾讯云API
var apiType = params.GetString("apiType")
if len(this.apiId) == 0 {
return errors.New("'id' should be not empty")
}
if len(this.apiToken) == 0 {
return errors.New("'token' should not be empty")
switch apiType {
case "tencentDNS":
this.tencentDNSProvider = NewTencentDNSProvider()
return this.tencentDNSProvider.Auth(params)
default:
this.apiId = params.GetString("id")
this.apiToken = params.GetString("token")
this.region = params.GetString("region")
if len(this.apiId) == 0 {
return errors.New("'id' should be not empty")
}
if len(this.apiToken) == 0 {
return errors.New("'token' should not be empty")
}
}
return nil
@@ -62,6 +71,10 @@ func (this *DNSPodProvider) Auth(params maps.Map) error {
// GetDomains 获取所有域名列表
func (this *DNSPodProvider) GetDomains() (domains []string, err error) {
if this.tencentDNSProvider != nil {
return this.tencentDNSProvider.GetDomains()
}
var offset = 0
var size = 3000
@@ -92,6 +105,10 @@ func (this *DNSPodProvider) GetDomains() (domains []string, err error) {
// GetRecords 获取域名列表
func (this *DNSPodProvider) GetRecords(domain string) (records []*dnstypes.Record, err error) {
if this.tencentDNSProvider != nil {
return this.tencentDNSProvider.GetRecords(domain)
}
var offset = 0
var size = 3000
for {
@@ -135,6 +152,10 @@ func (this *DNSPodProvider) GetRecords(domain string) (records []*dnstypes.Recor
// GetRoutes 读取线路数据
func (this *DNSPodProvider) GetRoutes(domain string) (routes []*dnstypes.Route, err error) {
if this.tencentDNSProvider != nil {
return this.tencentDNSProvider.GetRoutes(domain)
}
var domainInfoResp = new(dnspod.DomainInfoResponse)
err = this.doAPI("/Domain.Info", map[string]string{
"domain": domain,
@@ -217,6 +238,10 @@ func (this *DNSPodProvider) GetRoutes(domain string) (routes []*dnstypes.Route,
// QueryRecord 查询单个记录
func (this *DNSPodProvider) QueryRecord(domain string, name string, recordType dnstypes.RecordType) (*dnstypes.Record, error) {
if this.tencentDNSProvider != nil {
return this.tencentDNSProvider.QueryRecord(domain, name, recordType)
}
// 从缓存中读取
if this.ProviderId > 0 {
record, hasRecords, _ := sharedDomainRecordsCache.QueryDomainRecord(this.ProviderId, domain, name, recordType)
@@ -239,6 +264,10 @@ func (this *DNSPodProvider) QueryRecord(domain string, name string, recordType d
// QueryRecords 查询多个记录
func (this *DNSPodProvider) QueryRecords(domain string, name string, recordType dnstypes.RecordType) ([]*dnstypes.Record, error) {
if this.tencentDNSProvider != nil {
return this.tencentDNSProvider.QueryRecords(domain, name, recordType)
}
// 从缓存中读取
if this.ProviderId > 0 {
records, hasRecords, _ := sharedDomainRecordsCache.QueryDomainRecords(this.ProviderId, domain, name, recordType)
@@ -262,6 +291,10 @@ func (this *DNSPodProvider) QueryRecords(domain string, name string, recordType
// AddRecord 设置记录
func (this *DNSPodProvider) AddRecord(domain string, newRecord *dnstypes.Record) error {
if this.tencentDNSProvider != nil {
return this.tencentDNSProvider.AddRecord(domain, newRecord)
}
if newRecord == nil {
return errors.New("invalid new record")
}
@@ -298,6 +331,10 @@ func (this *DNSPodProvider) AddRecord(domain string, newRecord *dnstypes.Record)
// UpdateRecord 修改记录
func (this *DNSPodProvider) UpdateRecord(domain string, record *dnstypes.Record, newRecord *dnstypes.Record) error {
if this.tencentDNSProvider != nil {
return this.tencentDNSProvider.UpdateRecord(domain, record, newRecord)
}
if record == nil {
return errors.New("invalid record")
}
@@ -339,6 +376,10 @@ func (this *DNSPodProvider) UpdateRecord(domain string, record *dnstypes.Record,
// DeleteRecord 删除记录
func (this *DNSPodProvider) DeleteRecord(domain string, record *dnstypes.Record) error {
if this.tencentDNSProvider != nil {
return this.tencentDNSProvider.DeleteRecord(domain, record)
}
if record == nil {
return errors.New("invalid record to delete")
}
@@ -412,6 +453,10 @@ func (this *DNSPodProvider) doAPI(path string, params map[string]string, respPtr
// DefaultRoute 默认线路
func (this *DNSPodProvider) DefaultRoute() string {
if this.tencentDNSProvider != nil {
return this.tencentDNSProvider.DefaultRoute()
}
if this.isInternational() {
return "Default"
}

View File

@@ -0,0 +1,409 @@
// Copyright 2023 GoEdge CDN goedge.cdn@gmail.com. All rights reserved. Official site: https://goedge.cn .
package dnsclients
import (
"errors"
"github.com/TeaOSLab/EdgeAPI/internal/dnsclients/dnstypes"
"github.com/iwind/TeaGo/maps"
"github.com/iwind/TeaGo/types"
"github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common"
tencenterrors "github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common/errors"
"github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common/profile"
dnspod "github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/dnspod/v20210323"
"strings"
)
// TencentDNSProvider 腾讯云DNS云解析
type TencentDNSProvider struct {
BaseProvider
ProviderId int64
client *dnspod.Client
}
func NewTencentDNSProvider() *TencentDNSProvider {
return &TencentDNSProvider{}
}
// Auth 认证
func (this *TencentDNSProvider) Auth(params maps.Map) error {
var accessKeyId = params.GetString("accessKeyId")
var accessKeySecret = params.GetString("accessKeySecret")
if len(accessKeyId) == 0 {
return errors.New("'accessKeyId' required")
}
if len(accessKeySecret) == 0 {
return errors.New("'accessKeySecret' required")
}
client, err := dnspod.NewClient(common.NewCredential(accessKeyId, accessKeySecret), "", profile.NewClientProfile())
if err != nil {
return err
}
this.client = client
return nil
}
// GetDomains 获取所有域名列表
func (this *TencentDNSProvider) GetDomains() (domains []string, err error) {
var offset int64 = 0
var limit int64 = 1000
for {
var req = dnspod.NewDescribeDomainListRequest()
req.Offset = this.int64Val(offset)
req.Limit = this.int64Val(limit)
resp, respErr := this.client.DescribeDomainList(req)
if respErr != nil {
if this.isNotFoundErr(respErr) {
break
}
return nil, respErr
}
var countDomains = len(resp.Response.DomainList)
if countDomains == 0 {
break
}
for _, domainObj := range resp.Response.DomainList {
domains = append(domains, *domainObj.Name)
}
offset += int64(countDomains)
}
return
}
// GetRecords 获取域名列表
func (this *TencentDNSProvider) GetRecords(domain string) (records []*dnstypes.Record, err error) {
var offset uint64 = 0
var limit uint64 = 1000
for {
var req = dnspod.NewDescribeRecordListRequest()
req.Domain = this.stringVal(domain)
req.Offset = this.uint64Val(offset)
req.Limit = this.uint64Val(limit)
resp, respErr := this.client.DescribeRecordList(req)
if respErr != nil {
if this.isNotFoundErr(respErr) {
break
}
return nil, respErr
}
var countRecords = len(resp.Response.RecordList)
if countRecords == 0 {
break
}
for _, recordObj := range resp.Response.RecordList {
records = append(records, &dnstypes.Record{
Id: types.String(*recordObj.RecordId),
Name: *recordObj.Name,
Type: *recordObj.Type,
Value: this.fixCNAME(*recordObj.Type, *recordObj.Value),
Route: *recordObj.LineId,
TTL: types.Int32(*recordObj.TTL),
})
}
offset += uint64(countRecords)
}
// 写入缓存
if this.ProviderId > 0 {
sharedDomainRecordsCache.WriteDomainRecords(this.ProviderId, domain, records)
}
return
}
// GetRoutes 读取线路数据
func (this *TencentDNSProvider) GetRoutes(domain string) (routes []*dnstypes.Route, err error) {
// 等级信息
var domainGrade string
{
var req = dnspod.NewDescribeDomainRequest()
req.Domain = this.stringVal(domain)
resp, respErr := this.client.DescribeDomain(req)
if respErr != nil {
if this.isNotFoundErr(respErr) {
return
}
return nil, respErr
}
if resp.Response.DomainInfo == nil {
return
}
domainGrade = *resp.Response.DomainInfo.Grade
}
// 等级允许的线路
{
var req = dnspod.NewDescribeRecordLineListRequest()
req.Domain = this.stringVal(domain)
req.DomainGrade = this.stringVal(domainGrade)
resp, respErr := this.client.DescribeRecordLineList(req)
if respErr != nil {
return nil, respErr
}
for _, lineGroupObj := range resp.Response.LineGroupList {
routes = append(routes, &dnstypes.Route{
Name: "Group:" + *lineGroupObj.Name,
Code: *lineGroupObj.LineId,
})
}
for _, lineObj := range resp.Response.LineList {
routes = append(routes, &dnstypes.Route{
Name: *lineObj.Name,
Code: *lineObj.LineId,
})
}
}
return
}
// QueryRecord 查询单个记录
func (this *TencentDNSProvider) QueryRecord(domain string, name string, recordType dnstypes.RecordType) (*dnstypes.Record, error) {
// 从缓存中读取
if this.ProviderId > 0 {
record, hasRecords, _ := sharedDomainRecordsCache.QueryDomainRecord(this.ProviderId, domain, name, recordType)
if hasRecords { // 有效的搜索
return record, nil
}
}
var offset uint64 = 0
var limit uint64 = 1000
var req = dnspod.NewDescribeRecordFilterListRequest()
req.Domain = this.stringVal(domain)
req.Offset = this.uint64Val(offset)
req.Limit = this.uint64Val(limit)
req.SubDomain = this.stringVal(name)
req.RecordType = []*string{this.stringVal(recordType)}
resp, respErr := this.client.DescribeRecordFilterList(req)
if respErr != nil {
if this.isNotFoundErr(respErr) {
return nil, nil
}
return nil, respErr
}
var countRecords = len(resp.Response.RecordList)
if countRecords == 0 {
return nil, nil
}
for _, recordObj := range resp.Response.RecordList {
if *recordObj.Name == name && *recordObj.Type == recordType {
return &dnstypes.Record{
Id: types.String(*recordObj.RecordId),
Name: *recordObj.Name,
Type: *recordObj.Type,
Value: this.fixCNAME(*recordObj.Type, *recordObj.Value),
Route: *recordObj.LineId,
TTL: types.Int32(*recordObj.TTL),
}, nil
}
}
return nil, nil
}
// QueryRecords 查询多个记录
func (this *TencentDNSProvider) QueryRecords(domain string, name string, recordType dnstypes.RecordType) ([]*dnstypes.Record, error) {
// 从缓存中读取
if this.ProviderId > 0 {
records, hasRecords, _ := sharedDomainRecordsCache.QueryDomainRecords(this.ProviderId, domain, name, recordType)
if hasRecords { // 有效的搜索
return records, nil
}
}
var offset uint64 = 0
var limit uint64 = 1000
var records []*dnstypes.Record
for {
var req = dnspod.NewDescribeRecordFilterListRequest()
req.Domain = this.stringVal(domain)
req.Offset = this.uint64Val(offset)
req.Limit = this.uint64Val(limit)
req.SubDomain = this.stringVal(name)
req.RecordType = []*string{this.stringVal(recordType)}
resp, respErr := this.client.DescribeRecordFilterList(req)
if respErr != nil {
if this.isNotFoundErr(respErr) {
break
}
return nil, respErr
}
var countRecords = len(resp.Response.RecordList)
if countRecords == 0 {
break
}
for _, recordObj := range resp.Response.RecordList {
records = append(records, &dnstypes.Record{
Id: types.String(*recordObj.RecordId),
Name: *recordObj.Name,
Type: *recordObj.Type,
Value: this.fixCNAME(*recordObj.Type, *recordObj.Value),
Route: *recordObj.LineId,
TTL: types.Int32(*recordObj.TTL),
})
}
offset += uint64(countRecords)
}
return records, nil
}
// AddRecord 设置记录
func (this *TencentDNSProvider) AddRecord(domain string, newRecord *dnstypes.Record) error {
if newRecord == nil {
return errors.New("invalid new record")
}
// 在CHANGE记录后面加入点
if newRecord.Type == dnstypes.RecordTypeCNAME && !strings.HasSuffix(newRecord.Value, ".") {
newRecord.Value += "."
}
var ttl = newRecord.TTL
if ttl <= 0 {
ttl = 600
}
var req = dnspod.NewCreateRecordRequest()
req.Domain = this.stringVal(domain)
req.SubDomain = this.stringVal(newRecord.Name)
req.RecordType = this.stringVal(newRecord.Type)
req.TTL = this.uint64Val(uint64(ttl))
req.RecordLine = this.stringVal(this.DefaultRouteName()) // 默认必填项但以RecordLineId优先
req.RecordLineId = this.stringVal(newRecord.Route)
req.Value = this.stringVal(newRecord.Value)
resp, respErr := this.client.CreateRecord(req)
if respErr != nil {
return respErr
}
newRecord.Id = types.String(*resp.Response.RecordId)
// 加入缓存
if this.ProviderId > 0 {
sharedDomainRecordsCache.AddDomainRecord(this.ProviderId, domain, newRecord)
}
return nil
}
// UpdateRecord 修改记录
func (this *TencentDNSProvider) UpdateRecord(domain string, record *dnstypes.Record, newRecord *dnstypes.Record) error {
if record == nil {
return errors.New("invalid record")
}
if newRecord == nil {
return errors.New("invalid new record")
}
// 在CHANGE记录后面加入点
if newRecord.Type == dnstypes.RecordTypeCNAME && !strings.HasSuffix(newRecord.Value, ".") {
newRecord.Value += "."
}
var newRoute = newRecord.Route
if len(newRoute) == 0 {
newRoute = this.DefaultRoute()
}
var ttl = newRecord.TTL
if ttl <= 0 {
ttl = 600
}
var req = dnspod.NewModifyRecordRequest()
req.Domain = this.stringVal(domain)
req.RecordId = this.uint64Val(types.Uint64(record.Id))
req.SubDomain = this.stringVal(newRecord.Name)
req.RecordType = this.stringVal(newRecord.Type)
req.TTL = this.uint64Val(uint64(ttl))
req.RecordLine = this.stringVal(this.DefaultRouteName()) // 默认必填项但以RecordLineId优先
req.RecordLineId = this.stringVal(newRecord.Route)
req.Value = this.stringVal(newRecord.Value)
_, respErr := this.client.ModifyRecord(req)
if respErr != nil {
return respErr
}
// 修改缓存
if this.ProviderId > 0 {
sharedDomainRecordsCache.UpdateDomainRecord(this.ProviderId, domain, newRecord)
}
return nil
}
// DeleteRecord 删除记录
func (this *TencentDNSProvider) DeleteRecord(domain string, record *dnstypes.Record) error {
if record == nil {
return errors.New("invalid record to delete")
}
var req = dnspod.NewDeleteRecordRequest()
req.Domain = this.stringVal(domain)
req.RecordId = this.uint64Val(types.Uint64(record.Id))
_, respErr := this.client.DeleteRecord(req)
if respErr != nil {
if len(record.Id) > 0 && this.isRecordInvalidErr(respErr) {
return nil
}
return respErr
}
// 删除缓存
if this.ProviderId > 0 {
sharedDomainRecordsCache.DeleteDomainRecord(this.ProviderId, domain, record.Id)
}
return nil
}
// DefaultRoute 默认线路
func (this *TencentDNSProvider) DefaultRoute() string {
return "0"
}
func (this *TencentDNSProvider) DefaultRouteName() string {
return "默认"
}
func (this *TencentDNSProvider) fixCNAME(recordType string, recordValue string) string {
// 修正Record
if strings.ToUpper(recordType) == dnstypes.RecordTypeCNAME && !strings.HasSuffix(recordValue, ".") {
recordValue += "."
}
return recordValue
}
func (this *TencentDNSProvider) int64Val(v int64) *int64 {
return &v
}
func (this *TencentDNSProvider) uint64Val(v uint64) *uint64 {
return &v
}
func (this *TencentDNSProvider) stringVal(s string) *string {
return &s
}
func (this *TencentDNSProvider) isNotFoundErr(err error) bool {
if err == nil {
return false
}
var sdkErr *tencenterrors.TencentCloudSDKError
return errors.As(err, &sdkErr) && strings.HasPrefix(sdkErr.Code, "ResourceNotFound.")
}
func (this *TencentDNSProvider) isRecordInvalidErr(err error) bool {
if err == nil {
return false
}
var sdkErr *tencenterrors.TencentCloudSDKError
return errors.As(err, &sdkErr) && sdkErr.Code == "InvalidParameter.RecordIdInvalid"
}

View File

@@ -26,7 +26,7 @@ func FindAllProviderTypes() []maps.Map {
"description": "阿里云提供的DNS服务。",
},
{
"name": "DNSPod",
"name": "腾讯云DNSPod",
"code": ProviderTypeDNSPod,
"description": "DNSPod提供的DNS服务。",
},

View File

@@ -10,6 +10,10 @@ import (
// FindProvider 查找服务商实例
func FindProvider(providerType ProviderType, providerId int64) ProviderInterface {
switch providerType {
case ProviderTypeTencentDNS:
return &TencentDNSProvider{
ProviderId: providerId,
}
case ProviderTypeDNSPod:
return &DNSPodProvider{
ProviderId: providerId,