Skip to content

build(deps): gateway api 1.5.1 support via linkerd-kubert 0.27.0 - #15567

Merged
alpeb merged 7 commits into
mainfrom
alpeb/linkerd-kubert-0.27.0
Aug 12, 2026
Merged

build(deps): gateway api 1.5.1 support via linkerd-kubert 0.27.0#15567
alpeb merged 7 commits into
mainfrom
alpeb/linkerd-kubert-0.27.0

Conversation

@alpeb

@alpeb alpeb commented Aug 11, 2026

Copy link
Copy Markdown
Member

kube-rs (a.k.a "kube") 1.1.0 -> 3.1.0

This forces the rest of the workspace along with it:

  • k8s-openapi 0.25 -> 0.27
  • schemars 0.8 -> 1
  • ipnet switches from the json feature to serde + schemars1, since json still pulls in schemars 0.8
  • chrono is replaced by jiff 0.2 and drops out of the tree entirely, because k8s-openapi 0.27 backs metav1::Time with jiff::Timestamp instead of chrono::DateTime<Utc>

Source changes:

  • Timestamps: creation_timestamp, last_transition_time and the Route::creation_timestamp trait method move to jiff::Timestamp; Utc::now() becomes Timestamp::now() and MIN_UTC/MAX_UTC become Timestamp::MIN/MAX.
  • schemars 1: the hand-written JsonSchema impl for K8sDuration uses Cow<'static, str> for schema_name, inline_schema() in place of the inverted is_referenceable(), and the json_schema! macro. The schema is unchanged; the format is still deliberately unset.
  • kube 3.x deprecates kube::error::ErrorResponse in favor of kube::core::Status, and Error::Api now carries a Box<Status>.

gateway-api-rs (a.k.a "gateway-api") 0.16.0 -> 0.21.0

This bumps the gateway api spec support from 1.2.1 to 1.5.1
Forced to be bumped in tandem with the kube-rs bump as gateway-api-rs 0.16.0 was pinned to kube-rs 1.1.0

  • gateway-api renamed its generated sub-types, so HTTPRoute* becomes HttpRoute*, GRPCRoute* becomes GrpcRoute*, and likewise for TCP and TLS. The top-level CRD types keep their original names.
  • Several gateway-api fields are no longer optional: RouteStatusParents::conditions, Tls/TcpRouteRules::backend_refs, and TlsRouteSpec::hostnames/rules. Some(..) wrappers and the matching .flatten() calls are dropped, and route spec literals gain the new use_default_gateways field.

Note one behavior change the type system forces: now that RouteStatusParents::conditions is a plain Vec, the eq_time_insensitive_*_route_parent_statuses helpers can no longer distinguish an empty condition list from an absent one, so those two cases now compare equal where they previously compared unequal.

TLSRoute is pinned to v1alpha2

gateway-api-rs 0.21 moved its TLSRoute binding from v1alpha2 to v1. The other three kinds are unaffected:

kind 0.16.0 0.21.0
HTTPRoute v1 v1
GRPCRoute v1 v1
TCPRoute v1alpha2 v1alpha2
TLSRoute v1alpha2 v1

TLSRoute only graduated to v1 in Gateway API v1.5:

bundle TLSRoute versions served
v1.2.1 v1alpha2
v1.3.0 v1alpha2
v1.4.0 v1alpha2, v1alpha3
v1.5.1 v1, v1alpha2, v1alpha3

In order to still support Gateway API v1.2.1, we now have in policy-controller/k8s/api/src/lib.rs a local type pinned to v1alpha2 that shadows the one from the crate's glob import (v1). It reuses TlsRouteSpec/TlsRouteStatus unchanged, so it only overrides the group/version/kind the client addresses. It carries a hand-written Serialize because kube::CustomResource synthesizes apiVersion/kind rather than storing them as fields, plus a unit test asserting the pinned version.

Backwards compatibility

CI now covers v1.2.1/standard as the minimum and v1.5.1/experimental as the maximum, alongside the CLI's vendored CRDs (still bundle v1.1.1; unchanged by this PR).

No impact:

  • The webhook and RBAC are version-agnostic (apiVersions: ["*"], and is_kind compares group and kind only), so TLSRoutes submitted as v1 on a v1.5 cluster are still validated. Status patches address v1alpha2, which is served across the whole range.
  • useDefaultGateways, new in v1.5 on all four route specs, is Option plus skip_serializing_if. Linkerd never sets it, and never writes route specs back (only the status subresource), so nothing is stripped from user objects.
  • HTTPRoute and GRPCRoute keep their v1 bindings, valid from v1.2 onward. Their v1.3.0 to v1.5.1 deltas are either additive (CORS and ExternalAuth filters, requestRedirect.statusCode widened from [301, 302] to [301, 302, 303, 307, 308], GRPCRoute matches maxItems 8 to 64) or apiserver-side tightening that does not affect decoding.

Worth watching: decoding is now stricter than the endpoints we address.

The bindings are generated from the v1.5.1 schemas, so three fields lost their Option/#[serde(default)] and are mandatory on the wire:

field kinds required upstream since
status.parents[].conditions all four v1.5
spec.rules[].backendRefs TLSRoute, TCPRoute v1.5
spec.hostnames TLSRoute only in the v1/v1alpha3 schemas, never in v1alpha2

On a pre-v1.5 cluster an object omitting the first two is perfectly legal but no longer decodes. The third is stricter still: hostnames is optional in v1alpha2 in every release, so a TLSRoute without it fails to decode on any cluster in the supported range.

A failing object is logged and skipped rather than killing the watch; the route just never appears in the policy index. Admission is unaffected, since every Gateway API validator is lenient() and parse failures are admitted with a warning rather than denied, so there are no new rejections for users.

Unchanged behaviour worth noting: Linkerd still implements only the RequestHeaderModifier, ResponseHeaderModifier and RequestRedirect filters, so the new v1.5 CORS and ExternalAuth HTTPRoute filters are admitted and ignored, the same as the other filter types we do not support.

@alpeb
alpeb requested a review from a team as a code owner August 11, 2026 14:28
@alpeb
alpeb force-pushed the alpeb/linkerd-kubert-0.27.0 branch from 952580a to 6d798ab Compare August 11, 2026 14:47
@alpeb
alpeb marked this pull request as draft August 11, 2026 14:47
@alpeb
alpeb force-pushed the alpeb/linkerd-kubert-0.27.0 branch 2 times, most recently from 12c15d3 to 5085316 Compare August 11, 2026 20:00
alpeb added 5 commits August 11, 2026 15:02
This carries a kube-rs bump to 3.x, which forces the rest of the
workspace along with it:

* gateway-api 0.16 -> 0.21: this brings support for gateway api spec
  v1.5.1
* k8s-openapi 0.25 -> 0.27
* kube 1.1 -> 3.1
* schemars 0.8 -> 1
* ipnet switches from the `json` feature to `serde` + `schemars1`, since
  `json` still pulls in schemars 0.8
* chrono is replaced by jiff 0.2 and drops out of the tree entirely,
  because k8s-openapi 0.27 backs `metav1::Time` with `jiff::Timestamp`
  instead of `chrono::DateTime<Utc>`

Source changes:

* Timestamps: `creation_timestamp`, `last_transition_time` and the
  `Route::creation_timestamp` trait method move to `jiff::Timestamp`;
  `Utc::now()` becomes `Timestamp::now()` and `MIN_UTC`/`MAX_UTC` become
  `Timestamp::MIN`/`MAX`.
* schemars 1: the hand-written `JsonSchema` impl for `K8sDuration` uses
  `Cow<'static, str>` for `schema_name`, `inline_schema()` in place of
  the inverted `is_referenceable()`, and the `json_schema!` macro. The
  schema is unchanged; the format is still deliberately unset.
* gateway-api renamed its generated sub-types, so `HTTPRoute*` becomes
  `HttpRoute*`, `GRPCRoute*` becomes `GrpcRoute*`, and likewise for TCP
  and TLS. The top-level CRD types keep their original names.
* Several gateway-api fields are no longer optional:
  `RouteStatusParents::conditions`, `Tls/TcpRouteRules::backend_refs`,
  and `TlsRouteSpec::hostnames`/`rules`. `Some(..)` wrappers and the
  matching `.flatten()` calls are dropped, and route spec literals gain
  the new `use_default_gateways` field.
* kube 3.x deprecates `kube::error::ErrorResponse` in favor of
  `kube::core::Status`, and `Error::Api` now carries a `Box<Status>`.

Note one behavior change the type system forces: now that
`RouteStatusParents::conditions` is a plain `Vec`, the
`eq_time_insensitive_*_route_parent_statuses` helpers can no longer
distinguish an empty condition list from an absent one, so those two
cases now compare equal where they previously compared unequal.
@alpeb
alpeb force-pushed the alpeb/linkerd-kubert-0.27.0 branch from f9958aa to 9817f2a Compare August 11, 2026 22:30
@alpeb
alpeb marked this pull request as ready for review August 12, 2026 15:53
@alpeb
alpeb requested a review from adleong August 12, 2026 15:54
Comment thread Cargo.toml Outdated

@adleong adleong left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Really nice work!

@alpeb
alpeb merged commit 2f74727 into main Aug 12, 2026
100 of 108 checks passed
@alpeb
alpeb deleted the alpeb/linkerd-kubert-0.27.0 branch August 12, 2026 20:45
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