7.9.0 (2026-09-04) #8044
ash-thakur-rh
announced in
Announcements
Replies: 0 comments
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Uh oh!
There was an error while loading. Please reload this page.
Bugs
exec/attach/portForward/WebSocket-backed watches) on a derived client - one produced by callingnewBuilder()/build()on an already-builtHttpClient- no longer fall back to Vert.x's bareWebSocketClientdefaults.Vertx5HttpClientBuilder.build()'s short-circuit path for derived clients reused the original client's plain HTTP connection (with its configuration intact) but always created a brand-newWebSocketClientwith no options at all, discarding both the trust/key material (so TLS verified against the JVM default trust store instead of the configured cluster CA) and the configured limits (maxFrameSize/maxMessageSizefell back to 64 KiB/256 KiB instead of unlimited, andmaxConnectionsto 50 instead of 8192, so oversizedexec/attachmessages were silently dropped even on plain HTTP). This affectskubernetes-httpclient-vertx-5only, which is opt-in - the bundled defaultkubernetes-httpclient-vertx(Vert.x 4) serves WebSockets from the same client it reuses when deriving and was never affected - and it is present in 7.6.0 through 7.8.0. Derivation happens more often than it looks:OpenShiftClientImplderives on everyadapt(OpenShiftClient.class)to install its OAuth token-refresh interceptor,OpenShiftOAuthInterceptorderives on every token refresh, andBaseClient#newClientderives whenever a differingRequestConfigis set. Derived clients now reuse the original'sWebSocketClientoutright, the same way they already reused its HTTP client, so they can no longer drift from it and no second transport is allocated per derivation. Note that sharing the transport also means closing any client in a derived family closes it for the whole family:close()on a client obtained fromadapt(OpenShiftClient.class)now ends WebSocket operations on the client it was derived from as well, which is already what happened to that client's HTTP requests and what the other four implementations do. Nothing usable is lost, since the original's HTTP client was closed regardless; what changes is that the per-derivationWebSocketClientis no longer left behind unclosedexec/attach/portForwardand WebSocket-backed watches no longer connect straight to the API server and bypass a mandated egress proxy. Both implementations serve WebSockets from a transport separate from the HTTP client (a Vert.x 5WebSocketClient, and a second JettyHttpClientbehind theWebSocketClient) and neither was given the proxy configuration; Jetty's WebSocket transport now also receives the proxyBasicAuthenticationentry. The OkHttp, JDK and Vert.x 4 modules were unaffected because a single client serves both. Onhttpclient-vertx-5the configured connect timeout was not applied to the WebSocket client either, so a WebSocket connect could hang well past it. One consequence worth calling out: when the proxy credentials cannot be decoded -HttpClientUtils.decodeBasicCredentialsreturnsnullfor anything that is notBasic, or whose decoded value does not split into exactly two:-separated parts, so a proxy password containing a colon is enough - the client falls back to stampingProxy-Authorizationon the request instead of configuring it on the transport. Such WebSocket connections now reach the proxy and are rejected with a 407 rather than silently completing straight to the API server, so a setup that appeared to work only because it was bypassing the proxy will now failKUBE_API_TEST_STARTUP_TIMEOUTenvironment variable is now parsed instead of throwingClassCastExceptionon every use — the value (always aString) was passed toClass.cast()for anInteger/Booleantarget, which only widens reference types and never parses, so the timeout could not be configured via environment at all. A newstartupTimeoutattribute on@EnableKubeAPIServer(e.g.@EnableKubeAPIServer(startupTimeout = 180000)) allows overriding it declaratively, and all three configuration paths (annotation, builder, env var) now reject non-positive valuesHttpServerRequest#body()callback. Deferring the upgrade let the request end event be processed first, soHttpServerRequest#toWebSocket()intermittently threwIllegalStateException: Request has already been readand the upgrade was lost (surfacing as flakyexec/attachmock-server tests). Upgrade requests carry no body, so they are detected via theUpgradeheader and upgraded before the request is read; the asynchronous path is unchanged for regular HTTP requestsjavacdecodes it. As a defense in depth, each generated class is also re-parsed and structurally validated before it is written (with Java Unicode escape preprocessing enabled to matchjavac), aborting generation on any residual structural mismatchopenshift-modelno longer bundles theio.fabric8.openshift.api.model.config.*classes thatopenshift-model-configowns (itsExport-Packagewildcard inlined them from that dependency); they still reach consumers through it.Fabric8ClientInjectionHandlermoved toio.fabric8.kubeapitest.junit.injectImprovements
Dependency Upgrade
New Features
v1.TCPRouteandv1.UDPRoute(both graduated fromv1alpha2upstream in gateway-api v1.6.0). Thev1alpha2types remain available, but upstream has deprecated them and will remove them in a future release, so new code should use thev1typesNote: Breaking changes
certificates.k8s.io/v1alpha1/ClusterTrustBundle→ usecertificates.k8s.io/v1orv1beta1networking.k8s.io/v1beta1/IPAddress→ usenetworking.k8s.io/v1networking.k8s.io/v1beta1/ServiceCIDR→ usenetworking.k8s.io/v1storage.k8s.io/v1beta1/VolumeAttributesClass→ usestorage.k8s.io/v1scheduling.k8s.io/v1alpha2(entire API version, 28 types) → usev1alpha3orv1beta1VolumeMountconstructor signature changed (Kubernetes v1.37.0 addedbindMountOptionsfield). The canonical constructor now takesbindMountOptions(List) as its first parameter. Builder usage (new VolumeMountBuilder().with...()) is unaffectedv1.SessionPersistenceno longer exposesidleTimeout(removed upstream in gateway-api v1.6.0). Besides the field, this removesgetIdleTimeout()/setIdleTimeout(), collapses the canonical constructor from five arguments to four, and dropsSessionPersistenceFluent.withIdleTimeout()/getIdleTimeout()/hasIdleTimeout(), so the builder form (withNewSessionPersistence().withIdleTimeout(...)) no longer compiles. There is no runtime data loss: the class keeps its@JsonAnyGetter/@JsonAnySetter, and both the fluent and the builder carryadditionalPropertiesthrough, so JSON or YAML still containingidleTimeoutcontinues to deserialize and re-serialize intactFabric8ClientInjectionHandlermoved toio.fabric8.kubeapitest.junit.inject. It is resolved throughServiceLoader, so only code naming the class directly is affectedio.fabric8.openshift.api.model.config.*. Maven consumers are unaffected (openshift-model-configis a compile dependency), but OSGi deployments importing those packages must install theopenshift-model-configbundle, which theopenshift-clientKaraf feature already doesNew Contributors
Full Changelog: v7.8.0...v7.9.0
This discussion was created from the release 7.9.0 (2026-09-04).
All reactions