mirror of
https://github.com/StackExchange/dnscontrol.git
synced 2025-12-09 13:46:07 +08:00
ALIDNS: Fix NS modified
This commit is contained in:
parent
9b7bbbabe1
commit
528a8105eb
3 changed files with 61 additions and 23 deletions
|
|
@ -25,7 +25,7 @@ var features = providers.DocumentationNotes{
|
|||
providers.CanAutoDNSSEC: providers.Cannot(),
|
||||
providers.CanConcur: providers.Can(),
|
||||
providers.DocOfficiallySupported: providers.Cannot(),
|
||||
providers.DocDualHost: providers.Cannot(),
|
||||
providers.DocDualHost: providers.Can("Alibaba Cloud DNS allows full management of apex NS records"),
|
||||
providers.DocCreateDomains: providers.Cannot(),
|
||||
providers.CanUseRoute53Alias: providers.Cannot(),
|
||||
}
|
||||
|
|
@ -34,7 +34,7 @@ func init() {
|
|||
const providerName = "ALIDNS"
|
||||
const providerMaintainer = "@bytemain"
|
||||
fns := providers.DspFuncs{
|
||||
Initializer: newAliDnsDsp,
|
||||
Initializer: newAliDNSDsp,
|
||||
RecordAuditor: AuditRecords,
|
||||
}
|
||||
providers.RegisterDomainServiceProviderType(providerName, fns, features)
|
||||
|
|
@ -52,7 +52,7 @@ func init() {
|
|||
|
||||
}
|
||||
|
||||
type aliDnsDsp struct {
|
||||
type aliDNSDsp struct {
|
||||
client *alidns.Client
|
||||
domainVersionCache map[string]*domainVersionInfo
|
||||
cacheMu sync.Mutex
|
||||
|
|
@ -64,7 +64,7 @@ type domainVersionInfo struct {
|
|||
maxTTL uint32
|
||||
}
|
||||
|
||||
func newAliDnsDsp(config map[string]string, metadata json.RawMessage) (providers.DNSServiceProvider, error) {
|
||||
func newAliDNSDsp(config map[string]string, metadata json.RawMessage) (providers.DNSServiceProvider, error) {
|
||||
accessKeyID := config["access_key_id"]
|
||||
if accessKeyID == "" {
|
||||
return nil, fmt.Errorf("creds.json: access_key_id must not be empty")
|
||||
|
|
@ -92,14 +92,22 @@ func newAliDnsDsp(config map[string]string, metadata json.RawMessage) (providers
|
|||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &aliDnsDsp{
|
||||
return &aliDNSDsp{
|
||||
client: client,
|
||||
domainVersionCache: make(map[string]*domainVersionInfo),
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (a *aliDNSDsp) GetNameservers(domain string) ([]*models.Nameserver, error) {
|
||||
nsStrings, err := a.getNameservers(domain)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return models.ToNameserversStripTD(nsStrings)
|
||||
}
|
||||
|
||||
// GetZoneRecords returns an array of RecordConfig structs for a zone.
|
||||
func (a *aliDnsDsp) GetZoneRecords(domain string, meta map[string]string) (models.Records, error) {
|
||||
func (a *aliDNSDsp) GetZoneRecords(domain string, meta map[string]string) (models.Records, error) {
|
||||
// Fetch all pages of domain records.
|
||||
records, err := a.describeDomainRecordsAll(domain)
|
||||
if err != nil {
|
||||
|
|
@ -117,19 +125,25 @@ func (a *aliDnsDsp) GetZoneRecords(domain string, meta map[string]string) (model
|
|||
return nil, err
|
||||
}
|
||||
|
||||
// Skip apex NS records since Alibaba Cloud manages them automatically
|
||||
// and we cannot modify them (DocDualHost: Cannot)
|
||||
if rc.Type == "NS" && rc.GetLabel() == "@" {
|
||||
continue
|
||||
}
|
||||
out = append(out, rc)
|
||||
}
|
||||
|
||||
// Alibaba Cloud's DescribeDomainRecords API doesn't return NS records at the apex.
|
||||
// We need to fetch them separately using getNameservers and add them to the records.
|
||||
nameservers, err := a.getNameservers(domain)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
for _, ns := range nameservers {
|
||||
rc := nativeToRecordNS(ns, domain)
|
||||
out = append(out, rc)
|
||||
}
|
||||
|
||||
return out, nil
|
||||
}
|
||||
|
||||
func (a *aliDnsDsp) ListZones() ([]string, error) {
|
||||
func (a *aliDNSDsp) ListZones() ([]string, error) {
|
||||
return a.describeDomainsAll()
|
||||
}
|
||||
|
||||
|
|
@ -150,7 +164,7 @@ func deduplicateNameServerTargets(newRecs models.Records) models.Records {
|
|||
}
|
||||
|
||||
// PrepDesiredRecords munges any records to best suit this provider.
|
||||
func (a *aliDnsDsp) PrepDesiredRecords(dc *models.DomainConfig) {
|
||||
func (a *aliDNSDsp) PrepDesiredRecords(dc *models.DomainConfig) {
|
||||
versionInfo, err := a.getDomainVersionInfo(dc.Name)
|
||||
if err != nil {
|
||||
return
|
||||
|
|
@ -180,12 +194,13 @@ func (a *aliDnsDsp) PrepDesiredRecords(dc *models.DomainConfig) {
|
|||
dc.Records = recordsToKeep
|
||||
}
|
||||
|
||||
func (a *aliDnsDsp) GetZoneRecordsCorrections(dc *models.DomainConfig, existingRecords models.Records) ([]*models.Correction, int, error) {
|
||||
func (a *aliDNSDsp) GetZoneRecordsCorrections(dc *models.DomainConfig, existingRecords models.Records) ([]*models.Correction, int, error) {
|
||||
// Prepare desired records first to normalize TTLs and avoid warnings
|
||||
a.PrepDesiredRecords(dc)
|
||||
|
||||
var corrections []*models.Correction
|
||||
|
||||
// Azure is a "ByRecordSet" API.
|
||||
// Alibaba Cloud DNS is a "ByRecord" API.
|
||||
changes, actualChangeCount, err := diff2.ByRecord(existingRecords, dc, nil)
|
||||
if err != nil {
|
||||
return nil, 0, err
|
||||
|
|
|
|||
|
|
@ -8,7 +8,7 @@ import (
|
|||
"github.com/aliyun/alibaba-cloud-sdk-go/services/alidns"
|
||||
)
|
||||
|
||||
func (a *aliDnsDsp) getDomainVersionInfo(domain string) (*domainVersionInfo, error) {
|
||||
func (a *aliDNSDsp) getDomainVersionInfo(domain string) (*domainVersionInfo, error) {
|
||||
// Check cache first
|
||||
a.cacheMu.Lock()
|
||||
info, ok := a.domainVersionCache[domain]
|
||||
|
|
@ -52,7 +52,8 @@ func (a *aliDnsDsp) getDomainVersionInfo(domain string) (*domainVersionInfo, err
|
|||
return info, nil
|
||||
}
|
||||
|
||||
func (a *aliDnsDsp) GetNameservers(domain string) ([]*models.Nameserver, error) {
|
||||
// GetNameservers returns the nameservers for a domain.
|
||||
func (a *aliDNSDsp) getNameservers(domain string) ([]string, error) {
|
||||
req := alidns.CreateDescribeDomainInfoRequest()
|
||||
req.DomainName = domain
|
||||
|
||||
|
|
@ -61,10 +62,20 @@ func (a *aliDnsDsp) GetNameservers(domain string) ([]*models.Nameserver, error)
|
|||
return nil, err
|
||||
}
|
||||
|
||||
return models.ToNameservers(resp.DnsServers.DnsServer)
|
||||
// Add trailing dot to each nameserver to make them FQDNs
|
||||
nameservers := make([]string, len(resp.DnsServers.DnsServer))
|
||||
for i, ns := range resp.DnsServers.DnsServer {
|
||||
if ns != "" && ns[len(ns)-1] != '.' {
|
||||
nameservers[i] = ns + "."
|
||||
} else {
|
||||
nameservers[i] = ns
|
||||
}
|
||||
}
|
||||
|
||||
return nameservers, nil
|
||||
}
|
||||
|
||||
func (a *aliDnsDsp) deleteRecordset(records []*models.RecordConfig, domainName string) error {
|
||||
func (a *aliDNSDsp) deleteRecordset(records []*models.RecordConfig, domainName string) error {
|
||||
for _, r := range records {
|
||||
req := alidns.CreateDeleteDomainRecordRequest()
|
||||
original, ok := r.Original.(*alidns.Record)
|
||||
|
|
@ -81,7 +92,7 @@ func (a *aliDnsDsp) deleteRecordset(records []*models.RecordConfig, domainName s
|
|||
return nil
|
||||
}
|
||||
|
||||
func (a *aliDnsDsp) createRecordset(records []*models.RecordConfig, domainName string) error {
|
||||
func (a *aliDNSDsp) createRecordset(records []*models.RecordConfig, domainName string) error {
|
||||
for _, r := range records {
|
||||
req := alidns.CreateAddDomainRecordRequest()
|
||||
req.DomainName = domainName
|
||||
|
|
@ -103,7 +114,7 @@ func (a *aliDnsDsp) createRecordset(records []*models.RecordConfig, domainName s
|
|||
return nil
|
||||
}
|
||||
|
||||
func (a *aliDnsDsp) updateRecordset(existing, desired []*models.RecordConfig, domainName string) error {
|
||||
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
|
||||
|
|
@ -121,11 +132,12 @@ func (a *aliDnsDsp) updateRecordset(existing, desired []*models.RecordConfig, do
|
|||
|
||||
// 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) {
|
||||
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.Status = "Enable"
|
||||
req.DomainName = domain
|
||||
req.PageNumber = requests.NewInteger(pageNumber)
|
||||
req.PageSize = requests.NewInteger(pageSize)
|
||||
|
|
@ -150,7 +162,7 @@ func (a *aliDnsDsp) describeDomainRecordsAll(domain string) ([]*alidns.Record, e
|
|||
return out, nil
|
||||
}
|
||||
|
||||
func (a *aliDnsDsp) describeDomainsAll() ([]string, error) {
|
||||
func (a *aliDNSDsp) describeDomainsAll() ([]string, error) {
|
||||
// describeDomainsAll fetches all domains in the account, handling pagination.
|
||||
fetch := func(pageNumber, pageSize int) ([]string, int, error) {
|
||||
req := alidns.CreateDescribeDomainsRequest()
|
||||
|
|
|
|||
|
|
@ -97,3 +97,14 @@ func recordToNativePriority(r *models.RecordConfig) int64 {
|
|||
return 0
|
||||
}
|
||||
}
|
||||
|
||||
// nativeToRecordNS takes a NS record from DNS and returns a native RecordConfig struct.
|
||||
func nativeToRecordNS(ns string, origin string) *models.RecordConfig {
|
||||
rc := &models.RecordConfig{
|
||||
Type: "NS",
|
||||
TTL: 600,
|
||||
}
|
||||
rc.SetLabel("@", origin)
|
||||
rc.MustSetTarget(ns)
|
||||
return rc
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue