Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
19 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/workflows/e2e-httpclient-tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ jobs:
fail-fast: false
matrix:
kubernetes: [v1.33.0,v1.32.4,v1.31.8,v1.30.12,v1.29.14]
httpclient: [jdk,jetty,okhttp]
httpclient: [jdk,jetty,okhttp,vertx-5]
steps:
- name: Checkout
uses: actions/checkout@v5
Expand Down
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
#### Dependency Upgrade

#### New Features
* Fix #7174: Added Vert.x 5 HTTP client implementation with improved async handling and WebSocket separation

* Fix #7045: (java-generator) Extend the existingJavaTypes to support use of existing enumerations

Expand Down
65 changes: 65 additions & 0 deletions httpclient-vertx-5/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
# Vert.x 5 HTTP Client For Fabric8 Kubernetes Client

This module provides Vert.x 5.x HTTP client implementation for the Fabric8 Kubernetes Client, featuring improved async handling and WebSocket separation introduced in Vert.x 5.

## Features

- **Vert.x 5.0.1**: Uses latest stable Vert.x 5.x release
- **Async Operations**: Enhanced async HTTP request handling
- **WebSocket Separation**: Vert.x 5's separate HTTP and WebSocket client architecture
- **Backpressure Support**: Built-in flow control for streaming operations
- **Stack-based Recursion Guard**: Memory-safe recursion protection without ThreadLocal

## Usage

Add the dependency to your project:

```xml
<dependency>
<groupId>io.fabric8</groupId>
<artifactId>kubernetes-httpclient-vertx-5</artifactId>
<version>${fabric8.version}</version>
</dependency>
```

The HTTP client will be automatically discovered via service loader.

## Testing

### Running Integration Tests

To run integration tests specifically with the Vert.x 5 HTTP client:

```bash
# Run all integration tests with Vert.x 5
mvn -Phttpclient-vertx-5 -Pitests verify -Dtest.httpclient=vertx-5

# Run specific test with Vert.x 5
mvn -Phttpclient-vertx-5 test -Dtest=ConfigMapIT -Dtest.httpclient=vertx-5

# Run WebSocket tests with Vert.x 5
mvn -Phttpclient-vertx-5 test -Dtest=WatchIT -Dtest.httpclient=vertx-5
```

### Version Validation Test

A special test (`VertxVersionValidationIT`) validates that Vert.x 5.0.1 is actually being used:

```bash
mvn -Phttpclient-vertx-5 test -Dtest=VertxVersionValidationIT -Dtest.httpclient=vertx-5
```

### Dependency Verification

Verify the correct Vert.x version is being used:

```bash
mvn -Phttpclient-vertx-5 dependency:tree | grep vertx
# Should show: vertx-core:jar:5.0.1:compile
```

## Architecture Notes

- **WebSocket Client Separation**: Unlike Vert.x 4, Vert.x 5 uses separate HTTP and WebSocket clients
- **Dependency Management**: This module overrides parent POM's Vert.x version to ensure 5.0.1 is used
- **Profile Isolation**: The httpclient-vertx-5 profile ensures no conflicts with default Vert.x 4 usage
235 changes: 235 additions & 0 deletions httpclient-vertx-5/pom.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,235 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--

Copyright (C) 2015 Red Hat, Inc.

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.

-->
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<artifactId>kubernetes-client-project</artifactId>
<groupId>io.fabric8</groupId>
<version>7.4-SNAPSHOT</version>
</parent>

<artifactId>kubernetes-httpclient-vertx-5</artifactId>
<packaging>jar</packaging>
<name>Fabric8 :: Kubernetes :: HttpClient :: Vert.x 5</name>

<properties>
<vertx.version>5.0.1</vertx.version>
<osgi.require-capability>
osgi.extender;
filter:="(osgi.extender=osgi.serviceloader.registrar)",
</osgi.require-capability>
<osgi.provide-capability>
osgi.serviceloader;
osgi.serviceloader=io.fabric8.kubernetes.client.http.HttpClient$Factory
</osgi.provide-capability>
<osgi.import>
!android.util*,
*,
</osgi.import>
<osgi.export>
io.fabric8.kubernetes.client.vertx*;-noimport:=true,
</osgi.export>
<osgi.private>
</osgi.private>
</properties>

<dependencyManagement>
<dependencies>
<!-- Override parent POM's Vert.x 4.x dependency management to force Vert.x 5.x -->
<dependency>
<groupId>io.vertx</groupId>
<artifactId>vertx-core</artifactId>
<version>${vertx.version}</version>
</dependency>
<dependency>
<groupId>io.vertx</groupId>
<artifactId>vertx-web-client</artifactId>
<version>${vertx.version}</version>
</dependency>
<dependency>
<groupId>io.vertx</groupId>
<artifactId>vertx-web-common</artifactId>
<version>${vertx.version}</version>
</dependency>
<dependency>
<groupId>io.vertx</groupId>
<artifactId>vertx-auth-common</artifactId>
<version>${vertx.version}</version>
</dependency>
<dependency>
<groupId>io.vertx</groupId>
<artifactId>vertx-core-logging</artifactId>
<version>${vertx.version}</version>
</dependency>
<dependency>
<groupId>io.vertx</groupId>
<artifactId>vertx-web</artifactId>
<version>${vertx.version}</version>
</dependency>
<dependency>
<groupId>io.vertx</groupId>
<artifactId>vertx-bridge-common</artifactId>
<version>${vertx.version}</version>
</dependency>
<dependency>
<groupId>io.vertx</groupId>
<artifactId>vertx-uri-template</artifactId>
<version>${vertx.version}</version>
</dependency>
</dependencies>
</dependencyManagement>

<dependencies>
<dependency>
<groupId>io.fabric8</groupId>
<artifactId>kubernetes-client-api</artifactId>
</dependency>
<dependency>
<groupId>io.vertx</groupId>
<artifactId>vertx-core</artifactId>
<version>${vertx.version}</version>
</dependency>
<dependency>
<groupId>io.vertx</groupId>
<artifactId>vertx-web-client</artifactId>
<version>${vertx.version}</version>
</dependency>
<dependency>
<groupId>io.fabric8</groupId>
<artifactId>kubernetes-client-api</artifactId>
<type>test-jar</type>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>${lombok.version}</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-engine</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-params</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.mockito</groupId>
<artifactId>mockito-inline</artifactId>
</dependency>
<dependency>
<groupId>io.fabric8</groupId>
<artifactId>mockwebserver</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.assertj</groupId>
<artifactId>assertj-core</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.awaitility</groupId>
<artifactId>awaitility</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<!-- Required by SslTest -->
<groupId>org.bouncycastle</groupId>
<artifactId>bcpkix-jdk18on</artifactId>
<version>${bouncycastle.version}</version>
<scope>test</scope>
</dependency>
</dependencies>

<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<configuration>
<rerunFailingTestsCount>1</rerunFailingTestsCount>
</configuration>
</plugin>
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>exec-maven-plugin</artifactId>
<executions>
<execution>
<goals>
<goal>java</goal>
</goals>
</execution>
</executions>
<configuration>
<classpathScope>test</classpathScope>
</configuration>
</plugin>
<plugin>
<groupId>org.jacoco</groupId>
<artifactId>jacoco-maven-plugin</artifactId>
<executions>
<execution>
<id>report-aggregate</id>
<phase>verify</phase>
<goals>
<goal>report-aggregate</goal>
</goals>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.apache.felix</groupId>
<artifactId>maven-bundle-plugin</artifactId>
<version>${maven.bundle.plugin.version}</version>
<executions>
<execution>
<id>bundle</id>
<phase>package</phase>
<goals>
<goal>bundle</goal>
</goals>
<configuration>
<instructions>
<Bundle-Name>${project.name}</Bundle-Name>
<Bundle-SymbolicName>${project.groupId}.${project.artifactId}</Bundle-SymbolicName>
<Export-Package>${osgi.export}</Export-Package>
<Import-Package>${osgi.import}</Import-Package>
<DynamicImport-Package>${osgi.dynamic.import}</DynamicImport-Package>
<Require-Capability>${osgi.require-capability}</Require-Capability>
<Provide-Capability>${osgi.provide-capability}</Provide-Capability>
<Private-Package>${osgi.private}</Private-Package>
<Require-Bundle>${osgi.bundles}</Require-Bundle>
<Bundle-Activator>${osgi.activator}</Bundle-Activator>
<Export-Service>${osgi.export.service}</Export-Service>
<Include-Resource>
/META-INF/services/io.fabric8.kubernetes.client.http.HttpClient$Factory=target/classes/META-INF/services/io.fabric8.kubernetes.client.http.HttpClient$Factory,
</Include-Resource>
</instructions>
<classifier>bundle</classifier>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>

</project>
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
/*
* Copyright (C) 2015 Red Hat, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package io.fabric8.kubernetes.client.vertx;

import io.vertx.core.Future;
import io.vertx.core.Vertx;
import io.vertx.core.buffer.Buffer;
import lombok.RequiredArgsConstructor;

import java.io.InputStream;

@RequiredArgsConstructor
class AsyncInputReader {

private static final int CHUNK_SIZE = 2048;

private final Vertx vertx;
private final InputStream inputStream;
private byte[] readBuffer;

Future<Buffer> readNextChunk() {
return vertx.executeBlocking(() -> {
if (readBuffer == null) {
readBuffer = new byte[CHUNK_SIZE];
}
final int bytesRead = inputStream.read(readBuffer);
if (bytesRead == -1) {
return null; // EOF
}
return Buffer.buffer().appendBytes(readBuffer, 0, bytesRead);
});
}
}
Loading