Skip to content

OCPBUGS-49738: fix handling of host conflict#736

Open
jcmoraisjr wants to merge 1 commit intoopenshift:masterfrom
jcmoraisjr:OCPBUGS-49738-fix-routemap
Open

OCPBUGS-49738: fix handling of host conflict#736
jcmoraisjr wants to merge 1 commit intoopenshift:masterfrom
jcmoraisjr:OCPBUGS-49738-fix-routemap

Conversation

@jcmoraisjr
Copy link
Copy Markdown
Member

@jcmoraisjr jcmoraisjr commented Feb 23, 2026

Routes are grouped by host on three distinct hashmaps when allowWildcardRoutes is enabled. These hashmaps are updated whenever routes are added, modified or deleted, and their content is used to evaluate host conflicts. This hashmaps handling is done using the current host of the route resource, so, if the host value changes, the router does not find the entry on the hashmaps because it is using the current - and still not used - host value as the key.

The approach used on this update is to ignore the host from the router, and remove the resource from all the hosts instead, since the only match on all the hashmaps should be found on the key corresponding to the former host value.

Summary by CodeRabbit

  • Bug Fixes

    • Prevented stale host and wildcard conflicts when routes are updated, removed, or reassigned by ensuring prior host ownership is cleared before reclaiming.
  • Refactor

    • Centralized and simplified route/host cleanup for more consistent claiming and release behavior.
  • Tests

    • Added tests covering wildcard host lifecycle (add → modify → delete) to ensure hosts can be reclaimed without errors.

@openshift-ci-robot openshift-ci-robot added jira/severity-important Referenced Jira bug's severity is important for the branch this PR is targeting. jira/valid-reference Indicates that this PR references a valid Jira ticket of any type. jira/invalid-bug Indicates that a referenced Jira bug is invalid for the branch this PR is targeting. labels Feb 23, 2026
@openshift-ci-robot
Copy link
Copy Markdown
Contributor

@jcmoraisjr: This pull request references Jira Issue OCPBUGS-49738, which is invalid:

  • expected the bug to target the "4.22.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:

Routes are grouped by host on three distinct hashmaps when allowWildcardRoutes is enabled. These hashmaps are updated whenever routes are added, modified or deleted, and their content is used to evaluate host conflicts. This hashmaps handling is done using the current host of the route resource, so, if the host value changes, the router does not find the entry on the hashmaps because it is using the current - and still not used - host value as the key.

The approach used on this update is to ignore the host from the router, and remove the resource from all the hosts instead, since the only match on all the hashmaps should be found on the key corresponding to the former host value.

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 requested review from gcs278 and knobunc February 23, 2026 22:12
@jcmoraisjr
Copy link
Copy Markdown
Member Author

/jira refresh

@openshift-ci-robot openshift-ci-robot added jira/valid-bug Indicates that a referenced Jira bug is valid for the branch this PR is targeting. and removed jira/invalid-bug Indicates that a referenced Jira bug is invalid for the branch this PR is targeting. labels Feb 24, 2026
@openshift-ci-robot
Copy link
Copy Markdown
Contributor

@jcmoraisjr: This pull request references Jira Issue OCPBUGS-49738, 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 (4.22.0) matches configured target version for branch (4.22.0)
  • bug is in the state New, which is one of the valid states (NEW, ASSIGNED, POST)

Requesting review from QA contact:
/cc @melvinjoseph86

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.

@alebedev87
Copy link
Copy Markdown
Contributor

/assign @gcs278

@melvinjoseph86
Copy link
Copy Markdown

melvinjoseph86 commented Feb 25, 2026

Able to reproduce the issue 'HostAlreadyClaimed' on a unfixed build and also tested the same on cluster using this PR.

➜  oc get clusterversion
NAME      VERSION                                                AVAILABLE   PROGRESSING   SINCE   STATUS
version   4.22.0-0-2026-02-25-140247-test-ci-ln-8iitiib-latest   True        False         130m    Cluster version is 4.22.0-0-2026-02-25-140247-test-ci-ln-8iitiib-latest

➜  oc patch ingresscontroller default -n openshift-ingress-operator --type=merge -p '{"spec":{"routeAdmission":{"wildcardPolicy":"WildcardsAllowed"}}}'
ingresscontroller.operator.openshift.io/default patched

➜  oc create -f webrc.yaml 
replicationcontroller/web-server-rc created
service/service-secure created
service/service-unsecure created

➜  oc expose service service-unsecure --name httpd-cm1                                                                                            
route.route.openshift.io/httpd-cm1 exposed
➜  oc expose service service-unsecure --name httpd-cm2
route.route.openshift.io/httpd-cm2 exposed
➜  oc get svc
NAME               TYPE           CLUSTER-IP      EXTERNAL-IP                            PORT(S)     AGE
kubernetes         ClusterIP      172.30.0.1      <none>                                 443/TCP     168m
openshift          ExternalName   <none>          kubernetes.default.svc.cluster.local   <none>      163m
service-secure     ClusterIP      172.30.68.65    <none>                                 27443/TCP   106s
service-unsecure   ClusterIP      172.30.131.71   <none>                                 27017/TCP   105s

➜  oc get routes
NAME        HOST/PORT                                                           PATH   SERVICES           PORT   TERMINATION   WILDCARD
httpd-cm1   httpd-cm1-default.apps.ci-ln-8iitiib-76ef8.aws-4.ci.openshift.org          service-unsecure   http                 None
httpd-cm2   httpd-cm2-default.apps.ci-ln-8iitiib-76ef8.aws-4.ci.openshift.org          service-unsecure   http                 None

➜  oc patch route httpd-cm1 --type=merge -p '{"spec":{"host":"httpd-cm2-default.apps.ci-ln-8iitiib-76ef8.aws-4.ci.openshift.org"}}' 
route.route.openshift.io/httpd-cm1 patched
➜  oc patch route httpd-cm2 --type=merge -p '{"spec":{"host":"httpd-cm1-default.apps.ci-ln-8iitiib-76ef8.aws-4.ci.openshift.org"}}'
route.route.openshift.io/httpd-cm2 patched

➜  oc get routes  
NAME        HOST/PORT                                                           PATH   SERVICES           PORT   TERMINATION   WILDCARD
httpd-cm1   httpd-cm2-default.apps.ci-ln-8iitiib-76ef8.aws-4.ci.openshift.org          service-unsecure   http                 None
httpd-cm2   httpd-cm1-default.apps.ci-ln-8iitiib-76ef8.aws-4.ci.openshift.org          service-unsecure   http                 None
➜  oc get routes -o json | jq -r '.items[] |.metadata.name,.spec.host,.status.ingress[].conditions[].message'
httpd-cm1
httpd-cm2-default.apps.ci-ln-8iitiib-76ef8.aws-4.ci.openshift.org
null
httpd-cm2
httpd-cm1-default.apps.ci-ln-8iitiib-76ef8.aws-4.ci.openshift.org

Hence marking as verified
/verified by @mjoseph
@jcmoraisjr Does the existing e2e will handle this change or do we need to modify/add

@openshift-ci-robot openshift-ci-robot added the verified Signifies that the PR passed pre-merge verification criteria label Feb 25, 2026
@openshift-ci-robot
Copy link
Copy Markdown
Contributor

@melvinjoseph86: This PR has been marked as verified by @mjoseph.

Details

In response to this:

Able reproduce the issue 'HostAlreadyClaimed' on unfixed build and also tested the same on cluster using this PR.

➜  oc get clusterversion
NAME      VERSION                                                AVAILABLE   PROGRESSING   SINCE   STATUS
version   4.22.0-0-2026-02-25-140247-test-ci-ln-8iitiib-latest   True        False         130m    Cluster version is 4.22.0-0-2026-02-25-140247-test-ci-ln-8iitiib-latest

➜  oc patch ingresscontroller default -n openshift-ingress-operator --type=merge -p '{"spec":{"routeAdmission":{"wildcardPolicy":"WildcardsAllowed"}}}'
ingresscontroller.operator.openshift.io/default patched

➜  oc create -f webrc.yaml 
replicationcontroller/web-server-rc created
service/service-secure created
service/service-unsecure created

➜  oc expose service service-unsecure --name httpd-cm1                                                                                            
route.route.openshift.io/httpd-cm1 exposed
➜  oc expose service service-unsecure --name httpd-cm2
route.route.openshift.io/httpd-cm2 exposed
➜  oc get svc
NAME               TYPE           CLUSTER-IP      EXTERNAL-IP                            PORT(S)     AGE
kubernetes         ClusterIP      172.30.0.1      <none>                                 443/TCP     168m
openshift          ExternalName   <none>          kubernetes.default.svc.cluster.local   <none>      163m
service-secure     ClusterIP      172.30.68.65    <none>                                 27443/TCP   106s
service-unsecure   ClusterIP      172.30.131.71   <none>                                 27017/TCP   105s

➜  oc get routes
NAME        HOST/PORT                                                           PATH   SERVICES           PORT   TERMINATION   WILDCARD
httpd-cm1   httpd-cm1-default.apps.ci-ln-8iitiib-76ef8.aws-4.ci.openshift.org          service-unsecure   http                 None
httpd-cm2   httpd-cm2-default.apps.ci-ln-8iitiib-76ef8.aws-4.ci.openshift.org          service-unsecure   http                 None

➜  oc patch route httpd-cm1 --type=merge -p '{"spec":{"host":"httpd-cm2-default.apps.ci-ln-8iitiib-76ef8.aws-4.ci.openshift.org"}}' 
route.route.openshift.io/httpd-cm1 patched
➜  oc patch route httpd-cm2 --type=merge -p '{"spec":{"host":"httpd-cm1-default.apps.ci-ln-8iitiib-76ef8.aws-4.ci.openshift.org"}}'
route.route.openshift.io/httpd-cm2 patched

➜  oc get routes  
NAME        HOST/PORT                                                           PATH   SERVICES           PORT   TERMINATION   WILDCARD
httpd-cm1   httpd-cm2-default.apps.ci-ln-8iitiib-76ef8.aws-4.ci.openshift.org          service-unsecure   http                 None
httpd-cm2   httpd-cm1-default.apps.ci-ln-8iitiib-76ef8.aws-4.ci.openshift.org          service-unsecure   http                 None
➜  oc get routes -o json | jq -r '.items[] |.metadata.name,.spec.host,.status.ingress[].conditions[].message'
httpd-cm1
httpd-cm2-default.apps.ci-ln-8iitiib-76ef8.aws-4.ci.openshift.org
null
httpd-cm2
httpd-cm1-default.apps.ci-ln-8iitiib-76ef8.aws-4.ci.openshift.org

Hence marking as verified
/verified by @mjoseph
@jcmoraisjr Does the existing e2e will handle this change or do we need to modify/add

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.

@jcmoraisjr
Copy link
Copy Markdown
Member Author

@melvinjoseph86 I'm not sure we have an e2e that covers this scenario, it was unknown for us up to now. So it'd need to be added if we want the coverage.

@gcs278
Copy link
Copy Markdown
Contributor

gcs278 commented Apr 22, 2026

@CodeRabbit can you review this PR?

@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented Apr 22, 2026

@gcs278 Sure, I'll start reviewing this PR right away!

✅ Actions performed

Review triggered.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented Apr 22, 2026

Walkthrough

Route host ownership tracking was changed: RouteMap.RemoveRoute no longer returns a boolean and now deletes in-place via slices.DeleteFunc. HostAdmitter added a routeHosts map[types.UID]string cache; add/modify/delete flows use the cached prior host to remove claims from claimed/blocked maps before (re)claiming and update the cache. Tests were expanded to cover update/delete reclaiming behavior.

Changes

Host admitter ownership flow

Layer / File(s) Summary
Data Shape / API
pkg/router/controller/host_admitter.go
RouteMap.RemoveRoute signature changed to drop boolean return; HostAdmitter gains routeHosts map[types.UID]string.
Core Implementation
pkg/router/controller/host_admitter.go
On route add/modify, code now looks up routeHosts[route.UID] to pre-remove prior host and its wildcard key from claimedHosts, blockedWildcards, and claimedWildcards before applying current WildcardPolicy claims; on delete, cleanup uses the cached host and removes the UID entry from routeHosts.
Wiring / Integration
pkg/router/controller/host_admitter.go
Removed previous per-policy cross-map cleanup inside the wildcard switch; claim insertion and routeHosts[UID] update occur after pre-removal. RouteMap entries are updated/removed using slices.DeleteFunc.
Tests
pkg/router/controller/host_admitter_test.go
TestWildcardHostDeny updated to set ObjectMeta.UID and full RouteSpec (Host, Path, WildcardPolicy), uses wildcardAdmitter(true) and require assertions. New TestWildcardHostUpdate added to exercise Added→Modified→Deleted flows, asserting conflict errors and verifying ownership maps are cleared so hosts can be reclaimed.
Deps / Minor
pkg/router/controller/host_admitter_test.go
Added github.com/stretchr/testify/require for assertions.

Sequence Diagram(s)

sequenceDiagram
    participant K8sWatch as K8sWatch
    participant Admitter as HostAdmitter
    participant Map as RouteMap
    participant Claims as claimed/blocked maps

    K8sWatch->>Admitter: Add/Modify/Delete Route (UID, Spec{Host,Path,WildcardPolicy})
    Admitter->>Admitter: lookup routeHosts[UID] -> oldHost?
    alt oldHost exists
        Admitter->>Map: RemoveRoute(keyFor(oldHost), route)
        Admitter->>Claims: remove oldHost and wildcardKey from claimedHosts/blockedWildcards/claimedWildcards
    end
    alt event != Deleted
        Admitter->>Admitter: evaluate WildcardPolicy and attempt claim
        Admitter->>Map: Insert/claim new host entry
        Admitter->>Admitter: routeHosts[UID] = newHost
    else Deleted
        Admitter->>Admitter: delete routeHosts[UID]
    end
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

🚥 Pre-merge checks | ✅ 10 | ❌ 2

❌ Failed checks (2 warnings)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 25.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
Test Structure And Quality ⚠️ Warning TestWildcardHostUpdate uses bare require assertions without meaningful failure messages, inconsistent with established t.Fatalf patterns in the same file. Replace bare require calls with wrapped calls including context messages or use t.Fatalf following the file's established pattern for improved test failure diagnostics.
✅ Passed checks (10 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately reflects the main change: fixing host conflict handling by improving how routes are removed from internal maps when host values change.
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 pull request uses the standard Go testing.T framework, not Ginkgo. The imports show only testing with no Ginkgo packages, and grep confirms the absence of Ginkgo patterns.
Microshift Test Compatibility ✅ Passed This PR does not add Ginkgo e2e tests. The new test is a standard Go unit test, not a Ginkgo e2e test suite.
Single Node Openshift (Sno) Test Compatibility ✅ Passed The PR adds a standard Go unit test to controller-level code using func TestXxx(t *testing.T) pattern with no Ginkgo imports or e2e test patterns, so the custom check for Ginkgo e2e tests is not applicable.
Topology-Aware Scheduling Compatibility ✅ Passed Pull request modifies only application-level route admission control logic with no deployment manifests, scheduling constraints, affinity rules, topology specifications, or infrastructure-level changes.
Ote Binary Stdout Contract ✅ Passed The PR modifies controller code (host_admitter.go) and unit tests (host_admitter_test.go) with logging statements as runtime logic, not process-level initialization code, and no stdout writes detected.
Ipv6 And Disconnected Network Test Compatibility ✅ Passed The PR does not add any Ginkgo e2e tests. The new test function TestWildcardHostUpdate and modified TestWildcardHostDeny are standard Go unit tests using testing.T, not Ginkgo e2e tests.

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

✨ 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
Review rate limit: 0/1 reviews remaining, refill in 60 minutes.

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

@openshift-ci-robot openshift-ci-robot added jira/invalid-bug Indicates that a referenced Jira bug is invalid for the branch this PR is targeting. and removed jira/valid-bug Indicates that a referenced Jira bug is valid for the branch this PR is targeting. labels Apr 22, 2026
@openshift-ci-robot
Copy link
Copy Markdown
Contributor

@jcmoraisjr: This pull request references Jira Issue OCPBUGS-49738, which is invalid:

  • expected the bug to target either version "5.0." or "openshift-5.0.", but it targets "4.22.0" instead

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.

Details

In response to this:

Routes are grouped by host on three distinct hashmaps when allowWildcardRoutes is enabled. These hashmaps are updated whenever routes are added, modified or deleted, and their content is used to evaluate host conflicts. This hashmaps handling is done using the current host of the route resource, so, if the host value changes, the router does not find the entry on the hashmaps because it is using the current - and still not used - host value as the key.

The approach used on this update is to ignore the host from the router, and remove the resource from all the hosts instead, since the only match on all the hashmaps should be found on the key corresponding to the former host value.

Summary by CodeRabbit

  • Bug Fixes

  • Improved route removal and cleanup logic to ensure routes are properly removed from all relevant mappings before being reused or reassigned.

  • Refactor

  • Optimized internal route management operations for better efficiency and maintainability.

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.

Comment thread pkg/router/controller/host_admitter.go
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.

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
pkg/router/controller/host_admitter.go (1)

172-210: ⚠️ Potential issue | 🟠 Major

Move stale-entry cleanup before conflict detection.

Line 174 can return before Lines 207-210 run. If a route changes host and the new host is rejected as already claimed, its old host entry remains in the maps, so the original stale-claim bug still survives on the rejection path.

🐛 Proposed fix
 func (p *HostAdmitter) addRoute(route *routev1.Route) error {
+	// Remove old entries for this route from all hosts before conflict checks;
+	// this handles host changes even when the new host is rejected.
+	p.claimedHosts.RemoveRouteFromAllKeys(route)
+	p.blockedWildcards.RemoveRouteFromAllKeys(route)
+	p.claimedWildcards.RemoveRouteFromAllKeys(route)
+
 	// Find displaced routes (or error if an existing route displaces us)
 	displacedRoutes, err, ownerNamespace := p.displacedRoutes(route)
 	if err != nil {
 		msg := fmt.Sprintf("a route in another namespace holds host %s", route.Spec.Host)
 		if ownerNamespace == route.Namespace {
@@
 		p.plugin.HandleRoute(watch.Deleted, displacedRoute)
 	}
 
-	// Remove old entries for this route from all hosts, this handles the change of the host value
-	p.claimedHosts.RemoveRouteFromAllKeys(route)
-	p.blockedWildcards.RemoveRouteFromAllKeys(route)
-	p.claimedWildcards.RemoveRouteFromAllKeys(route)
-
 	if len(route.Spec.WildcardPolicy) == 0 {
 		route.Spec.WildcardPolicy = routev1.WildcardPolicyNone
 	}
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@pkg/router/controller/host_admitter.go` around lines 172 - 210, The stale
host entries cleanup must run before checking/early-returning on displaced
routes so a rejected new-host doesn't leave the old host claimed; move the calls
to p.claimedHosts.RemoveRouteFromAllKeys(route),
p.blockedWildcards.RemoveRouteFromAllKeys(route), and
p.claimedWildcards.RemoveRouteFromAllKeys(route) to just before invoking
p.displacedRoutes(route) (i.e., run cleanup on the incoming route first), then
call p.displacedRoutes(route) and proceed with the existing error handling and
displacedRoute removals as-is; ensure you reference all three
RemoveRouteFromAllKeys methods and keep the displacedRoutes/error flow unchanged
besides relocating the cleanup.
🧹 Nitpick comments (1)
pkg/router/controller/host_admitter.go (1)

38-42: Consider avoiding full-map scans on every route admission.

This helper is O(total routes) per call; used on every add/modify, bulk syncs can become O(n²). If route volume is high, consider tracking previous keys per namespace/name or limiting the full scan to update paths that can actually have stale entries.

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

In `@pkg/router/controller/host_admitter.go` around lines 38 - 42,
RemoveRouteFromAllKeys currently scans the entire RouteMap on every call which
is O(total routes) and leads to quadratic behavior during bulk syncs; change the
implementation to avoid full-map scans by tracking previously associated keys
per route (e.g., maintain a map[string]map[string]struct{} keyed by
namespace/name -> set of keys) so
RemoveRouteFromAllKeys(RouteMap.RemoveRouteFromAllKeys) can iterate only the
known keys for the given route (routev1.Route) and call RouteMap.RemoveRoute for
those entries, or alternatively update callers to pass the specific keys to
remove rather than relying on a global scan.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Outside diff comments:
In `@pkg/router/controller/host_admitter.go`:
- Around line 172-210: The stale host entries cleanup must run before
checking/early-returning on displaced routes so a rejected new-host doesn't
leave the old host claimed; move the calls to
p.claimedHosts.RemoveRouteFromAllKeys(route),
p.blockedWildcards.RemoveRouteFromAllKeys(route), and
p.claimedWildcards.RemoveRouteFromAllKeys(route) to just before invoking
p.displacedRoutes(route) (i.e., run cleanup on the incoming route first), then
call p.displacedRoutes(route) and proceed with the existing error handling and
displacedRoute removals as-is; ensure you reference all three
RemoveRouteFromAllKeys methods and keep the displacedRoutes/error flow unchanged
besides relocating the cleanup.

---

Nitpick comments:
In `@pkg/router/controller/host_admitter.go`:
- Around line 38-42: RemoveRouteFromAllKeys currently scans the entire RouteMap
on every call which is O(total routes) and leads to quadratic behavior during
bulk syncs; change the implementation to avoid full-map scans by tracking
previously associated keys per route (e.g., maintain a
map[string]map[string]struct{} keyed by namespace/name -> set of keys) so
RemoveRouteFromAllKeys(RouteMap.RemoveRouteFromAllKeys) can iterate only the
known keys for the given route (routev1.Route) and call RouteMap.RemoveRoute for
those entries, or alternatively update callers to pass the specific keys to
remove rather than relying on a global scan.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository: openshift/coderabbit/.coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: a4014cee-4bb7-40ef-87a0-3c4f7d28ca9b

📥 Commits

Reviewing files that changed from the base of the PR and between d8ed355 and d6ed14d.

📒 Files selected for processing (1)
  • pkg/router/controller/host_admitter.go

@jcmoraisjr jcmoraisjr force-pushed the OCPBUGS-49738-fix-routemap branch from d6ed14d to daab4aa Compare April 23, 2026 13:05
@openshift-ci-robot openshift-ci-robot removed the verified Signifies that the PR passed pre-merge verification criteria label Apr 23, 2026
@jcmoraisjr
Copy link
Copy Markdown
Member Author

/jira refresh

@openshift-ci-robot openshift-ci-robot added jira/valid-bug Indicates that a referenced Jira bug is valid for the branch this PR is targeting. and removed jira/invalid-bug Indicates that a referenced Jira bug is invalid for the branch this PR is targeting. labels Apr 23, 2026
@openshift-ci-robot
Copy link
Copy Markdown
Contributor

@jcmoraisjr: This pull request references Jira Issue OCPBUGS-49738, 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)

Requesting review from QA contact:
/cc @melvinjoseph86

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.

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: 1

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
pkg/router/controller/host_admitter_test.go (1)

157-259: ⚠️ Potential issue | 🟡 Minor

Avoid masking host conflicts with zero UIDs after enabling wildcard tracking.

Line 159 now enables the RouteMap conflict path, but these table fixtures still share the empty UID. HostAdmitter.displacedRoutes skips same-UID routes in pkg/router/controller/host_admitter.go:259-262, so duplicate-host cases can pass as “same route” rather than validating admission behavior.

🧪 Proposed test isolation fix
 func TestWildcardHostDeny(t *testing.T) {
-	p := &fakePlugin{}
-	admitter := NewHostAdmitter(p, wildcardAdmitter, true, false, LogRejections)
 	tests := []struct {
 		name   string
 		host   string
@@
 
 	for _, tc := range tests {
-		route := &routev1.Route{
-			ObjectMeta: metav1.ObjectMeta{
-				Name:      tc.name,
-				Namespace: "deny",
-			},
-			Spec: routev1.RouteSpec{Host: tc.host, WildcardPolicy: tc.policy},
-		}
+		t.Run(tc.name, func(t *testing.T) {
+			p := &fakePlugin{}
+			admitter := NewHostAdmitter(p, wildcardAdmitter, true, false, LogRejections)
+			route := &routev1.Route{
+				ObjectMeta: metav1.ObjectMeta{
+					Name:      tc.name,
+					Namespace: "deny",
+					UID:       types.UID(tc.name),
+				},
+				Spec: routev1.RouteSpec{Host: tc.host, WildcardPolicy: tc.policy},
+			}
 
-		err := admitter.HandleRoute(watch.Added, route)
-		if tc.errors {
-			if err == nil {
-				t.Fatalf("Test case %s expected errors, got none", tc.name)
-			}
-		} else {
-			if err != nil {
-				t.Fatalf("Test case %s expected no errors, got %v", tc.name, err)
+			err := admitter.HandleRoute(watch.Added, route)
+			if tc.errors {
+				if err == nil {
+					t.Fatalf("Test case %s expected errors, got none", tc.name)
+				}
+			} else {
+				if err != nil {
+					t.Fatalf("Test case %s expected no errors, got %v", tc.name, err)
+				}
 			}
-		}
+		})
 	}
 }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@pkg/router/controller/host_admitter_test.go` around lines 157 - 259, The test
uses multiple Route fixtures with empty ObjectMeta.UIDs, which masks conflict
detection because HostAdmitter.displacedRoutes ignores routes with the same UID;
update TestWildcardHostDeny to give each test route a unique UID (e.g.,
route.ObjectMeta.UID = types.UID(fmt.Sprintf("%s-uid", tc.name)) or similar)
before calling NewHostAdmitter/HandleRoute so duplicate-host cases are evaluated
as distinct routes and the wildcard conflict path is exercised correctly.
🤖 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/router/controller/host_admitter_test.go`:
- Around line 262-329: TestWildcardHostUpdate reuses one admitter and duplicate
UIDs across subtests and doesn't validate cleanup of route2's old host key;
update the test to create a fresh NewHostAdmitter per t.Run and assign unique
UIDs for each route (avoid reusing "1"/"2"), and add a third route (e.g.,
route3) that uses tc.oldHostRoute2 before modifying route2, call
admitter.HandleRoute(watch.Added, route3) to ensure the map entry for
oldHostRoute2 is exercised, then perform the Modified updates for route1/route2
with unique UIDs to assert the cleanup behavior implemented around
RemoveRouteFromAllKeys (host_admitter.go lines ~211-213) is covered.

---

Outside diff comments:
In `@pkg/router/controller/host_admitter_test.go`:
- Around line 157-259: The test uses multiple Route fixtures with empty
ObjectMeta.UIDs, which masks conflict detection because
HostAdmitter.displacedRoutes ignores routes with the same UID; update
TestWildcardHostDeny to give each test route a unique UID (e.g.,
route.ObjectMeta.UID = types.UID(fmt.Sprintf("%s-uid", tc.name)) or similar)
before calling NewHostAdmitter/HandleRoute so duplicate-host cases are evaluated
as distinct routes and the wildcard conflict path is exercised correctly.
🪄 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: openshift/coderabbit/.coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: ae9cb993-942f-43a8-a1ce-81641a5396ba

📥 Commits

Reviewing files that changed from the base of the PR and between d6ed14d and daab4aa.

📒 Files selected for processing (2)
  • pkg/router/controller/host_admitter.go
  • pkg/router/controller/host_admitter_test.go
🚧 Files skipped from review as they are similar to previous changes (1)
  • pkg/router/controller/host_admitter.go

Comment thread pkg/router/controller/host_admitter_test.go
@jcmoraisjr jcmoraisjr force-pushed the OCPBUGS-49738-fix-routemap branch from daab4aa to fe0db75 Compare April 23, 2026 13:40
@melvinjoseph86
Copy link
Copy Markdown

/retest-required

1 similar comment
@melvinjoseph86
Copy link
Copy Markdown

/retest-required

Copy link
Copy Markdown
Contributor

@gcs278 gcs278 left a comment

Choose a reason for hiding this comment

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

Nice PR - generally looks good, I just have a concern about performance and a minor unit test coverage addition.

require.NoError(t, err)
err = admitter.HandleRoute(watch.Modified, route2)
require.NoError(t, err)
})
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.

nit For complete coverage, consider adding a delete then recreate here with another route that is using the same hostname, since the bug https://redhat.atlassian.net/browse/OCPBUGS-49738 called out a "phantom" hostname claim even while the route was deleted.

Suggested change
})
route3name := tc.namePrefix + "-route3"
route3 := &routev1.Route{
ObjectMeta: metav1.ObjectMeta{
Name: route3name,
Namespace: "host-update",
UID: types.UID(route3name),
},
Spec: routev1.RouteSpec{Host: tc.oldHostRoute1, WildcardPolicy: tc.policy},
}
[...]
// Delete both routes
err = admitter.HandleRoute(watch.Deleted, route1)
require.NoError(t, err)
err = admitter.HandleRoute(watch.Deleted, route2)
require.NoError(t, err)
// New route should be able to claim route1's original host
err = admitter.HandleRoute(watch.Added, route3)
require.NoError(t, err)
})

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

Good idea, just added.

Comment thread pkg/router/controller/host_admitter.go Outdated
Comment on lines +210 to +212
p.claimedHosts.RemoveRouteFromAllKeys(route)
p.blockedWildcards.RemoveRouteFromAllKeys(route)
p.claimedWildcards.RemoveRouteFromAllKeys(route)
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.

I had claude do a rough benchmarking for me.

Master (before) PR (after) Ratio
routes-100 ~3,800 ns/op ~7,600 ns/op 2x slower
routes-1,000 ~8,500 ns/op ~85,500 ns/op 10x slower
routes-10,000 ~170,000 ns/op ~1,100,000 ns/op 6x slower

Nothing unexpected here - iterating over the routes can be expensive for large clusters.

My experience is that the router is particularly performance sensitive - and sometimes have customers with an enormous amount of routes (10k+).

The alternative to looping through is to use a data structure to do some "bookkeeping" of the previous route (key) to hostname (value), so that you could look up the route's previous hostname quickly and remove that without scanning.

Could look something like:

Suggested change
p.claimedHosts.RemoveRouteFromAllKeys(route)
p.blockedWildcards.RemoveRouteFromAllKeys(route)
p.claimedWildcards.RemoveRouteFromAllKeys(route)
if oldHost, ok := p.routeHosts[route.UID]; ok {
oldWildcardKey := routeapihelpers.GetDomainForHost(oldHost)
p.claimedHosts.RemoveRoute(oldHost, route)
p.blockedWildcards.RemoveRoute(oldWildcardKey, route)
p.claimedWildcards.RemoveRoute(oldWildcardKey, route)
}
p.routeHosts[route.UID] = route.Spec.Host

Did you consider adding a cache of route hostnames like this for better performance?

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

This is a fair point, in fact I was focusing more in the problem instead of in the solution. Just changed pretty much like you suggested, changing a bit in naming and location of the code.

@jcmoraisjr jcmoraisjr force-pushed the OCPBUGS-49738-fix-routemap branch from fe0db75 to 5f8894c Compare April 28, 2026 13:26
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.

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
pkg/router/controller/host_admitter.go (1)

145-150: ⚠️ Potential issue | 🟠 Major

Memory leak: routeHosts cache not cleaned up on route deletion.

When a route is deleted, the entry in p.routeHosts[route.UID] is never removed. This causes a memory leak over time as routes are deleted, and could cause stale behavior if a route UID is reused.

🔧 Proposed fix
 		case watch.Deleted:
 			p.claimedHosts.RemoveRoute(route.Spec.Host, route)
 			wildcardKey := routeapihelpers.GetDomainForHost(route.Spec.Host)
 			p.claimedWildcards.RemoveRoute(wildcardKey, route)
 			p.blockedWildcards.RemoveRoute(wildcardKey, route)
+			delete(p.routeHosts, route.UID)
 		}
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@pkg/router/controller/host_admitter.go` around lines 145 - 150, The Deleted
case in the watch handler is missing cleanup of the per-route cache entry in
p.routeHosts; add code in the watch.Deleted branch to remove the entry for the
deleted route (e.g., delete(p.routeHosts, route.UID) or
p.routeHosts.Delete(route.UID) depending on the container type) and, if
p.routeHosts is protected by a mutex, perform the deletion under the same lock
used elsewhere to avoid races.
🧹 Nitpick comments (1)
pkg/router/controller/host_admitter.go (1)

24-35: Misleading variable name: removed contains remaining elements, not removed ones.

slices.DeleteFunc returns the modified slice with matching elements removed, so removed actually holds the elements that were not removed. Consider renaming to remaining for clarity.

♻️ Suggested rename for clarity
 func (srm RouteMap) RemoveRoute(key string, route *routev1.Route) {
 	source := srm[key]
-	removed := slices.DeleteFunc(source, func(r *routev1.Route) bool {
+	remaining := slices.DeleteFunc(source, func(r *routev1.Route) bool {
 		return r.Namespace == route.Namespace && r.Name == route.Name
 	})
 
-	if len(removed) > 0 {
-		srm[key] = removed
+	if len(remaining) > 0 {
+		srm[key] = remaining
 	} else {
 		delete(srm, key)
 	}
 }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@pkg/router/controller/host_admitter.go` around lines 24 - 35, The variable
name `removed` in RouteMap.RemoveRoute is misleading because slices.DeleteFunc
returns the slice after deletion (the remaining elements); rename `removed` to
`remaining` (or similar) and update uses in the function (the assignment
srm[key] = remaining and the else branch) to reflect that it contains the
elements that remain rather than the ones removed—this keeps semantics clear in
the RemoveRoute function and matches the behavior of slices.DeleteFunc.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Outside diff comments:
In `@pkg/router/controller/host_admitter.go`:
- Around line 145-150: The Deleted case in the watch handler is missing cleanup
of the per-route cache entry in p.routeHosts; add code in the watch.Deleted
branch to remove the entry for the deleted route (e.g., delete(p.routeHosts,
route.UID) or p.routeHosts.Delete(route.UID) depending on the container type)
and, if p.routeHosts is protected by a mutex, perform the deletion under the
same lock used elsewhere to avoid races.

---

Nitpick comments:
In `@pkg/router/controller/host_admitter.go`:
- Around line 24-35: The variable name `removed` in RouteMap.RemoveRoute is
misleading because slices.DeleteFunc returns the slice after deletion (the
remaining elements); rename `removed` to `remaining` (or similar) and update
uses in the function (the assignment srm[key] = remaining and the else branch)
to reflect that it contains the elements that remain rather than the ones
removed—this keeps semantics clear in the RemoveRoute function and matches the
behavior of slices.DeleteFunc.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository: openshift/coderabbit/.coderabbit.yaml

Review profile: CHILL

Plan: Enterprise

Run ID: e42df920-e088-45f1-bf5f-a1a2e2247e97

📥 Commits

Reviewing files that changed from the base of the PR and between daab4aa and 5f8894c.

📒 Files selected for processing (2)
  • pkg/router/controller/host_admitter.go
  • pkg/router/controller/host_admitter_test.go

@jcmoraisjr jcmoraisjr force-pushed the OCPBUGS-49738-fix-routemap branch 2 times, most recently from 704aaf6 to 31a6c97 Compare April 28, 2026 14:27
Comment thread pkg/router/controller/host_admitter.go Outdated
@@ -153,6 +147,7 @@ func (p *HostAdmitter) HandleRoute(eventType watch.EventType, route *routev1.Rou
wildcardKey := routeapihelpers.GetDomainForHost(route.Spec.Host)
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.

I think there is another nuanced variation of this bug with delete behavior that we should consider fixing while we are here. Consider the scenario:

  1. RouteX added with hostA: maps have entries under A, routeHosts[UID] = A
  2. RouteX modified to hostB, but rejected by displacedRoutes: maps still have entries under hostA, routeHosts[UID] still = A
  3. RouteX deleted: route.Spec.Host = B, but maps have the route under A: RemoveRoute("B", route) is a no-op, stale entry leaks

In this scenario, we'd be attempting to clean up entries in claimedHosts, claimedWildcards, and blockedWildcards using a host that was never admitted. routeHosts is effectively the "last successfully admitted host" while the route might have failed to admit it's current host.

Should we also use routeHosts here to fix that bug? Also, if you do end up fixing this, consider a unit test, like TestDeleteAfterRejectedHostChange to verify the bug I'm describing & the fix.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

Good catch, got it, makes sense, just updated as suggested.

I reused the same tests to cover this new scenario, since this is a complement of what the test already implements, how do the changes sound?

Comment thread pkg/router/controller/host_admitter.go Outdated
p.blockedWildcards.RemoveRoute(oldWildcardKey, route)
p.claimedWildcards.RemoveRoute(oldWildcardKey, route)
}
p.routeHosts[route.UID] = route.Spec.Host
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.

Should this go below the switch statement? The switch statement's default case is a rejection for an unsupported wildcard policy, which means we'd be storing a route host in our map that was rejected.

Probably more of defensive coding comment - I don't know if it's possible to trigger the Default case with API validation.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

In fact I think the API validation blocks this path to happen, but it worth to use a defensive code here. Just changed as suggested.

Routes are grouped by host on three distinct hashmaps when
allowWildcardRoutes is enabled. These hashmaps are updated whenever
routes are added, modified or deleted, and their content is used to
evaluate host conflicts. This hashmaps handling is done using the
current host of the route resource, so, if the host value changes, the
router does not find the entry on the hashmaps because it is using the
current - and still not used - host value as the key.

The approach used on this update is to cache the host from the router
when it's added, and remove the resource from the cached host, which is
the key of the hashmaps used to evaluate conflicts.
@jcmoraisjr jcmoraisjr force-pushed the OCPBUGS-49738-fix-routemap branch from 31a6c97 to c223ef7 Compare May 4, 2026 14:25
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.

🧹 Nitpick comments (1)
pkg/router/controller/host_admitter.go (1)

218-238: ⚡ Quick win

Pre-removal of old claims happens before wildcard-policy validation — state can become inconsistent if the default branch is reached.

When the pre-removal block (lines 218–224) runs, it removes the route's old claims from claimedHosts, blockedWildcards, and claimedWildcards. If the switch then hits default, it returns an error after those removals but before inserting any new claims. The downstream plugin's HandleRoute is never called (the caller returns on error), so the route continues to be served — but the admitted-host entry is now gone from all three maps, allowing another route to claim the same host. routeHosts[route.UID] is also stale (still holds the old host). The recovery path on a subsequent add/modify is a no-op pre-removal followed by correct re-insertion, so the state is eventually corrected, but there is a window of inconsistency.

While WildcardPolicyNone and WildcardPolicySubdomain are the only values currently valid via API admission, a forward-compatibility edge exists if a new policy type is added to the API without a corresponding router update.

The simplest defensive fix is to validate the policy before mutating any state:

🛡️ Suggested defensive fix: validate policy before pre-removal
+	// Validate the wildcard policy before touching claimed/blocked maps so that
+	// an unsupported policy cannot leave the maps in an inconsistent state.
+	switch route.Spec.WildcardPolicy {
+	case routev1.WildcardPolicyNone, routev1.WildcardPolicySubdomain:
+		// valid, fall through
+	default:
+		err := fmt.Errorf("unsupported wildcard policy %s", route.Spec.WildcardPolicy)
+		p.recorder.RecordRouteRejection(route, "RouteNotAdmitted", err.Error())
+		return err
+	}
+
 	// Restore the old host and old wildcard key, removing from the previously claimed ones
 	if oldHost, found := p.routeHosts[route.UID]; found {
 		oldWildcardKey := routeapihelpers.GetDomainForHost(oldHost)
 		// ensure the route doesn't exist as a claimed host or blocked wildcard - in case it previously was
 		p.claimedHosts.RemoveRoute(oldHost, route)
 		p.blockedWildcards.RemoveRoute(oldWildcardKey, route)
 		p.claimedWildcards.RemoveRoute(oldWildcardKey, route)
 	}

 	switch route.Spec.WildcardPolicy {
 	case routev1.WildcardPolicyNone:
 		p.claimedHosts.InsertRoute(route.Spec.Host, route)
 		p.blockedWildcards.InsertRoute(wildcardKey, route)
 	case routev1.WildcardPolicySubdomain:
 		p.claimedWildcards.InsertRoute(wildcardKey, route)
-	default:
-		err := fmt.Errorf("unsupported wildcard policy %s", route.Spec.WildcardPolicy)
-		p.recorder.RecordRouteRejection(route, "RouteNotAdmitted", err.Error())
-		return err
 	}
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@pkg/router/controller/host_admitter.go` around lines 218 - 238, Pre-validate
the route's WildcardPolicy before mutating admission state: move or add a policy
validation step at the start of the admission path in host_admitter (where
p.routeHosts is referenced) to return an error and call
p.recorder.RecordRouteRejection for unsupported policies before performing the
pre-removal block that calls p.claimedHosts.RemoveRoute,
p.blockedWildcards.RemoveRoute and p.claimedWildcards.RemoveRoute; keep the
existing switch (route.Spec.WildcardPolicy ->
routev1.WildcardPolicyNone/routev1.WildcardPolicySubdomain/default) but ensure
the default branch can never run after state was already mutated by performing
the validation first and only then doing the removals and subsequent InsertRoute
calls.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Nitpick comments:
In `@pkg/router/controller/host_admitter.go`:
- Around line 218-238: Pre-validate the route's WildcardPolicy before mutating
admission state: move or add a policy validation step at the start of the
admission path in host_admitter (where p.routeHosts is referenced) to return an
error and call p.recorder.RecordRouteRejection for unsupported policies before
performing the pre-removal block that calls p.claimedHosts.RemoveRoute,
p.blockedWildcards.RemoveRoute and p.claimedWildcards.RemoveRoute; keep the
existing switch (route.Spec.WildcardPolicy ->
routev1.WildcardPolicyNone/routev1.WildcardPolicySubdomain/default) but ensure
the default branch can never run after state was already mutated by performing
the validation first and only then doing the removals and subsequent InsertRoute
calls.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository: openshift/coderabbit/.coderabbit.yaml

Review profile: CHILL

Plan: Enterprise

Run ID: d4690f66-7e46-4c8e-99e7-72e407829202

📥 Commits

Reviewing files that changed from the base of the PR and between 5f8894c and c223ef7.

📒 Files selected for processing (2)
  • pkg/router/controller/host_admitter.go
  • pkg/router/controller/host_admitter_test.go
🚧 Files skipped from review as they are similar to previous changes (1)
  • pkg/router/controller/host_admitter_test.go

@openshift-ci
Copy link
Copy Markdown
Contributor

openshift-ci Bot commented May 4, 2026

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

@gcs278
Copy link
Copy Markdown
Contributor

gcs278 commented May 4, 2026

LGTM. Code Rabbit did point out that there is an minor inconsistency with removing the old routes from the hashmaps lookups before the wildcard policy is validated. Practically this can't happen today since the API validates the policy before it reaches the router, so I'm okay with moving forward. Feel free to address if you want.

Thanks for the quick turn around!

/approve
/lgtm

@openshift-ci openshift-ci Bot added the lgtm Indicates that a PR is ready to be merged. label May 4, 2026
@openshift-ci
Copy link
Copy Markdown
Contributor

openshift-ci Bot commented May 4, 2026

[APPROVALNOTIFIER] This PR is APPROVED

This pull-request has been approved by: gcs278

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 May 4, 2026
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. jira/severity-important Referenced Jira bug's severity is important 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.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants