Skip to content

OCPCLOUD-3074: Validate Azure dual-stack load balancers - #31452

Open
bandrade wants to merge 3 commits into
openshift:mainfrom
bandrade:ocpcloud-3074-azure-dualstack-ccm-e2e
Open

OCPCLOUD-3074: Validate Azure dual-stack load balancers#31452
bandrade wants to merge 3 commits into
openshift:mainfrom
bandrade:ocpcloud-3074-azure-dualstack-ccm-e2e

Conversation

@bandrade

@bandrade bandrade commented Jul 29, 2026

Copy link
Copy Markdown
Contributor

What changed

  • add an Azure-only dual-stack CCM end-to-end test
  • create public and internal RequireDualStack LoadBalancer Services
  • require exactly one IPv4 and one IPv6 ingress address on each Service
  • verify HTTP connectivity through all four load-balancer addresses
  • wait for Service finalizer cleanup and retry transient Kubernetes API errors

Why

This provides the targeted automation requested by
OCPCLOUD-3074 and complements
the manual Azure dual-stack validation performed for
openshift/installer#10656.

The test is selected by [Suite:openshift/conformance/parallel] and is gated by
the AzureDualStackInstall feature gate, so the existing IPv4-primary and
IPv6-primary Azure optional jobs can exercise it.

Validation

  • go test ./test/extended/cloud_controller_manager
  • go vet ./test/extended/cloud_controller_manager
  • make openshift-tests
  • confirmed the test is discovered in [Suite:openshift/conformance/parallel]

Summary by CodeRabbit

  • Tests
    • Added an end-to-end Azure dual-stack (IPv4/IPv6) networking test covering backend readiness and load balancer reachability.
    • Validates the backend Deployment’s readiness probe exists and performs an HTTP GET against the backend port.
    • Ensures both public and internal load balancer Services publish exactly one IPv4 and one IPv6 ingress.
    • Verifies connectivity to each ingress by issuing HTTP requests to /hostname from a probe running on the control-plane.
    • Improves retry timing and cleanup to reduce flakiness.

@openshift-merge-bot

Copy link
Copy Markdown
Contributor

Pipeline controller notification
This repo is configured to use the pipeline controller. Second-stage tests will be triggered either automatically or after lgtm label is added, depending on the repository configuration. The pipeline controller will automatically detect which contexts are required and will utilize /test Prow commands to trigger the second stage.

For optional jobs, comment /test ? to see a list of all defined jobs. To trigger manually all jobs from second stage use /pipeline required command.

This repository is configured in: automatic mode

@openshift-ci

openshift-ci Bot commented Jul 29, 2026

Copy link
Copy Markdown
Contributor

Skipping CI for Draft Pull Request.
If you want CI signal for your change, please convert it to an actual PR.
You can still manually trigger a test run with /test all

@openshift-ci-robot

openshift-ci-robot commented Jul 29, 2026

Copy link
Copy Markdown

@bandrade: This pull request references OCPCLOUD-3074 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 "5.0.0" version, but no target version was set.

Details

In response to this:

What changed

  • add an Azure-only dual-stack CCM end-to-end test
  • create public and internal RequireDualStack LoadBalancer Services
  • require exactly one IPv4 and one IPv6 ingress address on each Service
  • verify HTTP connectivity through all four load-balancer addresses
  • wait for Service finalizer cleanup and retry transient Kubernetes API errors

Why

This provides the targeted automation requested by
OCPCLOUD-3074 and complements
the manual Azure dual-stack validation performed for
openshift/installer#10656.

The test is selected by [Suite:openshift/conformance/parallel] and is gated by
the AzureDualStackInstall feature gate, so the existing IPv4-primary and
IPv6-primary Azure optional jobs can exercise it.

Validation

  • go test ./test/extended/cloud_controller_manager
  • go vet ./test/extended/cloud_controller_manager
  • make openshift-tests
  • confirmed the test is discovered in [Suite:openshift/conformance/parallel]

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.

@openshift-ci-robot openshift-ci-robot added the jira/valid-reference Indicates that this PR references a valid Jira ticket of any type. label Jul 29, 2026
@openshift-ci openshift-ci Bot added the do-not-merge/work-in-progress Indicates that a PR should not merge because it is a work in progress. label Jul 29, 2026
@coderabbitai

coderabbitai Bot commented Jul 29, 2026

Copy link
Copy Markdown

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Repository YAML (base), Central YAML (inherited)

Review profile: CHILL

Plan: Pro Plus

Run ID: 7242a7a5-1f58-40c1-b558-aa1921221750

📥 Commits

Reviewing files that changed from the base of the PR and between 59a8a83 and d7b1fed.

📒 Files selected for processing (1)
  • test/extended/cloud_controller_manager/azure_dualstack.go

Walkthrough

Adds an Azure dual-stack end-to-end test that deploys a readiness-probed backend, creates public and internal LoadBalancer Services, validates IPv4 and IPv6 ingress publication and reachability, and performs context-aware cleanup.

Changes

Azure dual-stack validation

Layer / File(s) Summary
Dual-stack service provisioning
test/extended/cloud_controller_manager/azure_dualstack.go
Deploys the readiness-probed backend and creates public and internal Azure dual-stack LoadBalancer Services.
Ingress publication and connectivity
test/extended/cloud_controller_manager/azure_dualstack.go
Waits for exactly one IPv4 and one IPv6 ingress, selects an eligible ready control-plane node, and probes each ingress through a host-networked Pod.
Context-aware service cleanup
test/extended/cloud_controller_manager/azure_dualstack.go
Deletes Services with an extended timeout derived from the caller’s context, retries transient errors, and waits for removal.

Estimated code review effort: 4 (Complex) | ~45 minutes

Sequence Diagram(s)

sequenceDiagram
  participant GinkgoTest
  participant KubernetesAPI
  participant AzureLoadBalancer
  participant ProbePod
  GinkgoTest->>KubernetesAPI: Create readiness-probed backend
  GinkgoTest->>KubernetesAPI: Create public and internal dual-stack Services
  KubernetesAPI->>AzureLoadBalancer: Provision load balancers
  AzureLoadBalancer-->>KubernetesAPI: Publish IPv4 and IPv6 ingress addresses
  GinkgoTest->>KubernetesAPI: Poll Service state
  GinkgoTest->>ProbePod: Execute curl for each ingress address
  ProbePod->>AzureLoadBalancer: Request /hostname
  AzureLoadBalancer-->>ProbePod: Return backend response
  GinkgoTest->>KubernetesAPI: Delete Services and wait for removal
Loading

Suggested reviewers: maysamacedo, joelspeed


Caution

Pre-merge checks failed

Please resolve all errors before merging. Addressing warnings is optional.

  • Ignore

❌ Failed checks (1 error, 1 warning)

Check name Status Explanation Resolution
Container-Privileges ❌ Error The new probe pod explicitly sets pod.Spec.HostNetwork = true, which is a disallowed container/K8s privilege setting under this check. Remove hostNetwork from the pod spec, or justify it only if the check explicitly allows this exception; otherwise use a non-host-networked probe.
Test Structure And Quality ⚠️ Warning The test has good timeouts and cleanup, but several bare HaveOccurred assertions remain and setup/teardown live in the It instead of BeforeEach/AfterEach. Add failure messages to the remaining assertions and refactor setup/cleanup into BeforeEach/AfterEach (or align with repo conventions) for clearer, consistent structure.
✅ Passed checks (13 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly summarizes the main change: an Azure dual-stack load balancer validation test.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Stable And Deterministic Test Names ✅ Passed The only Ginkgo title is a static literal; it contains no generated names, IPs, dates, or other run-specific values.
Microshift Test Compatibility ✅ Passed The new Ginkgo test is tagged [apigroup:config.openshift.io], which MicroShift CI auto-skips, so its OpenShift API usage is covered.
Single Node Openshift (Sno) Test Compatibility ✅ Passed No distinct multi-node or HA requirement is encoded; it only uses one ready control-plane node and can run with all pods on a single node.
Topology-Aware Scheduling Compatibility ✅ Passed The new test only pins a probe pod to a ready control-plane node after skipping External topology; it adds no replica, affinity, spread, or worker-only assumptions.
Ote Binary Stdout Contract ✅ Passed No process-level stdout writes or suite hooks were added; logging is confined to It blocks and helpers.
Ipv6 And Disconnected Network Test Compatibility ✅ Passed Uses net.JoinHostPort and explicit IPv4/IPv6 handling; no hardcoded IPv4-only assumptions or public internet dependencies found.
No-Weak-Crypto ✅ Passed The added Azure dual-stack test contains no MD5/SHA1/DES/RC4/3DES/Blowfish/ECB use, custom crypto, or secret/token comparisons.
No-Sensitive-Data-In-Logs ✅ Passed No added logs expose credentials, PII, or internal hostnames; logging is limited to test names, counts, and generic retry messages.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

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

@openshift-ci

openshift-ci Bot commented Jul 29, 2026

Copy link
Copy Markdown
Contributor

[APPROVALNOTIFIER] This PR is NOT APPROVED

This pull-request has been approved by: bandrade
Once this PR has been reviewed and has the lgtm label, please assign maysamacedo 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

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

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)
test/extended/cloud_controller_manager/azure_dualstack.go (2)

263-265: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Cleanup discards the spec context instead of detaching cancellation from it. deleteAzureLoadBalancerServicesAndWait fabricates a fresh context.Background(), so framework/audit values carried on the spec context are lost during cleanup; the call site compounds this by registering a DeferCleanup closure with no ctx parameter.

  • test/extended/cloud_controller_manager/azure_dualstack.go#L263-L265: accept ctx context.Context and derive the bounded cleanup context with context.WithTimeout(context.WithoutCancel(ctx), …) instead of context.Background().
  • test/extended/cloud_controller_manager/azure_dualstack.go#L92-L95: change the closure to func(ctx context.Context) and forward ctx to the helper, matching the other two DeferCleanup blocks at Line 77 and Line 117.
♻️ Proposed change
-		g.DeferCleanup(func() {
-			err := deleteAzureLoadBalancerServicesAndWait(client, namespace, serviceNames...)
+		g.DeferCleanup(func(ctx context.Context) {
+			err := deleteAzureLoadBalancerServicesAndWait(ctx, client, namespace, serviceNames...)
 			o.Expect(err).NotTo(o.HaveOccurred())
 		})
-func deleteAzureLoadBalancerServicesAndWait(client kubernetes.Interface, namespace string, names ...string) error {
-	ctx, cancel := context.WithTimeout(context.Background(), 10*time.Minute)
-	defer cancel()
+func deleteAzureLoadBalancerServicesAndWait(ctx context.Context, client kubernetes.Interface, namespace string, names ...string) error {
+	// Detach cancellation so cleanup still runs after the spec context is canceled, but keep it bounded.
+	ctx, cancel := context.WithTimeout(context.WithoutCancel(ctx), 10*time.Minute)
+	defer cancel()

Based on learnings, avoid switching to context.Background() for deferred cleanup that must run after the spec context is canceled; instead detach cancellation with context.WithoutCancel(ctx) and apply an explicit timeout.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@test/extended/cloud_controller_manager/azure_dualstack.go` around lines 263 -
265, Update deleteAzureLoadBalancerServicesAndWait to accept a context.Context
and derive its 10-minute timeout from context.WithoutCancel(ctx) rather than
context.Background(), preserving context values while allowing cleanup after
cancellation. At the call site, change the DeferCleanup closure to accept ctx
context.Context and forward it to the helper; no direct changes are needed at
the other DeferCleanup blocks.

Source: Learnings


122-127: 🩺 Stability & Availability | 🔵 Trivial | ⚡ Quick win

Consider a shared deadline for both LoadBalancer waits.

GetServiceLoadBalancerCreationTimeout returns up to 45m on larger clusters, and each service consumes that budget independently here; combined with four 5m probes this can blow past the declared [Timeout:45m] and surface as an opaque spec timeout. Both services are created up-front, so a single bounded context for the whole wait phase is sufficient.

♻️ Sketch
+		lbCtx, cancelLB := context.WithTimeout(ctx, e2eservice.GetServiceLoadBalancerCreationTimeout(ctx, client))
+		defer cancelLB()
 		for i, service := range services {
 			g.By(fmt.Sprintf("waiting for %s to publish IPv4 and IPv6 ingress addresses", service.Name))
-			service, err = waitForAzureDualStackLoadBalancer(ctx, client, namespace, service.Name)
+			service, err = waitForAzureDualStackLoadBalancer(lbCtx, client, namespace, service.Name)
 			o.Expect(err).NotTo(o.HaveOccurred())
 			services[i] = service
 		}
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@test/extended/cloud_controller_manager/azure_dualstack.go` around lines 122 -
127, Use one shared timeout/deadline context for the entire service-wait loop in
the dual-stack test, rather than allowing each waitForAzureDualStackLoadBalancer
call to consume GetServiceLoadBalancerCreationTimeout independently. Create the
bounded context before iterating over services, pass it to both waits, and
preserve the existing per-service validation and assignment behavior.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@test/extended/cloud_controller_manager/azure_dualstack.go`:
- Around line 272-312: Update the two PollUntilContextTimeout phases in the
service deletion flow to have independent time budgets: derive a separate
timeout context for each phase, or extend the parent deadline to cover both
10-minute polls. Ensure the delete-request phase and the finalizer-wait phase
each receive their full intended budget and timeout errors remain attributable
to the phase that exhausts its budget.
- Around line 65-74: The container setup loop in the backend.Run callback must
validate the generated readiness probe and its HTTPGet handler before assigning
the port. Guard container.ReadinessProbe and ReadinessProbe.HTTPGet, and fail
cleanly through the test’s existing error mechanism when either is absent; only
assign the port when both are present.

---

Nitpick comments:
In `@test/extended/cloud_controller_manager/azure_dualstack.go`:
- Around line 263-265: Update deleteAzureLoadBalancerServicesAndWait to accept a
context.Context and derive its 10-minute timeout from context.WithoutCancel(ctx)
rather than context.Background(), preserving context values while allowing
cleanup after cancellation. At the call site, change the DeferCleanup closure to
accept ctx context.Context and forward it to the helper; no direct changes are
needed at the other DeferCleanup blocks.
- Around line 122-127: Use one shared timeout/deadline context for the entire
service-wait loop in the dual-stack test, rather than allowing each
waitForAzureDualStackLoadBalancer call to consume
GetServiceLoadBalancerCreationTimeout independently. Create the bounded context
before iterating over services, pass it to both waits, and preserve the existing
per-service validation and assignment behavior.
🪄 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), Central YAML (inherited)

Review profile: CHILL

Plan: Pro Plus

Run ID: 41211148-db78-434f-b162-d5537c0b7916

📥 Commits

Reviewing files that changed from the base of the PR and between ed2a43c and d0a6446.

📒 Files selected for processing (1)
  • test/extended/cloud_controller_manager/azure_dualstack.go

Comment thread test/extended/cloud_controller_manager/azure_dualstack.go
Comment thread test/extended/cloud_controller_manager/azure_dualstack.go
@bandrade
bandrade marked this pull request as ready for review July 30, 2026 13:53
@openshift-ci openshift-ci Bot removed the do-not-merge/work-in-progress Indicates that a PR should not merge because it is a work in progress. label Jul 30, 2026
@openshift-ci
openshift-ci Bot requested review from JoelSpeed and MaysaMacedo July 30, 2026 13:54

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@test/extended/cloud_controller_manager/azure_dualstack.go`:
- Around line 125-130: Update the sequential service-wait loop around
waitForAzureDualStackLoadBalancer so each service receives its own load-balancer
creation timeout. Stop sharing loadBalancerContext across iterations; pass ctx
directly, relying on waitForAzureDualStackLoadBalancer to create a fresh timeout
per call, or create and cancel a per-iteration timeout context.
🪄 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), Central YAML (inherited)

Review profile: CHILL

Plan: Pro Plus

Run ID: a6c2e457-ca8f-4c54-9cda-0dda85302b85

📥 Commits

Reviewing files that changed from the base of the PR and between d0a6446 and 59a8a83.

📒 Files selected for processing (1)
  • test/extended/cloud_controller_manager/azure_dualstack.go

Comment thread test/extended/cloud_controller_manager/azure_dualstack.go Outdated
@openshift-merge-bot

Copy link
Copy Markdown
Contributor

Scheduling required tests:
/test e2e-aws-csi
/test e2e-aws-ovn-fips
/test e2e-aws-ovn-microshift
/test e2e-aws-ovn-microshift-serial
/test e2e-aws-ovn-serial-1of2
/test e2e-aws-ovn-serial-2of2
/test e2e-gcp-csi
/test e2e-gcp-ovn
/test e2e-gcp-ovn-upgrade
/test e2e-metal-ipi-ovn-ipv6
/test e2e-vsphere-ovn
/test e2e-vsphere-ovn-upi

@bandrade

Copy link
Copy Markdown
Contributor Author

/test e2e-gcp-ovn
/test e2e-gcp-ovn-upgrade

@bandrade

Copy link
Copy Markdown
Contributor Author

/unhold

@openshift-ci

openshift-ci Bot commented Jul 31, 2026

Copy link
Copy Markdown
Contributor

@bandrade: all tests passed!

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.

@bandrade

Copy link
Copy Markdown
Contributor Author

@JoelSpeed @MaysaMacedo can you PTAL?

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

Labels

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