johannes-engler-mw opened a new pull request, #2834:
URL: https://github.com/apache/apisix-ingress-controller/pull/2834
<!-- Please answer these questions before submitting a pull request -->
### Type of change:
- [x] Bugfix
### What this PR does / why we need it:
Fixes #2833.
When a Gateway API route's `parentRefs` are repointed at a Gateway belonging
to a different
`GatewayClass.spec.controllerName`, the new controller picks the route up,
but the previous
controller never removes the configuration it had already pushed. Its data
plane keeps serving
the route indefinitely — until the controller process happens to restart.
`ParseRouteParentRefs` skips parentRefs whose GatewayClass belongs to
another controller
(`utils.go:357-359`), so the reconciler ends up with an empty gateway list
and returns early:
```go
if len(gateways) == 0 {
return ctrl.Result{}, nil
}
```
`Provider.Delete` was only reachable from the `IgnoreNotFound` branch, i.e.
when the object is
deleted from the cluster. There was no path for "this object used to be mine
and no longer is".
Because the periodic sync replays the in-memory store
(`ConfigManager.List()` →
`GetResources()`) rather than re-deriving state from Kubernetes, the
orphaned service is
re-pushed to the data plane on every sync period. Restarting the controller
is the only thing
that clears it, since startup rebuilds the store from scratch.
This PR calls `Provider.Delete` before that early return, in all five route
reconcilers
(HTTPRoute, GRPCRoute, TCPRoute, UDPRoute, TLSRoute).
This is the same fix #2543 applied to Ingress for the equivalent
`ingressClassName` case, whose
description states the general problem:
> the controller simply ignores the Ingress resource. However, this behavior
is problematic: the
> corresponding configuration is not removed and remains in the data plane,
which may result in
> incorrect routing or stale configurations.
`ingress_controller.go:159-166` has carried that cleanup since; the Gateway
API reconcilers never
received the equivalent.
#### Notes for reviewers
- **`TypeMeta` is set before the call.** `Provider.Delete` derives both the
store key
(`utils.NamespacedNameKind`) and the resource labels (`label.GenLabel`)
from
`obj.GetObjectKind()`, which is empty on objects read through the client.
The existing
`IgnoreNotFound` branches already set it for the same reason.
- **No-op when there is nothing to remove.** `DeleteConfig` →
`applyStoreChanges(args, true)`
looks the key up in `ConfigManager` first; for a route this controller
never translated, the
delta is empty and neither the store nor ADC is touched. Routes belonging
to other controllers
therefore cost one map lookup.
- **One observation left alone deliberately.** `apisixProvider.Delete` calls
`syncNotify()`
unconditionally, so a reconcile of a route owned by another controller now
nudges the sync
loop even when the delta was empty. `syncNotify` is a non-blocking send to
a buffered channel,
so these coalesce, but making it conditional on a non-empty delta would
mean changing the
`Provider.Delete` signature to return the delta. That felt out of scope
here — happy to follow
up separately if you would prefer it in this PR.
### Pre-submission checklist:
- [x] Did you explain what problem does this PR solve? Or what new features
have been added?
- [x] Have you added corresponding test cases?
- [ ] Have you modified the corresponding document?
- [x] Is this PR backward compatible?
The test is in `test/e2e/gatewayapi/httproute.go`, in the existing
"HTTPRoute with Multiple
Gateway" context: it attaches an HTTPRoute to the additional gateway, then
repoints `parentRefs`
at a Gateway whose GatewayClass names `apisix.apache.org/not-exist`. The
route object itself is
never deleted, so it exercises the empty-gateway-list path rather than the
deletion path.
Verified against a kind cluster by rebuilding the controller image from each
revision and
re-running the same test binary:
```console
# controller built from master, test present
$ make e2e-test TEST_FOCUS="stop being served after moving"
[FAIL] ... HTTPRoute should stop being served after moving to another
controller's Gateway
test/e2e/gatewayapi/httproute.go:461
FAIL! -- 0 Passed | 1 Failed | 1 Pending | 232 Skipped
# controller built with this fix, same test
$ make e2e-test TEST_FOCUS="stop being served after moving"
SUCCESS! -- 1 Passed | 0 Failed | 1 Pending | 232 Skipped
```
Line 461 is the closing assertion: every earlier step passes in both runs,
including the one
that confirms the route is served through the additional gateway before the
move. Without the
fix the gateway keeps answering `200` for the full 30s retry window after
`parentRefs` move away.
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: [email protected]
For queries about this service, please contact Infrastructure at:
[email protected]