mirror of
https://github.com/StackExchange/dnscontrol.git
synced 2025-12-09 05:36:27 +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.CanAutoDNSSEC: providers.Cannot(),
|
||||||
providers.CanConcur: providers.Can(),
|
providers.CanConcur: providers.Can(),
|
||||||
providers.DocOfficiallySupported: providers.Cannot(),
|
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.DocCreateDomains: providers.Cannot(),
|
||||||
providers.CanUseRoute53Alias: providers.Cannot(),
|
providers.CanUseRoute53Alias: providers.Cannot(),
|
||||||
}
|
}
|
||||||
|
|
@ -34,7 +34,7 @@ func init() {
|
||||||
const providerName = "ALIDNS"
|
const providerName = "ALIDNS"
|
||||||
const providerMaintainer = "@bytemain"
|
const providerMaintainer = "@bytemain"
|
||||||
fns := providers.DspFuncs{
|
fns := providers.DspFuncs{
|
||||||
Initializer: newAliDnsDsp,
|
Initializer: newAliDNSDsp,
|
||||||
RecordAuditor: AuditRecords,
|
RecordAuditor: AuditRecords,
|
||||||
}
|
}
|
||||||
providers.RegisterDomainServiceProviderType(providerName, fns, features)
|
providers.RegisterDomainServiceProviderType(providerName, fns, features)
|
||||||
|
|
@ -52,7 +52,7 @@ func init() {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
type aliDnsDsp struct {
|
type aliDNSDsp struct {
|
||||||
client *alidns.Client
|
client *alidns.Client
|
||||||
domainVersionCache map[string]*domainVersionInfo
|
domainVersionCache map[string]*domainVersionInfo
|
||||||
cacheMu sync.Mutex
|
cacheMu sync.Mutex
|
||||||
|
|
@ -64,7 +64,7 @@ type domainVersionInfo struct {
|
||||||
maxTTL uint32
|
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"]
|
accessKeyID := config["access_key_id"]
|
||||||
if accessKeyID == "" {
|
if accessKeyID == "" {
|
||||||
return nil, fmt.Errorf("creds.json: access_key_id must not be empty")
|
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 {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
return &aliDnsDsp{
|
return &aliDNSDsp{
|
||||||
client: client,
|
client: client,
|
||||||
domainVersionCache: make(map[string]*domainVersionInfo),
|
domainVersionCache: make(map[string]*domainVersionInfo),
|
||||||
}, nil
|
}, 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.
|
// 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.
|
// Fetch all pages of domain records.
|
||||||
records, err := a.describeDomainRecordsAll(domain)
|
records, err := a.describeDomainRecordsAll(domain)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
@ -117,19 +125,25 @@ func (a *aliDnsDsp) GetZoneRecords(domain string, meta map[string]string) (model
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
// Skip apex NS records since Alibaba Cloud manages them automatically
|
out = append(out, rc)
|
||||||
// and we cannot modify them (DocDualHost: Cannot)
|
}
|
||||||
if rc.Type == "NS" && rc.GetLabel() == "@" {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
|
// 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)
|
out = append(out, rc)
|
||||||
}
|
}
|
||||||
|
|
||||||
return out, nil
|
return out, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a *aliDnsDsp) ListZones() ([]string, error) {
|
func (a *aliDNSDsp) ListZones() ([]string, error) {
|
||||||
return a.describeDomainsAll()
|
return a.describeDomainsAll()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -150,7 +164,7 @@ func deduplicateNameServerTargets(newRecs models.Records) models.Records {
|
||||||
}
|
}
|
||||||
|
|
||||||
// PrepDesiredRecords munges any records to best suit this provider.
|
// 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)
|
versionInfo, err := a.getDomainVersionInfo(dc.Name)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return
|
return
|
||||||
|
|
@ -180,12 +194,13 @@ func (a *aliDnsDsp) PrepDesiredRecords(dc *models.DomainConfig) {
|
||||||
dc.Records = recordsToKeep
|
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)
|
a.PrepDesiredRecords(dc)
|
||||||
|
|
||||||
var corrections []*models.Correction
|
var corrections []*models.Correction
|
||||||
|
|
||||||
// Azure is a "ByRecordSet" API.
|
// Alibaba Cloud DNS is a "ByRecord" API.
|
||||||
changes, actualChangeCount, err := diff2.ByRecord(existingRecords, dc, nil)
|
changes, actualChangeCount, err := diff2.ByRecord(existingRecords, dc, nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, 0, err
|
return nil, 0, err
|
||||||
|
|
|
||||||
|
|
@ -8,7 +8,7 @@ import (
|
||||||
"github.com/aliyun/alibaba-cloud-sdk-go/services/alidns"
|
"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
|
// Check cache first
|
||||||
a.cacheMu.Lock()
|
a.cacheMu.Lock()
|
||||||
info, ok := a.domainVersionCache[domain]
|
info, ok := a.domainVersionCache[domain]
|
||||||
|
|
@ -52,7 +52,8 @@ func (a *aliDnsDsp) getDomainVersionInfo(domain string) (*domainVersionInfo, err
|
||||||
return info, nil
|
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 := alidns.CreateDescribeDomainInfoRequest()
|
||||||
req.DomainName = domain
|
req.DomainName = domain
|
||||||
|
|
||||||
|
|
@ -61,10 +62,20 @@ func (a *aliDnsDsp) GetNameservers(domain string) ([]*models.Nameserver, error)
|
||||||
return nil, err
|
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 {
|
for _, r := range records {
|
||||||
req := alidns.CreateDeleteDomainRecordRequest()
|
req := alidns.CreateDeleteDomainRecordRequest()
|
||||||
original, ok := r.Original.(*alidns.Record)
|
original, ok := r.Original.(*alidns.Record)
|
||||||
|
|
@ -81,7 +92,7 @@ func (a *aliDnsDsp) deleteRecordset(records []*models.RecordConfig, domainName s
|
||||||
return nil
|
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 {
|
for _, r := range records {
|
||||||
req := alidns.CreateAddDomainRecordRequest()
|
req := alidns.CreateAddDomainRecordRequest()
|
||||||
req.DomainName = domainName
|
req.DomainName = domainName
|
||||||
|
|
@ -103,7 +114,7 @@ func (a *aliDnsDsp) createRecordset(records []*models.RecordConfig, domainName s
|
||||||
return nil
|
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.
|
// Strategy: Delete all existing records, then create all desired records.
|
||||||
// This is the simplest and most reliable approach because:
|
// This is the simplest and most reliable approach because:
|
||||||
// 1. The number of records in a recordset may change
|
// 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
|
// describeDomainRecordsAll fetches all domain records for 'domain', handling
|
||||||
// pagination transparently. It returns the slice of *alidns.Record or an error.
|
// 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
|
// The SDK returns a slice of value Records (not pointers). We fetch pages
|
||||||
// as values and then convert to pointers before returning.
|
// as values and then convert to pointers before returning.
|
||||||
fetch := func(pageNumber, pageSize int) ([]alidns.Record, int, error) {
|
fetch := func(pageNumber, pageSize int) ([]alidns.Record, int, error) {
|
||||||
req := alidns.CreateDescribeDomainRecordsRequest()
|
req := alidns.CreateDescribeDomainRecordsRequest()
|
||||||
|
req.Status = "Enable"
|
||||||
req.DomainName = domain
|
req.DomainName = domain
|
||||||
req.PageNumber = requests.NewInteger(pageNumber)
|
req.PageNumber = requests.NewInteger(pageNumber)
|
||||||
req.PageSize = requests.NewInteger(pageSize)
|
req.PageSize = requests.NewInteger(pageSize)
|
||||||
|
|
@ -150,7 +162,7 @@ func (a *aliDnsDsp) describeDomainRecordsAll(domain string) ([]*alidns.Record, e
|
||||||
return out, nil
|
return out, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a *aliDnsDsp) describeDomainsAll() ([]string, error) {
|
func (a *aliDNSDsp) describeDomainsAll() ([]string, error) {
|
||||||
// describeDomainsAll fetches all domains in the account, handling pagination.
|
// describeDomainsAll fetches all domains in the account, handling pagination.
|
||||||
fetch := func(pageNumber, pageSize int) ([]string, int, error) {
|
fetch := func(pageNumber, pageSize int) ([]string, int, error) {
|
||||||
req := alidns.CreateDescribeDomainsRequest()
|
req := alidns.CreateDescribeDomainsRequest()
|
||||||
|
|
|
||||||
|
|
@ -97,3 +97,14 @@ func recordToNativePriority(r *models.RecordConfig) int64 {
|
||||||
return 0
|
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