Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: Implement support for PTR records #22

Merged
merged 2 commits into from
Nov 6, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
74 changes: 14 additions & 60 deletions internal/infoblox/common.go
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand All @@ -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()
Expand All @@ -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")
// }
// }
// }
//}
49 changes: 49 additions & 0 deletions internal/infoblox/infoblox.go
Original file line number Diff line number Diff line change
Expand Up @@ -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"
)
Expand Down Expand Up @@ -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))
Expand Down
9 changes: 3 additions & 6 deletions internal/infoblox/infoblox_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -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
}
Expand Down Expand Up @@ -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"),
Expand Down Expand Up @@ -845,7 +843,6 @@ func TestInfobloxApplyChanges(t *testing.T) {
}

func TestInfobloxApplyChangesReverse(t *testing.T) {
t.Skip()
client := mockIBConnector{}

testInfobloxApplyChangesInternal(t, false, true, &client)
Expand Down
Loading