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"
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
adns "github.com/Azure/azure-sdk-for-go/services/dns/mgmt/2018-05-01/dns"
aauth "github.com/Azure/go-autorest/autorest/azure/auth"
2019-09-19 09:45:14 +08:00
"github.com/Azure/go-autorest/autorest/to"
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
2020-04-15 04:47:30 +08:00
"github.com/StackExchange/dnscontrol/v3/models"
"github.com/StackExchange/dnscontrol/v3/pkg/diff"
"github.com/StackExchange/dnscontrol/v3/providers"
2019-09-19 09:45:14 +08:00
)
2020-10-26 00:58:43 +08:00
type azurednsAPI 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 00:58:43 +08:00
func newAzureDNS ( m map [ string ] string , metadata json . RawMessage ) ( * azurednsAPI , error ) {
2020-06-18 21:37:57 +08:00
subID , rg := m [ "SubscriptionID" ] , m [ "ResourceGroup" ]
2019-09-19 09:45:14 +08:00
2020-06-18 21:37:57 +08:00
zonesClient := adns . NewZonesClient ( subID )
recordsClient := adns . NewRecordSetsClient ( subID )
2019-09-19 09:45:14 +08:00
clientCredentialAuthorizer := aauth . NewClientCredentialsConfig ( m [ "ClientID" ] , m [ "ClientSecret" ] , m [ "TenantID" ] )
authorizer , authErr := clientCredentialAuthorizer . Authorizer ( )
if authErr != nil {
return nil , authErr
}
zonesClient . Authorizer = authorizer
recordsClient . Authorizer = authorizer
2020-10-26 00:58:43 +08:00
api := & azurednsAPI { 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 {
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." ) ,
2019-09-19 09:45:14 +08:00
providers . DocCreateDomains : providers . Can ( ) ,
2019-10-31 21:44:42 +08:00
providers . DocDualHost : providers . Can ( "Azure does not permit modifying the existing NS records, only adding/removing additional records." ) ,
2020-02-25 20:23:04 +08:00
providers . DocOfficiallySupported : providers . Can ( ) ,
2019-09-19 09:45:14 +08:00
providers . CanUsePTR : providers . Can ( ) ,
providers . CanUseSRV : providers . Can ( ) ,
providers . CanUseTXTMulti : providers . Can ( ) ,
providers . CanUseCAA : providers . Can ( ) ,
providers . CanUseNAPTR : providers . Cannot ( ) ,
providers . CanUseSSHFP : providers . Cannot ( ) ,
providers . CanUseTLSA : providers . Cannot ( ) ,
2020-02-19 00:35:13 +08:00
providers . CanGetZones : providers . Can ( ) ,
2020-03-03 00:25:42 +08:00
providers . CanUseAzureAlias : providers . Can ( ) ,
2019-09-19 09:45:14 +08:00
}
func init ( ) {
2020-06-18 21:37:57 +08:00
providers . RegisterDomainServiceProviderType ( "AZURE_DNS" , newAzureDNSDsp , features )
2020-03-03 00:25:42 +08:00
providers . RegisterCustomRecordType ( "AZURE_ALIAS" , "AZURE_DNS" , "" )
2019-09-19 09:45:14 +08:00
}
2020-10-26 00:58:43 +08:00
func ( a * azurednsAPI ) getExistingZones ( ) ( * adns . ZoneListResult , error ) {
2020-08-27 01:45:02 +08:00
// Please note — this function doesn't work with > 100 zones
// https://github.com/StackExchange/dnscontrol/issues/792
// Copied this code to getZones and ListZones and modified it for using a paging
// As a result getExistingZones is not used anymore
2019-09-19 09:45:14 +08:00
ctx , cancel := context . WithTimeout ( context . Background ( ) , 6000 * time . Second )
defer cancel ( )
zonesIterator , zonesErr := a . zonesClient . ListByResourceGroupComplete ( ctx , * a . resourceGroup , to . Int32Ptr ( 100 ) )
if zonesErr != nil {
2020-02-19 00:35:13 +08:00
return nil , zonesErr
2019-09-19 09:45:14 +08:00
}
zonesResult := zonesIterator . Response ( )
2020-02-19 00:35:13 +08:00
return & zonesResult , nil
}
2020-10-26 00:58:43 +08:00
func ( a * azurednsAPI ) getZones ( ) error {
2020-02-19 00:35:13 +08:00
a . zones = make ( map [ string ] * adns . Zone )
2020-08-19 03:13:08 +08:00
ctx , cancel := context . WithTimeout ( context . Background ( ) , 6000 * time . Second )
defer cancel ( )
zonesIterator , zonesErr := a . zonesClient . ListByResourceGroup ( ctx , * a . resourceGroup , to . Int32Ptr ( 100 ) )
if zonesErr != nil {
2020-09-04 19:30:41 +08:00
return fmt . Errorf ( "getZones: zonesErr: %w" , zonesErr )
2020-02-19 00:35:13 +08:00
}
2020-08-27 01:45:02 +08:00
// Check getExistingZones and https://github.com/StackExchange/dnscontrol/issues/792 for the details
2020-08-19 03:13:08 +08:00
for zonesIterator . NotDone ( ) {
zonesResult := zonesIterator . Response ( )
for _ , z := range * zonesResult . Value {
zone := z
domain := strings . TrimSuffix ( * z . Name , "." )
a . zones [ domain ] = & zone
}
zonesIterator . NextWithContext ( ctx )
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 00:58:43 +08:00
func ( a * azurednsAPI ) 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
2019-09-19 09:45:14 +08:00
if zone . ZoneProperties != nil {
2020-03-01 23:33:24 +08:00
for _ , ns := range * zone . ZoneProperties . NameServers {
nss = append ( nss , ns )
2019-09-19 09:45:14 +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 00:58:43 +08:00
func ( a * azurednsAPI ) ListZones ( ) ( [ ] string , error ) {
2020-08-19 03:13:08 +08:00
var zones [ ] string
2020-02-18 21:59:18 +08:00
2020-08-19 03:13:08 +08:00
ctx , cancel := context . WithTimeout ( context . Background ( ) , 6000 * time . Second )
defer cancel ( )
zonesIterator , zonesErr := a . zonesClient . ListByResourceGroup ( ctx , * a . resourceGroup , to . Int32Ptr ( 100 ) )
if zonesErr != nil {
2020-09-04 19:30:41 +08:00
return nil , fmt . Errorf ( "ListZones: zonesErr: %w" , zonesErr )
2020-02-19 00:35:13 +08:00
}
2020-08-27 01:45:02 +08:00
// Check getExistingZones and https://github.com/StackExchange/dnscontrol/issues/792 for the details
2020-08-19 03:13:08 +08:00
for zonesIterator . NotDone ( ) {
zonesResult := zonesIterator . Response ( )
for _ , z := range * zonesResult . Value {
domain := strings . TrimSuffix ( * z . Name , "." )
zones = append ( zones , domain )
}
zonesIterator . NextWithContext ( ctx )
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 00:58:43 +08:00
func ( a * azurednsAPI ) 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 00:58:43 +08:00
func ( a * azurednsAPI ) 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
}
models . PostProcessRecords ( existingRecords )
2020-02-19 00:35:13 +08:00
return existingRecords , records , zoneName , nil
}
2020-10-26 00:58:43 +08:00
func ( a * azurednsAPI ) GetDomainCorrections ( dc * models . DomainConfig ) ( [ ] * models . Correction , error ) {
2020-02-19 00:35:13 +08:00
err := dc . Punycode ( )
if err != nil {
return nil , err
}
var corrections [ ] * models . Correction
existingRecords , records , zoneName , err := a . getExistingRecords ( dc . Name )
if err != nil {
return nil , err
}
2019-09-19 09:45:14 +08:00
differ := diff . New ( dc )
2020-08-21 03:49:00 +08:00
namesToUpdate , err := differ . ChangedGroups ( existingRecords )
if err != nil {
return nil , err
}
2019-09-19 09:45:14 +08:00
if len ( namesToUpdate ) == 0 {
return nil , nil
}
updates := map [ models . RecordKey ] [ ] * models . RecordConfig { }
for k := range namesToUpdate {
updates [ k ] = nil
for _ , rc := range dc . Records {
if rc . Key ( ) == k {
updates [ k ] = append ( updates [ k ] , rc )
}
}
}
for k , recs := range updates {
if len ( recs ) == 0 {
var rrset * adns . RecordSet
for _ , r := range records {
2019-12-10 02:51:23 +08:00
if strings . TrimSuffix ( * r . RecordSetProperties . Fqdn , "." ) == k . NameFQDN && nativeToRecordType ( r . Type ) == nativeToRecordType ( to . StringPtr ( k . Type ) ) {
2019-09-19 09:45:14 +08:00
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 ( )
2020-02-06 07:19:24 +08:00
_ , err := a . recordsClient . Delete ( ctx , * a . resourceGroup , zoneName , * rrset . Name , nativeToRecordType ( rrset . Type ) , "" )
2020-07-07 08:18:24 +08:00
// Artificially slow things down after a delete, as the API can take time to register it. The tests fail if we delete and then recheck too quickly.
2020-07-01 17:55:20 +08:00
time . Sleep ( 10 * time . Millisecond )
2019-09-19 09:45:14 +08:00
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 {
2020-03-03 00:25:42 +08:00
rrset , recordType := a . recordToNative ( k , recs )
2019-09-19 09:45:14 +08:00
var recordName string
for _ , r := range recs {
i := int64 ( r . TTL )
rrset . TTL = & i // TODO: make sure that ttls are consistent within a set
recordName = r . Name
}
for _ , r := range records {
2019-12-10 02:51:23 +08:00
existingRecordType := nativeToRecordType ( r . Type )
2019-09-19 09:45:14 +08:00
changedRecordType := nativeToRecordType ( to . StringPtr ( k . Type ) )
if strings . TrimSuffix ( * r . RecordSetProperties . Fqdn , "." ) == k . NameFQDN && ( changedRecordType == adns . CNAME || existingRecordType == adns . CNAME ) {
if existingRecordType == adns . A || existingRecordType == adns . AAAA || changedRecordType == adns . A || changedRecordType == adns . AAAA { //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 ( )
2020-02-06 07:19:24 +08:00
_ , err := a . recordsClient . Delete ( ctx , * a . resourceGroup , zoneName , recordName , existingRecordType , "" )
2020-07-07 08:18:24 +08:00
// Artificially slow things down after a delete, as the API can take time to register it. The tests fail if we delete and then recheck too quickly.
2020-07-01 17:55:20 +08:00
time . Sleep ( 10 * time . Millisecond )
2019-09-19 09:45:14 +08:00
if err != nil {
return err
}
return 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 ( )
2020-02-06 07:19:24 +08:00
_ , err := a . recordsClient . CreateOrUpdate ( ctx , * a . resourceGroup , zoneName , recordName , recordType , * rrset , "" , "" )
2020-07-07 08:18:24 +08:00
// Artificially slow things down after a delete, as the API can take time to register it. The tests fail if we delete and then recheck too quickly.
2020-07-01 17:55:20 +08:00
time . Sleep ( 10 * time . Millisecond )
2019-09-19 09:45:14 +08:00
if err != nil {
return err
}
return nil
} ,
} )
}
}
2020-07-01 17:55:20 +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 ) } )
2019-09-19 09:45:14 +08:00
return corrections , nil
}
func nativeToRecordType ( recordType * string ) adns . RecordType {
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" :
2019-09-19 09:45:14 +08:00
return adns . A
2020-03-03 00:25:42 +08:00
case "AAAA" , "AZURE_ALIAS_AAAA" :
2019-09-19 09:45:14 +08:00
return adns . AAAA
case "CAA" :
return adns . CAA
2020-03-03 00:25:42 +08:00
case "CNAME" , "AZURE_ALIAS_CNAME" :
2019-09-19 09:45:14 +08:00
return adns . CNAME
case "MX" :
return adns . MX
case "NS" :
return adns . NS
case "PTR" :
return adns . PTR
case "SRV" :
return adns . SRV
case "TXT" :
return adns . TXT
case "SOA" :
return adns . 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" , * recordType ) )
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" :
2020-02-18 21:45:31 +08:00
if set . ARecords != nil {
2020-02-08 03:25:08 +08:00
for _ , rec := range * set . ARecords {
rc := & models . RecordConfig { TTL : uint32 ( * set . TTL ) }
rc . SetLabelFromFQDN ( * set . Fqdn , origin )
rc . Type = "A"
_ = rc . SetTarget ( * rec . Ipv4Address )
results = append ( results , rc )
}
2020-03-03 00:25:42 +08:00
} else {
rc := & models . RecordConfig {
Type : "AZURE_ALIAS" ,
TTL : uint32 ( * set . TTL ) ,
AzureAlias : map [ string ] string {
"type" : "A" ,
} ,
}
rc . SetLabelFromFQDN ( * set . Fqdn , origin )
_ = rc . SetTarget ( * set . TargetResource . ID )
results = append ( results , rc )
2019-09-19 09:45:14 +08:00
}
case "Microsoft.Network/dnszones/AAAA" :
2020-02-18 21:45:31 +08:00
if set . AaaaRecords != nil {
2020-02-08 03:25:08 +08:00
for _ , rec := range * set . AaaaRecords {
rc := & models . RecordConfig { TTL : uint32 ( * set . TTL ) }
rc . SetLabelFromFQDN ( * set . Fqdn , origin )
rc . Type = "AAAA"
_ = rc . SetTarget ( * rec . Ipv6Address )
results = append ( results , rc )
}
2020-03-03 00:25:42 +08:00
} else {
rc := & models . RecordConfig {
Type : "AZURE_ALIAS" ,
TTL : uint32 ( * set . TTL ) ,
AzureAlias : map [ string ] string {
"type" : "AAAA" ,
} ,
}
rc . SetLabelFromFQDN ( * set . Fqdn , origin )
_ = rc . SetTarget ( * set . TargetResource . ID )
results = append ( results , rc )
2019-09-19 09:45:14 +08:00
}
case "Microsoft.Network/dnszones/CNAME" :
2020-03-03 00:25:42 +08:00
if set . CnameRecord != nil {
rc := & models . RecordConfig { TTL : uint32 ( * set . TTL ) }
rc . SetLabelFromFQDN ( * set . Fqdn , origin )
rc . Type = "CNAME"
_ = rc . SetTarget ( * set . CnameRecord . Cname )
results = append ( results , rc )
} else {
rc := & models . RecordConfig {
Type : "AZURE_ALIAS" ,
TTL : uint32 ( * set . TTL ) ,
AzureAlias : map [ string ] string {
"type" : "CNAME" ,
} ,
}
rc . SetLabelFromFQDN ( * set . Fqdn , origin )
_ = rc . SetTarget ( * set . TargetResource . ID )
results = append ( results , rc )
}
2019-09-19 09:45:14 +08:00
case "Microsoft.Network/dnszones/NS" :
for _ , rec := range * set . NsRecords {
rc := & models . RecordConfig { TTL : uint32 ( * set . TTL ) }
rc . SetLabelFromFQDN ( * set . Fqdn , origin )
rc . Type = "NS"
_ = rc . SetTarget ( * rec . Nsdname )
results = append ( results , rc )
}
case "Microsoft.Network/dnszones/PTR" :
for _ , rec := range * set . PtrRecords {
rc := & models . RecordConfig { TTL : uint32 ( * set . TTL ) }
rc . SetLabelFromFQDN ( * set . Fqdn , origin )
rc . Type = "PTR"
_ = rc . SetTarget ( * rec . Ptrdname )
results = append ( results , rc )
}
case "Microsoft.Network/dnszones/TXT" :
2020-02-18 21:45:31 +08:00
if len ( * set . TxtRecords ) == 0 { // Empty String Record Parsing
2019-09-19 09:45:14 +08:00
rc := & models . RecordConfig { TTL : uint32 ( * set . TTL ) }
rc . SetLabelFromFQDN ( * set . Fqdn , origin )
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 {
for _ , rec := range * set . TxtRecords {
rc := & models . RecordConfig { TTL : uint32 ( * set . TTL ) }
rc . SetLabelFromFQDN ( * set . Fqdn , origin )
rc . Type = "TXT"
_ = rc . SetTargetTXTs ( * rec . Value )
results = append ( results , rc )
}
2019-09-19 09:45:14 +08:00
}
case "Microsoft.Network/dnszones/MX" :
for _ , rec := range * set . MxRecords {
rc := & models . RecordConfig { TTL : uint32 ( * set . TTL ) }
rc . SetLabelFromFQDN ( * set . Fqdn , origin )
rc . Type = "MX"
_ = rc . SetTargetMX ( uint16 ( * rec . Preference ) , * rec . Exchange )
results = append ( results , rc )
}
case "Microsoft.Network/dnszones/SRV" :
for _ , rec := range * set . SrvRecords {
rc := & models . RecordConfig { TTL : uint32 ( * set . TTL ) }
rc . SetLabelFromFQDN ( * set . Fqdn , origin )
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" :
for _ , rec := range * set . CaaRecords {
rc := & models . RecordConfig { TTL : uint32 ( * set . TTL ) }
rc . SetLabelFromFQDN ( * set . Fqdn , origin )
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-10-26 00:58:43 +08:00
func ( a * azurednsAPI ) recordToNative ( recordKey models . RecordKey , recordConfig [ ] * models . RecordConfig ) ( * adns . RecordSet , adns . RecordType ) {
2019-09-19 09:45:14 +08:00
recordSet := & adns . RecordSet { Type : to . StringPtr ( recordKey . Type ) , RecordSetProperties : & adns . RecordSetProperties { } }
for _ , rec := range recordConfig {
switch recordKey . Type {
case "A" :
if recordSet . ARecords == nil {
recordSet . ARecords = & [ ] adns . ARecord { }
}
* recordSet . ARecords = append ( * recordSet . ARecords , adns . ARecord { Ipv4Address : to . StringPtr ( rec . Target ) } )
case "AAAA" :
if recordSet . AaaaRecords == nil {
recordSet . AaaaRecords = & [ ] adns . AaaaRecord { }
}
* recordSet . AaaaRecords = append ( * recordSet . AaaaRecords , adns . AaaaRecord { Ipv6Address : to . StringPtr ( rec . Target ) } )
case "CNAME" :
recordSet . CnameRecord = & adns . CnameRecord { Cname : to . StringPtr ( rec . Target ) }
case "NS" :
if recordSet . NsRecords == nil {
recordSet . NsRecords = & [ ] adns . NsRecord { }
}
* recordSet . NsRecords = append ( * recordSet . NsRecords , adns . NsRecord { Nsdname : to . StringPtr ( rec . Target ) } )
case "PTR" :
if recordSet . PtrRecords == nil {
recordSet . PtrRecords = & [ ] adns . PtrRecord { }
}
* recordSet . PtrRecords = append ( * recordSet . PtrRecords , adns . PtrRecord { Ptrdname : to . StringPtr ( rec . Target ) } )
case "TXT" :
if recordSet . TxtRecords == nil {
recordSet . TxtRecords = & [ ] adns . TxtRecord { }
}
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 ] == "" ) {
* recordSet . TxtRecords = append ( * recordSet . TxtRecords , adns . TxtRecord { Value : & rec . TxtStrings } )
}
2019-09-19 09:45:14 +08:00
case "MX" :
if recordSet . MxRecords == nil {
recordSet . MxRecords = & [ ] adns . MxRecord { }
}
* recordSet . MxRecords = append ( * recordSet . MxRecords , adns . MxRecord { Exchange : to . StringPtr ( rec . Target ) , Preference : to . Int32Ptr ( int32 ( rec . MxPreference ) ) } )
case "SRV" :
if recordSet . SrvRecords == nil {
recordSet . SrvRecords = & [ ] adns . SrvRecord { }
}
* recordSet . SrvRecords = append ( * recordSet . SrvRecords , adns . SrvRecord { Target : to . StringPtr ( rec . Target ) , Port : to . Int32Ptr ( int32 ( rec . SrvPort ) ) , Weight : to . Int32Ptr ( int32 ( rec . SrvWeight ) ) , Priority : to . Int32Ptr ( int32 ( rec . SrvPriority ) ) } )
case "CAA" :
if recordSet . CaaRecords == nil {
recordSet . CaaRecords = & [ ] adns . CaaRecord { }
}
* recordSet . CaaRecords = append ( * recordSet . CaaRecords , adns . CaaRecord { Value : to . StringPtr ( rec . Target ) , 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" ]
recordSet . TargetResource = & adns . SubResource { ID : to . StringPtr ( rec . Target ) }
2019-09-19 09:45:14 +08:00
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" , recordKey . Type ) )
2019-09-19 09:45:14 +08:00
}
}
2020-03-03 00:25:42 +08:00
return recordSet , nativeToRecordType ( to . StringPtr ( * recordSet . Type ) )
2019-09-19 09:45:14 +08:00
}
2020-10-26 00:58:43 +08:00
func ( a * azurednsAPI ) 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 ( )
2020-07-29 01:35:56 +08:00
recordsIterator , recordsErr := a . recordsClient . ListAllByDNSZone ( ctx , * a . resourceGroup , zoneName , to . Int32Ptr ( 1000 ) , "" )
2019-09-19 09:45:14 +08:00
if recordsErr != nil {
return nil , recordsErr
}
2020-07-29 01:35:56 +08:00
for recordsIterator . NotDone ( ) {
recordsResult := recordsIterator . Response ( )
for _ , r := range * recordsResult . Value {
record := r
records = append ( records , & record )
}
recordsIterator . NextWithContext ( ctx )
2019-09-19 09:45:14 +08:00
}
return records , nil
}
2020-10-26 00:58:43 +08:00
func ( a * azurednsAPI ) EnsureDomainExists ( domain string ) error {
2019-09-19 09:45:14 +08:00
if _ , ok := a . zones [ domain ] ; ok {
return nil
}
fmt . Printf ( "Adding zone for %s to Azure dns account\n" , domain )
ctx , cancel := context . WithTimeout ( context . Background ( ) , 6000 * time . Second )
defer cancel ( )
_ , err := a . zonesClient . CreateOrUpdate ( ctx , * a . resourceGroup , domain , adns . Zone { Location : to . StringPtr ( "global" ) } , "" , "" )
if err != nil {
return err
}
return nil
}