2019-09-19 09:45:14 +08:00
package azuredns
import (
"context"
"encoding/json"
"fmt"
2020-07-01 17:55:20 +08:00
"sort"
2019-10-31 21:44:42 +08:00
"strings"
"time"
2022-08-14 19:42:41 +08:00
aauth "github.com/Azure/azure-sdk-for-go/sdk/azidentity"
adns "github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/dns/armdns"
2019-09-19 09:45:14 +08:00
"github.com/Azure/go-autorest/autorest/to"
2020-04-15 04:47:30 +08:00
"github.com/StackExchange/dnscontrol/v3/models"
"github.com/StackExchange/dnscontrol/v3/pkg/diff"
2022-12-12 04:02:58 +08:00
"github.com/StackExchange/dnscontrol/v3/pkg/diff2"
2022-08-14 19:42:41 +08:00
"github.com/StackExchange/dnscontrol/v3/pkg/printer"
2021-03-08 02:19:22 +08:00
"github.com/StackExchange/dnscontrol/v3/pkg/txtutil"
2020-04-15 04:47:30 +08:00
"github.com/StackExchange/dnscontrol/v3/providers"
2019-09-19 09:45:14 +08:00
)
2020-10-26 21:25:30 +08:00
type azurednsProvider struct {
2020-03-03 00:25:42 +08:00
zonesClient * adns . ZonesClient
recordsClient * adns . RecordSetsClient
zones map [ string ] * adns . Zone
resourceGroup * string
2020-06-18 21:37:57 +08:00
subscriptionID * string
2019-09-19 09:45:14 +08:00
}
2020-06-18 21:37:57 +08:00
func newAzureDNSDsp ( conf map [ string ] string , metadata json . RawMessage ) ( providers . DNSServiceProvider , error ) {
return newAzureDNS ( conf , metadata )
2019-09-19 09:45:14 +08:00
}
2020-10-26 21:25:30 +08:00
func newAzureDNS ( m map [ string ] string , metadata json . RawMessage ) ( * azurednsProvider , error ) {
2020-06-18 21:37:57 +08:00
subID , rg := m [ "SubscriptionID" ] , m [ "ResourceGroup" ]
2022-08-14 19:42:41 +08:00
clientID , clientSecret , tenantID := m [ "ClientID" ] , m [ "ClientSecret" ] , m [ "TenantID" ]
credential , authErr := aauth . NewClientSecretCredential ( tenantID , clientID , clientSecret , nil )
2019-09-19 09:45:14 +08:00
if authErr != nil {
return nil , authErr
}
2022-08-14 19:42:41 +08:00
zonesClient , zoneErr := adns . NewZonesClient ( subID , credential , nil )
if zoneErr != nil {
return nil , zoneErr
}
recordsClient , recordErr := adns . NewRecordSetsClient ( subID , credential , nil )
if recordErr != nil {
return nil , recordErr
}
2019-09-19 09:45:14 +08:00
2022-08-14 19:42:41 +08:00
api := & azurednsProvider { zonesClient : zonesClient , recordsClient : recordsClient , resourceGroup : to . StringPtr ( rg ) , subscriptionID : to . StringPtr ( subID ) }
2019-09-19 09:45:14 +08:00
err := api . getZones ( )
if err != nil {
return nil , err
}
return api , nil
}
var features = providers . DocumentationNotes {
2022-03-03 00:19:15 +08:00
providers . CanGetZones : providers . Can ( ) ,
2020-03-03 00:25:42 +08:00
providers . CanUseAlias : providers . Cannot ( "Azure DNS does not provide a generic ALIAS functionality. Use AZURE_ALIAS instead." ) ,
2022-03-03 00:19:15 +08:00
providers . CanUseAzureAlias : providers . Can ( ) ,
2019-09-19 09:45:14 +08:00
providers . CanUseCAA : providers . Can ( ) ,
providers . CanUseNAPTR : providers . Cannot ( ) ,
2022-03-03 00:19:15 +08:00
providers . CanUsePTR : providers . Can ( ) ,
providers . CanUseSRV : providers . Can ( ) ,
2019-09-19 09:45:14 +08:00
providers . CanUseSSHFP : providers . Cannot ( ) ,
providers . CanUseTLSA : providers . Cannot ( ) ,
2022-03-03 00:19:15 +08:00
providers . DocCreateDomains : providers . Can ( ) ,
providers . DocDualHost : providers . Can ( "Azure does not permit modifying the existing NS records, only adding/removing additional records." ) ,
providers . DocOfficiallySupported : providers . Can ( ) ,
2019-09-19 09:45:14 +08:00
}
func init ( ) {
2021-03-08 02:19:22 +08:00
fns := providers . DspFuncs {
2021-05-02 23:04:42 +08:00
Initializer : newAzureDNSDsp ,
2021-03-09 09:14:30 +08:00
RecordAuditor : AuditRecords ,
2021-03-08 02:19:22 +08:00
}
providers . RegisterDomainServiceProviderType ( "AZURE_DNS" , fns , features )
2020-03-03 00:25:42 +08:00
providers . RegisterCustomRecordType ( "AZURE_ALIAS" , "AZURE_DNS" , "" )
2019-09-19 09:45:14 +08:00
}
2022-08-14 19:42:41 +08:00
func ( a * azurednsProvider ) getExistingZones ( ) ( [ ] * adns . Zone , error ) {
2019-09-19 09:45:14 +08:00
ctx , cancel := context . WithTimeout ( context . Background ( ) , 6000 * time . Second )
defer cancel ( )
2022-08-14 19:42:41 +08:00
zonesPager := a . zonesClient . NewListByResourceGroupPager ( * a . resourceGroup , nil )
var zones [ ] * adns . Zone
for zonesPager . More ( ) {
nextResult , zonesErr := zonesPager . NextPage ( ctx )
if zonesErr != nil {
return nil , zonesErr
}
zones = append ( zones , nextResult . Value ... )
2019-09-19 09:45:14 +08:00
}
2022-08-14 19:42:41 +08:00
return zones , nil
2020-02-19 00:35:13 +08:00
}
2020-10-26 21:25:30 +08:00
func ( a * azurednsProvider ) getZones ( ) error {
2020-02-19 00:35:13 +08:00
a . zones = make ( map [ string ] * adns . Zone )
2022-08-14 19:42:41 +08:00
zones , err := a . getExistingZones ( )
if err != nil {
return err
2020-02-19 00:35:13 +08:00
}
2022-08-14 19:42:41 +08:00
for _ , z := range zones {
zone := z
domain := strings . TrimSuffix ( * z . Name , "." )
a . zones [ domain ] = zone
2019-09-19 09:45:14 +08:00
}
return nil
}
type errNoExist struct {
domain string
}
func ( e errNoExist ) Error ( ) string {
return fmt . Sprintf ( "Domain %s not found in you Azure account" , e . domain )
}
2020-10-26 21:25:30 +08:00
func ( a * azurednsProvider ) GetNameservers ( domain string ) ( [ ] * models . Nameserver , error ) {
2019-09-19 09:45:14 +08:00
zone , ok := a . zones [ domain ]
if ! ok {
return nil , errNoExist { domain }
}
2020-03-01 23:33:24 +08:00
var nss [ ] string
2022-08-14 19:42:41 +08:00
if zone . Properties != nil {
for _ , ns := range zone . Properties . NameServers {
nss = append ( nss , * ns )
}
2019-09-19 09:45:14 +08:00
}
2022-08-14 19:42:41 +08:00
2020-03-01 23:33:24 +08:00
return models . ToNameserversStripTD ( nss )
2019-09-19 09:45:14 +08:00
}
2020-10-26 21:25:30 +08:00
func ( a * azurednsProvider ) ListZones ( ) ( [ ] string , error ) {
2022-08-14 19:42:41 +08:00
zonesResult , err := a . getExistingZones ( )
if err != nil {
return nil , err
2020-02-19 00:35:13 +08:00
}
2022-08-14 19:42:41 +08:00
var zones [ ] string
2020-02-19 00:35:13 +08:00
2022-08-14 19:42:41 +08:00
for _ , z := range zonesResult {
domain := strings . TrimSuffix ( * z . Name , "." )
zones = append ( zones , domain )
2020-02-19 00:35:13 +08:00
}
return zones , nil
}
// GetZoneRecords gets the records of a zone and returns them in RecordConfig format.
2020-10-26 21:25:30 +08:00
func ( a * azurednsProvider ) GetZoneRecords ( domain string ) ( models . Records , error ) {
2020-02-19 00:35:13 +08:00
existingRecords , _ , _ , err := a . getExistingRecords ( domain )
2019-09-19 09:45:14 +08:00
if err != nil {
return nil , err
}
2020-02-19 00:35:13 +08:00
return existingRecords , nil
}
2019-09-19 09:45:14 +08:00
2020-10-26 21:25:30 +08:00
func ( a * azurednsProvider ) getExistingRecords ( domain string ) ( models . Records , [ ] * adns . RecordSet , string , error ) {
2020-02-19 00:35:13 +08:00
zone , ok := a . zones [ domain ]
2019-09-19 09:45:14 +08:00
if ! ok {
2020-02-19 00:35:13 +08:00
return nil , nil , "" , errNoExist { domain }
2019-09-19 09:45:14 +08:00
}
2020-08-31 08:38:08 +08:00
zoneName := * zone . Name
2020-02-06 07:19:24 +08:00
records , err := a . fetchRecordSets ( zoneName )
2019-09-19 09:45:14 +08:00
if err != nil {
2020-02-19 00:35:13 +08:00
return nil , nil , "" , err
2019-09-19 09:45:14 +08:00
}
2020-02-19 00:35:13 +08:00
var existingRecords models . Records
2019-09-19 09:45:14 +08:00
for _ , set := range records {
2020-02-19 00:35:13 +08:00
existingRecords = append ( existingRecords , nativeToRecords ( set , zoneName ) ... )
2019-09-19 09:45:14 +08:00
}
2021-03-08 02:19:22 +08:00
// FIXME(tlim): PostProcessRecords is usually called in GetDomainCorrections.
2019-09-19 09:45:14 +08:00
models . PostProcessRecords ( existingRecords )
2021-03-08 02:19:22 +08:00
// FIXME(tlim): The "records" return value is usually stored in RecordConfig.Original.
2020-02-19 00:35:13 +08:00
return existingRecords , records , zoneName , nil
}
2020-10-26 21:25:30 +08:00
func ( a * azurednsProvider ) GetDomainCorrections ( dc * models . DomainConfig ) ( [ ] * models . Correction , error ) {
2020-02-19 00:35:13 +08:00
err := dc . Punycode ( )
if err != nil {
return nil , err
}
existingRecords , records , zoneName , err := a . getExistingRecords ( dc . Name )
if err != nil {
return nil , err
}
2019-09-19 09:45:14 +08:00
2021-03-08 02:19:22 +08:00
txtutil . SplitSingleLongTxt ( dc . Records ) // Autosplit long TXT records
2022-12-12 04:02:58 +08:00
var corrections [ ] * models . Correction
2022-12-12 06:28:58 +08:00
if ! diff2 . EnableDiff2 {
2019-09-19 09:45:14 +08:00
2022-12-12 04:02:58 +08:00
differ := diff . New ( dc )
namesToUpdate , err := differ . ChangedGroups ( existingRecords )
if err != nil {
return nil , err
}
if len ( namesToUpdate ) == 0 {
return nil , nil
}
2019-09-19 09:45:14 +08:00
2022-12-12 04:02:58 +08:00
updates := map [ models . RecordKey ] [ ] * models . RecordConfig { }
2019-09-19 09:45:14 +08:00
2022-12-12 04:02:58 +08:00
for k := range namesToUpdate {
updates [ k ] = nil
for _ , rc := range dc . Records {
if rc . Key ( ) == k {
updates [ k ] = append ( updates [ k ] , rc )
}
2019-09-19 09:45:14 +08:00
}
}
2022-12-12 04:02:58 +08:00
for k , recs := range updates {
if len ( recs ) == 0 {
var rrset * adns . RecordSet
for _ , r := range records {
if strings . TrimSuffix ( * r . Properties . Fqdn , "." ) == k . NameFQDN {
n1 , err := nativeToRecordType ( r . Type )
if err != nil {
return nil , err
}
n2 , err := nativeToRecordType ( to . StringPtr ( k . Type ) )
if err != nil {
return nil , err
}
if n1 == n2 {
rrset = r
break
}
}
}
if rrset != nil {
corrections = append ( corrections ,
& models . Correction {
Msg : strings . Join ( namesToUpdate [ k ] , "\n" ) ,
F : func ( ) error {
ctx , cancel := context . WithTimeout ( context . Background ( ) , 6000 * time . Second )
defer cancel ( )
rt , err := nativeToRecordType ( rrset . Type )
if err != nil {
return err
}
_ , err = a . recordsClient . Delete ( ctx , * a . resourceGroup , zoneName , * rrset . Name , rt , nil )
if err != nil {
return err
}
return nil
} ,
} )
} else {
return nil , fmt . Errorf ( "no record set found to delete. Name: '%s'. Type: '%s'" , k . NameFQDN , k . Type )
}
} else {
rrset , recordType , err := a . recordToNative ( k , recs )
if err != nil {
return nil , err
}
var recordName string
for _ , r := range recs {
i := int64 ( r . TTL )
rrset . Properties . TTL = & i // TODO: make sure that ttls are consistent within a set
recordName = r . Name
}
for _ , r := range records {
existingRecordType , err := nativeToRecordType ( r . Type )
2020-11-14 05:32:40 +08:00
if err != nil {
return nil , err
}
2022-12-12 04:02:58 +08:00
changedRecordType , err := nativeToRecordType ( to . StringPtr ( k . Type ) )
2020-11-14 05:32:40 +08:00
if err != nil {
return nil , err
}
2022-12-12 04:02:58 +08:00
if strings . TrimSuffix ( * r . Properties . Fqdn , "." ) == k . NameFQDN && ( changedRecordType == adns . RecordTypeCNAME || existingRecordType == adns . RecordTypeCNAME ) {
if existingRecordType == adns . RecordTypeA || existingRecordType == adns . RecordTypeAAAA || changedRecordType == adns . RecordTypeA || changedRecordType == adns . RecordTypeAAAA { //CNAME cannot coexist with an A or AA
corrections = append ( corrections ,
& models . Correction {
Msg : strings . Join ( namesToUpdate [ k ] , "\n" ) ,
F : func ( ) error {
ctx , cancel := context . WithTimeout ( context . Background ( ) , 6000 * time . Second )
defer cancel ( )
_ , err := a . recordsClient . Delete ( ctx , * a . resourceGroup , zoneName , recordName , existingRecordType , nil )
if err != nil {
return err
}
return nil
} ,
} )
}
2020-11-14 05:32:40 +08:00
}
2019-09-19 09:45:14 +08:00
}
2022-12-12 04:02:58 +08:00
2019-09-19 09:45:14 +08:00
corrections = append ( corrections ,
& models . Correction {
Msg : strings . Join ( namesToUpdate [ k ] , "\n" ) ,
F : func ( ) error {
ctx , cancel := context . WithTimeout ( context . Background ( ) , 6000 * time . Second )
defer cancel ( )
2022-12-12 04:02:58 +08:00
_ , err := a . recordsClient . CreateOrUpdate ( ctx , * a . resourceGroup , zoneName , recordName , recordType , * rrset , nil )
2019-09-19 09:45:14 +08:00
if err != nil {
return err
}
return nil
} ,
} )
}
}
2022-12-12 04:02:58 +08:00
// Sort the records for cosmetic reasons: It just makes a long list
// of deletes or adds easier to read if they are in sorted order.
// That said, it may be risky to sort them (sort key is the text
// message "Msg") if there are deletes that must happen before adds.
// Reading the above code it isn't clear that any of the updates are
// order-dependent. That said, all the tests pass.
// If in the future this causes a bug, we can either just remove
// this next line, or (even better) put any order-dependent
// operations in a single models.Correction{}.
sort . Slice ( corrections , func ( i , j int ) bool { return diff . CorrectionLess ( corrections , i , j ) } )
return corrections , nil
2019-09-19 09:45:14 +08:00
}
2020-07-01 17:55:20 +08:00
2022-12-12 06:28:58 +08:00
// Azure is a "ByRSet" API.
instructions , err := diff2 . ByLabel ( existingRecords , dc , nil )
if err != nil {
return nil , err
}
for _ , inst := range instructions {
switch inst . Type {
case diff2 . CHANGE , diff2 . CREATE :
var rrset * adns . RecordSet
var recordName string
var recordType adns . RecordType
if len ( inst . Old ) == 0 { // Create
rrset = & adns . RecordSet { Type : to . StringPtr ( inst . Key . Type ) , Properties : & adns . RecordSetProperties { } }
recordType , _ = nativeToRecordType ( to . StringPtr ( inst . Key . Type ) )
recordName = inst . Key . NameFQDN
} else { // Change
rrset = inst . Old [ 0 ] . Original . ( * adns . RecordSet )
recordType , _ = nativeToRecordType ( to . StringPtr ( * rrset . Type ) )
recordName = * rrset . Name
}
// ^^^ this is broken and can probably be cleaned up significantly by
// someone that understands Azure's API.
corrections = append ( corrections ,
& models . Correction {
Msg : strings . Join ( inst . Msgs , "\n" ) ,
F : func ( ) error {
ctx , cancel := context . WithTimeout ( context . Background ( ) , 6000 * time . Second )
defer cancel ( )
_ , err := a . recordsClient . CreateOrUpdate ( ctx , * a . resourceGroup , zoneName , recordName , recordType , * rrset , nil )
if err != nil {
return err
}
return nil
} ,
} )
case diff2 . DELETE :
fmt . Printf ( "DEBUG: azure inst=%s\n" , inst )
rrset := inst . Old [ 0 ] . Original . ( * adns . RecordSet )
corrections = append ( corrections ,
& models . Correction {
Msg : strings . Join ( inst . Msgs , "\n" ) ,
F : func ( ) error {
ctx , cancel := context . WithTimeout ( context . Background ( ) , 6000 * time . Second )
defer cancel ( )
rt , err := nativeToRecordType ( rrset . Type )
if err != nil {
return err
}
_ , err = a . recordsClient . Delete ( ctx , * a . resourceGroup , zoneName , * rrset . Name , rt , nil )
if err != nil {
return err
}
return nil
} ,
} )
}
}
2020-07-01 17:55:20 +08:00
2019-09-19 09:45:14 +08:00
return corrections , nil
}
2020-11-14 05:32:40 +08:00
func nativeToRecordType ( recordType * string ) ( adns . RecordType , error ) {
2019-12-10 02:51:23 +08:00
recordTypeStripped := strings . TrimPrefix ( * recordType , "Microsoft.Network/dnszones/" )
switch recordTypeStripped {
2020-03-03 00:25:42 +08:00
case "A" , "AZURE_ALIAS_A" :
2022-08-14 19:42:41 +08:00
return adns . RecordTypeA , nil
2020-03-03 00:25:42 +08:00
case "AAAA" , "AZURE_ALIAS_AAAA" :
2022-08-14 19:42:41 +08:00
return adns . RecordTypeAAAA , nil
2019-09-19 09:45:14 +08:00
case "CAA" :
2022-08-14 19:42:41 +08:00
return adns . RecordTypeCAA , nil
2020-03-03 00:25:42 +08:00
case "CNAME" , "AZURE_ALIAS_CNAME" :
2022-08-14 19:42:41 +08:00
return adns . RecordTypeCNAME , nil
2019-09-19 09:45:14 +08:00
case "MX" :
2022-08-14 19:42:41 +08:00
return adns . RecordTypeMX , nil
2019-09-19 09:45:14 +08:00
case "NS" :
2022-08-14 19:42:41 +08:00
return adns . RecordTypeNS , nil
2019-09-19 09:45:14 +08:00
case "PTR" :
2022-08-14 19:42:41 +08:00
return adns . RecordTypePTR , nil
2019-09-19 09:45:14 +08:00
case "SRV" :
2022-08-14 19:42:41 +08:00
return adns . RecordTypeSRV , nil
2019-09-19 09:45:14 +08:00
case "TXT" :
2022-08-14 19:42:41 +08:00
return adns . RecordTypeTXT , nil
2019-09-19 09:45:14 +08:00
case "SOA" :
2022-08-14 19:42:41 +08:00
return adns . RecordTypeSOA , nil
2019-09-19 09:45:14 +08:00
default :
2020-11-14 05:32:40 +08:00
// Unimplemented type. Return adns.A as a decoy, but send an error.
2022-08-14 19:42:41 +08:00
return adns . RecordTypeA , fmt . Errorf ( "rc.String rtype %v unimplemented" , * recordType )
2019-09-19 09:45:14 +08:00
}
}
2023-01-10 01:51:18 +08:00
func safeTarget ( t * string ) string {
if t == nil {
return "foundnil"
}
return * t
}
2019-09-19 09:45:14 +08:00
func nativeToRecords ( set * adns . RecordSet , origin string ) [ ] * models . RecordConfig {
var results [ ] * models . RecordConfig
switch rtype := * set . Type ; rtype {
case "Microsoft.Network/dnszones/A" :
2022-08-14 19:42:41 +08:00
if set . Properties . ARecords != nil {
for _ , rec := range set . Properties . ARecords {
2022-12-12 06:28:58 +08:00
rc := & models . RecordConfig { TTL : uint32 ( * set . Properties . TTL ) , Original : set }
2022-08-14 19:42:41 +08:00
rc . SetLabelFromFQDN ( * set . Properties . Fqdn , origin )
2020-02-08 03:25:08 +08:00
rc . Type = "A"
2022-08-14 19:42:41 +08:00
_ = rc . SetTarget ( * rec . IPv4Address )
2020-02-08 03:25:08 +08:00
results = append ( results , rc )
}
2020-03-03 00:25:42 +08:00
} else {
rc := & models . RecordConfig {
Type : "AZURE_ALIAS" ,
2022-08-14 19:42:41 +08:00
TTL : uint32 ( * set . Properties . TTL ) ,
2020-03-03 00:25:42 +08:00
AzureAlias : map [ string ] string {
"type" : "A" ,
} ,
2022-12-12 06:28:58 +08:00
Original : set ,
2020-03-03 00:25:42 +08:00
}
2022-08-14 19:42:41 +08:00
rc . SetLabelFromFQDN ( * set . Properties . Fqdn , origin )
2023-01-10 01:51:18 +08:00
_ = rc . SetTarget ( safeTarget ( set . Properties . TargetResource . ID ) )
2020-03-03 00:25:42 +08:00
results = append ( results , rc )
2019-09-19 09:45:14 +08:00
}
case "Microsoft.Network/dnszones/AAAA" :
2022-08-14 19:42:41 +08:00
if set . Properties . AaaaRecords != nil {
for _ , rec := range set . Properties . AaaaRecords {
2022-12-12 06:28:58 +08:00
rc := & models . RecordConfig { TTL : uint32 ( * set . Properties . TTL ) , Original : set }
2022-08-14 19:42:41 +08:00
rc . SetLabelFromFQDN ( * set . Properties . Fqdn , origin )
2020-02-08 03:25:08 +08:00
rc . Type = "AAAA"
2022-08-14 19:42:41 +08:00
_ = rc . SetTarget ( * rec . IPv6Address )
2020-02-08 03:25:08 +08:00
results = append ( results , rc )
}
2020-03-03 00:25:42 +08:00
} else {
rc := & models . RecordConfig {
Type : "AZURE_ALIAS" ,
2022-08-14 19:42:41 +08:00
TTL : uint32 ( * set . Properties . TTL ) ,
2020-03-03 00:25:42 +08:00
AzureAlias : map [ string ] string {
"type" : "AAAA" ,
} ,
2022-12-12 06:28:58 +08:00
Original : set ,
2020-03-03 00:25:42 +08:00
}
2022-08-14 19:42:41 +08:00
rc . SetLabelFromFQDN ( * set . Properties . Fqdn , origin )
2023-01-10 01:51:18 +08:00
_ = rc . SetTarget ( safeTarget ( set . Properties . TargetResource . ID ) )
2020-03-03 00:25:42 +08:00
results = append ( results , rc )
2019-09-19 09:45:14 +08:00
}
case "Microsoft.Network/dnszones/CNAME" :
2022-08-14 19:42:41 +08:00
if set . Properties . CnameRecord != nil {
2022-12-12 06:28:58 +08:00
rc := & models . RecordConfig { TTL : uint32 ( * set . Properties . TTL ) , Original : set }
2022-08-14 19:42:41 +08:00
rc . SetLabelFromFQDN ( * set . Properties . Fqdn , origin )
2020-03-03 00:25:42 +08:00
rc . Type = "CNAME"
2022-08-14 19:42:41 +08:00
_ = rc . SetTarget ( * set . Properties . CnameRecord . Cname )
2020-03-03 00:25:42 +08:00
results = append ( results , rc )
} else {
rc := & models . RecordConfig {
Type : "AZURE_ALIAS" ,
2022-08-14 19:42:41 +08:00
TTL : uint32 ( * set . Properties . TTL ) ,
2020-03-03 00:25:42 +08:00
AzureAlias : map [ string ] string {
"type" : "CNAME" ,
} ,
2022-12-12 06:28:58 +08:00
Original : set ,
2020-03-03 00:25:42 +08:00
}
2022-08-14 19:42:41 +08:00
rc . SetLabelFromFQDN ( * set . Properties . Fqdn , origin )
2023-01-10 01:51:18 +08:00
_ = rc . SetTarget ( safeTarget ( set . Properties . TargetResource . ID ) )
2020-03-03 00:25:42 +08:00
results = append ( results , rc )
}
2019-09-19 09:45:14 +08:00
case "Microsoft.Network/dnszones/NS" :
2022-08-14 19:42:41 +08:00
for _ , rec := range set . Properties . NsRecords {
2022-12-12 06:28:58 +08:00
rc := & models . RecordConfig { TTL : uint32 ( * set . Properties . TTL ) , Original : set }
2022-08-14 19:42:41 +08:00
rc . SetLabelFromFQDN ( * set . Properties . Fqdn , origin )
2019-09-19 09:45:14 +08:00
rc . Type = "NS"
_ = rc . SetTarget ( * rec . Nsdname )
results = append ( results , rc )
}
case "Microsoft.Network/dnszones/PTR" :
2022-08-14 19:42:41 +08:00
for _ , rec := range set . Properties . PtrRecords {
2022-12-12 06:28:58 +08:00
rc := & models . RecordConfig { TTL : uint32 ( * set . Properties . TTL ) , Original : set }
2022-08-14 19:42:41 +08:00
rc . SetLabelFromFQDN ( * set . Properties . Fqdn , origin )
2019-09-19 09:45:14 +08:00
rc . Type = "PTR"
_ = rc . SetTarget ( * rec . Ptrdname )
results = append ( results , rc )
}
case "Microsoft.Network/dnszones/TXT" :
2022-08-14 19:42:41 +08:00
if len ( set . Properties . TxtRecords ) == 0 { // Empty String Record Parsing
2022-12-12 06:28:58 +08:00
rc := & models . RecordConfig { TTL : uint32 ( * set . Properties . TTL ) , Original : set }
2022-08-14 19:42:41 +08:00
rc . SetLabelFromFQDN ( * set . Properties . Fqdn , origin )
2019-09-19 09:45:14 +08:00
rc . Type = "TXT"
2020-02-18 21:45:31 +08:00
_ = rc . SetTargetTXT ( "" )
2019-09-19 09:45:14 +08:00
results = append ( results , rc )
2020-02-18 21:45:31 +08:00
} else {
2022-08-14 19:42:41 +08:00
for _ , rec := range set . Properties . TxtRecords {
2022-12-12 06:28:58 +08:00
rc := & models . RecordConfig { TTL : uint32 ( * set . Properties . TTL ) , Original : set }
2022-08-14 19:42:41 +08:00
rc . SetLabelFromFQDN ( * set . Properties . Fqdn , origin )
2020-02-18 21:45:31 +08:00
rc . Type = "TXT"
2022-08-14 19:42:41 +08:00
var txts [ ] string
for _ , txt := range rec . Value {
txts = append ( txts , * txt )
}
_ = rc . SetTargetTXTs ( txts )
2020-02-18 21:45:31 +08:00
results = append ( results , rc )
}
2019-09-19 09:45:14 +08:00
}
case "Microsoft.Network/dnszones/MX" :
2022-08-14 19:42:41 +08:00
for _ , rec := range set . Properties . MxRecords {
2022-12-12 06:28:58 +08:00
rc := & models . RecordConfig { TTL : uint32 ( * set . Properties . TTL ) , Original : set }
2022-08-14 19:42:41 +08:00
rc . SetLabelFromFQDN ( * set . Properties . Fqdn , origin )
2019-09-19 09:45:14 +08:00
rc . Type = "MX"
_ = rc . SetTargetMX ( uint16 ( * rec . Preference ) , * rec . Exchange )
results = append ( results , rc )
}
case "Microsoft.Network/dnszones/SRV" :
2022-08-14 19:42:41 +08:00
for _ , rec := range set . Properties . SrvRecords {
2022-12-12 06:28:58 +08:00
rc := & models . RecordConfig { TTL : uint32 ( * set . Properties . TTL ) , Original : set }
2022-08-14 19:42:41 +08:00
rc . SetLabelFromFQDN ( * set . Properties . Fqdn , origin )
2019-09-19 09:45:14 +08:00
rc . Type = "SRV"
_ = rc . SetTargetSRV ( uint16 ( * rec . Priority ) , uint16 ( * rec . Weight ) , uint16 ( * rec . Port ) , * rec . Target )
results = append ( results , rc )
}
case "Microsoft.Network/dnszones/CAA" :
2022-08-14 19:42:41 +08:00
for _ , rec := range set . Properties . CaaRecords {
2022-12-12 06:28:58 +08:00
rc := & models . RecordConfig { TTL : uint32 ( * set . Properties . TTL ) , Original : set }
2022-08-14 19:42:41 +08:00
rc . SetLabelFromFQDN ( * set . Properties . Fqdn , origin )
2019-09-19 09:45:14 +08:00
rc . Type = "CAA"
_ = rc . SetTargetCAA ( uint8 ( * rec . Flags ) , * rec . Tag , * rec . Value )
results = append ( results , rc )
}
case "Microsoft.Network/dnszones/SOA" :
default :
Switch to Go 1.13 error wrapping (#604)
* Replaced errors.Wrap with fmt.Errorf (#589)
* Find: errors\.Wrap\(([^,]+),\s+(["`][^"`]*)(["`])\)
Replace: fmt.Errorf($2: %w$3, $1)
* Replaced errors.Wrapf with fmt.Errorf (#589)
* Find: errors\.Wrapf\(([^,]+),\s+(["`][^"`]*)(["`])\)
Replace: fmt.Errorf($2: %w$3, $1)
* Find: errors\.Wrapf\(([^,]+),\s+(["`][^"`]*)(["`])(,[^)]+)\)
* Replace: fmt.Errorf($2: %w$3$4, $1)
* Replaced errors.Errorf with fmt.Errorf (#589)
* Find: errors\.Errorf
Replace: fmt.Errorf
* Cleaned up remaining imports
* Cleanup
* Regenerate provider support matrix
This was broken by #533 ... and it's now the third time this has been missed.
2020-01-29 00:06:56 +08:00
panic ( fmt . Errorf ( "rc.String rtype %v unimplemented" , * set . Type ) )
2019-09-19 09:45:14 +08:00
}
return results
}
2020-11-14 05:32:40 +08:00
func ( a * azurednsProvider ) recordToNative ( recordKey models . RecordKey , recordConfig [ ] * models . RecordConfig ) ( * adns . RecordSet , adns . RecordType , error ) {
2022-08-14 19:42:41 +08:00
recordSet := & adns . RecordSet { Type : to . StringPtr ( recordKey . Type ) , Properties : & adns . RecordSetProperties { } }
2019-09-19 09:45:14 +08:00
for _ , rec := range recordConfig {
switch recordKey . Type {
case "A" :
2022-08-14 19:42:41 +08:00
if recordSet . Properties . ARecords == nil {
recordSet . Properties . ARecords = [ ] * adns . ARecord { }
2019-09-19 09:45:14 +08:00
}
2022-08-14 19:42:41 +08:00
recordSet . Properties . ARecords = append ( recordSet . Properties . ARecords , & adns . ARecord { IPv4Address : to . StringPtr ( rec . GetTargetField ( ) ) } )
2019-09-19 09:45:14 +08:00
case "AAAA" :
2022-08-14 19:42:41 +08:00
if recordSet . Properties . AaaaRecords == nil {
recordSet . Properties . AaaaRecords = [ ] * adns . AaaaRecord { }
2019-09-19 09:45:14 +08:00
}
2022-08-14 19:42:41 +08:00
recordSet . Properties . AaaaRecords = append ( recordSet . Properties . AaaaRecords , & adns . AaaaRecord { IPv6Address : to . StringPtr ( rec . GetTargetField ( ) ) } )
2019-09-19 09:45:14 +08:00
case "CNAME" :
2022-08-14 19:42:41 +08:00
recordSet . Properties . CnameRecord = & adns . CnameRecord { Cname : to . StringPtr ( rec . GetTargetField ( ) ) }
2019-09-19 09:45:14 +08:00
case "NS" :
2022-08-14 19:42:41 +08:00
if recordSet . Properties . NsRecords == nil {
recordSet . Properties . NsRecords = [ ] * adns . NsRecord { }
2019-09-19 09:45:14 +08:00
}
2022-08-14 19:42:41 +08:00
recordSet . Properties . NsRecords = append ( recordSet . Properties . NsRecords , & adns . NsRecord { Nsdname : to . StringPtr ( rec . GetTargetField ( ) ) } )
2019-09-19 09:45:14 +08:00
case "PTR" :
2022-08-14 19:42:41 +08:00
if recordSet . Properties . PtrRecords == nil {
recordSet . Properties . PtrRecords = [ ] * adns . PtrRecord { }
2019-09-19 09:45:14 +08:00
}
2022-08-14 19:42:41 +08:00
recordSet . Properties . PtrRecords = append ( recordSet . Properties . PtrRecords , & adns . PtrRecord { Ptrdname : to . StringPtr ( rec . GetTargetField ( ) ) } )
2019-09-19 09:45:14 +08:00
case "TXT" :
2022-08-14 19:42:41 +08:00
if recordSet . Properties . TxtRecords == nil {
recordSet . Properties . TxtRecords = [ ] * adns . TxtRecord { }
2019-09-19 09:45:14 +08:00
}
2020-02-18 21:45:31 +08:00
// Empty TXT record needs to have no value set in it's properties
if ! ( len ( rec . TxtStrings ) == 1 && rec . TxtStrings [ 0 ] == "" ) {
2022-08-14 19:42:41 +08:00
var txts [ ] * string
for _ , txt := range rec . TxtStrings {
txts = append ( txts , to . StringPtr ( txt ) )
}
recordSet . Properties . TxtRecords = append ( recordSet . Properties . TxtRecords , & adns . TxtRecord { Value : txts } )
2020-02-18 21:45:31 +08:00
}
2019-09-19 09:45:14 +08:00
case "MX" :
2022-08-14 19:42:41 +08:00
if recordSet . Properties . MxRecords == nil {
recordSet . Properties . MxRecords = [ ] * adns . MxRecord { }
2019-09-19 09:45:14 +08:00
}
2022-08-14 19:42:41 +08:00
recordSet . Properties . MxRecords = append ( recordSet . Properties . MxRecords , & adns . MxRecord { Exchange : to . StringPtr ( rec . GetTargetField ( ) ) , Preference : to . Int32Ptr ( int32 ( rec . MxPreference ) ) } )
2019-09-19 09:45:14 +08:00
case "SRV" :
2022-08-14 19:42:41 +08:00
if recordSet . Properties . SrvRecords == nil {
recordSet . Properties . SrvRecords = [ ] * adns . SrvRecord { }
2019-09-19 09:45:14 +08:00
}
2022-08-14 19:42:41 +08:00
recordSet . Properties . SrvRecords = append ( recordSet . Properties . SrvRecords , & adns . SrvRecord { Target : to . StringPtr ( rec . GetTargetField ( ) ) , Port : to . Int32Ptr ( int32 ( rec . SrvPort ) ) , Weight : to . Int32Ptr ( int32 ( rec . SrvWeight ) ) , Priority : to . Int32Ptr ( int32 ( rec . SrvPriority ) ) } )
2019-09-19 09:45:14 +08:00
case "CAA" :
2022-08-14 19:42:41 +08:00
if recordSet . Properties . CaaRecords == nil {
recordSet . Properties . CaaRecords = [ ] * adns . CaaRecord { }
2019-09-19 09:45:14 +08:00
}
2022-08-14 19:42:41 +08:00
recordSet . Properties . CaaRecords = append ( recordSet . Properties . CaaRecords , & adns . CaaRecord { Value : to . StringPtr ( rec . GetTargetField ( ) ) , Tag : to . StringPtr ( rec . CaaTag ) , Flags : to . Int32Ptr ( int32 ( rec . CaaFlag ) ) } )
2020-03-03 00:25:42 +08:00
case "AZURE_ALIAS_A" , "AZURE_ALIAS_AAAA" , "AZURE_ALIAS_CNAME" :
* recordSet . Type = rec . AzureAlias [ "type" ]
2022-08-14 19:42:41 +08:00
recordSet . Properties . TargetResource = & adns . SubResource { ID : to . StringPtr ( rec . GetTargetField ( ) ) }
2019-09-19 09:45:14 +08:00
default :
2022-08-14 19:42:41 +08:00
return nil , adns . RecordTypeA , fmt . Errorf ( "rc.String rtype %v unimplemented" , recordKey . Type ) // ands.A is a placeholder
2019-09-19 09:45:14 +08:00
}
}
2020-03-03 00:25:42 +08:00
2020-11-14 05:32:40 +08:00
rt , err := nativeToRecordType ( to . StringPtr ( * recordSet . Type ) )
if err != nil {
2022-08-14 19:42:41 +08:00
return nil , adns . RecordTypeA , err // adns.A is a placeholder
2020-11-14 05:32:40 +08:00
}
return recordSet , rt , nil
2019-09-19 09:45:14 +08:00
}
2020-10-26 21:25:30 +08:00
func ( a * azurednsProvider ) fetchRecordSets ( zoneName string ) ( [ ] * adns . RecordSet , error ) {
2020-02-06 07:19:24 +08:00
if zoneName == "" {
2019-09-19 09:45:14 +08:00
return nil , nil
}
var records [ ] * adns . RecordSet
ctx , cancel := context . WithTimeout ( context . Background ( ) , 6000 * time . Second )
defer cancel ( )
2022-08-14 19:42:41 +08:00
recordsPager := a . recordsClient . NewListAllByDNSZonePager ( * a . resourceGroup , zoneName , nil )
2019-09-19 09:45:14 +08:00
2022-08-14 19:42:41 +08:00
for recordsPager . More ( ) {
nextResult , recordsErr := recordsPager . NextPage ( ctx )
if recordsErr != nil {
return nil , recordsErr
2020-07-29 01:35:56 +08:00
}
2022-08-14 19:42:41 +08:00
records = append ( records , nextResult . Value ... )
2019-09-19 09:45:14 +08:00
}
return records , nil
}
2020-10-26 21:25:30 +08:00
func ( a * azurednsProvider ) EnsureDomainExists ( domain string ) error {
2019-09-19 09:45:14 +08:00
if _ , ok := a . zones [ domain ] ; ok {
return nil
}
2022-06-18 21:01:02 +08:00
printer . Printf ( "Adding zone for %s to Azure dns account\n" , domain )
2019-09-19 09:45:14 +08:00
ctx , cancel := context . WithTimeout ( context . Background ( ) , 6000 * time . Second )
defer cancel ( )
2022-08-14 19:42:41 +08:00
_ , err := a . zonesClient . CreateOrUpdate ( ctx , * a . resourceGroup , domain , adns . Zone { Location : to . StringPtr ( "global" ) } , nil )
2019-09-19 09:45:14 +08:00
if err != nil {
return err
}
return nil
}