Skip to content

OCPBUGS-87018: Revert conditional deletion of openshift-ingress NetworkPolicy - #8662

Merged
openshift-merge-bot[bot] merged 1 commit into
openshift:mainfrom
csrwng:revert-openshift-ingress-np-deletion
Jun 4, 2026
Merged

OCPBUGS-87018: Revert conditional deletion of openshift-ingress NetworkPolicy#8662
openshift-merge-bot[bot] merged 1 commit into
openshift:mainfrom
csrwng:revert-openshift-ingress-np-deletion

Conversation

@csrwng

@csrwng csrwng commented Jun 3, 2026

Copy link
Copy Markdown
Contributor

Summary

Problem

When the management cluster kube-apiserver undergoes a revision rollout (cert rotation, config change, or forced redeployment), all hosted cluster private-router NLBs experience sustained traffic blackouts. The issue was introduced in HO v0.1.75 and does not self-heal — manual deletion of HCP router pods is required to restore traffic.

Root Cause

During a MC KAS rollout, ovnkube-controller briefly loses its API connection and re-syncs. During this re-sync, it writes OVN NorthDB logical flows that reference port groups before those port groups are fully restored. ovn-controller fails to parse the flow match rules:

lflow|WARN|error parsing match "... inport == @a15503844857551241179":
  Syntax error at `@a15503844857551241179' expecting port group name.

These broken flows are the allow rules for NodePort/LoadBalancer ingress traffic. Without them, the namespace default-deny ingress ACL drops all NLB traffic to HCP router pods on port 8443.

Evidence from must-gather

ACL logging confirmed the mechanism:

  • 11,110 ACL drops across all 6 router pods on 3 hosted clusters
  • 100% of drops target router IPs on port 8443
  • Drops correlate exactly with ovn-controller lflow parse errors during the KAS rollout window
  • Each HC namespace has a different missing port group, but the pattern is identical
Node HC Router IP ACL Drops Window
ovnkube-node-25pbh hc-c (4.18) 10.128.34.26 4,773 17:45–17:49
ovnkube-node-htzlx hc-c (4.18) 10.128.35.25 4,928 17:45–17:52
ovnkube-node-49p92 hc-c2 (4.21) 10.128.195.22 188 17:46–17:50
ovnkube-node-dwlb6 hc-c2 (4.21) 10.128.197.21 329 17:46–17:52
ovnkube-node-btfb9 hc-default 10.128.200.22 536 17:43–17:51
ovnkube-node-575vk hc-default 10.128.201.22 356 17:43–17:50

Why re-adding the policy helps

The exact mechanism by which the openshift-ingress NetworkPolicy prevents the race is not yet fully understood — other policies in the namespace also use podSelector: {}, so it is not simply the presence of a broad port group. It may be related to the cross-namespace namespaceSelector reference (matching network.openshift.io/policy-group: ingress) or to reducing the amount of OVN NorthDB churn during re-sync. Regardless, manual testing confirmed that re-applying the policy prevents the outage, and removing it reliably reproduces it.

The underlying OVN-Kubernetes bug (non-atomic port group + logical flow updates during re-sync) should be tracked and fixed separately.

Test plan

  • Unit tests updated — all deletion test cases changed to expect creation
  • All network policy tests pass
  • Manual verification: trigger MC KAS rollout with this fix applied, confirm no HC API blackout
  • Verify the openshift-ingress NetworkPolicy is present in HCP namespaces for private/PublicAndPrivate clusters

🤖 Generated with Claude Code

@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: LGTM mode

@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 Jun 3, 2026
@openshift-ci

openshift-ci Bot commented Jun 3, 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 added jira/severity-critical Referenced Jira bug's severity is critical for the branch this PR is targeting. jira/valid-reference Indicates that this PR references a valid Jira ticket of any type. labels Jun 3, 2026
@openshift-ci-robot

Copy link
Copy Markdown

@csrwng: This pull request references Jira Issue OCPBUGS-87018, which is invalid:

  • expected the bug to target the "5.0.0" version, but no target version was set

Comment /jira refresh to re-evaluate validity if changes to the Jira bug are made, or edit the title of this pull request to link to a different bug.

The bug has been updated to refer to the pull request using the external bug tracker.

Details

In response to this:

Summary

Problem

When the management cluster kube-apiserver undergoes a revision rollout (cert rotation, config change, or forced redeployment), all hosted cluster private-router NLBs experience sustained traffic blackouts. The issue was introduced in HO v0.1.75 and does not self-heal — manual deletion of HCP router pods is required to restore traffic.

Root Cause

During a MC KAS rollout, ovnkube-controller briefly loses its API connection and re-syncs. During this re-sync, it writes OVN NorthDB logical flows that reference port groups before those port groups are fully restored. ovn-controller fails to parse the flow match rules:

lflow|WARN|error parsing match "... inport == @a15503844857551241179":
 Syntax error at `@a15503844857551241179' expecting port group name.

These broken flows are the allow rules for NodePort/LoadBalancer ingress traffic. Without them, the namespace default-deny ingress ACL drops all NLB traffic to HCP router pods on port 8443.

Evidence from must-gather

ACL logging confirmed the mechanism:

  • 11,110 ACL drops across all 6 router pods on 3 hosted clusters
  • 100% of drops target router IPs on port 8443
  • Drops correlate exactly with ovn-controller lflow parse errors during the KAS rollout window
  • Each HC namespace has a different missing port group, but the pattern is identical
Node HC Router IP ACL Drops Window
ovnkube-node-25pbh hc-c (4.18) 10.128.34.26 4,773 17:45–17:49
ovnkube-node-htzlx hc-c (4.18) 10.128.35.25 4,928 17:45–17:52
ovnkube-node-49p92 hc-c2 (4.21) 10.128.195.22 188 17:46–17:50
ovnkube-node-dwlb6 hc-c2 (4.21) 10.128.197.21 329 17:46–17:52
ovnkube-node-btfb9 hc-default 10.128.200.22 536 17:43–17:51
ovnkube-node-575vk hc-default 10.128.201.22 356 17:43–17:50

Why this workaround works

The openshift-ingress NetworkPolicy uses podSelector: {} (matching all pods in the namespace). Its presence changes the OVN port group structure in a way that avoids the re-sync race condition. Manual testing confirmed that re-applying the policy to affected namespaces prevents the outage during KAS rollouts.

The underlying OVN-Kubernetes bug (non-atomic port group + logical flow updates during re-sync) should be tracked and fixed separately.

Test plan

  • Unit tests updated — all expectDeleted test cases changed to expect creation
  • All network policy tests pass
  • Manual verification: trigger MC KAS rollout with this fix applied, confirm no HC API blackout
  • Verify the openshift-ingress NetworkPolicy is present in HCP namespaces for private/PublicAndPrivate clusters

🤖 Generated with Claude Code

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/invalid-bug Indicates that a referenced Jira bug is invalid for the branch this PR is targeting. label Jun 3, 2026
@coderabbitai

coderabbitai Bot commented Jun 3, 2026

Copy link
Copy Markdown
Contributor
📝 Walkthrough

Walkthrough

This pull request refactors how the hosted cluster reconciler manages the openshift-ingress NetworkPolicy. The change removes conditional creation/deletion logic based on HCP route labels, replacing it with unconditional reconciliation that always ensures the policy exists in the control plane namespace. The reconcileIngressNetworkPolicy helper method is deleted entirely, and its conditional behavior is removed. The test suite is updated to eliminate per-case expectation flags and instead universally assert that the policy is created across all scenarios, with a comment explaining the rationale related to OVN-Kubernetes port group cleanup.

Sequence Diagram(s)

sequenceDiagram
  participant HostedClusterReconciler
  participant createOrUpdate
  participant KubernetesAPI
  participant OpenshiftIngressNetworkPolicy
  HostedClusterReconciler->>createOrUpdate: call reconcileOpenshiftIngressNetworkPolicy
  createOrUpdate->>KubernetesAPI: apply NetworkPolicy resource
  KubernetesAPI-->>createOrUpdate: success/failure
  createOrUpdate-->>HostedClusterReconciler: result (wrapped on failure)
Loading

Suggested reviewers

  • muraee
  • bryan-cox
🚥 Pre-merge checks | ✅ 11
✅ Passed checks (11 passed)
Check name Status Explanation
Title check ✅ Passed The title accurately summarizes the main change: reverting conditional deletion logic for the openshift-ingress NetworkPolicy, which is the primary purpose of this PR.
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 All test names in network_policies_test.go are static and deterministic. No UUIDs, timestamps, generated suffixes, IPs, or dynamic names found in table-driven tests.
Test Structure And Quality ✅ Passed Table-driven test with isolated cases; fake clients; meaningful error messages; no async ops; follows codebase conventions.
Topology-Aware Scheduling Compatibility ✅ Passed PR modifies only NetworkPolicy objects (network access controls), not scheduling constraints. No pod affinity, replicas, node selectors, or topology constraints are involved.
Ipv6 And Disconnected Network Test Compatibility ✅ Passed This PR does not add new Ginkgo e2e tests. It only modifies existing standard Go unit tests (using testing.T), which fall outside the scope of this IPv6/disconnected network compatibility check.
No-Weak-Crypto ✅ Passed PR contains no weak cryptography. Changes are limited to network policy reconciliation logic in Kubernetes controllers with no crypto-related imports or function calls.
Container-Privileges ✅ Passed PR modifies Go controller code for NetworkPolicy reconciliation, not container/pod specifications. No privileged settings, host access, or capability declarations are introduced in these changes.
No-Sensitive-Data-In-Logs ✅ Passed Logging statements only log safe, non-sensitive data: IP validation status, RBAC errors, generic errors. No passwords, tokens, API keys, PII, or customer data exposed.
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ 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 added area/hypershift-operator Indicates the PR includes changes for the hypershift operator and API - outside an OCP release and removed do-not-merge/needs-area labels Jun 3, 2026
@openshift-ci

openshift-ci Bot commented Jun 3, 2026

Copy link
Copy Markdown
Contributor

[APPROVALNOTIFIER] This PR is APPROVED

This pull-request has been approved by: csrwng

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

The pull request process is described 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

@openshift-ci openshift-ci Bot added the approved Indicates a PR has been approved by an approver from all required OWNERS files. label Jun 3, 2026
@csrwng

csrwng commented Jun 3, 2026

Copy link
Copy Markdown
Contributor Author

/jira refresh

@openshift-ci-robot openshift-ci-robot added the jira/valid-bug Indicates that a referenced Jira bug is valid for the branch this PR is targeting. label Jun 3, 2026
@openshift-ci-robot

Copy link
Copy Markdown

@csrwng: This pull request references Jira Issue OCPBUGS-87018, which is valid. The bug has been moved to the POST state.

3 validation(s) were run on this bug
  • bug is open, matching expected state (open)
  • bug target version (5.0.0) matches configured target version for branch (5.0.0)
  • bug is in the state New, which is one of the valid states (NEW, ASSIGNED, POST)
Details

In response to this:

/jira refresh

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 removed the jira/invalid-bug Indicates that a referenced Jira bug is invalid for the branch this PR is targeting. label Jun 3, 2026

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🧹 Nitpick comments (1)
hypershift-operator/controllers/hostedcluster/network_policies_test.go (1)

269-277: ⚡ Quick win

Assert the reconciled end state, not just the createOrUpdate call.

This no longer verifies the regression the PR is fixing. The test passes as soon as reconcileNetworkPolicies invokes the stub, even if a future change deletes the policy later or fails to preserve a pre-existing object. Please keep one case that seeds openshift-ingress in the fake client and then assert it still exists after reconcile.

Also applies to: 457-459

🤖 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 `@hypershift-operator/controllers/hostedcluster/network_policies_test.go`
around lines 269 - 277, The test currently only asserts that the createOrUpdate
stub was invoked, which misses regressions where reconcileNetworkPolicies later
deletes or fails to preserve an existing openshift-ingress NetworkPolicy; update
the test cases to include at least one scenario that seeds the fake client with
a pre-existing NetworkPolicy named "openshift-ingress", call
reconcileNetworkPolicies, then fetch the NetworkPolicy from the fake client and
assert it still exists and has expected fields (preserve
name/namespace/important labels/ports) instead of only asserting the
createOrUpdate stub was called; locate the reconciliation helper
reconcileNetworkPolicies and the test table in network_policies_test.go to add
the seeded object and the post-reconcile existence assertion.
🤖 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.

Nitpick comments:
In `@hypershift-operator/controllers/hostedcluster/network_policies_test.go`:
- Around line 269-277: The test currently only asserts that the createOrUpdate
stub was invoked, which misses regressions where reconcileNetworkPolicies later
deletes or fails to preserve an existing openshift-ingress NetworkPolicy; update
the test cases to include at least one scenario that seeds the fake client with
a pre-existing NetworkPolicy named "openshift-ingress", call
reconcileNetworkPolicies, then fetch the NetworkPolicy from the fake client and
assert it still exists and has expected fields (preserve
name/namespace/important labels/ports) instead of only asserting the
createOrUpdate stub was called; locate the reconciliation helper
reconcileNetworkPolicies and the test table in network_policies_test.go to add
the seeded object and the post-reconcile existence assertion.

ℹ️ Review info
⚙️ Run configuration

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

Review profile: CHILL

Plan: Enterprise

Run ID: 6444553f-ed81-4b9b-8034-5f9ad84e2cce

📥 Commits

Reviewing files that changed from the base of the PR and between 98f62ed and 2d4b968.

📒 Files selected for processing (2)
  • hypershift-operator/controllers/hostedcluster/network_policies.go
  • hypershift-operator/controllers/hostedcluster/network_policies_test.go

@codecov

codecov Bot commented Jun 3, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 71.42857% with 2 lines in your changes missing coverage. Please review.
✅ Project coverage is 41.41%. Comparing base (b593a02) to head (00101fe).
⚠️ Report is 13 commits behind head on main.

Files with missing lines Patch % Lines
...ator/controllers/hostedcluster/network_policies.go 71.42% 1 Missing and 1 partial ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##             main    #8662      +/-   ##
==========================================
- Coverage   41.41%   41.41%   -0.01%     
==========================================
  Files         756      756              
  Lines       93623    93612      -11     
==========================================
- Hits        38777    38772       -5     
+ Misses      52120    52116       -4     
+ Partials     2726     2724       -2     
Files with missing lines Coverage Δ
...ator/controllers/hostedcluster/network_policies.go 77.19% <71.42%> (+0.35%) ⬆️
Flag Coverage Δ
cmd-support 34.87% <ø> (ø)
cpo-hostedcontrolplane 43.50% <ø> (ø)
cpo-other 42.79% <ø> (ø)
hypershift-operator 51.49% <71.42%> (+<0.01%) ⬆️
other 31.64% <ø> (ø)

Flags with carried forward coverage won't be shown. Click here to find out more.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

@csrwng
csrwng marked this pull request as ready for review June 3, 2026 22:35
@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 Jun 3, 2026
@openshift-ci
openshift-ci Bot requested review from jparrill and sjenning June 3, 2026 22:35
…k policy based on route labeling"

This reverts commit 27f49d7.

The original change conditionally deleted the openshift-ingress
NetworkPolicy when LabelHCPRoutes was true (AWS/GCP private clusters,
clusters with dedicated KAS DNS, ARO HCP). While the policy is
functionally unnecessary in those cases, its absence triggers an
OVN-Kubernetes bug during management cluster kube-apiserver revision
rollouts.

When the MC KAS rolls out, ovnkube-controller briefly loses its API
connection and re-syncs. During this re-sync, it writes OVN NorthDB
logical flows that reference port groups before those port groups are
fully restored. ovn-controller on each node then fails to parse the
flow match rules:

  lflow|WARN|error parsing match "... inport == @a15503844857551241179":
    Syntax error at `@a15503844857551241179' expecting port group name.

These broken flow rules are the allow rules for NodePort/LoadBalancer
ingress traffic. Without them, the namespace default-deny ingress ACL
drops all NLB traffic to HCP router pods on port 8443. This causes a
complete API blackout for all hosted clusters on the management cluster,
lasting 20-30+ minutes until router pods are manually deleted.

ACL logging from the must-gather confirms the mechanism — 11,110 drops
across all 6 router pods on 3 hosted clusters, 100% targeting router
IPs on port 8443, correlated exactly with the ovn-controller lflow
errors during the KAS rollout window.

The presence of the openshift-ingress NetworkPolicy (which uses
podSelector: {} matching all pods) changes the OVN port group structure
in a way that avoids this race. Manual testing confirmed that
re-applying the policy prevents the outage.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@csrwng
csrwng force-pushed the revert-openshift-ingress-np-deletion branch from 2d4b968 to 00101fe Compare June 3, 2026 22:40
@openshift-ci-robot

Copy link
Copy Markdown

@csrwng: This pull request references Jira Issue OCPBUGS-87018, which is valid.

3 validation(s) were run on this bug
  • bug is open, matching expected state (open)
  • bug target version (5.0.0) matches configured target version for branch (5.0.0)
  • bug is in the state POST, which is one of the valid states (NEW, ASSIGNED, POST)
Details

In response to this:

Summary

Problem

When the management cluster kube-apiserver undergoes a revision rollout (cert rotation, config change, or forced redeployment), all hosted cluster private-router NLBs experience sustained traffic blackouts. The issue was introduced in HO v0.1.75 and does not self-heal — manual deletion of HCP router pods is required to restore traffic.

Root Cause

During a MC KAS rollout, ovnkube-controller briefly loses its API connection and re-syncs. During this re-sync, it writes OVN NorthDB logical flows that reference port groups before those port groups are fully restored. ovn-controller fails to parse the flow match rules:

lflow|WARN|error parsing match "... inport == @a15503844857551241179":
 Syntax error at `@a15503844857551241179' expecting port group name.

These broken flows are the allow rules for NodePort/LoadBalancer ingress traffic. Without them, the namespace default-deny ingress ACL drops all NLB traffic to HCP router pods on port 8443.

Evidence from must-gather

ACL logging confirmed the mechanism:

  • 11,110 ACL drops across all 6 router pods on 3 hosted clusters
  • 100% of drops target router IPs on port 8443
  • Drops correlate exactly with ovn-controller lflow parse errors during the KAS rollout window
  • Each HC namespace has a different missing port group, but the pattern is identical
Node HC Router IP ACL Drops Window
ovnkube-node-25pbh hc-c (4.18) 10.128.34.26 4,773 17:45–17:49
ovnkube-node-htzlx hc-c (4.18) 10.128.35.25 4,928 17:45–17:52
ovnkube-node-49p92 hc-c2 (4.21) 10.128.195.22 188 17:46–17:50
ovnkube-node-dwlb6 hc-c2 (4.21) 10.128.197.21 329 17:46–17:52
ovnkube-node-btfb9 hc-default 10.128.200.22 536 17:43–17:51
ovnkube-node-575vk hc-default 10.128.201.22 356 17:43–17:50

Why this workaround works

The openshift-ingress NetworkPolicy uses podSelector: {} (matching all pods in the namespace). Its presence changes the OVN port group structure in a way that avoids the re-sync race condition. Manual testing confirmed that re-applying the policy to affected namespaces prevents the outage during KAS rollouts.

The underlying OVN-Kubernetes bug (non-atomic port group + logical flow updates during re-sync) should be tracked and fixed separately.

Test plan

  • Unit tests updated — all expectDeleted test cases changed to expect creation
  • All network policy tests pass
  • Manual verification: trigger MC KAS rollout with this fix applied, confirm no HC API blackout
  • Verify the openshift-ingress NetworkPolicy is present in HCP namespaces for private/PublicAndPrivate clusters

🤖 Generated with Claude Code

Summary by CodeRabbit

  • Bug Fixes
  • Network ingress policy for the control plane is now always ensured, preventing stale networking configurations during control plane rollouts and improving reliability.
  • Tests
  • Test suite updated to reflect the always-present ingress policy expectation, validating consistent policy creation across scenarios.

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.

@joshbranham

Copy link
Copy Markdown
Contributor

/lgtm

@openshift-ci openshift-ci Bot added the lgtm Indicates that a PR is ready to be merged. label Jun 3, 2026
@openshift-merge-bot

Copy link
Copy Markdown
Contributor

Scheduling tests matching the pipeline_run_if_changed or not excluded by pipeline_skip_if_only_changed parameters:
/test e2e-aks-4-22
/test e2e-aws-4-22
/test e2e-aks
/test e2e-aws
/test e2e-aws-upgrade-hypershift-operator
/test e2e-azure-self-managed
/test e2e-azure-v2-self-managed
/test e2e-kubevirt-aws-ovn-reduced
/test e2e-v2-aws
/test e2e-v2-gke

@cwbotbot

cwbotbot commented Jun 4, 2026

Copy link
Copy Markdown

Test Results

e2e-aks

e2e-aws

@enxebre

enxebre commented Jun 4, 2026

Copy link
Copy Markdown
Member

For posterity - For understanding the rationale behind why this "unrelated" change solve the problem see outcome of https://redhat.atlassian.net/browse/OCPBUGS-87020

@enxebre

enxebre commented Jun 4, 2026

Copy link
Copy Markdown
Member

/test e2e-aks-4-22

@hypershift-jira-solve-ci

Copy link
Copy Markdown
Contributor

This confirms the flow. The validateNodePoolConditions at line 376 is called before nodePoolTest.Run() — it validates the initial state. The fact that it fails here means the ReachedIgnitionEndpoint condition was never set to True after the initial node provisioning.

The node did boot and became ready (line 1716: "Successfully waited for 1 nodes to become ready"), which means the ignition payload was served. But the annotation on the token secret that records this fact was never applied — this is a best-effort annotation update in the ignition server (start.go:280) that can silently fail.

This is a pre-existing flake unrelated to the NetworkPolicy changes in PR #8662. The PR only modifies the openshift-ingress NetworkPolicy reconciliation in the HostedCluster controller — it does not touch the ignition server, token secret handling, or condition evaluation logic.

Now I have everything I need to produce the final report.

Test Failure Analysis Complete

Job Information

Test Failure Analysis

Error

nodepool_test.go:429: Failed to wait for NodePool e2e-clusters-slrkv/node-pool-wzffw-test-inplaceupgrade to have correct status in 20m0s: context deadline exceeded
eventually.go:225: observed *v1beta1.NodePool e2e-clusters-slrkv/node-pool-wzffw-test-inplaceupgrade invalid at RV 68424 after 20m0s: incorrect condition: wanted ReachedIgnitionEndpoint=True, got ReachedIgnitionEndpoint=False: ignitionNotReached

Summary

The TestNodePoolInPlaceUpgrade test timed out waiting for the ReachedIgnitionEndpoint condition to become True on the NodePool. The node successfully booted and became ready (after 16m36s), proving that the ignition payload was served, but the ignition server's best-effort annotation update on the token secret silently failed — the condition never transitioned from False. This is a pre-existing flake unrelated to the PR's NetworkPolicy changes: the PR only modifies openshift-ingress NetworkPolicy reconciliation and does not touch the ignition server, token secrets, or condition evaluation logic.

Root Cause

The failure is a known flaky behavior in the ReachedIgnitionEndpoint condition tracking mechanism, not caused by PR #8662.

How ReachedIgnitionEndpoint works:

  1. When a node boots, it contacts the ignition server to fetch its payload
  2. The ignition server serves the payload and then attempts to annotate the token secret with hypershift.openshift.io/ignition-reached: True (ignition-server/cmd/start.go:280)
  3. The NodePool controller checks this annotation to set the ReachedIgnitionEndpoint condition (hypershift-operator/controllers/nodepool/conditions.go:830)

Why it failed:

  • The node DID successfully boot and become ready (log: "Successfully waited for 1 nodes to become ready for NodePool ... in 16m36.075s")
  • This proves the ignition server served the payload successfully
  • However, the annotation update on the token secret is best-effort — if the Get or Update call fails, it only logs a message and does not retry (start.go:277-283)
  • The annotation was never set, so the condition remained False: ignitionNotReached
  • The validateNodePoolConditions function (nodepool_test.go:376) timed out after 20 minutes waiting for ReachedIgnitionEndpoint=True

Why this is unrelated to PR #8662:

  • PR OCPBUGS-87018: Revert conditional deletion of openshift-ingress NetworkPolicy #8662 reverts conditional deletion of the openshift-ingress NetworkPolicy — it modifies only hypershift-operator/controllers/hostedcluster/network_policies.go and its test file
  • The PR does NOT touch: the ignition server, token secret handling, NodePool condition evaluation, or the ReachedIgnitionEndpoint logic
  • The openshift-ingress NetworkPolicy allows traffic from namespaces labeled network.openshift.io/policy-group: ingress into the HCP namespace — this is about management cluster ingress routing, not node-to-ignition-server connectivity
  • All other tests (including TestNodePoolReplaceUpgrade, TestCreateCluster, TestAutoscaling, etc.) passed, confirming the cluster and network are healthy
Recommendations
  1. Treat as a pre-existing flake — This failure is not caused by the PR's NetworkPolicy changes. The PR should be safe to merge with a /retest to clear this flake.

  2. File a tracking issue for the ReachedIgnitionEndpoint flake — The ignition server's best-effort annotation update (start.go:277-283) should be made more robust, e.g., by adding retries with backoff when the Update call fails. The current code silently swallows the error, leading to a permanently stuck False condition.

  3. Consider adding a reconciliation loop for the annotation — The NodePool controller already has logic (conditions.go:556) to preserve the condition for InPlace upgrades. A similar approach could handle the case where the annotation was never set despite the node being ready: if a node is Ready and the NodePool has the expected number of replicas, the condition could be set to True even if the annotation is missing.

Evidence
Evidence Detail
Failing test TestNodePool/HostedCluster0/Main/TestNodePoolInPlaceUpgrade (2196.10s)
Error condition ReachedIgnitionEndpoint=False: ignitionNotReached (expected True)
Node readiness Node became ready after 16m36s — ignition payload was served successfully
Failure point validateNodePoolConditions (nodepool_test.go:376) — called BEFORE upgrade, during initial NodePool validation
Annotation code ignition-server/cmd/start.go:277-283 — best-effort annotation update, silently logs failures
Condition code hypershift-operator/controllers/nodepool/conditions.go:830 — checks for annotation on token secret
PR scope Only modifies network_policies.go and network_policies_test.go — no ignition/token/condition code changes
Other tests 405 tests passed, 48 skipped — only TestNodePoolInPlaceUpgrade failed (confirming isolated flake)
Platform Azure AKS with ARO-HCP managed service (MANAGED_SERVICE=ARO-HCP)

@csrwng

csrwng commented Jun 4, 2026

Copy link
Copy Markdown
Contributor Author

/retest-required

@csrwng

csrwng commented Jun 4, 2026

Copy link
Copy Markdown
Contributor Author

/verified by @csrwng
Tested manually to ensure that the new HO results in the ingress network policy getting re-added to a PublicAndPrivate AWS hosted cluster control plane namespace.

@openshift-ci-robot openshift-ci-robot added the verified Signifies that the PR passed pre-merge verification criteria label Jun 4, 2026
@openshift-ci-robot

Copy link
Copy Markdown

@csrwng: This PR has been marked as verified by @csrwng.

Details

In response to this:

/verified by @csrwng
Tested manually to ensure that the new HO results in the ingress network policy getting re-added to a PublicAndPrivate AWS hosted cluster control plane namespace.

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

openshift-ci Bot commented Jun 4, 2026

Copy link
Copy Markdown
Contributor

@csrwng: 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.

@openshift-merge-bot
openshift-merge-bot Bot merged commit 43e1c86 into openshift:main Jun 4, 2026
42 checks passed
@openshift-ci-robot

Copy link
Copy Markdown

@csrwng: Jira Issue Verification Checks: Jira Issue OCPBUGS-87018
✔️ This pull request was pre-merge verified.
✔️ All associated pull requests have merged.
✔️ All associated, merged pull requests were pre-merge verified.

Jira Issue OCPBUGS-87018 has been moved to the MODIFIED state and will move to the VERIFIED state when the change is available in an accepted nightly payload. 🕓

Details

In response to this:

Summary

Problem

When the management cluster kube-apiserver undergoes a revision rollout (cert rotation, config change, or forced redeployment), all hosted cluster private-router NLBs experience sustained traffic blackouts. The issue was introduced in HO v0.1.75 and does not self-heal — manual deletion of HCP router pods is required to restore traffic.

Root Cause

During a MC KAS rollout, ovnkube-controller briefly loses its API connection and re-syncs. During this re-sync, it writes OVN NorthDB logical flows that reference port groups before those port groups are fully restored. ovn-controller fails to parse the flow match rules:

lflow|WARN|error parsing match "... inport == @a15503844857551241179":
 Syntax error at `@a15503844857551241179' expecting port group name.

These broken flows are the allow rules for NodePort/LoadBalancer ingress traffic. Without them, the namespace default-deny ingress ACL drops all NLB traffic to HCP router pods on port 8443.

Evidence from must-gather

ACL logging confirmed the mechanism:

  • 11,110 ACL drops across all 6 router pods on 3 hosted clusters
  • 100% of drops target router IPs on port 8443
  • Drops correlate exactly with ovn-controller lflow parse errors during the KAS rollout window
  • Each HC namespace has a different missing port group, but the pattern is identical
Node HC Router IP ACL Drops Window
ovnkube-node-25pbh hc-c (4.18) 10.128.34.26 4,773 17:45–17:49
ovnkube-node-htzlx hc-c (4.18) 10.128.35.25 4,928 17:45–17:52
ovnkube-node-49p92 hc-c2 (4.21) 10.128.195.22 188 17:46–17:50
ovnkube-node-dwlb6 hc-c2 (4.21) 10.128.197.21 329 17:46–17:52
ovnkube-node-btfb9 hc-default 10.128.200.22 536 17:43–17:51
ovnkube-node-575vk hc-default 10.128.201.22 356 17:43–17:50

Why re-adding the policy helps

The exact mechanism by which the openshift-ingress NetworkPolicy prevents the race is not yet fully understood — other policies in the namespace also use podSelector: {}, so it is not simply the presence of a broad port group. It may be related to the cross-namespace namespaceSelector reference (matching network.openshift.io/policy-group: ingress) or to reducing the amount of OVN NorthDB churn during re-sync. Regardless, manual testing confirmed that re-applying the policy prevents the outage, and removing it reliably reproduces it.

The underlying OVN-Kubernetes bug (non-atomic port group + logical flow updates during re-sync) should be tracked and fixed separately.

Test plan

  • Unit tests updated — all deletion test cases changed to expect creation
  • All network policy tests pass
  • Manual verification: trigger MC KAS rollout with this fix applied, confirm no HC API blackout
  • Verify the openshift-ingress NetworkPolicy is present in HCP namespaces for private/PublicAndPrivate clusters

🤖 Generated with Claude Code

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-merge-robot

Copy link
Copy Markdown
Contributor

Fix included in release 5.0.0-0.nightly-2026-06-06-100407

csrwng added a commit to csrwng/hypershift-1 that referenced this pull request Jun 17, 2026
…gress NetworkPolicy

Reverts the revert PR openshift#8662 to re-apply the original PR openshift#7872 behavior:
conditionally create or delete the openshift-ingress NetworkPolicy based
on whether routes are labeled for the HCP router (LabelHCPRoutes).

The OVN-Kubernetes port group race that prompted the revert is being
addressed via PR openshift#8689 (--hcp-egress-block-cidrs flag), making the
blanket always-create workaround unnecessary.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

approved Indicates a PR has been approved by an approver from all required OWNERS files. area/hypershift-operator Indicates the PR includes changes for the hypershift operator and API - outside an OCP release jira/severity-critical Referenced Jira bug's severity is critical for the branch this PR is targeting. jira/valid-bug Indicates that a referenced Jira bug is valid for the branch this PR is targeting. jira/valid-reference Indicates that this PR references a valid Jira ticket of any type. lgtm Indicates that a PR is ready to be merged. verified Signifies that the PR passed pre-merge verification criteria

Projects

None yet

Development

Successfully merging this pull request may close these issues.

6 participants