diff --git a/docs/tutorials/pdns.md b/docs/tutorials/pdns.md index 72aa3fc85e..0c394dc338 100644 --- a/docs/tutorials/pdns.md +++ b/docs/tutorials/pdns.md @@ -172,3 +172,102 @@ Once the API shows the record correctly, you can double check your record using: ```bash $ dig @${PDNS_FQDN} echo.example.com. ``` + +## Using CRD source to manage DNS records in PowerDNS + +[CRD source](https://github.com/kubernetes-sigs/external-dns/blob/master/docs/contributing/crd-source.md) provides a generic mechanism and declarative way to manage DNS records in PowerDNS using external-dns. + +```bash +external-dns --source=crd --provider=pdns \ + --pdns-server={{ pdns-api-url }} \ + --pdns-api-key={{ pdns-api-key }} \ + --domain-filter=example.com \ + --managed-record-types=A \ + --managed-record-types=CNAME \ + --managed-record-types=TXT \ + --managed-record-types=MX \ + --managed-record-types=SRV +``` + +Not all the record types are enabled by default so we can enable the required record types using `--managed-record-types`. + +* Example for record type `A` + +```yaml +apiVersion: externaldns.k8s.io/v1alpha1 +kind: DNSEndpoint +metadata: + name: examplearecord +spec: + endpoints: + - dnsName: example.com + recordTTL: 60 + recordType: A + targets: + - 10.0.0.1 +``` + +* Example for record type `CNAME` + +```yaml +apiVersion: externaldns.k8s.io/v1alpha1 +kind: DNSEndpoint +metadata: + name: examplecnamerecord +spec: + endpoints: + - dnsName: test-a.example.com + recordTTL: 300 + recordType: CNAME + targets: + - example.com +``` + +* Example for record type `TXT` + +```yaml +apiVersion: externaldns.k8s.io/v1alpha1 +kind: DNSEndpoint +metadata: + name: exampletxtrecord +spec: + endpoints: + - dnsName: example.com + recordTTL: 3600 + recordType: TXT + targets: + - '"v=spf1 include:spf.protection.example.com include:example.org -all"' + - '"apple-domain-verification=XXXXXXXXXXXXX"' +``` + +* Example for record type `MX` + +```yaml +apiVersion: externaldns.k8s.io/v1alpha1 +kind: DNSEndpoint +metadata: + name: examplemxrecord +spec: + endpoints: + - dnsName: example.com + recordTTL: 3600 + recordType: MX + targets: + - "10 mailhost1.example.com" +``` + +* Example for record type `SRV` + +```yaml +apiVersion: externaldns.k8s.io/v1alpha1 +kind: DNSEndpoint +metadata: + name: examplesrvrecord +spec: + endpoints: + - dnsName: _service._tls.example.com + recordTTL: 180 + recordType: SRV + targets: + - "100 1 443 service.example.com" +``` \ No newline at end of file diff --git a/provider/pdns/pdns.go b/provider/pdns/pdns.go index fbc7cc22fa..1d9b563323 100644 --- a/provider/pdns/pdns.go +++ b/provider/pdns/pdns.go @@ -314,7 +314,7 @@ func (p *PDNSProvider) ConvertEndpointsToZones(eps []*endpoint.Endpoint, changet records := []pgo.Record{} RecordType_ := ep.RecordType for _, t := range ep.Targets { - if ep.RecordType == "CNAME" || ep.RecordType == "ALIAS" { + if ep.RecordType == "CNAME" || ep.RecordType == "ALIAS" || ep.RecordType == "MX" || ep.RecordType == "SRV" { t = provider.EnsureTrailingDot(t) } records = append(records, pgo.Record{Content: t}) diff --git a/provider/pdns/pdns_test.go b/provider/pdns/pdns_test.go index 01489da9c7..13f5a7efcc 100644 --- a/provider/pdns/pdns_test.go +++ b/provider/pdns/pdns_test.go @@ -117,6 +117,27 @@ var ( }, } + // RRSet with MX record + RRSetMXRecord = pgo.RrSet{ + Name: "example.com.", + Type_: "MX", + Ttl: 300, + Records: []pgo.Record{ + {Content: "10 mailhost1.example.com", Disabled: false, SetPtr: false}, + {Content: "10 mailhost2.example.com", Disabled: false, SetPtr: false}, + }, + } + + // RRSet with SRV record + RRSetSRVRecord = pgo.RrSet{ + Name: "_service._tls.example.com.", + Type_: "SRV", + Ttl: 300, + Records: []pgo.Record{ + {Content: "100 1 443 service.example.com", Disabled: false, SetPtr: false}, + }, + } + endpointsDisabledRecord = []*endpoint.Endpoint{ endpoint.NewEndpointWithTTL("example.com", endpoint.RecordTypeA, endpoint.TTL(300), "8.8.8.8"), } @@ -144,6 +165,8 @@ var ( endpoint.NewEndpointWithTTL("example.com", endpoint.RecordTypeTXT, endpoint.TTL(300), "'would smell as sweet'"), endpoint.NewEndpointWithTTL("example.com", endpoint.RecordTypeA, endpoint.TTL(300), "8.8.8.8", "8.8.4.4", "4.4.4.4"), endpoint.NewEndpointWithTTL("alias.example.com", endpoint.RecordTypeCNAME, endpoint.TTL(300), "example.by.any.other.name.com"), + endpoint.NewEndpointWithTTL("example.com", endpoint.RecordTypeMX, endpoint.TTL(300), "10 mailhost1.example.com", "10 mailhost2.example.com"), + endpoint.NewEndpointWithTTL("_service._tls.example.com", endpoint.RecordTypeSRV, endpoint.TTL(300), "100 1 443 service.example.com"), } endpointsMultipleZones = []*endpoint.Endpoint{ @@ -233,7 +256,7 @@ var ( Type_: "Zone", Url: "/api/v1/servers/localhost/zones/example.com.", Kind: "Native", - Rrsets: []pgo.RrSet{RRSetCNAMERecord, RRSetTXTRecord, RRSetMultipleRecords, RRSetALIASRecord}, + Rrsets: []pgo.RrSet{RRSetCNAMERecord, RRSetTXTRecord, RRSetMultipleRecords, RRSetALIASRecord, RRSetMXRecord, RRSetSRVRecord}, } ZoneEmptyToSimplePatch = pgo.Zone{ @@ -944,6 +967,20 @@ func (suite *NewPDNSProviderTestSuite) TestPDNSConvertEndpointsToZones() { } } + // Check endpoints of type MX and SRV always have their values end with a trailing dot. + zlist, err = p.ConvertEndpointsToZones(endpointsMixedRecords, PdnsReplace) + assert.Nil(suite.T(), err) + + for _, z := range zlist { + for _, rs := range z.Rrsets { + if rs.Type_ == "MX" || rs.Type_ == "SRV" { + for _, r := range rs.Records { + assert.Equal(suite.T(), uint8(0x2e), r.Content[len(r.Content)-1]) + } + } + } + } + // Check endpoints of type CNAME are converted to ALIAS on the domain apex zlist, err = p.ConvertEndpointsToZones(endpointsApexRecords, PdnsReplace) assert.Nil(suite.T(), err)