dnscontrol/providers/alidns/api.go
2025-12-04 01:39:26 +08:00

151 lines
4.1 KiB
Go

package alidns
import (
"fmt"
"github.com/StackExchange/dnscontrol/v4/models"
"github.com/aliyun/alibaba-cloud-sdk-go/sdk/requests"
"github.com/aliyun/alibaba-cloud-sdk-go/services/alidns"
)
func (a *aliDnsDsp) getDomainVersionInfo(domain string) (*domainVersionInfo, error) {
// Check cache first
a.cacheMu.Lock()
info, ok := a.domainVersionCache[domain]
a.cacheMu.Unlock()
if ok {
return info, nil
}
req := alidns.CreateDescribeDomainInfoRequest()
req.DomainName = domain
resp, err := a.client.DescribeDomainInfo(req)
if err != nil {
return nil, err
}
// Determine minTTL based on VersionCode
var minTTL uint32
switch resp.VersionCode {
case "version_enterprise_advanced":
minTTL = 1 // Enterprise Ultimate Edition
case "version_personal", "mianfei":
minTTL = 600 // Personal Edition and Free Edition
default:
// Use MinTtl from API if available, otherwise default to 600
if resp.MinTtl > 0 {
minTTL = uint32(resp.MinTtl)
} else {
minTTL = 600
}
}
info = &domainVersionInfo{
versionCode: resp.VersionCode,
minTTL: minTTL,
maxTTL: 86400,
}
a.cacheMu.Lock()
a.domainVersionCache[domain] = info
a.cacheMu.Unlock()
return info, nil
}
func (a *aliDnsDsp) GetNameservers(domain string) ([]*models.Nameserver, error) {
req := alidns.CreateDescribeDomainInfoRequest()
req.DomainName = domain
resp, err := a.client.DescribeDomainInfo(req)
if err != nil {
return nil, err
}
return models.ToNameservers(resp.DnsServers.DnsServer)
}
func (a *aliDnsDsp) deleteRecordset(records []*models.RecordConfig, domainName string) error {
for _, r := range records {
req := alidns.CreateDeleteDomainRecordRequest()
original, ok := r.Original.(*alidns.Record)
if !ok {
return fmt.Errorf("deleteRecordset: record original is not of type *alidns.Record")
}
req.RecordId = original.RecordId
_, err := a.client.DeleteDomainRecord(req)
if err != nil {
return err
}
}
return nil
}
func (a *aliDnsDsp) createRecordset(records []*models.RecordConfig, domainName string) error {
for _, r := range records {
req := alidns.CreateAddDomainRecordRequest()
req.DomainName = domainName
req.RR = r.Name
req.Type = r.Type
req.TTL = requests.Integer(fmt.Sprintf("%d", r.TTL))
req.Value = recordToNativeContent(r)
// Set priority for MX and SRV records
if r.Type == "MX" || r.Type == "SRV" {
req.Priority = requests.Integer(fmt.Sprintf("%d", recordToNativePriority(r)))
}
_, err := a.client.AddDomainRecord(req)
if err != nil {
return err
}
}
return nil
}
func (a *aliDnsDsp) updateRecordset(existing, desired []*models.RecordConfig, domainName string) error {
// Strategy: Delete all existing records, then create all desired records.
// This is the simplest and most reliable approach because:
// 1. The number of records in a recordset may change
// 2. There's no guaranteed 1:1 mapping between existing and desired records
// 3. Alibaba Cloud API requires RecordId for updates, which desired records don't have
// Delete all existing records first
if err := a.deleteRecordset(existing, domainName); err != nil {
return err
}
// Then create all desired records
return a.createRecordset(desired, domainName)
}
// describeDomainRecordsAll fetches all domain records for 'domain', handling
// pagination transparently. It returns the slice of *alidns.Record or an error.
func (a *aliDnsDsp) describeDomainRecordsAll(domain string) ([]*alidns.Record, error) {
// The SDK returns a slice of value Records (not pointers). We fetch pages
// as values and then convert to pointers before returning.
fetch := func(pageNumber, pageSize int) ([]alidns.Record, int, error) {
req := alidns.CreateDescribeDomainRecordsRequest()
req.DomainName = domain
req.PageNumber = requests.NewInteger(pageNumber)
req.PageSize = requests.NewInteger(pageSize)
resp, err := a.client.DescribeDomainRecords(req)
if err != nil {
return nil, 0, err
}
total := int(resp.TotalCount)
return resp.DomainRecords.Record, total, nil
}
vals, err := paginateAll(fetch)
if err != nil {
return nil, err
}
out := make([]*alidns.Record, 0, len(vals))
for i := range vals {
out = append(out, &vals[i])
}
return out, nil
}