From ca1cbafb48379eecee06294f050f6f5cd2fec0cc Mon Sep 17 00:00:00 2001 From: Thom Wijtenburg Date: Wed, 6 Nov 2024 16:32:17 +0100 Subject: [PATCH] feat: Implement support for PTR records (#22) * feat: Implement PTR records * fix: fix linter errors --- internal/infoblox/common.go | 74 ++++++------------------------ internal/infoblox/infoblox.go | 49 ++++++++++++++++++++ internal/infoblox/infoblox_test.go | 9 ++-- 3 files changed, 66 insertions(+), 66 deletions(-) diff --git a/internal/infoblox/common.go b/internal/infoblox/common.go index 15220a7..fb11a89 100644 --- a/internal/infoblox/common.go +++ b/internal/infoblox/common.go @@ -101,31 +101,20 @@ func ToHostResponseMap(res []ibclient.HostRecord) *ResponseMap { return rm } -// TODO: ToPTRResponseMap -//if p.createPTR { -// // infoblox doesn't accept reverse zone's fqdn, and instead expects .in-addr.arpa zone -// // so convert our zone fqdn (if it is a correct cidr block) into in-addr.arpa address and pass that into infoblox -// // example: 10.196.38.0/24 becomes 38.196.10.in-addr.arpa -// arpaZone, err := transform.ReverseDomainName(zone.Fqdn) -// if err == nil { -// var resP []ibclient.RecordPTR -// objP := ibclient.NewEmptyRecordPTR() -// objP.Zone = arpaZone -// objP.View = p.view -// err = p.client.GetObject(objP, "", searchParams, &resP) -// if err != nil && !isNotFoundError(err) { -// return nil, fmt.Errorf("could not fetch PTR records from zone '%s': %w", zone.Fqdn, err) -// } -// for _, res := range resP { -// endpoints = append(endpoints, endpoint.NewEndpointWithTTL(res.PtrdName, -// endpoint.RecordTypePTR, -// endpoint.TTL(int(res.Ttl)), -// res.Ipv4Addr, -// ), -// ) -// } -// } -//} +func ToPTRResponseMap(res []ibclient.RecordPTR) *ResponseMap { + rm := &ResponseMap{ + Map: make(map[string]ResponseDetails), + RecordType: ibclient.PtrRecord, + } + for _, record := range res { + if _, ok := rm.Map[AsString(record.PtrdName)]; !ok { + rm.Map[AsString(record.PtrdName)] = ResponseDetails{{Target: AsString(record.Ipv4Addr), TTL: AsInt64(record.Ttl)}} + continue + } + rm.Map[AsString(record.PtrdName)] = append(rm.Map[AsString(record.PtrdName)], ResponseDetail{Target: AsString(record.Ipv4Addr), TTL: AsInt64(record.Ttl)}) + } + return rm +} func (rd ResponseDetails) ToEndpointDetail() (targets []string, ttl endpoint.TTL) { for _, v := range rd { @@ -136,10 +125,6 @@ func (rd ResponseDetails) ToEndpointDetail() (targets []string, ttl endpoint.TTL } func (rm *ResponseMap) ToEndpoints() []*endpoint.Endpoint { - // TODO: PTR provider specific label records - // if p.createPTR { - // newEndpoint.WithProviderSpecific(providerSpecificInfobloxPtrRecord, "true") - // } var endpoints []*endpoint.Endpoint for k, v := range rm.Map { targets, ttl := v.ToEndpointDetail() @@ -149,34 +134,3 @@ func (rm *ResponseMap) ToEndpoints() []*endpoint.Endpoint { } return endpoints } - -// TODO: update A records that have PTR record created for them already -//if p.createPTR { -// // save all ptr records into map for a quick look up -// ptrRecordsMap := make(map[string]bool) -// for _, ptrRecord := range endpoints { -// if ptrRecord.RecordType != endpoint.RecordTypePTR { -// continue -// } -// ptrRecordsMap[ptrRecord.DNSName] = true -// } -// -// for i := range endpoints { -// if endpoints[i].RecordType != endpoint.RecordTypeA { -// continue -// } -// // if PTR record already exists for A record, then mark it as such -// if ptrRecordsMap[endpoints[i].DNSName] { -// found := false -// for j := range endpoints[i].ProviderSpecific { -// if endpoints[i].ProviderSpecific[j].Name == providerSpecificInfobloxPtrRecord { -// endpoints[i].ProviderSpecific[j].Value = "true" -// found = true -// } -// } -// if !found { -// endpoints[i].WithProviderSpecific(providerSpecificInfobloxPtrRecord, "true") -// } -// } -// } -//} diff --git a/internal/infoblox/infoblox.go b/internal/infoblox/infoblox.go index 71e0e61..88e45d6 100644 --- a/internal/infoblox/infoblox.go +++ b/internal/infoblox/infoblox.go @@ -32,6 +32,7 @@ import ( log "github.com/sirupsen/logrus" "sigs.k8s.io/external-dns/endpoint" + "sigs.k8s.io/external-dns/pkg/rfc2317" "sigs.k8s.io/external-dns/plan" "sigs.k8s.io/external-dns/provider" ) @@ -240,6 +241,54 @@ func (p *Provider) Records(_ context.Context) (endpoints []*endpoint.Endpoint, e } endpointsTXT := ToTXTResponseMap(resT).ToEndpoints() endpoints = append(endpoints, endpointsTXT...) + + if p.config.CreatePTR { + arpaZone, err := rfc2317.CidrToInAddr(zone.Fqdn) + if err == nil { + var resP []ibclient.RecordPTR + objP := ibclient.NewEmptyRecordPTR() + objP.View = p.config.View + objP.Zone = arpaZone + err = PagingGetObject(p.client, objP, "", map[string]string{"zone": arpaZone, "view": p.config.View}, &resP) + if err != nil && !isNotFoundError(err) { + return nil, fmt.Errorf("could not fetch PTR records from zone '%s': %w", zone.Fqdn, err) + } + endpointsPTR := ToPTRResponseMap(resP).ToEndpoints() + endpoints = append(endpoints, endpointsPTR...) + } else { + log.Debugf("Could not fetch PTR records from zone '%s': %s", zone.Fqdn, err) + } + } + } + + if p.config.CreatePTR { + // save all ptr records into map for a quick look up + ptrRecordsMap := make(map[string]bool) + for _, ptrRecord := range endpoints { + if ptrRecord.RecordType != endpoint.RecordTypePTR { + continue + } + ptrRecordsMap[ptrRecord.DNSName] = true + } + + for i := range endpoints { + if endpoints[i].RecordType != endpoint.RecordTypeA { + continue + } + // if PTR record already exists for A record, then mark it as such + if ptrRecordsMap[endpoints[i].DNSName] { + found := false + for j := range endpoints[i].ProviderSpecific { + if endpoints[i].ProviderSpecific[j].Name == providerSpecificInfobloxPtrRecord { + endpoints[i].ProviderSpecific[j].Value = "true" + found = true + } + } + if !found { + endpoints[i].WithProviderSpecific(providerSpecificInfobloxPtrRecord, "true") + } + } + } } log.Debugf("fetched %d records from infoblox", len(endpoints)) diff --git a/internal/infoblox/infoblox_test.go b/internal/infoblox/infoblox_test.go index d9076bc..e68a69b 100644 --- a/internal/infoblox/infoblox_test.go +++ b/internal/infoblox/infoblox_test.go @@ -339,12 +339,11 @@ func (client *mockIBConnector) GetObject(obj ibclient.IBObject, ref string, quer ref != object.(*ibclient.RecordPTR).Ref { continue } - if *obj.(*ibclient.RecordPTR).PtrdName != "" && - obj.(*ibclient.RecordPTR).PtrdName != object.(*ibclient.RecordPTR).PtrdName { + if AsString(obj.(*ibclient.RecordPTR).PtrdName) != "" && + AsString(obj.(*ibclient.RecordPTR).PtrdName) != AsString(object.(*ibclient.RecordPTR).PtrdName) { continue } - // TODO: - if !strings.Contains(req.queryParams, fmt.Sprintf("ipv4addr:%s name:%s", AsString(object.(*ibclient.RecordPTR).Ipv4Addr), AsString(object.(*ibclient.RecordPTR).Name))) { + if !strings.Contains(req.queryParams, fmt.Sprintf("name:%s", AsString(object.(*ibclient.RecordPTR).Name))) { if !strings.Contains(req.queryParams, fmt.Sprintf("zone:%s", object.(*ibclient.RecordPTR).Zone)) { continue } @@ -790,7 +789,6 @@ func TestInfobloxAdjustEndpoints(t *testing.T) { } func TestInfobloxRecordsReverse(t *testing.T) { - t.Skip() client := mockIBConnector{ mockInfobloxZones: &[]ibclient.ZoneAuth{ createMockInfobloxZone("10.0.0.0/24"), @@ -845,7 +843,6 @@ func TestInfobloxApplyChanges(t *testing.T) { } func TestInfobloxApplyChangesReverse(t *testing.T) { - t.Skip() client := mockIBConnector{} testInfobloxApplyChangesInternal(t, false, true, &client)