Skip to content

CORS-4372: Create IPv6 records for GCP#1410

Open
barbacbd wants to merge 1 commit into
openshift:masterfrom
barbacbd:CORS-4372
Open

CORS-4372: Create IPv6 records for GCP#1410
barbacbd wants to merge 1 commit into
openshift:masterfrom
barbacbd:CORS-4372

Conversation

@barbacbd
Copy link
Copy Markdown
Contributor

@barbacbd barbacbd commented Apr 2, 2026

pkg/util/aws/dualstack.go:

  • Removed the "aws specific" capability of determining stack type

pkg/util/ipfamily/ipfamily.go:

  • Created the common function to determine stack type dynamically.

pkg/util/ipfamily/ipfamily_test.go:

  • Generated tests for the stack determination

pkg/dns/gcp/provider.go:

  • Added dual-stack DNS support for GCP *.apps records

pkg/operator/controller/dns/controller.go:

  • Add IP family to the controller call.

pkg/util/aws/dualstack.go:

- Removed the "aws specific" capability of determining stack type

pkg/util/ipfamily/ipfamily.go:

- Created the common function to determine stack type dynamically.

pkg/util/ipfamily/ipfamily_test.go:

- Generated tests for the stack determination

pkg/dns/gcp/provider.go:

- Added dual-stack DNS support for GCP *.apps records

pkg/operator/controller/dns/controller.go:

- Add IP family to the controller call.
@openshift-ci-robot openshift-ci-robot added the jira/valid-reference Indicates that this PR references a valid Jira ticket of any type. label Apr 2, 2026
@openshift-ci-robot
Copy link
Copy Markdown
Contributor

openshift-ci-robot commented Apr 2, 2026

@barbacbd: This pull request references CORS-4372 which is a valid jira issue.

Warning: The referenced jira issue has an invalid target version for the target branch this PR targets: expected the story to target the "4.22.0" version, but no target version was set.

Details

In response to this:

pkg/util/aws/dualstack.go:

  • Removed the "aws specific" capability of determining stack type

pkg/util/ipfamily/ipfamily.go:

  • Created the common function to determine stack type dynamically.

pkg/util/ipfamily/ipfamily_test.go:

  • Generated tests for the stack determination

pkg/dns/gcp/provider.go:

  • Added dual-stack DNS support for GCP *.apps records

pkg/operator/controller/dns/controller.go:

  • Add IP family to the controller call.

Instructions for interacting with me using PR comments are available here. If you have questions or suggestions related to my behavior, please file an issue against the openshift-eng/jira-lifecycle-plugin repository.

@barbacbd
Copy link
Copy Markdown
Contributor Author

barbacbd commented Apr 2, 2026

/hold

@openshift-ci openshift-ci Bot added the do-not-merge/hold Indicates that a PR should not merge because someone has issued a /hold command. label Apr 2, 2026
@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented Apr 2, 2026

📝 Walkthrough

Walkthrough

The changes add dual-stack DNS record support to the GCP provider by introducing an IPFamily configuration field and implementing conditional record creation. The GCP provider now filters targets by IP version (IPv4/IPv6) to generate appropriate A and AAAA records when dual-stack is enabled. A new ipfamily utility package provides an IsDualStack function that centralizes dual-stack detection logic. The DNS controller initializes this field when creating GCP providers. Helper functions filter IP addresses by version, and the Replace operation was refactored to batch delete records instead of paginating one-by-one.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Comment @coderabbitai help to get the list of available commands and usage tips.

@openshift-ci openshift-ci Bot requested review from candita and davidesalerno April 2, 2026 12:02
@openshift-ci
Copy link
Copy Markdown
Contributor

openshift-ci Bot commented Apr 2, 2026

[APPROVALNOTIFIER] This PR is NOT APPROVED

This pull-request has been approved by:
Once this PR has been reviewed and has the lgtm label, please assign rfredette for approval. For more information see the Code Review Process.

The full list of commands accepted by this bot can be found here.

Details Needs approval from an approver in each of these files:

Approvers can indicate their approval by writing /approve in a comment
Approvers can cancel approval by writing /approve cancel in a comment

Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🧹 Nitpick comments (2)
pkg/util/ipfamily/ipfamily_test.go (1)

9-45: Consider adding a test case for IPv6.

The test covers IPv4 but not the single-stack IPv6 case (configv1.IPv6). While not critical, adding this case would ensure complete coverage of all expected IPFamilyType values.

Suggested addition
 		{
 			name:     "IPv4 is not dual-stack",
 			ipFamily: configv1.IPv4,
 			expected: false,
 		},
+		{
+			name:     "IPv6 is not dual-stack",
+			ipFamily: configv1.IPv6,
+			expected: false,
+		},
 		{
 			name:     "DualStackIPv4Primary is dual-stack",
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@pkg/util/ipfamily/ipfamily_test.go` around lines 9 - 45, TestIsDualStack is
missing a case for single-stack IPv6; add a table-driven test entry with name
like "IPv6 is not dual-stack", ipFamily: configv1.IPv6 and expected: false so
IsDualStack(configv1.IPv6) is asserted; update the tests slice in
TestIsDualStack to include this new struct entry (refer to the TestIsDualStack
function and the tests []struct with fields name, ipFamily, expected).
pkg/dns/gcp/provider_dualstack_test.go (1)

107-139: Replace the trivial TestConfigIPFamily with tests for actual dual-stack behavior.

The TestConfigIPFamily test only verifies struct field assignment, which Go guarantees. Meanwhile, the Ensure, Replace, and Delete methods contain the actual dual-stack logic (filtering IPv4/IPv6, creating/deleting separate A and AAAA records) but have no test coverage. Since this file is specifically for dual-stack testing, it should prioritize tests for these main methods instead.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@pkg/dns/gcp/provider_dualstack_test.go` around lines 107 - 139, Replace the
trivial TestConfigIPFamily with table-driven tests that exercise the actual
dual-stack logic in Ensure, Replace, and Delete rather than just struct
assignment: write tests that construct a Config (with IPFamily set to
configv1.IPv4, configv1.IPv6/DualStackIPv4Primary/DualStackIPv6Primary) and call
Config.Ensure, Config.Replace, and Config.Delete using a mocked GCP DNS client
to assert that the code filters addresses correctly and issues the expected A
and/or AAAA record create/update/delete calls (check calls or requests made by
the mock), and include cases that validate separate handling of IPv4 vs IPv6
records and order/primary behavior; reference Config, Ensure, Replace, Delete
and the IPFamily values when implementing these tests.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@pkg/dns/gcp/provider.go`:
- Around line 230-237: The Delete branch currently always constructs deletions
for A records even when a target is IPv6-only and dual-stack mode is disabled
(mirroring the Ensure issue); update Delete in pkg/dns/gcp/provider.go (the
Delete method) to detect the same condition that Ensure uses for A records with
IPv6-only targets and, when dual-stack is not enabled, skip creating/deleting
the malformed A record (no-op) instead of calling resourceRecordSet(record);
keep the existing http.StatusNotFound handling unchanged so behavior remains
consistent with Ensure.
- Around line 125-132: The current logic in the block handling RecordType ==
ARecordType falls back to resourceRecordSet(record) even when targets are
IPv6-only, which would produce invalid A records; update the code in the
provider.go path that builds additions (the branch that sets additions =
[]*gdnsv1.ResourceRecordSet{resourceRecordSet(record)}) to detect when
RecordType == ARecordType and the record's Targets contain only IPv6 addresses
(no IPv4), and in that case either (a) construct an AAAA record instead (convert
RecordType to AAAA and call resourceRecordSet on a modified record) or (b) skip
creating the record and emit a warning via the logger; ensure the check
references RecordType, ARecordType, IPFamily/dual-stack logic and uses
resourceRecordSet(record) only for valid IPv4 targets.

---

Nitpick comments:
In `@pkg/dns/gcp/provider_dualstack_test.go`:
- Around line 107-139: Replace the trivial TestConfigIPFamily with table-driven
tests that exercise the actual dual-stack logic in Ensure, Replace, and Delete
rather than just struct assignment: write tests that construct a Config (with
IPFamily set to configv1.IPv4,
configv1.IPv6/DualStackIPv4Primary/DualStackIPv6Primary) and call Config.Ensure,
Config.Replace, and Config.Delete using a mocked GCP DNS client to assert that
the code filters addresses correctly and issues the expected A and/or AAAA
record create/update/delete calls (check calls or requests made by the mock),
and include cases that validate separate handling of IPv4 vs IPv6 records and
order/primary behavior; reference Config, Ensure, Replace, Delete and the
IPFamily values when implementing these tests.

In `@pkg/util/ipfamily/ipfamily_test.go`:
- Around line 9-45: TestIsDualStack is missing a case for single-stack IPv6; add
a table-driven test entry with name like "IPv6 is not dual-stack", ipFamily:
configv1.IPv6 and expected: false so IsDualStack(configv1.IPv6) is asserted;
update the tests slice in TestIsDualStack to include this new struct entry
(refer to the TestIsDualStack function and the tests []struct with fields name,
ipFamily, expected).
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository YAML (base), Organization UI (inherited)

Review profile: CHILL

Plan: Pro

Run ID: 67f53d13-2707-4a92-9f73-ddbaf2c1f3d8

📥 Commits

Reviewing files that changed from the base of the PR and between 3c1da4b and c5a6090.

📒 Files selected for processing (6)
  • pkg/dns/gcp/provider.go
  • pkg/dns/gcp/provider_dualstack_test.go
  • pkg/operator/controller/dns/controller.go
  • pkg/util/aws/dualstack.go
  • pkg/util/ipfamily/ipfamily.go
  • pkg/util/ipfamily/ipfamily_test.go

Comment thread pkg/dns/gcp/provider.go
Comment on lines +125 to +132
} else {
// Not dual-stack, create A record as-is.
additions = []*gdnsv1.ResourceRecordSet{resourceRecordSet(record)}
}
} else {
// For non-A records (CNAME, etc.), create the record as-is.
additions = []*gdnsv1.ResourceRecordSet{resourceRecordSet(record)}
}
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Potential issue: IPv6-only targets may create invalid A records.

When RecordType is ARecordType and targets contain only IPv6 addresses (no IPv4), but IPFamily is not dual-stack, the code falls through to line 127 and calls resourceRecordSet(record). This creates an A record with IPv6 addresses in Rrdatas, which is invalid—IPv6 addresses must be in AAAA records.

Consider handling this edge case by checking if targets contain only IPv6 addresses and creating an AAAA record instead, or skipping record creation entirely with a warning.

Suggested fix
 	} else {
-		// Not dual-stack, create A record as-is.
-		additions = []*gdnsv1.ResourceRecordSet{resourceRecordSet(record)}
+		// Not dual-stack. Create A record with IPv4 targets only.
+		// If there are IPv6 targets but no IPv4, this is unexpected for A record type.
+		if len(ipv4Targets) > 0 {
+			aRecord := &gdnsv1.ResourceRecordSet{
+				Name:    record.Spec.DNSName,
+				Rrdatas: ipv4Targets,
+				Type:    "A",
+				Ttl:     record.Spec.RecordTTL,
+			}
+			additions = append(additions, aRecord)
+		} else if len(ipv6Targets) > 0 {
+			log.Info("A record requested but only IPv6 targets found, skipping", "record", record.Spec.DNSName)
+		}
 	}
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@pkg/dns/gcp/provider.go` around lines 125 - 132, The current logic in the
block handling RecordType == ARecordType falls back to resourceRecordSet(record)
even when targets are IPv6-only, which would produce invalid A records; update
the code in the provider.go path that builds additions (the branch that sets
additions = []*gdnsv1.ResourceRecordSet{resourceRecordSet(record)}) to detect
when RecordType == ARecordType and the record's Targets contain only IPv6
addresses (no IPv4), and in that case either (a) construct an AAAA record
instead (convert RecordType to AAAA and call resourceRecordSet on a modified
record) or (b) skip creating the record and emit a warning via the logger;
ensure the check references RecordType, ARecordType, IPFamily/dual-stack logic
and uses resourceRecordSet(record) only for valid IPv4 targets.

Comment thread pkg/dns/gcp/provider.go
Comment on lines +230 to +237
} else {
// Not dual-stack, delete A record as-is.
deletions = []*gdnsv1.ResourceRecordSet{resourceRecordSet(record)}
}
} else {
// For non-A records (CNAME, etc.), delete the record as-is.
deletions = []*gdnsv1.ResourceRecordSet{resourceRecordSet(record)}
}
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

Same concern applies here: IPv6-only targets with non-dual-stack config.

This mirrors the issue in Ensure. However, since Delete gracefully handles http.StatusNotFound on line 247, attempting to delete a non-existent malformed record won't cause failures—it will just silently succeed. Consider aligning the fix with Ensure for consistency.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@pkg/dns/gcp/provider.go` around lines 230 - 237, The Delete branch currently
always constructs deletions for A records even when a target is IPv6-only and
dual-stack mode is disabled (mirroring the Ensure issue); update Delete in
pkg/dns/gcp/provider.go (the Delete method) to detect the same condition that
Ensure uses for A records with IPv6-only targets and, when dual-stack is not
enabled, skip creating/deleting the malformed A record (no-op) instead of
calling resourceRecordSet(record); keep the existing http.StatusNotFound
handling unchanged so behavior remains consistent with Ensure.

@openshift-ci
Copy link
Copy Markdown
Contributor

openshift-ci Bot commented Apr 2, 2026

@barbacbd: The following tests failed, say /retest to rerun all failed tests or /retest-required to rerun all mandatory failed tests:

Test name Commit Details Required Rerun command
ci/prow/e2e-aws-ovn-hypershift-conformance c5a6090 link true /test e2e-aws-ovn-hypershift-conformance
ci/prow/e2e-aws-operator-techpreview c5a6090 link false /test e2e-aws-operator-techpreview
ci/prow/hypershift-e2e-aks c5a6090 link true /test hypershift-e2e-aks
ci/prow/e2e-aws-ovn-serial-1of2 c5a6090 link true /test e2e-aws-ovn-serial-1of2
ci/prow/e2e-aws-ovn c5a6090 link true /test e2e-aws-ovn

Full PR test history. Your PR dashboard.

Details

Instructions for interacting with me using PR comments are available here. If you have questions or suggestions related to my behavior, please file an issue against the kubernetes-sigs/prow repository. I understand the commands that are listed here.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

do-not-merge/hold Indicates that a PR should not merge because someone has issued a /hold command. jira/valid-reference Indicates that this PR references a valid Jira ticket of any type.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants