Conversation
MaxRink
requested review from
Buzzglo,
TebogoTS,
ampie,
januarios,
k0da and
kuritka
as code owners
August 6, 2026 17:32
MaxRink
added a commit
to MaxRink/external-dns-infoblox-webhook
that referenced
this pull request
Aug 6, 2026
…ranch GitHub only registers a workflow, and therefore only evaluates its push-tag trigger, once the file has been seen on the repository default branch. tcaas-image.yaml existed solely on tcaas-main, so it was never registered: actions/workflows lists only the four upstream workflows and three -telekom.N tag pushes produced zero runs. Add the file to main so the trigger registers. Also add workflow_dispatch with an explicit ref input for on-demand rebuilds, and a guard that refuses to publish unless the resolved ref is a v*-telekom.* tag, so a dispatch from main cannot publish a misleading image tag. This file is fork-only and is deleted together with the rest of the bridge once upstream ships PRs AbsaOSS#69/AbsaOSS#70.
MaxRink
added a commit
to MaxRink/external-dns-infoblox-webhook
that referenced
this pull request
Aug 15, 2026
PR AbsaOSS#69 added AAAA records but deliberately left PTR creation to A records only, on the assumption that the reverse zone lookup was IPv4 specific. It turns out most of that machinery is already family agnostic: - rfc2317.CidrToInAddr already derives ip6.arpa nibble names for IPv6 CIDRs ("2001:db8::/64" -> "0.0.0.0.0.0.0.0.8.b.d.0.1.0.0.2.ip6.arpa"), so Records() needs no change to fetch PTR records from an IPv6 reverse zone. - findReverseZone uses net.ParseCIDR and net.IPNet.Contains, both of which already match IPv6 addresses against IPv6 reverse zones. What actually had to change: - ChangesByZone now derives the companion PTR change for AAAA endpoints as well as A endpoints, and AdjustEndpoints / Records() track the infoblox-ptr-record-exists property for AAAA endpoints too. - recordSet() addresses a PTR record through ipv6addr instead of ipv4addr when the target is an IPv6 address, both when building the object and when looking the existing object up. A record:ptr carries its target in exactly one of the two fields, never in both. - ToPTRResponseMap() falls back to Ipv6Addr when Ipv4Addr is empty, so PTR records read back from an ip6.arpa zone yield a target instead of an empty string. CreatePTR still gates all of this, so nothing changes for users who do not opt in. As before, the reverse zone has to be part of the DOMAIN_FILTER; the README documents the IPv6 CIDR form.
MaxRink
added a commit
to MaxRink/external-dns-infoblox-webhook
that referenced
this pull request
Aug 28, 2026
PR AbsaOSS#69 added AAAA records but deliberately left PTR creation to A records only, on the assumption that the reverse zone lookup was IPv4 specific. It turns out most of that machinery is already family agnostic: - rfc2317.CidrToInAddr already derives ip6.arpa nibble names for IPv6 CIDRs ("2001:db8::/64" -> "0.0.0.0.0.0.0.0.8.b.d.0.1.0.0.2.ip6.arpa"), so Records() needs no change to fetch PTR records from an IPv6 reverse zone. - findReverseZone uses net.ParseCIDR and net.IPNet.Contains, both of which already match IPv6 addresses against IPv6 reverse zones. What actually had to change: - ChangesByZone now derives the companion PTR change for AAAA endpoints as well as A endpoints, and AdjustEndpoints / Records() track the infoblox-ptr-record-exists property for AAAA endpoints too. - recordSet() addresses a PTR record through ipv6addr instead of ipv4addr when the target is an IPv6 address, both when building the object and when looking the existing object up. A record:ptr carries its target in exactly one of the two fields, never in both. - ToPTRResponseMap() falls back to Ipv6Addr when Ipv4Addr is empty, so PTR records read back from an ip6.arpa zone yield a target instead of an empty string. CreatePTR still gates all of this, so nothing changes for users who do not opt in. As before, the reverse zone has to be part of the DOMAIN_FILTER; the README documents the IPv6 CIDR form.
The provider previously fetched and reconciled only A, CNAME, TXT, NS, host and PTR records, so IPv6 services managed through ExternalDNS could never be reconciled against Infoblox: AAAA records already present in a zone were invisible to Records() and any AAAA endpoint in a plan was silently dropped by recordSet() because the switch had no matching case. This adds AAAA end-to-end, following the existing patterns for A records: - ToAAAAResponseMap() maps []ibclient.RecordAAAA onto the shared ResponseMap using the ibclient.AaaaRecord type constant. - Records() fetches record:aaaa per zone through PagingGetObject, the same way A records are fetched. - ToHostAAAAResponseMap() surfaces the Ipv6Addrs of host records as AAAA endpoints, mirroring how Ipv4Addrs are already surfaced as A endpoints. Both host mappers now skip records that carry no address of the respective family, so an IPv4-only or IPv6-only host record no longer yields an endpoint with an empty target. - recordSet() builds a RecordAAAA for create/update/delete and looks the existing object up by name and ipv6addr. - getRefID() resolves the object reference and log fields for RecordAAAA. Infoblox can return the same IPv6 address more than once for a name (the same address in a different but equivalent notation). Such duplicates would produce a permanently dirty plan, so ToAAAAResponseMap de-duplicates targets via the new ResponseDetails.Contains helper. PTR records for AAAA are deliberately not created: the reverse zone lookup path is built around IPv4 (rfc2317.CidrToInAddr) and ip6.arpa delegation would need separate handling. CreatePTR therefore keeps applying to A records only.
ToAAAAResponseMap skips a target that the response map already holds, to avoid a permanent diff in the plan. The comment says that this also covers the same address in a different notation, but the comparison was a plain string comparison, so it did not. Compare the canonical form of an IP target instead. Targets that are not IP addresses keep the plain string comparison.
MaxRink
force-pushed
the
feat/aaaa-record-support
branch
from
August 28, 2026 01:34
0641210 to
4f534b1
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Closes #37.
What
Adds AAAA (IPv6) records end-to-end, following the existing patterns for A records.
ToAAAAResponseMap()maps[]ibclient.RecordAAAAonto the sharedResponseMapusing theibclient.AaaaRecordtype constant.Records()fetchesrecord:aaaaper zone throughPagingGetObject, the same way A records are fetched (sameView/Ea/Zonehandling,isNotFoundErrortolerance andFailedApiCallsTotalaccounting).ToHostAAAAResponseMap()surfaces theIpv6Addrsof host records as AAAA endpoints, mirroring howIpv4Addrsalready become A endpoints. Both host mappers now skip records carrying no address of the respective family, so an IPv4-only or IPv6-only host record no longer yields an endpoint with an empty target.recordSet()builds aRecordAAAAfor create/update/delete, looking the existing object up byname+ipv6addr.getRefID()resolves the object reference and log fields forRecordAAAA.Infoblox can return the same IPv6 address more than once for a name (the same address in a different but equivalent notation). Left alone that produces a permanently dirty plan, so
ToAAAAResponseMapde-duplicates targets via a newResponseDetails.Containshelper.Why
The provider handled A, CNAME, TXT, NS, host and PTR records only. Two consequences today:
Records().recordSet()— theswitch ep.RecordTypehas no matching case, so it returns a zero value witherr == nil. No error surfaces; the record simply never gets created.So IPv6 services managed through ExternalDNS could not be reconciled against Infoblox at all.
Not included
PTR records are still created for A records only. The reverse-zone path is IPv4-oriented (
rfc2317.CidrToInAddr,net.ParseCIDR+Contains, andrecord:ptrkeyed onipv4addr);ip6.arpanibble-zone delegation needs separate handling and is better as its own change. Getting it half-right would create broken reverse records.Testing
internal/infoblox/infoblox_test.goextends the existing mock connector (create/get/delete/update cases, the paging response type, object factories, plus a new host-record factory taking IPv4 and IPv6 address lists) and covers:record:aaaaGetObject request and query params, in both the plain andviewvariantsApplyChanges, including in-filter and out-of-filter domains and the reverse/PTR variantgo build,go vet,go test ./...andgolangci-lint run ./...(0 issues) all pass;mainwas verified green beforehand so nothing pre-existing is attributed here.The new tests were mutation-checked to confirm they actually assert the new behaviour: removing the AAAA fetch, the de-duplication guard, or the
recordSetAAAA case each makes them fail.Also adds AAAA to the supported-records table in the README.
Context
We maintain a fork of external-dns carrying an equivalent AAAA patch against the old in-tree Infoblox provider (removed upstream in v0.15.0). Contributing it here instead lets us drop that fork and consume stock upstream external-dns — which is why the implementation deliberately follows this repo's conventions rather than porting the old provider's shape.