Description
What would you like to be added:
Add documentation, possibly a new page in the Reference section of the website, and additional RouteConditionReason
and ListenerConditionReason
types as needed to clarify intended handling of invalid BackendRefs configurations. This is a bit more complicated than just #1109, as the implications of initially applying or resolving changes to a Route's BackendRefs or a ReferencePolicy may require triggering actions or settings statuses across several objects.
Why this is needed:
There are a few distinct cases by which a BackendRef
could be or become invalid, and I think it may be helpful to define and use more specific terms than "invalid" in the spec, as well as centralize and specify the intended behavior for each case more explicitly.
One specific difficulty is the lack of specificity around when a Route Accepted
condition should be set, and whether an Accepted { status: false, reason: Invalid }
condition should be set in any of these cases (and/or reflected in a ListenerConditionType
status) given the lack of granularity in indicating status per BackendRef versus the status of the Route or Listener as a whole.
It's also slightly unclear if attachedRoutes
on ListenerStatus
is intended to communicate the same thing as a route having an Accepted { status: true, reason: Accepted }
route parent status condition referencing that listener because of the difference between the words used ("attached" vs "accepted", refs #1111).
"not accepted"
This case is when the Route has not been accepted by a Gateway Listener. The HTTPRouteInvalidCrossNamespace
conformance test illustrates one example where this is an intended outcome, but it's not clear how this status should be communicated. The test suggests that no RouteParentStatus should be set on the Route because, having been rejected, it does not have an actual parent, only an intended parent - setting an Accepted { status: False }
condition (what RouteConditionReason?) could be an alternative way to communicate this status though.
RouteParentStatus conditions
- None?
- [Alternatively?]
Accepted { status: False }
Listener handling
- A Route that is in a namespace not allowed by a Gateway Listener's
allowedRoutes
should be rejected by the GatewayController. - This is similar to the
InvalidRouteKinds
case, but I'm guessing that no similar status should be set due to cross-namespace security concerns because a Route in another namespace shouldn't be able to have any impact on a Gateway to which it is not allowed to bind.
ListenerStatus
attachedRoutes
should not count this Route- Conditions:
Ready { status: True, reason: Ready }
TODO:
- Update the
HTTPRouteInvalidCrossNamespace
conformance test to check for anAccepted {status: False}
condition. This feels reasonable enough because even though the route was not accepted by the gateway (and therefore shouldn't be able to affect the gateway in any way), there should be a definitive controller which evaluated and rejected the route which has sufficient privileges to manage a route status appropriately. - Add an
InvalidRouteKind
RouteConditionReason and update theHTTPRouteDisallowedKind
conformance test for communicating the case where a route is rejected because its kind is not specified in theallowedRoutes.kinds
field of the listener it is targeting. - Add an
InvalidRouteNamespace
RouteConditionReason and conformance test for communicating the cases (Selector
,Same
) where a route is rejected because it lives in a namespace that is not allowed by theallowedRoutes.namespaces
field of the listener it is targeting. - Add an
InvalidRouteHostname
RouteConditionReason and update theHTTPRouteListenerHostnameMatching
conformance test or add a new one for communicating the case where a route is rejected because it does not have at least one intersecting hostname with the listener it is targeting.
"unpermitted"
This case is when a Route has a BackendRef to an object in another namespace, where the object in the other namespace does not have a ReferencePolicy explicitly allowing the reference. This could reasonably be expected to be checked when the Route is created, and should be clarified to note that it should additionally be checked whenever the Route is modified or a ReferencePolicy with a to
field resolving to a BackendRef of the route is deleted, modified, or created.
This should be expected to be dynamic - revoking a ReferencePolicy should stop routing traffic to a BackendRef.
RouteParentStatus conditions
Accepted { status: True }
ResolvedRefs { status: False, reason: RefNotPermitted }
Ready { status: False, reason: Invalid }
[Not Implemented]
Listener handling
-
As described in
HTTPBackendRef
If there is a cross-namespace reference to an existing object that is not covered by a ReferencePolicy, the controller must ensure the “ResolvedRefs” condition on the Route is set to status: False, with the “RefNotPermitted” reason and not configure this backend in the underlying implementation.
-
This wording is likewise a bit confusing in that it only describes how each specific BackendRef should be handled, and not whether this should impact if the entire Route is determined to be "invalid". Notably, this case omits any mention of "dropping" anything from a Gateway as the "not found" case describes.
-
Should likely implement the same behavior described above in the "not found" section for sending HTTP 503 responses for invalid unpermitted BackendRefs.
ListenerStatus
attachedRoutes
should count this Route as long as it has RouteConditionTypeAccepted { status: True }
- Conditions:
ResolvedRefs { status: False, reason: RefNotPermitted }
- UNRESOLVED: Should this set
Ready { status: False, reason: Invalid }
if any single BackendRef on an accepted route is not permitted?
TODO:
- UNRESOLVED: (needs consensus before implementation) Update the
HTTPRouteInvalidCrossNamespaceBackendRef
conformance test to assert that a route with zero permitted backends:- sets either an
Accepted {status: True}
orAccepted {status: False}
route condition - is either counted (if accepted) or not counted (if rejected) in listener
attachedRoutes
- sets a
ResolvedRefs {status: False, reason: ReasonNotPermitted}
listener condition if route issues of accepted routes should "bubble up" to listeners
- sets either an
- conformance: add test for partial acceptance of a route with one allowed and one unpermitted backend reference #1143
"not found"
This case is when the Route has at least one BackendRef that does not exist or cannot be resolved. This could reasonably be expected to be checked when the Route is created, but unclear if/when state changes could cause this to need to be updated.
UNRESOLVED:
- Does this case include zero service instances ready?
- It's unclear if this case should prevent the Route from being accepted by a Gateway when initially applied, even if all BackendRefs on a Route are not found. I could see potential value in a use case for being able to configure Routes before deploying a new service.
RouteParentStatus conditions
ResolvedRefs { status: False, reason: InvalidBackendRef }
Listener handling
-
As described in
HTTPBackendRef
:If the referent cannot be found, this HTTPBackendRef is invalid and must be dropped from the Gateway. The controller must ensure the “ResolvedRefs” condition on the Route is set to status: False and not configure this backend in the underlying implementation.
-
The part that's a bit confusing with this wording is that it only describes how each specific BackendRef should be handled, and not whether this should impact if the entire Route is determined to be "invalid". The term "dropped" seems to imply active management of some object directly related to a Gateway (as opposed to the underlying implementation), which seems to be overly broad behavior if inferred to mean removing an entire Route from a Listener if one BackendRef became invalid.
-
The
backendRefs
field on HTTPRouteRule additionally states:If unspecified or invalid (refers to a non-existent resource or a Service with no endpoints), the rule performs no forwarding. If there are also no filters specified that would result in a response being sent, a HTTP 503 status code is returned. 503 responses must be sent so that the overall weight is respected; if an invalid backend is requested to have 80% of requests, then 80% of requests must get a 503 instead.
(cobbling this information together from disjointed sources is an example of the difficulty described in docs: API specification information architecture obscures important content #1031)
ListenerStatus
attachedRoutes
should count this Route as long as it has RouteConditionTypeAccepted { status: True }
- Conditions
ResolvedRefs { status: False, reason: InvalidBackendRef }
- Would require adding
InvalidBackendRef
ListenerConditionReason
- UNRESOLVED: Should a route with this issue should affect listener status?
- Would require adding
- UNRESOLVED: Should this set
Ready { status: False, reason: Invalid }
if any single BackendRef on an accepted route is not found?
TODO:
- Add
InvalidBackendRef
RouteConditionReason, with a description similar to theInvalidCertificateRef
ListenerConditionReason - Clarify lifecycle watch expectations of when this status would be updated (service created/deleted, zero endpoints ready?)
"invalid"
This case is when the Route is syntactically or semantically invalid.
NOTE:
- Ideally, the admission webhook should prevent this Route from ever being applied to avoid accidentally dropping traffic if modifying an existing Route.
RouteParentStatus conditions
Accepted { status: False, reason: Invalid | InvalidParameters }
Listener handling
- A Route that is syntactically or semantically invalid should be rejected by the GatewayController or admission webhook.
ListenerStatus
attachedRoutes
should not count this Route- Conditions:
Ready { status: True, reason: Ready }
"not ready yet"
This case is when the Route is syntactically or semantically valid, all BackendRefs exist, can be resolved, and are permitted by a ReferencePolicy as applicable, and the route has been accepted by the GatewayController, but the underlying implementation is not fully configured or routing traffic yet. Expected to be a transient state.
NOTE:
- It can be quite difficult for implementations to know when a route has transitioned from this state to being fully "ready" and actively able to route traffic.
RouteParentStatus conditions
Accepted { status: True }
Ready { status: False, reason: Pending }
[Not Implemented]
Listener handling
- Not yet defined.
ListenerStatus
attachedRoutes
should count this Route- Conditions:
Ready { status: True, reason: Ready }