From b30ed871d13989f9f26201bf59d04d332f00a69a Mon Sep 17 00:00:00 2001 From: Marc Nuri Date: Mon, 25 Nov 2024 17:20:19 +0100 Subject: [PATCH] feat: user Vert.x as the default HttpClient implementation Signed-off-by: Marc Nuri --- .github/workflows/e2e-httpclient-tests.yml | 2 +- CHANGELOG.md | 1 + chaos-tests/pom.xml | 4 +- doc/FAQ.md | 148 ++++++++++++------ doc/MIGRATION-v7.md | 9 ++ kubernetes-client/pom.xml | 4 +- kubernetes-itests/pom.xml | 10 +- .../kubernetes/client/mock/PodTest.java | 3 +- 8 files changed, 120 insertions(+), 61 deletions(-) diff --git a/.github/workflows/e2e-httpclient-tests.yml b/.github/workflows/e2e-httpclient-tests.yml index 5ffda4984ff..1df86937403 100644 --- a/.github/workflows/e2e-httpclient-tests.yml +++ b/.github/workflows/e2e-httpclient-tests.yml @@ -39,7 +39,7 @@ jobs: fail-fast: false matrix: kubernetes: [v1.28.1,v1.27.5] - httpclient: [jdk,jetty,vertx] + httpclient: [jdk,jetty,okhttp] steps: - name: Checkout uses: actions/checkout@v4 diff --git a/CHANGELOG.md b/CHANGELOG.md index a7aa509bb68..7ada4d0e800 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -43,6 +43,7 @@ * Fix #6158: Removed deprecated methods from `io.fabric8.kubernetes.client.utils.IOHelpers` class * Fix #6159: Removed deprecated `io.fabric8.kubernetes.client.utils.Utils.getPluralFromKind` method * Fix #6361: Renamed SettableBeanPropertyDelegate to SettableBeanPropertyDelegating +* Fix #6470: Switched default HTTP client from OkHttp to Vert.x (`kubernetes-httpclient-vertx`) * Fix #6603: Removed deprecated `io.fabric8.openshift.api.model.runtime.RawExtension` class * Fix #6605: Removed deprecated `ApiVersionUtil` classes in extension modules * Fix #6609: Removed deprecated `io.fabric8.crd.generator.CRDInfo.getVersion` method diff --git a/chaos-tests/pom.xml b/chaos-tests/pom.xml index 4b96d012687..416563f722c 100644 --- a/chaos-tests/pom.xml +++ b/chaos-tests/pom.xml @@ -49,13 +49,13 @@ io.fabric8 - kubernetes-httpclient-okhttp + kubernetes-httpclient-vertx io.fabric8 - kubernetes-httpclient-okhttp + kubernetes-httpclient-vertx test diff --git a/doc/FAQ.md b/doc/FAQ.md index b4a5a09990c..366f95114ba 100644 --- a/doc/FAQ.md +++ b/doc/FAQ.md @@ -1,26 +1,29 @@ # Frequently Asked Questions: ### How do I use KubernetesClient with IPv6 Kubernetes Clusters? -We're aware of this [issue](https://github.com/fabric8io/kubernetes-client/issues/2632) in Fabric8 Kubernetes Client. Unfortunately, this is caused by the OkHttp transitive dependency. You can check the suggested workaround here: - -[Using KubernetesClient with IPv6 based Kubernetes Clusters](./KubernetesClientWithIPv6Clusters.md) +The Kubernetes Client and all its HttpClient provided implementations should be compatible with IPv6 Kubernetes Clusters. ### What artifact(s) should my project depend on? -Fabric8 version 6 introduces more options with regards to dependencies. +Fabric8 Kubernetes Client version 6 introduced more options with regards to dependencies. -1. Have compile dependencies on kubernetes-client or openshift-client - this is no different than what was done with version 5 and before. If you have done custom development involving effectively internal classes, you'll need to still use this option. +1. Have `compile` dependencies on `kubernetes-client` or `openshift-client` - this is no different than what was done with version 5 and before. + If you have done custom development involving effectively internal classes, you'll need to still use this option. -2. Have compile dependencies on kubernetes-client-api or openshift-client-api, and a runtime dependency on kubernetes-client or openshift-client. This option will provide your application with a cleaner compile time classpath. +2. Have `compile` dependencies on `kubernetes-client-api` or `openshift-client-api`, + and a runtime dependency on `kubernetes-client` or `openshift-client`. + This option will provide your application with a cleaner compile time classpath. -Furthermore you will also have choices in the HttpClient that is utilized. +Furthermore, you will also have choices in the HttpClient implementation that is utilized. -By default kubernetes-client has a runtime dependency on OkHttp (kubernetes-httpclient-okhttp). If you need to directly manipulate OkHttp, you add a compile dependency to kubernetes-httpclient-okhttp. +By default, kubernetes-client has a runtime dependency on Vert.x (`kubernetes-httpclient-vertx`). -If you wish to use another HttpClient implementation typically you will exclude kubernetes-httpclient-okhttp and include the other runtime or compile dependency instead. +If you wish to use another HttpClient implementation typically you will exclude `kubernetes-httpclient-vertx` and include the other runtime or compile dependency instead. ### I've tried adding a dependency to kubernetes-client, but I'm still getting weird class loading issues, what gives? -More than likely your project already has transitive dependencies to a conflicting version of the Fabric8 Kubernetes Client. For example spring-cloud-dependencies already depends upon the client. You should fully override the client version in this case via the kubernetes-client-bom: +More than likely your project already has transitive dependencies to a conflicting version of the Fabric8 Kubernetes Client. +For example spring-cloud-dependencies already depends upon the client. +You should fully override the client version in this case via the `kubernetes-client-bom`: ```xml @@ -32,36 +35,55 @@ More than likely your project already has transitive dependencies to a conflicti import pom - ... + + + ``` -That will align all of the transitive Fabric8 Kubernetes Client dependencies to you chosen version, fabric8.client.version. Please be aware though that substituting a different major version of the client may not be fully compatible with the existing usage in your dependency - if you run into an issue, please check for or create an issue for an updated version of that project's library that contains a later version of the Fabric8 Kubernetes Client. +That will align all of the transitive Fabric8 Kubernetes Client dependencies to you chosen version, fabric8.client.version. +Please be aware though that substituting a different major version of the client may not be fully compatible with the existing usage in your dependency - if you run into an issue, please check for or create an issue for an updated version of that project's library that contains a later version of the Fabric8 Kubernetes Client. ### What threading concerns are there? -There has been a lot of changes under the covers with thread utilization in the Fabric8 client over the 5.x and 6.x releases. So the exact details of what threads are created / used where will depend on the particular release version. +There has been a lot of changes under the covers with thread utilization in the Fabric8 client over the 5.x and 6.x releases. +So the exact details of what threads are created / used where will depend on the particular release version. -At the core the thread utilization will depend upon the HTTP client implementation. Per client OkHttp maintains a pool of threads for task execution. It will dedicate 2 threads out of that pool per WebSocket connection. If you have a lot of WebSocket usage (Informer or Watches) with OkHttp, you can expect to see a large number of threads in use. +At the core the thread utilization will depend upon the HTTP client implementation. +Per client OkHttp maintains a pool of threads for task execution. +It will dedicate 2 threads out of that pool per WebSocket connection. +If you have a lot of WebSocket usage (Informer or Watches) with OkHttp, you can expect to see a large number of threads in use. -With the JDK, Jetty, or Vert.x http clients they will maintain a smaller worker pool for all tasks that is typically sized by default based upon your available processors, and typically a selector / coordinator thread(s). It does not matter how many Informers or Watches you run, the same threads are shared. +With the JDK, Jetty, or Vert.x http clients they will maintain a smaller worker pool for all tasks that is typically sized by default based upon your available processors, and typically a selector / coordinator thread(s). +It does not matter how many Informers or Watches you run, the same threads are shared. -To ease developer burden the callbacks on Watchers and ResourceEventHandlers will not be done directly by an http client thread, but the order of calls will be guaranteed. This will make the logic you include in those callbacks tolerant to some blocking without compromising the on-going work at the HTTP client level. However you should avoid truly long running operations as this will cause further events to queue and may eventually case memory issues. +To ease developer burden the callbacks on Watchers and ResourceEventHandlers will not be done directly by an HTTP client thread, but the order of calls will be guaranteed. +This will make the logic you include in those callbacks tolerant to some blocking without compromising the on-going work at the HTTP client level. +However, you should avoid truly long running operations as this will cause further events to queue and may eventually case memory issues. -> **Note:** It is recommended with any HTTP client implementation that logic you supply via Watchers, ExecListeners, ResourceEventHandlers, Predicates, Interceptors, LeaderCallbacks, etc. does not execute long running tasks. +> [!NOTE] +> It is recommended with any HTTP client implementation that logic you supply via Watchers, ExecListeners, ResourceEventHandlers, Predicates, Interceptors, LeaderCallbacks, etc. does not execute long running tasks. -On top of the http client threads the Fabric8 client maintains a task thread pool for scheduled tasks and for tasks that are called from WebSocket operations, such as handling input and output streams and ResourceEventHandler call backs. This thread pool defaults to an unlimited number of cached threads, which will be shutdown when the client is closed - that is a sensible default with as the amount of concurrently running async tasks will typically be low. If you would rather take full control over the threading use KubernetesClientBuilder.withExecutor or KubernetesClientBuilder.withExecutorSupplier - however note that constraining this thread pool too much will result in a build up of event processing queues. +On top of the HTTP client threads the Fabric8 client maintains a task thread pool for scheduled tasks and for tasks that are called from WebSocket operations, such as handling input and output streams and ResourceEventHandler call backs. +This thread pool defaults to an unlimited number of cached threads, which will be shutdown when the client is closed - that is a sensible default with as the amount of concurrently running async tasks will typically be low. +If you would rather take full control over the threading use KubernetesClientBuilder.withExecutor or KubernetesClientBuilder.withExecutorSupplier - however note that constraining this thread pool too much will result in a build up of event processing queues. -Finally the fabric8 client will use 1 thread per PortForward and an additional thread per socket connection - this may be improved upon in the future. +Finally, the fabric8 client will use 1 thread per PortForward and an additional thread per socket connection - this may be improved upon in the future. ### What additional logging is available? -Like many java application the Fabric8 Client utilizes [slf4j](https://www.slf4j.org/). You may configure support for whatever underlying logging framework suits your needs. The logging contexts for the Fabric8 Client follow the standard convention of the package structure - everything from within the client will be rooted at the io.fabric8 context. Third-party dependencies, including the chosen HTTP client implementation, will have different root contexts. +Like many Java application the Fabric8 Client utilizes [slf4j](https://www.slf4j.org/). +You may configure support for whatever underlying logging framework suits your needs. +The logging contexts for the Fabric8 Client follow the standard convention of the package structure - everything from within the client will be rooted at the io.fabric8 context. +Third-party dependencies, including the chosen HTTP client implementation, will have different root contexts. -If you are using pod exec, which can occur indirectly via pod operations like copying files, and not seeing the expected behavior - please enable debug logging for the io.fabric8.kubernetes.client.dsl.internal context. That will provide the stdErr and stdOut as debug logs to further diagnose what is occurring. +If you are using Pod exec, which can occur indirectly via pod operations like copying files, and not seeing the expected behavior - please enable debug logging for the io.fabric8.kubernetes.client.dsl.internal context. +That will provide the stdErr and stdOut as debug logs to further diagnose what is occurring. ### How to use KubernetesClient in OSGi? -Fabric8 Kubernetes Client provides ManagedKubernetesClient and ManagedOpenShiftClient as [OSGi Declarative Service](https://docs.osgi.org/specification/osgi.cmpn/7.0.0/service.component.html). In order to use it, you must have [Service Component Runtime (SCR)](https://docs.osgi.org/specification/osgi.cmpn/7.0.0/service.component.html#service.component-service.component.runtime) feature enabled in your OSGi runtime. In [Apache Karaf](https://karaf.apache.org/), you can add this to Karaf Maven Plugin configuration: +Fabric8 Kubernetes Client provides `ManagedKubernetesClient` and `ManagedOpenShiftClient` as [OSGi Declarative Service](https://docs.osgi.org/specification/osgi.cmpn/7.0.0/service.component.html). +In order to use it, you must have [Service Component Runtime (SCR)](https://docs.osgi.org/specification/osgi.cmpn/7.0.0/service.component.html#service.component-service.component.runtime) feature enabled in your OSGi runtime. +In [Apache Karaf](https://karaf.apache.org/), you can add this to the Karaf Maven Plugin configuration: ```xml org.apache.karaf.tooling @@ -75,7 +97,8 @@ Fabric8 Kubernetes Client provides ManagedKubernetesClient and ManagedOpenShiftC ``` -You would need to provide component configuration files for the client you're using. For example, in case of [Apache Karaf](https://karaf.apache.org/), place configuration files in this directory: +You need to provide component configuration files for the client you're using. +For example, in case of [Apache Karaf](https://karaf.apache.org/), place configuration files in this directory: ``` src/ └── main @@ -86,31 +109,34 @@ src/ │ ├── io.fabric8.openshift.client.cfg ``` -Once added KubernetesClient declarative services would be exposed automatically on startup. Then you can inject it in your project. Here is an example using Apache camel's `@BeanInject` annotation: +Once added KubernetesClient declarative services would be exposed automatically on startup. +Then you can inject it in your project. +Here is an example using Apache camel's `@BeanInject` annotation: ```java @BeanInject - private KubernetesClient kubernetesClient + private KubernetesClient kubernetesClient; ``` ### Why am I getting Exception when using `*` in NO_PROXY ? -Starting Fabric8 Kubernetes Client v6.1.0, we've change NO_PROXY matching as simple as possible and not support any meta characters. It honors the [GNU WGet Spec](https://www.gnu.org/software/wget/manual/html_node/Proxies.html). +Starting Fabric8 Kubernetes Client v6.1.0, we've changed `NO_PROXY` matching as simple as possible and not support any meta characters. +It honors the [GNU WGet Spec](https://www.gnu.org/software/wget/manual/html_node/Proxies.html). -So instead of providing NO_PROXY like this: +So instead of providing `NO_PROXY` like this: (Unsupported) :x: -```java +``` NO_PROXY: localhost,127.0.0.1,*.google.com, *.github.com ``` we should provide it like this: (Supported) :heavy_check_mark: -```java +``` NO_PROXY: localhost,127.0.0.1,.google.com,.github.com ``` -### How does KubernetesClient loads proxy URL from various sources? +### How does KubernetesClient load proxy URL from various sources? KubernetesClient loads proxy URL from the following sources (in decreasing order of precedence): - `ConfigBuilder.withHttpProxy` / `ConfigBuilder.withHttpsProxy` @@ -123,9 +149,11 @@ URLs with `http`, `https`, and `socks5` schemes are supported. ### Optimistic Locking Behavior -Unfortunately it's a little complicated as it depends on what operation you are doing - we'll work towards ensuring the Javadocs are as informative as possible. Here is quick overview: +Unfortunately it's a little complicated as it depends on what operation you are doing - we'll work towards ensuring the Javadocs are as informative as possible. +Here is quick overview: -- Basic mutative operations such as update and all variations of patch (patch, edit, accept, serverSideApply) that operate on a given item - are all locked to the resourceVersion on that item. If you don't want this behavior then set the resourceVersion to null: +- Basic mutative operations such as update and all variations of patch (patch, edit, accept, serverSideApply) that operate on a given item - are all locked to the resourceVersion on that item. + If you don't want this behavior then set the resourceVersion to null: ``` resource.accept(x -> { @@ -134,59 +162,81 @@ resource.accept(x -> { }); ``` -When the resourceVersion is null for an update the client obtains the latest resourceVersion prior to attempting the PUT operation - in a rare circumstance this may still fail due to a concurrent modification. +When the resourceVersion is null for an update the client obtains the latest resourceVersion prior to attempting the `PUT` operation - in a rare circumstance this may still fail due to a concurrent modification. When the resourceVersion is null for a patch the server will always attempt to perform the patch - but of course there may be conflicts to deal with if there has been an intervening modification. -**Note:** that when using informers - do not make modifications to the resources obtained from the cache - especially to the resourceVersion. +> [!NOTE] +> When using informers - do not make modifications to the resources obtained from the cache - especially to the resourceVersion. -**Note:** it is not recommended to use serverSideApply directly against modified existing resources - the intent is to apply only the desired state owned by the applier. See the next topic for more. +> [!NOTE] +> It is not recommended to use serverSideApply directly against modified existing resources - the intent is to apply only the desired state owned by the applier. See the next topic for more. - Delete is not locked by default, you may use the applicable lockResourceVersion method if you want the delete to apply only to a specific resourceVersion -- Specialized mutative operations are generally unlocked - this includes scale, rolling operations (resume, pause, restart), and others. The rationale is that you want the narrow operation to succeed even if there has been an intervening change. If you encounter a situation where you require these operations be locked, please raise an issue so that we can see about making the locking function applicable. +- Specialized mutative operations are generally unlocked - this includes scale, rolling operations (resume, pause, restart), and others. + The rationale is that you want the narrow operation to succeed even if there has been an intervening change. + If you encounter a situation where you require these operations be locked, please raise an issue so that we can see about making the locking function applicable. -- A handful of additional operations, such as undo, updateImage, and others are currently locked by default. This may not be intentional - under the covers this is apply a json patch; older versions of json patching that created the resource diff were unlocked by default. If you encounter an exception due to a concurrent modification performing an operation that seems like it should ignore that possibility by default please raise an issue. +- A handful of additional operations, such as undo, updateImage, and others are currently locked by default. + This may not be intentional - under the covers this is apply a json patch; older versions of json patching that created the resource diff were unlocked by default. + If you encounter an exception due to a concurrent modification performing an operation that seems like it should ignore that possibility by default please raise an issue. -- Legacy operations such as createOrReplace or replace were effectively unlocked - they would repeatedly retry the operation with the freshest resourceVersion until it succeeded. These methods have been deprecated because of the complexity of their implementation and the broad unlocking behavior by default could be considered unsafe. +- Legacy operations such as createOrReplace or replace were effectively unlocked - they would repeatedly retry the operation with the freshest resourceVersion until it succeeded. + These methods have been deprecated because of the complexity of their implementation and the broad unlocking behavior by default could be considered unsafe. ### Alternatives to createOrReplace and replace -createOrReplace was introduced as an alternative to the kubectl apply operation. Over the years there were quite a few issues highlighting where the behavior was different, and there were only limited workarounds and improvements offered. Given the additional complexity of matching the kubectl client side apply behavior, that was never offered as an option. Now that there is first class support for serverSideApply it can be used, but it comes with a couple of caveats: +`createOrReplace` was introduced as an alternative to the kubectl apply operation. +Over the years there were quite a few issues highlighting where the behavior was different, and there were only limited workarounds and improvements offered. +Given the additional complexity of matching the kubectl client side apply behavior, that was never offered as an option. +Now that there is first class support for serverSideApply it can be used, but it comes with a couple of caveats: -- you will want to use forceConficts - resource.forceConflicts().serverSideApply() - this is especially true when acting as a controller updating a resource that [manages](https://kubernetes.io/docs/reference/using-api/server-side-apply/#using-server-side-apply-in-a-controller) +- You will want to use forceConflicts - `resource.forceConflicts().serverSideApply()` - this is especially true when acting as a controller updating a resource that [manages](https://kubernetes.io/docs/reference/using-api/server-side-apply/#using-server-side-apply-in-a-controller) -- for some resource types serverSideApply may cause vacuous revisions - see https://github.com/kubernetes/kubernetes/issues/118519 - if you are being informed of modifications on those resources you must either filter those out, don't perform the serverSideApply, or use the [java-operator-sdk](https://github.com/java-operator-sdk/java-operator-sdk) that should handle that possibility already. +- For some resource types serverSideApply may cause vacuous revisions - see https://github.com/kubernetes/kubernetes/issues/118519 - if you are being informed of modifications on those resources you must either filter those out, don't perform the serverSideApply, or use the [java-operator-sdk](https://github.com/java-operator-sdk/java-operator-sdk) that should handle that possibility already. -- Keep in mind that serverSideApply is not the same as client side apply. In particular serverSideApply does not treat list merging the same, which may lead to unexpected behavior when list item merge keys are modified by actors other than the manager of that field. See the upstream issue: https://github.com/kubernetes/kubernetes/issues/118725 +- Keep in mind that serverSideApply is not the same as client side apply. + In particular serverSideApply does not treat list merging the same, which may lead to unexpected behavior when list item merge keys are modified by actors other than the manager of that field. + See the upstream issue: https://github.com/kubernetes/kubernetes/issues/118725 -- a common pattern for createOrReplace was obtaining the current resource from the api server (possibly via an informer cache), making modifications, then calling createOrReplace. Doing something similar with serverSideApply will fail as the managedFields will be populated. While you may be tempted to simply clear the managedFields and the resourceVersion, this is generally not what you should be doing unless you want your logic to assume ownership of every field on the resource. Instead you should reorganize your code to apply only the desired state that you wish to apply. If you have a more involved situation please read the [upstream server side apply documentation](https://kubernetes.io/docs/reference/using-api/server-side-apply/) to understand topics like transferring ownership and partial patches. +- A common pattern for createOrReplace was obtaining the current resource from the api server (possibly via an informer cache), making modifications, then calling createOrReplace. + Doing something similar with serverSideApply will fail as the managedFields will be populated. + While you may be tempted to simply clear the managedFields and the resourceVersion, this is generally not what you should be doing unless you want your logic to assume ownership of every field on the resource. + Instead you should reorganize your code to apply only the desired state that you wish to apply. + If you have a more involved situation please read the [upstream server side apply documentation](https://kubernetes.io/docs/reference/using-api/server-side-apply/) to understand topics like transferring ownership and partial patches. -If the limitations / changes necessary to use serverSideApply are too much, you may also use the createOr method. Instead of +If the limitations / changes necessary to use serverSideApply are too much, you may also use the createOr method. +Instead of: ``` resource.createOrReplace() ``` -you would use +you would use: ``` resource.unlock().createOr(NonDeletingOperation::update) ``` -Or NonDeletingOperation::patch. The use of the unlock function is optional and is only needed if you are starting with a item that has the resourceVersion populated. If you have any concern over replacing concurrent changes you should omit the usage of the unlock function. +Or `NonDeletingOperation::patch`. +The use of the unlock function is optional and is only needed if you are starting with a item that has the resourceVersion populated. +If you have any concern over replacing concurrent changes you should omit the usage of the unlock function. The alternative to replace is either serverSideApply - with the same caveats as above - or to use update, but with resourceVersion set to null or usage of the unlock function. -**Note:** that when using informers - do not make modifications to the resources obtained from the cache - especially to the resourceVersion. If you use the unlock function it will make changes to a copy of your item. + +> [!NOTE] +> When using informers - do not make modifications to the resources obtained from the cache - especially to the resourceVersion. +> If you use the unlock function it will make changes to a copy of your item. ### What credentials does the client use for authentication? By default, KubernetesClient tries to look up for Kubernetes Cluster information in the following sources: -- Kube Config file (`~/.kube/config` or `kubeconfig` environment variable) +- `kubeconfig` file (`~/.kube/config` or `kubeconfig` environment variable) - Currently mounted ServiceAccount inside Pod (`/var/run/secrets/kubernetes.io/serviceaccount/`) - System properties - Environment variables Be aware that the cluster autoconfiguration sets up more than just authentication information; see the implementation of `io.fabric8.kubernetes.client.Config#configFromSysPropsOrEnvVars` for details. -#### Running KubernetesClient from outside of a Kubernetes cluster: +#### Running KubernetesClient from outside a Kubernetes cluster: When running KubernetesClient outside a Kubernetes cluster, KubernetesClient tries looking into user's `~/.kube/config` (or file set by `kubeconfig` environment variable), System properties and Environment variables for fetching Kubernetes Cluster information. #### Running KubernetesClient from within a Pod in Kubernetes cluster: diff --git a/doc/MIGRATION-v7.md b/doc/MIGRATION-v7.md index 90c47bf0b98..cc09c0bfc38 100644 --- a/doc/MIGRATION-v7.md +++ b/doc/MIGRATION-v7.md @@ -2,6 +2,7 @@ ## Contents - [Java baseline set to Java 11](#java-11) +- [Vert.x as default HttpClient implementation](#vertx-httpclient) - [Bouncy Castle is no longer needed](#bouncy-castle) - [Config changes](#config-changes) - [Support for multiple kubeconfig files](#config-changes-multiple-kubeconfig) @@ -41,6 +42,14 @@ Starting from version 7.0.0, you will need a Java 11+ runtime (using the latest It's been more than 10 years since Java 8 was released, and it's no longer supported by most vendors. We made our best effort to keep the client compatible with Java 8 for as long as possible, but it's time to move on. +## Vert.x as default HttpClient implementation + +OkHttp has been replaced by Vert.x as the default HttpClient implementation. +As of version 7.0.0, the Fabric8 Kubernetes Client `io.fabric8:kubernetes-client` and `io.fabric8:openshift-client` include a transitive dependency to the `io.fabric8:kubernetes-httpclient-vertx` module. + +If you want to continue using OkHttp as the HttpClient, you can do so by adding the `io.fabric8:kubernetes-httpclient-okhttp` module as a dependency. +It is also recommended (although not mandatory) to add an exclusion for the `io.fabric8:kubernetes-httpclient-vertx` module to avoid having both implementations in the classpath. + ## Bouncy Castle is no longer needed The Bouncy Castle library is no longer needed as a dependency. diff --git a/kubernetes-client/pom.xml b/kubernetes-client/pom.xml index 1873030749c..2ff3508c446 100644 --- a/kubernetes-client/pom.xml +++ b/kubernetes-client/pom.xml @@ -67,7 +67,7 @@ io.fabric8 - kubernetes-httpclient-okhttp + kubernetes-httpclient-vertx runtime @@ -205,7 +205,7 @@ - kubernetes-httpclient-okhttp + kubernetes-httpclient-vertx ${project.name} diff --git a/kubernetes-itests/pom.xml b/kubernetes-itests/pom.xml index 90acaba271f..c3d7d82932b 100644 --- a/kubernetes-itests/pom.xml +++ b/kubernetes-itests/pom.xml @@ -102,7 +102,7 @@ io.fabric8 - kubernetes-httpclient-okhttp + kubernetes-httpclient-vertx @@ -122,7 +122,7 @@ io.fabric8 - kubernetes-httpclient-okhttp + kubernetes-httpclient-vertx @@ -133,7 +133,7 @@ - httpclient-vertx + httpclient-okhttp io.fabric8 @@ -142,13 +142,13 @@ io.fabric8 - kubernetes-httpclient-okhttp + kubernetes-httpclient-vertx io.fabric8 - kubernetes-httpclient-vertx + kubernetes-httpclient-okhttp diff --git a/kubernetes-tests/src/test/java/io/fabric8/kubernetes/client/mock/PodTest.java b/kubernetes-tests/src/test/java/io/fabric8/kubernetes/client/mock/PodTest.java index 1cdb07be6ff..e80c66fc429 100644 --- a/kubernetes-tests/src/test/java/io/fabric8/kubernetes/client/mock/PodTest.java +++ b/kubernetes-tests/src/test/java/io/fabric8/kubernetes/client/mock/PodTest.java @@ -46,7 +46,6 @@ import io.fabric8.kubernetes.client.utils.InputStreamPumper; import io.fabric8.kubernetes.client.utils.Utils; import io.fabric8.mockwebserver.internal.WebSocketMessage; -import okio.ByteString; import org.awaitility.Awaitility; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; @@ -830,7 +829,7 @@ void testPortForward() throws IOException { } while (read >= 0); buffer.flip(); channel.socket().close(); - assertEquals("Hello World", ByteString.of(buffer).utf8()); + assertEquals("Hello World", StandardCharsets.UTF_8.decode(buffer).toString()); assertFalse(portForward.errorOccurred()); assertEquals(0, portForward.getClientThrowables().size()); assertEquals(0, portForward.getServerThrowables().size());