Skip to content

fix: cannot use ingress when disabling gateway API#388

Merged
AlinsRan merged 3 commits intomasterfrom
fix/disable-gatewayapi-not-use-ingress
Feb 4, 2026
Merged

fix: cannot use ingress when disabling gateway API#388
AlinsRan merged 3 commits intomasterfrom
fix/disable-gatewayapi-not-use-ingress

Conversation

@AlinsRan
Copy link
Contributor

@AlinsRan AlinsRan commented Feb 4, 2026

Type of change:

  • Bugfix
  • New feature provided
  • Improve performance
  • Backport patches
  • Documentation
  • Refactor
  • Chore
  • CI/CD or Tests

What this PR does / why we need it:

When disabling the gateway API, the ingress resource cannot be used because the httproutepolicy does not have an index set.

Pre-submission checklist:

  • Did you explain what problem does this PR solve? Or what new features have been added?
  • Have you added corresponding test cases?
  • Have you modified the corresponding document?
  • Is this PR backward compatible? If it is not backward compatible, please discuss on the mailing list first

Summary by CodeRabbit

  • Bug Fixes

    • Fixed error handling in request reconciliation to log errors while continuing operations instead of aborting.
  • Refactor

    • Added indexer configuration for additional resource type to optimize query performance.

@coderabbitai
Copy link

coderabbitai bot commented Feb 4, 2026

📝 Walkthrough

Walkthrough

This PR adds HTTPRoutePolicy indexer configuration and modifies error handling in HTTPRoute and Ingress controllers. Errors during NotFound scenarios or status updates are now logged and processing continues, rather than causing early termination.

Changes

Cohort / File(s) Summary
HTTPRoutePolicy Indexer Setup
internal/controller/indexer/indexer.go
Introduces setHTTPRoutePolicyIndexer() function to configure indexing for HTTPRoutePolicy resources via PolicyTargetRefs and registers it in the SetupIndexer registration map.
Controller Error Handling Updates
internal/controller/httproute_controller.go, internal/controller/ingress_controller.go
Modifies Reconcile error handling to log errors and continue processing instead of returning early when NotFound or status update failures occur during deletion scenarios.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Poem

🐰 A policy indexer hops into view,
While errors now logged, not returned through,
Controllers keep dancing when things disappear,
Deleting with grace, no early frontier! 🌟

🚥 Pre-merge checks | ✅ 2 | ❌ 1
❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The PR title 'fix: cannot use ingress when disabling gateway API' directly corresponds to the root cause and fix described in the PR objectives: addressing the inability to use Ingress resources when Gateway API is disabled.

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

✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch fix/disable-gatewayapi-not-use-ingress

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

@AlinsRan AlinsRan requested a review from ronething February 4, 2026 09:00
Copy link

@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

🤖 Fix all issues with AI agents
In `@internal/controller/httproutepolicy.go`:
- Around line 47-50: The current handler swallows all errors from r.List (the
call using client.MatchingFields{indexer.PolicyTargetRefs: key}), returning nil
and preventing requeue; change it to import k8serrors
("k8s.io/apimachinery/pkg/api/errors") and, after r.List, return the error
unless k8serrors.IsNotFound(err) is true — i.e., only ignore not-found errors
(CRD missing) and otherwise log and return the error so the reconcile will
requeue and transient/RBAC issues are retried.

Comment on lines 47 to 50
if err := r.List(context.Background(), &list, client.MatchingFields{indexer.PolicyTargetRefs: key}); err != nil {
return err
r.Log.Error(err, "failed to list HTTPRoutePolicies for HTTPRoute", "httproute", utils.NamespacedName(httpRoute))
return nil
}
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🏁 Script executed:

# First, let's find and examine the httproutepolicy.go file
find . -name "httproutepolicy.go" -type f

Repository: api7/api7-ingress-controller

Length of output: 112


🏁 Script executed:

# Read the file to understand the error handling patterns
head -200 internal/controller/httproutepolicy.go | cat -n

Repository: api7/api7-ingress-controller

Length of output: 9114


🏁 Script executed:

# Check the imports in the file
grep -n "^import\|^\"" internal/controller/httproutepolicy.go | head -30

Repository: api7/api7-ingress-controller

Length of output: 83


🏁 Script executed:

# Get the complete imports section
sed -n '20,39p' internal/controller/httproutepolicy.go

Repository: api7/api7-ingress-controller

Length of output: 796


🏁 Script executed:

# Check if apierrors is used elsewhere in the controller package
grep -r "apierrors" internal/controller/ --include="*.go" | head -20

Repository: api7/api7-ingress-controller

Length of output: 54


🏁 Script executed:

# Check for meta.IsNoMatchError usage in the codebase
grep -r "IsNoMatchError" . --include="*.go"

Repository: api7/api7-ingress-controller

Length of output: 54


🏁 Script executed:

# Verify all 4 error handling patterns exist as claimed
grep -n "if err := r.List" internal/controller/httproutepolicy.go

Repository: api7/api7-ingress-controller

Length of output: 512


🏁 Script executed:

# Check what error handling patterns are used elsewhere in the controller package
grep -r "apierrors\|IsNotFound\|IsNoMatchError" internal/controller/ --include="*.go" -B2 -A2 | head -50

Repository: api7/api7-ingress-controller

Length of output: 2475


🏁 Script executed:

# Check the Go modules to understand available Kubernetes API dependencies
cat go.mod | grep -E "k8s.io|sigs.k8s.io"

Repository: api7/api7-ingress-controller

Length of output: 877


🏁 Script executed:

# Look for error handling patterns in other reconcilers in this package
grep -n "r.List" internal/controller/*.go | head -20

Repository: api7/api7-ingress-controller

Length of output: 2610


🏁 Script executed:

# Check if there are other error handling patterns used for client.List errors
grep -A3 "if err := r.List" internal/controller/*.go | grep -E "apierrors|IsNotFound|IsNoMatch|meta\." | head -20

Repository: api7/api7-ingress-controller

Length of output: 54


🏁 Script executed:

# Check what k8serrors import is used in the codebase
grep -r "k8serrors\|apierrors" internal/controller/ --include="*.go" | grep "^[^:]*:.*import" -A20 | head -30

Repository: api7/api7-ingress-controller

Length of output: 54


🏁 Script executed:

# Look at the actual import in the files that use k8serrors
grep -r "k8serrors" internal/controller/ --include="*.go" -l | head -1 | xargs grep -B30 "k8serrors" | grep import -A15

Repository: api7/api7-ingress-controller

Length of output: 706


🏁 Script executed:

# Check Go documentation for meta.IsNoMatchError
grep -r "meta\\.Is" . --include="*.go"

Repository: api7/api7-ingress-controller

Length of output: 54


🏁 Script executed:

# Look for any List error handling with specific error checks in the codebase
grep -A5 "if err := r.List" internal/controller/*.go | grep -E "IsNotFound|apierrors|meta\.|errors\\.Is"

Repository: api7/api7-ingress-controller

Length of output: 54


🏁 Script executed:

# Check what's imported from apimachinery in files that do error checking
grep -l "k8serrors" internal/controller/*.go | head -1 | xargs head -50 | grep -A20 "^import"

Repository: api7/api7-ingress-controller

Length of output: 785


🏁 Script executed:

# Check if IsNoMatchError is available in the meta package
python3 << 'EOF'
import subprocess
result = subprocess.run(['go', 'doc', 'k8s.io/apimachinery/pkg/api/meta', 'IsNoMatchError'], 
                       capture_output=True, text=True, cwd='/tmp')
print("STDOUT:", result.stdout)
print("STDERR:", result.stderr)
print("Return code:", result.returncode)
EOF

Repository: api7/api7-ingress-controller

Length of output: 159


🏁 Script executed:

# Check the actual context around the List calls to understand what errors could occur
sed -n '40,55p' internal/controller/httproutepolicy.go
sed -n '107,120p' internal/controller/httproutepolicy.go

Repository: api7/api7-ingress-controller

Length of output: 1373


🏁 Script executed:

# Look for any other CRD-missing or custom resource error handling in the codebase
grep -r "CRD\|no match\|NotFound" internal/controller/ --include="*.go" -i | grep -i "list\|error" | head -10

Repository: api7/api7-ingress-controller

Length of output: 809


🏁 Script executed:

# Check what happens when IndexedFields don't exist - look at indexer setup
grep -r "PolicyTargetRefs" . --include="*.go" -B3 -A3

Repository: api7/api7-ingress-controller

Length of output: 4898


🏁 Script executed:

# Check the Kubernetes API to understand what errors can be returned from List operations
grep -r "IsNotFound\|IsAlreadyExists\|IsForbidden\|IsUnauthorized" internal/controller/ --include="*.go" -h | sort | uniq

Repository: api7/api7-ingress-controller

Length of output: 138


🏁 Script executed:

# Look for any documentation on FieldIndexer errors in the codebase
find . -name "*.go" -type f -exec grep -l "FieldIndexer\|IndexField" {} \; | head -3 | xargs grep -A10 "IndexField"

Repository: api7/api7-ingress-controller

Length of output: 24077


🏁 Script executed:

# Check if there's a meta package import anywhere that might have IsNoMatchError
grep -r "apimachinery/pkg/api/meta" . --include="*.go"

Repository: api7/api7-ingress-controller

Length of output: 357


🏁 Script executed:

# Check what's being used from the meta package in files that import it
grep -A5 -B5 "apimachinery/pkg/api/meta" internal/controller/consumer_controller.go | head -30

Repository: api7/api7-ingress-controller

Length of output: 382


🏁 Script executed:

# Check the actual usage of meta package in those files
grep "meta\." internal/controller/consumer_controller.go internal/controller/policies.go internal/controller/status.go internal/controller/utils.go

Repository: api7/api7-ingress-controller

Length of output: 443


🏁 Script executed:

# Check if there's any comment or documentation about handling "no match" errors in field indexing
grep -r "no match\|NoMatch" . --include="*.go" -i

Repository: api7/api7-ingress-controller

Length of output: 2216


🏁 Script executed:

# Verify what error types can be returned from List with field indexers
# Check controller-runtime documentation by looking at how List is used in the codebase
grep -r "FieldIndexer\|field.Indexer" . --include="*.go" | head -10

Repository: api7/api7-ingress-controller

Length of output: 1003


🏁 Script executed:

# Look for any error handling patterns for List calls in similar controllers
grep -B2 -A8 "if err := r.List" internal/controller/consumer_controller.go | head -30

Repository: api7/api7-ingress-controller

Length of output: 1260


🏁 Script executed:

# Check if there's documentation about what errors can occur from field-indexed List operations
grep -r "indexer\|IndexField" internal/controller/*.go | grep -i "error" | head -10

Repository: api7/api7-ingress-controller

Length of output: 54


Don't swallow List errors unconditionally.

Returning nil here prevents requeue on transient/RBAC failures and can leave policies stale. Consider ignoring only "not found" errors when the HTTPRoutePolicy CRD is missing, and return other errors to trigger requeue.

✅ Safer pattern
- if err := r.List(context.Background(), &list, client.MatchingFields{indexer.PolicyTargetRefs: key}); err != nil {
-     r.Log.Error(err, "failed to list HTTPRoutePolicies for HTTPRoute", "httproute", utils.NamespacedName(httpRoute))
-     return nil
- }
+ if err := r.List(context.Background(), &list, client.MatchingFields{indexer.PolicyTargetRefs: key}); err != nil {
+     if k8serrors.IsNotFound(err) {
+         r.Log.Info("HTTPRoutePolicy API not available; skipping", "httproute", utils.NamespacedName(httpRoute))
+         return nil
+     }
+     return err
+ }

(Requires adding: k8serrors "k8s.io/apimachinery/pkg/api/errors")

🤖 Prompt for AI Agents
In `@internal/controller/httproutepolicy.go` around lines 47 - 50, The current
handler swallows all errors from r.List (the call using
client.MatchingFields{indexer.PolicyTargetRefs: key}), returning nil and
preventing requeue; change it to import k8serrors
("k8s.io/apimachinery/pkg/api/errors") and, after r.List, return the error
unless k8serrors.IsNotFound(err) is true — i.e., only ignore not-found errors
(CRD missing) and otherwise log and return the error so the reconcile will
requeue and transient/RBAC issues are retried.

)
if err := r.List(context.Background(), &list, client.MatchingFields{indexer.PolicyTargetRefs: key}); err != nil {
return err
r.Log.Error(err, "failed to list HTTPRoutePolicies for HTTPRoute", "httproute", utils.NamespacedName(httpRoute))
Copy link
Contributor

Choose a reason for hiding this comment

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

We should consider adding some code comments, otherwise it doesn't seem to explain why we return nil instead of an error.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

This method of handling is not very good, I have updated a new version.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

The processing of ingress should be consistent with httproute, rather than returning directly.

Copy link
Contributor

@ronething ronething left a comment

Choose a reason for hiding this comment

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

others lgtm.

Copy link

@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: 0

Caution

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

⚠️ Outside diff range comments (1)
internal/controller/ingress_controller.go (1)

213-215: ⚠️ Potential issue | 🟠 Major

Don’t apply an update when HTTPRoutePolicy processing fails unexpectedly.

Line 213-215 now logs and continues, which can push an incomplete TranslateContext to the provider (dropping policies on transient errors). Please return/requeue for unexpected failures and only suppress errors that indicate the policy resource/index is unavailable.

Suggested guard
- if err := r.processHTTPRoutePolicies(tctx, ingress); err != nil {
-     r.Log.Error(err, "failed to process HTTPRoutePolicy", "ingress", ingress.Name)
- }
+ if err := r.processHTTPRoutePolicies(tctx, ingress); err != nil {
+     if isHTTPRoutePolicyUnavailable(err) {
+         r.Log.V(1).Info("skip HTTPRoutePolicy processing; policy resource unavailable", "ingress", ingress.Name, "err", err)
+     } else {
+         r.Log.Error(err, "failed to process HTTPRoutePolicy", "ingress", ingress.Name)
+         return ctrl.Result{}, err
+     }
+ }
🧹 Nitpick comments (2)
internal/controller/ingress_controller.go (1)

145-147: Gate status-update suppression to known “policy unavailable” errors.

Line 145-147 now logs and continues on any error. If the failure is transient (API outage/conflict), the HTTPRoutePolicy status cleanup is never retried. Consider only suppressing errors that indicate the HTTPRoutePolicy CRD/index is unavailable (Gateway API disabled), and requeue for the rest.

internal/controller/httproute_controller.go (1)

157-159: Avoid swallowing unexpected status-update errors.

Line 157-159 logs and continues for any error. If this is a transient API/server failure, the HTTPRoutePolicy status won’t be retried. Consider suppressing only “policy unavailable” errors and requeueing for everything else.

@github-actions
Copy link
Contributor

github-actions bot commented Feb 4, 2026

conformance test report - apisix-standalone mode

apiVersion: gateway.networking.k8s.io/v1
date: "2026-02-04T09:27:07Z"
gatewayAPIChannel: experimental
gatewayAPIVersion: v1.3.0
implementation:
  contact: null
  organization: APISIX
  project: apisix-ingress-controller
  url: https://github.com/apache/apisix-ingress-controller.git
  version: v2.0.0
kind: ConformanceReport
mode: default
profiles:
- core:
    result: success
    statistics:
      Failed: 0
      Passed: 12
      Skipped: 0
  name: GATEWAY-GRPC
  summary: Core tests succeeded.
- core:
    result: partial
    skippedTests:
    - HTTPRouteHTTPSListener
    statistics:
      Failed: 0
      Passed: 32
      Skipped: 1
  extended:
    result: partial
    skippedTests:
    - HTTPRouteRedirectPortAndScheme
    statistics:
      Failed: 0
      Passed: 11
      Skipped: 1
    supportedFeatures:
    - GatewayAddressEmpty
    - GatewayPort8080
    - HTTPRouteBackendProtocolWebSocket
    - HTTPRouteDestinationPortMatching
    - HTTPRouteHostRewrite
    - HTTPRouteMethodMatching
    - HTTPRoutePathRewrite
    - HTTPRoutePortRedirect
    - HTTPRouteQueryParamMatching
    - HTTPRouteRequestMirror
    - HTTPRouteResponseHeaderModification
    - HTTPRouteSchemeRedirect
    unsupportedFeatures:
    - GatewayHTTPListenerIsolation
    - GatewayInfrastructurePropagation
    - GatewayStaticAddresses
    - HTTPRouteBackendProtocolH2C
    - HTTPRouteBackendRequestHeaderModification
    - HTTPRouteBackendTimeout
    - HTTPRouteParentRefPort
    - HTTPRoutePathRedirect
    - HTTPRouteRequestMultipleMirrors
    - HTTPRouteRequestPercentageMirror
    - HTTPRouteRequestTimeout
  name: GATEWAY-HTTP
  summary: Core tests partially succeeded with 1 test skips. Extended tests partially
    succeeded with 1 test skips.
- core:
    result: partial
    skippedTests:
    - TLSRouteSimpleSameNamespace
    statistics:
      Failed: 0
      Passed: 10
      Skipped: 1
  name: GATEWAY-TLS
  summary: Core tests partially succeeded with 1 test skips.

@github-actions
Copy link
Contributor

github-actions bot commented Feb 4, 2026

conformance test report - apisix mode

apiVersion: gateway.networking.k8s.io/v1
date: "2026-02-04T09:27:34Z"
gatewayAPIChannel: experimental
gatewayAPIVersion: v1.3.0
implementation:
  contact: null
  organization: APISIX
  project: apisix-ingress-controller
  url: https://github.com/apache/apisix-ingress-controller.git
  version: v2.0.0
kind: ConformanceReport
mode: default
profiles:
- core:
    result: success
    statistics:
      Failed: 0
      Passed: 12
      Skipped: 0
  name: GATEWAY-GRPC
  summary: Core tests succeeded.
- core:
    failedTests:
    - HTTPRouteInvalidBackendRefUnknownKind
    result: failure
    skippedTests:
    - HTTPRouteHTTPSListener
    statistics:
      Failed: 1
      Passed: 31
      Skipped: 1
  extended:
    result: partial
    skippedTests:
    - HTTPRouteRedirectPortAndScheme
    statistics:
      Failed: 0
      Passed: 11
      Skipped: 1
    supportedFeatures:
    - GatewayAddressEmpty
    - GatewayPort8080
    - HTTPRouteBackendProtocolWebSocket
    - HTTPRouteDestinationPortMatching
    - HTTPRouteHostRewrite
    - HTTPRouteMethodMatching
    - HTTPRoutePathRewrite
    - HTTPRoutePortRedirect
    - HTTPRouteQueryParamMatching
    - HTTPRouteRequestMirror
    - HTTPRouteResponseHeaderModification
    - HTTPRouteSchemeRedirect
    unsupportedFeatures:
    - GatewayHTTPListenerIsolation
    - GatewayInfrastructurePropagation
    - GatewayStaticAddresses
    - HTTPRouteBackendProtocolH2C
    - HTTPRouteBackendRequestHeaderModification
    - HTTPRouteBackendTimeout
    - HTTPRouteParentRefPort
    - HTTPRoutePathRedirect
    - HTTPRouteRequestMultipleMirrors
    - HTTPRouteRequestPercentageMirror
    - HTTPRouteRequestTimeout
  name: GATEWAY-HTTP
  summary: Core tests failed with 1 test failures. Extended tests partially succeeded
    with 1 test skips.
- core:
    result: partial
    skippedTests:
    - TLSRouteSimpleSameNamespace
    statistics:
      Failed: 0
      Passed: 10
      Skipped: 1
  name: GATEWAY-TLS
  summary: Core tests partially succeeded with 1 test skips.

@github-actions
Copy link
Contributor

github-actions bot commented Feb 4, 2026

conformance test report

apiVersion: gateway.networking.k8s.io/v1
date: "2026-02-04T09:49:22Z"
gatewayAPIChannel: experimental
gatewayAPIVersion: v1.3.0
implementation:
  contact: null
  organization: APISIX
  project: apisix-ingress-controller
  url: https://github.com/apache/apisix-ingress-controller.git
  version: v2.0.0
kind: ConformanceReport
mode: default
profiles:
- core:
    failedTests:
    - GatewayModifyListeners
    result: failure
    skippedTests:
    - HTTPRouteHTTPSListener
    statistics:
      Failed: 1
      Passed: 31
      Skipped: 1
  extended:
    failedTests:
    - HTTPRouteBackendProtocolWebSocket
    result: failure
    skippedTests:
    - HTTPRouteRedirectPortAndScheme
    statistics:
      Failed: 1
      Passed: 10
      Skipped: 1
    supportedFeatures:
    - GatewayAddressEmpty
    - GatewayPort8080
    - HTTPRouteBackendProtocolWebSocket
    - HTTPRouteDestinationPortMatching
    - HTTPRouteHostRewrite
    - HTTPRouteMethodMatching
    - HTTPRoutePathRewrite
    - HTTPRoutePortRedirect
    - HTTPRouteQueryParamMatching
    - HTTPRouteRequestMirror
    - HTTPRouteResponseHeaderModification
    - HTTPRouteSchemeRedirect
    unsupportedFeatures:
    - GatewayHTTPListenerIsolation
    - GatewayInfrastructurePropagation
    - GatewayStaticAddresses
    - HTTPRouteBackendProtocolH2C
    - HTTPRouteBackendRequestHeaderModification
    - HTTPRouteBackendTimeout
    - HTTPRouteParentRefPort
    - HTTPRoutePathRedirect
    - HTTPRouteRequestMultipleMirrors
    - HTTPRouteRequestPercentageMirror
    - HTTPRouteRequestTimeout
  name: GATEWAY-HTTP
  summary: Core tests failed with 1 test failures. Extended tests failed with 1 test
    failures.
- core:
    failedTests:
    - GatewayModifyListeners
    - TLSRouteSimpleSameNamespace
    result: failure
    statistics:
      Failed: 2
      Passed: 9
      Skipped: 0
  name: GATEWAY-TLS
  summary: Core tests failed with 2 test failures.
- core:
    failedTests:
    - GRPCExactMethodMatching
    - GRPCRouteHeaderMatching
    - GRPCRouteListenerHostnameMatching
    - GatewayModifyListeners
    result: failure
    statistics:
      Failed: 4
      Passed: 8
      Skipped: 0
  name: GATEWAY-GRPC
  summary: Core tests failed with 4 test failures.

@AlinsRan AlinsRan merged commit 241a4d5 into master Feb 4, 2026
20 of 23 checks passed
@AlinsRan AlinsRan deleted the fix/disable-gatewayapi-not-use-ingress branch February 4, 2026 10:20
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants