diff --git a/extensions/camel-k/client/src/test/java/io/fabric8/camelk/client/CamelKClientAdaptTest.java b/extensions/camel-k/client/src/test/java/io/fabric8/camelk/client/CamelKClientAdaptTest.java index 99155c40012..c6c8412ea76 100644 --- a/extensions/camel-k/client/src/test/java/io/fabric8/camelk/client/CamelKClientAdaptTest.java +++ b/extensions/camel-k/client/src/test/java/io/fabric8/camelk/client/CamelKClientAdaptTest.java @@ -25,6 +25,7 @@ import io.fabric8.kubernetes.client.dsl.internal.OperationSupport; import io.fabric8.kubernetes.client.http.HttpClient; import io.fabric8.kubernetes.client.impl.KubernetesClientImpl; +import io.fabric8.kubernetes.client.utils.Serialization; import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.params.ParameterizedTest; @@ -47,7 +48,8 @@ class CamelKClientAdaptTest { public void setUp() { HttpClient mockClient = mock(HttpClient.class, Mockito.RETURNS_DEEP_STUBS); Config config = new ConfigBuilder().withMasterUrl("https://localhost:8443/").build(); - kubernetesClient = new KubernetesClientImpl(mockClient, config); + kubernetesClient = new KubernetesClientImpl(mockClient, config, () -> Runnable::run, + Serialization.getKubernetesSerialization()); } @AfterEach diff --git a/extensions/chaosmesh/client/src/test/java/io/fabric8/chaosmesh/client/ChaosMeshClientAdaptTest.java b/extensions/chaosmesh/client/src/test/java/io/fabric8/chaosmesh/client/ChaosMeshClientAdaptTest.java index 6d8efa95324..3cddba92961 100644 --- a/extensions/chaosmesh/client/src/test/java/io/fabric8/chaosmesh/client/ChaosMeshClientAdaptTest.java +++ b/extensions/chaosmesh/client/src/test/java/io/fabric8/chaosmesh/client/ChaosMeshClientAdaptTest.java @@ -25,6 +25,7 @@ import io.fabric8.kubernetes.client.dsl.internal.OperationSupport; import io.fabric8.kubernetes.client.http.HttpClient; import io.fabric8.kubernetes.client.impl.KubernetesClientImpl; +import io.fabric8.kubernetes.client.utils.Serialization; import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.params.ParameterizedTest; @@ -46,7 +47,8 @@ class ChaosMeshClientAdaptTest { public void setUp() { HttpClient mockClient = Mockito.mock(HttpClient.class, Mockito.RETURNS_DEEP_STUBS); Config config = new ConfigBuilder().withMasterUrl("https://localhost:8443/").build(); - kubernetesClient = new KubernetesClientImpl(mockClient, config); + kubernetesClient = new KubernetesClientImpl(mockClient, config, () -> Runnable::run, + Serialization.getKubernetesSerialization()); } @AfterEach diff --git a/extensions/istio/client/src/test/java/io/fabric8/istio/client/IstioClientAdaptTest.java b/extensions/istio/client/src/test/java/io/fabric8/istio/client/IstioClientAdaptTest.java index 71eea5cc66c..8ee70d6bf2c 100644 --- a/extensions/istio/client/src/test/java/io/fabric8/istio/client/IstioClientAdaptTest.java +++ b/extensions/istio/client/src/test/java/io/fabric8/istio/client/IstioClientAdaptTest.java @@ -25,6 +25,7 @@ import io.fabric8.kubernetes.client.dsl.internal.OperationSupport; import io.fabric8.kubernetes.client.http.HttpClient; import io.fabric8.kubernetes.client.impl.KubernetesClientImpl; +import io.fabric8.kubernetes.client.utils.Serialization; import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.params.ParameterizedTest; @@ -46,7 +47,8 @@ class IstioClientAdaptTest { public void setUp() { HttpClient mockClient = Mockito.mock(HttpClient.class, Mockito.RETURNS_DEEP_STUBS); Config config = new ConfigBuilder().withMasterUrl("https://localhost:8443/").build(); - kubernetesClient = new KubernetesClientImpl(mockClient, config); + kubernetesClient = new KubernetesClientImpl(mockClient, config, () -> Runnable::run, + Serialization.getKubernetesSerialization()); } @AfterEach diff --git a/extensions/knative/client/src/test/java/io/fabric8/knative/client/KnativeClientAdaptTest.java b/extensions/knative/client/src/test/java/io/fabric8/knative/client/KnativeClientAdaptTest.java index ddb3bf80357..6a39d4f3487 100644 --- a/extensions/knative/client/src/test/java/io/fabric8/knative/client/KnativeClientAdaptTest.java +++ b/extensions/knative/client/src/test/java/io/fabric8/knative/client/KnativeClientAdaptTest.java @@ -25,6 +25,7 @@ import io.fabric8.kubernetes.client.dsl.internal.OperationSupport; import io.fabric8.kubernetes.client.http.HttpClient; import io.fabric8.kubernetes.client.impl.KubernetesClientImpl; +import io.fabric8.kubernetes.client.utils.Serialization; import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.params.ParameterizedTest; @@ -46,7 +47,8 @@ class KnativeClientAdaptTest { public void setUp() { HttpClient mockClient = Mockito.mock(HttpClient.class, Mockito.RETURNS_DEEP_STUBS); Config config = new ConfigBuilder().withMasterUrl("https://localhost:8443/").build(); - kubernetesClient = new KubernetesClientImpl(mockClient, config); + kubernetesClient = new KubernetesClientImpl(mockClient, config, () -> Runnable::run, + Serialization.getKubernetesSerialization()); } @AfterEach diff --git a/extensions/open-cluster-management/client/src/test/java/io/fabric8/openclustermanagement/client/OpenClusterManagementClientAdaptTest.java b/extensions/open-cluster-management/client/src/test/java/io/fabric8/openclustermanagement/client/OpenClusterManagementClientAdaptTest.java index 4f1339f9b4a..77c92932164 100644 --- a/extensions/open-cluster-management/client/src/test/java/io/fabric8/openclustermanagement/client/OpenClusterManagementClientAdaptTest.java +++ b/extensions/open-cluster-management/client/src/test/java/io/fabric8/openclustermanagement/client/OpenClusterManagementClientAdaptTest.java @@ -25,6 +25,7 @@ import io.fabric8.kubernetes.client.dsl.internal.OperationSupport; import io.fabric8.kubernetes.client.http.HttpClient; import io.fabric8.kubernetes.client.impl.KubernetesClientImpl; +import io.fabric8.kubernetes.client.utils.Serialization; import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.params.ParameterizedTest; @@ -46,7 +47,8 @@ class OpenClusterManagementClientAdaptTest { public void setUp() { HttpClient mockClient = Mockito.mock(HttpClient.class, Mockito.RETURNS_DEEP_STUBS); Config config = new ConfigBuilder().withMasterUrl("https://localhost:8443/").build(); - kubernetesClient = new KubernetesClientImpl(mockClient, config); + kubernetesClient = new KubernetesClientImpl(mockClient, config, () -> Runnable::run, + Serialization.getKubernetesSerialization()); } @AfterEach diff --git a/extensions/service-catalog/client/src/test/java/io/fabric8/servicecatalog/client/ServiceCatalogClientAdaptTest.java b/extensions/service-catalog/client/src/test/java/io/fabric8/servicecatalog/client/ServiceCatalogClientAdaptTest.java index 8ecb6906aac..b1ce99f8b99 100644 --- a/extensions/service-catalog/client/src/test/java/io/fabric8/servicecatalog/client/ServiceCatalogClientAdaptTest.java +++ b/extensions/service-catalog/client/src/test/java/io/fabric8/servicecatalog/client/ServiceCatalogClientAdaptTest.java @@ -25,6 +25,7 @@ import io.fabric8.kubernetes.client.dsl.internal.OperationSupport; import io.fabric8.kubernetes.client.http.HttpClient; import io.fabric8.kubernetes.client.impl.KubernetesClientImpl; +import io.fabric8.kubernetes.client.utils.Serialization; import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.params.ParameterizedTest; @@ -46,7 +47,8 @@ class ServiceCatalogClientAdaptTest { public void setUp() { HttpClient mockClient = Mockito.mock(HttpClient.class, Mockito.RETURNS_DEEP_STUBS); Config config = new ConfigBuilder().withMasterUrl("https://localhost:8443/").build(); - kubernetesClient = new KubernetesClientImpl(mockClient, config); + kubernetesClient = new KubernetesClientImpl(mockClient, config, () -> Runnable::run, + Serialization.getKubernetesSerialization()); } @AfterEach diff --git a/extensions/tekton/client/src/test/java/io/fabric8/tekton/client/TektonClientAdaptTest.java b/extensions/tekton/client/src/test/java/io/fabric8/tekton/client/TektonClientAdaptTest.java index 515d6dce865..b01aaa5e88c 100644 --- a/extensions/tekton/client/src/test/java/io/fabric8/tekton/client/TektonClientAdaptTest.java +++ b/extensions/tekton/client/src/test/java/io/fabric8/tekton/client/TektonClientAdaptTest.java @@ -25,6 +25,7 @@ import io.fabric8.kubernetes.client.dsl.internal.OperationSupport; import io.fabric8.kubernetes.client.http.HttpClient; import io.fabric8.kubernetes.client.impl.KubernetesClientImpl; +import io.fabric8.kubernetes.client.utils.Serialization; import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.params.ParameterizedTest; @@ -46,7 +47,8 @@ class TektonClientAdaptTest { public void setUp() { HttpClient mockClient = Mockito.mock(HttpClient.class, Mockito.RETURNS_DEEP_STUBS); Config config = new ConfigBuilder().withMasterUrl("https://localhost:8443/").build(); - kubernetesClient = new KubernetesClientImpl(mockClient, config); + kubernetesClient = new KubernetesClientImpl(mockClient, config, () -> Runnable::run, + Serialization.getKubernetesSerialization()); } @AfterEach diff --git a/extensions/verticalpodautoscaler/client/src/test/java/io/fabric8/verticalpodautoscaler/client/VerticalPodAutoscalerClientAdaptTest.java b/extensions/verticalpodautoscaler/client/src/test/java/io/fabric8/verticalpodautoscaler/client/VerticalPodAutoscalerClientAdaptTest.java index 0f1215d79da..4ce567fc67e 100644 --- a/extensions/verticalpodautoscaler/client/src/test/java/io/fabric8/verticalpodautoscaler/client/VerticalPodAutoscalerClientAdaptTest.java +++ b/extensions/verticalpodautoscaler/client/src/test/java/io/fabric8/verticalpodautoscaler/client/VerticalPodAutoscalerClientAdaptTest.java @@ -25,6 +25,7 @@ import io.fabric8.kubernetes.client.dsl.internal.OperationSupport; import io.fabric8.kubernetes.client.http.HttpClient; import io.fabric8.kubernetes.client.impl.KubernetesClientImpl; +import io.fabric8.kubernetes.client.utils.Serialization; import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.params.ParameterizedTest; @@ -46,7 +47,8 @@ class VerticalPodAutoscalerClientAdaptTest { public void setUp() { HttpClient mockClient = Mockito.mock(HttpClient.class, Mockito.RETURNS_DEEP_STUBS); Config config = new ConfigBuilder().withMasterUrl("https://localhost:8443/").build(); - kubernetesClient = new KubernetesClientImpl(mockClient, config); + kubernetesClient = new KubernetesClientImpl(mockClient, config, () -> Runnable::run, + Serialization.getKubernetesSerialization()); } @AfterEach diff --git a/extensions/volcano/client/src/test/java/io/fabric8/volcano/client/VolcanoClientAdaptTest.java b/extensions/volcano/client/src/test/java/io/fabric8/volcano/client/VolcanoClientAdaptTest.java index 17c153d0907..c53e9dbe816 100644 --- a/extensions/volcano/client/src/test/java/io/fabric8/volcano/client/VolcanoClientAdaptTest.java +++ b/extensions/volcano/client/src/test/java/io/fabric8/volcano/client/VolcanoClientAdaptTest.java @@ -25,6 +25,7 @@ import io.fabric8.kubernetes.client.dsl.internal.OperationSupport; import io.fabric8.kubernetes.client.http.HttpClient; import io.fabric8.kubernetes.client.impl.KubernetesClientImpl; +import io.fabric8.kubernetes.client.utils.Serialization; import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.params.ParameterizedTest; @@ -46,7 +47,8 @@ class VolcanoClientAdaptTest { public void setUp() { HttpClient mockClient = Mockito.mock(HttpClient.class, Mockito.RETURNS_DEEP_STUBS); Config config = new ConfigBuilder().withMasterUrl("https://localhost:8443/").build(); - kubernetesClient = new KubernetesClientImpl(mockClient, config); + kubernetesClient = new KubernetesClientImpl(mockClient, config, () -> Runnable::run, + Serialization.getKubernetesSerialization()); } @AfterEach diff --git a/extensions/volumesnapshot/client/src/test/java/io/fabric8/volumesnapshot/client/VolumeSnapshotClientAdaptTest.java b/extensions/volumesnapshot/client/src/test/java/io/fabric8/volumesnapshot/client/VolumeSnapshotClientAdaptTest.java index 3ab73a35877..5e5d8a8bac8 100644 --- a/extensions/volumesnapshot/client/src/test/java/io/fabric8/volumesnapshot/client/VolumeSnapshotClientAdaptTest.java +++ b/extensions/volumesnapshot/client/src/test/java/io/fabric8/volumesnapshot/client/VolumeSnapshotClientAdaptTest.java @@ -25,6 +25,7 @@ import io.fabric8.kubernetes.client.dsl.internal.OperationSupport; import io.fabric8.kubernetes.client.http.HttpClient; import io.fabric8.kubernetes.client.impl.KubernetesClientImpl; +import io.fabric8.kubernetes.client.utils.Serialization; import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.params.ParameterizedTest; @@ -46,7 +47,8 @@ class VolumeSnapshotClientAdaptTest { public void setUp() { HttpClient mockClient = Mockito.mock(HttpClient.class, Mockito.RETURNS_DEEP_STUBS); Config config = new ConfigBuilder().withMasterUrl("https://localhost:8443/").build(); - kubernetesClient = new KubernetesClientImpl(mockClient, config); + kubernetesClient = new KubernetesClientImpl(mockClient, config, () -> Runnable::run, + Serialization.getKubernetesSerialization()); } @AfterEach diff --git a/junit/kubernetes-server-mock/src/test/java/io/fabric8/kubernetes/client/server/mock/crud/KubernetesCrudDispatcherFinalizerTest.java b/junit/kubernetes-server-mock/src/test/java/io/fabric8/kubernetes/client/server/mock/crud/KubernetesCrudDispatcherFinalizerTest.java index a52af3822ae..9b3bc847d43 100644 --- a/junit/kubernetes-server-mock/src/test/java/io/fabric8/kubernetes/client/server/mock/crud/KubernetesCrudDispatcherFinalizerTest.java +++ b/junit/kubernetes-server-mock/src/test/java/io/fabric8/kubernetes/client/server/mock/crud/KubernetesCrudDispatcherFinalizerTest.java @@ -18,6 +18,8 @@ import io.fabric8.kubernetes.api.model.HasMetadata; import io.fabric8.kubernetes.api.model.ObjectMetaBuilder; import io.fabric8.kubernetes.client.KubernetesClient; +import io.fabric8.kubernetes.client.Watcher; +import io.fabric8.kubernetes.client.WatcherException; import io.fabric8.kubernetes.client.server.mock.KubernetesCrudDispatcher; import io.fabric8.kubernetes.client.server.mock.KubernetesMockServer; import io.fabric8.kubernetes.client.server.mock.crud.crd.Owl; @@ -35,7 +37,12 @@ import java.util.List; import static org.assertj.core.api.Assertions.assertThat; -import static org.junit.jupiter.api.Assertions.*; +import static org.junit.jupiter.api.Assertions.assertDoesNotThrow; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertNull; +import static org.junit.jupiter.api.Assertions.assertTrue; class KubernetesCrudDispatcherFinalizerTest { @@ -112,6 +119,20 @@ void removeFinalizerByReplace() { // Given: Owl owl = createOwlWithFinalizer("owl-with-finalizer"); + client.resources(Owl.class).watch(new Watcher() { + + @Override + public void eventReceived(Action action, Owl resource) { + System.out.println(action + " " + Serialization.asYaml(resource)); + } + + @Override + public void onClose(WatcherException cause) { + + } + + }); + // When owl with finalizer is deleted: client.resources(Owl.class).resource(owl).delete(); Owl owlThatShouldBeMarkedForDeletion = client.resources(Owl.class).resource(owl).get(); diff --git a/kubernetes-client-api/src/main/java/io/fabric8/kubernetes/client/DefaultKubernetesClient.java b/kubernetes-client-api/src/main/java/io/fabric8/kubernetes/client/DefaultKubernetesClient.java index 292aaf456d7..47ef633c919 100644 --- a/kubernetes-client-api/src/main/java/io/fabric8/kubernetes/client/DefaultKubernetesClient.java +++ b/kubernetes-client-api/src/main/java/io/fabric8/kubernetes/client/DefaultKubernetesClient.java @@ -21,9 +21,6 @@ import io.fabric8.kubernetes.client.http.HttpClient.Factory; import io.fabric8.kubernetes.client.http.StandardHttpClientBuilder; import io.fabric8.kubernetes.client.utils.HttpClientUtils; -import io.fabric8.kubernetes.client.utils.Serialization; - -import java.io.InputStream; /** * Class for Default Kubernetes Client implementing KubernetesClient interface. @@ -36,14 +33,6 @@ public class DefaultKubernetesClient extends NamespacedKubernetesClientAdapter load(InputStream is); + NamespaceListVisitFromServerGetDeleteRecreateWaitApplicable load(InputStream is); /** * Load a Kubernetes list object @@ -308,7 +307,7 @@ MixedOperation resourceList(String s); + NamespaceListVisitFromServerGetDeleteRecreateWaitApplicable resourceList(String s); /** * KubernetesResourceList operations diff --git a/kubernetes-client-api/src/main/java/io/fabric8/kubernetes/client/KubernetesClientBuilder.java b/kubernetes-client-api/src/main/java/io/fabric8/kubernetes/client/KubernetesClientBuilder.java index e4957f51735..d6aef054226 100644 --- a/kubernetes-client-api/src/main/java/io/fabric8/kubernetes/client/KubernetesClientBuilder.java +++ b/kubernetes-client-api/src/main/java/io/fabric8/kubernetes/client/KubernetesClientBuilder.java @@ -16,10 +16,11 @@ package io.fabric8.kubernetes.client; +import com.fasterxml.jackson.databind.ObjectMapper; import io.fabric8.kubernetes.client.http.HttpClient; import io.fabric8.kubernetes.client.informers.ResourceEventHandler; import io.fabric8.kubernetes.client.utils.HttpClientUtils; -import io.fabric8.kubernetes.client.utils.Serialization; +import io.fabric8.kubernetes.client.utils.KubernetesSerialization; import java.io.InputStream; import java.lang.reflect.InvocationTargetException; @@ -47,6 +48,7 @@ default void onClose(Executor executor) { private Class clazz; private ExecutorSupplier executorSupplier; private Consumer builderConsumer; + private KubernetesSerialization kubernetesSerialization = new KubernetesSerialization(new ObjectMapper()); public KubernetesClientBuilder() { // basically the same logic as in KubernetesResourceUtil for finding list types @@ -75,8 +77,9 @@ public KubernetesClient build() { this.factory = HttpClientUtils.getHttpClientFactory(); } HttpClient client = getHttpClient(); - return clazz.getConstructor(HttpClient.class, Config.class, ExecutorSupplier.class).newInstance(client, config, - executorSupplier); + return clazz.getConstructor(HttpClient.class, Config.class, ExecutorSupplier.class, KubernetesSerialization.class) + .newInstance(client, config, + executorSupplier, kubernetesSerialization); } catch (InstantiationException | IllegalAccessException | IllegalArgumentException | InvocationTargetException | NoSuchMethodException | SecurityException e) { throw KubernetesClientException.launderThrowable(e); @@ -96,13 +99,18 @@ public KubernetesClientBuilder withConfig(Config config) { return this; } + public KubernetesClientBuilder withKubernetesSerialization(KubernetesSerialization kubernetesSerialization) { + this.kubernetesSerialization = kubernetesSerialization; + return this; + } + public KubernetesClientBuilder withConfig(String config) { - this.config = Serialization.unmarshal(config, Config.class); + this.config = kubernetesSerialization.unmarshal(config, Config.class); return this; } public KubernetesClientBuilder withConfig(InputStream config) { - this.config = Serialization.unmarshal(config, Config.class); + this.config = kubernetesSerialization.unmarshal(config, Config.class); return this; } diff --git a/kubernetes-client-api/src/main/java/io/fabric8/kubernetes/client/NamespacedKubernetesClientAdapter.java b/kubernetes-client-api/src/main/java/io/fabric8/kubernetes/client/NamespacedKubernetesClientAdapter.java index b402a39153b..7d327382c04 100644 --- a/kubernetes-client-api/src/main/java/io/fabric8/kubernetes/client/NamespacedKubernetesClientAdapter.java +++ b/kubernetes-client-api/src/main/java/io/fabric8/kubernetes/client/NamespacedKubernetesClientAdapter.java @@ -78,7 +78,6 @@ import io.fabric8.kubernetes.client.dsl.NamespaceableResource; import io.fabric8.kubernetes.client.dsl.NetworkAPIGroupDSL; import io.fabric8.kubernetes.client.dsl.NonNamespaceOperation; -import io.fabric8.kubernetes.client.dsl.ParameterNamespaceListVisitFromServerGetDeleteRecreateWaitApplicable; import io.fabric8.kubernetes.client.dsl.PodResource; import io.fabric8.kubernetes.client.dsl.PolicyAPIGroupDSL; import io.fabric8.kubernetes.client.dsl.RbacAPIGroupDSL; @@ -255,12 +254,12 @@ public NonNamespaceOperation load(InputStream is) { + public NamespaceListVisitFromServerGetDeleteRecreateWaitApplicable load(InputStream is) { return getClient().load(is); } @Override - public ParameterNamespaceListVisitFromServerGetDeleteRecreateWaitApplicable resourceList(String s) { + public NamespaceListVisitFromServerGetDeleteRecreateWaitApplicable resourceList(String s) { return getClient().resourceList(s); } diff --git a/kubernetes-client-api/src/main/java/io/fabric8/kubernetes/client/dsl/ParameterNamespaceListVisitFromServerGetDeleteRecreateWaitApplicable.java b/kubernetes-client-api/src/main/java/io/fabric8/kubernetes/client/dsl/ParameterNamespaceListVisitFromServerGetDeleteRecreateWaitApplicable.java deleted file mode 100644 index cd5d60582f9..00000000000 --- a/kubernetes-client-api/src/main/java/io/fabric8/kubernetes/client/dsl/ParameterNamespaceListVisitFromServerGetDeleteRecreateWaitApplicable.java +++ /dev/null @@ -1,29 +0,0 @@ -/** - * 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.dsl; - -/** - * @deprecated It is no longer necessary to associate parameters prior to deserialization. - *

- * reference {@link NamespaceListVisitFromServerGetDeleteRecreateWaitApplicable} instead - */ -@Deprecated -public interface ParameterNamespaceListVisitFromServerGetDeleteRecreateWaitApplicable - extends NamespaceListVisitFromServerGetDeleteRecreateWaitApplicable, - Parameterizable> { - -} diff --git a/kubernetes-client-api/src/main/java/io/fabric8/kubernetes/client/informers/cache/ReducedStateItemStore.java b/kubernetes-client-api/src/main/java/io/fabric8/kubernetes/client/informers/cache/ReducedStateItemStore.java index 951c1438bee..010939594e7 100644 --- a/kubernetes-client-api/src/main/java/io/fabric8/kubernetes/client/informers/cache/ReducedStateItemStore.java +++ b/kubernetes-client-api/src/main/java/io/fabric8/kubernetes/client/informers/cache/ReducedStateItemStore.java @@ -18,7 +18,7 @@ import io.fabric8.kubernetes.api.model.GenericKubernetesResource; import io.fabric8.kubernetes.api.model.HasMetadata; -import io.fabric8.kubernetes.client.utils.Serialization; +import io.fabric8.kubernetes.client.utils.KubernetesSerialization; import java.util.ArrayList; import java.util.Arrays; @@ -42,6 +42,7 @@ public class ReducedStateItemStore implements ItemStore fields = new ArrayList<>(); private final Class typeClass; private final KeyState keyState; + private KubernetesSerialization serialization; public static class KeyState { @@ -101,7 +102,8 @@ public KeyState(Function keyFunction, Function typeClass, String... valueFields) { + public ReducedStateItemStore(KeyState keyState, Class typeClass, KubernetesSerialization serialization, + String... valueFields) { this.keyState = keyState; fields.add(new String[] { METADATA, "resourceVersion" }); if (valueFields != null) { @@ -110,13 +112,14 @@ public ReducedStateItemStore(KeyState keyState, Class typeClass, String... va } } this.typeClass = typeClass; + this.serialization = serialization; } Object[] store(V value) { if (value == null) { return null; } - Map raw = Serialization.jsonMapper().convertValue(value, Map.class); + Map raw = serialization.convertValue(value, Map.class); return fields.stream().map(f -> GenericKubernetesResource.get(raw, (Object[]) f)).toArray(); } @@ -129,7 +132,7 @@ V restore(String key, Object[] values) { String[] keyParts = this.keyState.keyFieldFunction.apply(key); applyFields(keyParts, raw, this.keyState.keyFields); - return Serialization.jsonMapper().convertValue(raw, typeClass); + return serialization.convertValue(raw, typeClass); } private static void applyFields(Object[] values, Map raw, List fields) { diff --git a/kubernetes-client-api/src/main/java/io/fabric8/kubernetes/client/utils/BackwardsCompatibilityInterceptor.java b/kubernetes-client-api/src/main/java/io/fabric8/kubernetes/client/utils/BackwardsCompatibilityInterceptor.java index e099dbc8c29..18767823ee2 100644 --- a/kubernetes-client-api/src/main/java/io/fabric8/kubernetes/client/utils/BackwardsCompatibilityInterceptor.java +++ b/kubernetes-client-api/src/main/java/io/fabric8/kubernetes/client/utils/BackwardsCompatibilityInterceptor.java @@ -15,7 +15,8 @@ */ package io.fabric8.kubernetes.client.utils; -import io.fabric8.kubernetes.api.model.HasMetadata; +import com.fasterxml.jackson.databind.JsonNode; +import com.fasterxml.jackson.databind.node.ObjectNode; import io.fabric8.kubernetes.client.http.BasicBuilder; import io.fabric8.kubernetes.client.http.HttpRequest; import io.fabric8.kubernetes.client.http.HttpRequest.Builder; @@ -165,19 +166,18 @@ public CompletableFuture afterFailure(Builder builder, HttpResponse HttpRequest request = response.request(); if (request.bodyString() != null && !request.method().equalsIgnoreCase(PATCH)) { - Object object = Serialization.unmarshal(request.bodyString()); - if (object instanceof HasMetadata) { - HasMetadata h = (HasMetadata) object; - h.setApiVersion(target.group + "/" + target.version); + JsonNode object = Serialization.unmarshal(request.bodyString(), JsonNode.class); + if (object.get("apiVersion") != null) { + ((ObjectNode) object).put("apiVersion", target.group + "/" + target.version); switch (request.method()) { case "POST": - builder.post(JSON, Serialization.asJson(h)); + builder.post(JSON, Serialization.asJson(object)); break; case "PUT": - builder.put(JSON, Serialization.asJson(h)); + builder.put(JSON, Serialization.asJson(object)); break; case "DELETE": - builder.delete(JSON, Serialization.asJson(h)); + builder.delete(JSON, Serialization.asJson(object)); break; default: return CompletableFuture.completedFuture(false); diff --git a/kubernetes-client-api/src/main/java/io/fabric8/kubernetes/client/utils/KubernetesResourceUtil.java b/kubernetes-client-api/src/main/java/io/fabric8/kubernetes/client/utils/KubernetesResourceUtil.java index 554af3c3d6a..d7e0691c3f7 100644 --- a/kubernetes-client-api/src/main/java/io/fabric8/kubernetes/client/utils/KubernetesResourceUtil.java +++ b/kubernetes-client-api/src/main/java/io/fabric8/kubernetes/client/utils/KubernetesResourceUtil.java @@ -383,7 +383,7 @@ public static List convertMapToEnvVarList(Map envVarMap) * Check whether a Kubernetes resource is Ready or not. Applicable only to * Deployment, ReplicaSet, Pod, ReplicationController, Endpoints, Node and * StatefulSet - * + * * @param item item which needs to be checked * @return boolean value indicating it's status */ @@ -393,7 +393,7 @@ public static boolean isResourceReady(HasMetadata item) { /** * Calculates age of a kubernetes resource - * + * * @param kubernetesResource * @return a positive duration indicating age of the kubernetes resource */ @@ -435,7 +435,7 @@ private static Class loadRelated(Class type, String suffix, Class defau public static Secret createDockerRegistrySecret(String dockerServer, String username, String password) throws JsonProcessingException { Map dockerConfigMap = createDockerRegistryConfigMap(dockerServer, username, password); - String dockerConfigAsStr = Serialization.jsonMapper().writeValueAsString(dockerConfigMap); + String dockerConfigAsStr = Serialization.asJson(dockerConfigMap); return createDockerSecret(DEFAULT_CONTAINER_IMAGE_REGISTRY_SECRET_NAME, dockerConfigAsStr); } @@ -452,7 +452,7 @@ public static Secret createDockerRegistrySecret(String dockerServer, String user public static Secret createDockerRegistrySecret(String dockerServer, String username, String password, String secretName) throws JsonProcessingException { Map dockerConfigMap = createDockerRegistryConfigMap(dockerServer, username, password); - String dockerConfigAsStr = Serialization.jsonMapper().writeValueAsString(dockerConfigMap); + String dockerConfigAsStr = Serialization.asJson(dockerConfigMap); return createDockerSecret(secretName, dockerConfigAsStr); } diff --git a/kubernetes-client-api/src/main/java/io/fabric8/kubernetes/client/utils/KubernetesSerialization.java b/kubernetes-client-api/src/main/java/io/fabric8/kubernetes/client/utils/KubernetesSerialization.java new file mode 100644 index 00000000000..84bb472daff --- /dev/null +++ b/kubernetes-client-api/src/main/java/io/fabric8/kubernetes/client/utils/KubernetesSerialization.java @@ -0,0 +1,368 @@ +/** + * 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.utils; + +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.core.type.TypeReference; +import com.fasterxml.jackson.databind.DeserializationConfig; +import com.fasterxml.jackson.databind.DeserializationFeature; +import com.fasterxml.jackson.databind.JsonDeserializer; +import com.fasterxml.jackson.databind.JsonSerializer; +import com.fasterxml.jackson.databind.KeyDeserializer; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.databind.SerializationConfig; +import com.fasterxml.jackson.databind.cfg.HandlerInstantiator; +import com.fasterxml.jackson.databind.cfg.MapperConfig; +import com.fasterxml.jackson.databind.introspect.Annotated; +import com.fasterxml.jackson.databind.jsontype.TypeIdResolver; +import com.fasterxml.jackson.databind.jsontype.TypeResolverBuilder; +import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule; +import io.fabric8.kubernetes.api.model.KubernetesResource; +import io.fabric8.kubernetes.api.model.KubernetesResourceList; +import io.fabric8.kubernetes.api.model.runtime.RawExtension; +import io.fabric8.kubernetes.client.KubernetesClientException; +import io.fabric8.kubernetes.internal.KubernetesDeserializer; +import io.fabric8.kubernetes.model.jackson.UnmatchedFieldTypeModule; +import org.snakeyaml.engine.v2.api.Dump; +import org.snakeyaml.engine.v2.api.DumpSettings; +import org.snakeyaml.engine.v2.api.Load; +import org.snakeyaml.engine.v2.api.LoadSettings; +import org.snakeyaml.engine.v2.common.FlowStyle; +import org.snakeyaml.engine.v2.common.ScalarStyle; +import org.snakeyaml.engine.v2.nodes.NodeTuple; +import org.snakeyaml.engine.v2.nodes.ScalarNode; +import org.snakeyaml.engine.v2.nodes.Tag; +import org.snakeyaml.engine.v2.representer.StandardRepresenter; + +import java.io.BufferedInputStream; +import java.io.ByteArrayInputStream; +import java.io.IOException; +import java.io.InputStream; +import java.lang.reflect.Type; +import java.nio.charset.StandardCharsets; +import java.util.ArrayList; +import java.util.List; +import java.util.Map; + +public class KubernetesSerialization { + + private final ObjectMapper mapper; + private final UnmatchedFieldTypeModule unmatchedFieldTypeModule = new UnmatchedFieldTypeModule(); + private final KubernetesDeserializer kubernetesDeserializer = new KubernetesDeserializer(); + + public KubernetesSerialization(ObjectMapper mapper) { + this.mapper = mapper; + mapper.registerModules(new JavaTimeModule(), unmatchedFieldTypeModule); + mapper.disable(DeserializationFeature.FAIL_ON_INVALID_SUBTYPE); + HandlerInstantiator instanciator = mapper.getDeserializationConfig().getHandlerInstantiator(); + mapper.setConfig(mapper.getDeserializationConfig().with(new HandlerInstantiator() { + + @Override + public JsonDeserializer deserializerInstance(DeserializationConfig config, Annotated annotated, Class deserClass) { + if (deserClass == KubernetesDeserializer.class) { + return kubernetesDeserializer; + } + if (instanciator == null) { + return null; + } + return instanciator.deserializerInstance(config, annotated, deserClass); + } + + @Override + public KeyDeserializer keyDeserializerInstance(DeserializationConfig config, Annotated annotated, + Class keyDeserClass) { + if (instanciator == null) { + return null; + } + return instanciator.keyDeserializerInstance(config, annotated, keyDeserClass); + } + + @Override + public JsonSerializer serializerInstance(SerializationConfig config, Annotated annotated, Class serClass) { + if (instanciator == null) { + return null; + } + return instanciator.serializerInstance(config, annotated, serClass); + } + + @Override + public TypeResolverBuilder typeResolverBuilderInstance(MapperConfig config, Annotated annotated, + Class builderClass) { + if (instanciator == null) { + return null; + } + return instanciator.typeResolverBuilderInstance(config, annotated, builderClass); + } + + @Override + public TypeIdResolver typeIdResolverInstance(MapperConfig config, Annotated annotated, Class resolverClass) { + if (instanciator == null) { + return null; + } + return instanciator.typeIdResolverInstance(config, annotated, resolverClass); + } + + })); + } + + /** + * Returns a JSON representation of the given object. + * + *

+ * If the provided object contains a JsonAnyGetter annotated method with a Map that contains an entry that + * overrides a field of the provided object, the Map entry will take precedence upon serialization. Properties won't + * be duplicated. + * + * @param object the object to serialize. + * @param the type of the object being serialized. + * @return a String containing a JSON representation of the provided object. + */ + public String asJson(T object) { + try { + return mapper.writeValueAsString(object); + } catch (JsonProcessingException e) { + throw KubernetesClientException.launderThrowable(e); + } + } + + /** + * Returns a YAML representation of the given object. + * + *

+ * If the provided object contains a JsonAnyGetter annotated method with a Map that contains an entry that + * overrides a field of the provided object, the Map entry will take precedence upon serialization. Properties won't + * be duplicated. + * + * @param object the object to serialize. + * @param the type of the object being serialized. + * @return a String containing a JSON representation of the provided object. + */ + public String asYaml(T object) { + DumpSettings settings = DumpSettings.builder() + .setExplicitStart(true).setDefaultFlowStyle(FlowStyle.BLOCK).build(); + final Dump yaml = new Dump(settings, new StandardRepresenter(settings) { + private boolean quote = true; + + @Override + protected NodeTuple representMappingEntry(java.util.Map.Entry entry) { + Object key = entry.getKey(); + if (key instanceof String) { + // to match the previous format, don't quote keys + quote = false; + String str = (String) key; + // the abbreviations y/n are not part of the snakeyaml core schema + if (str.length() == 1) { + char start = str.charAt(0); + quote = (start == 'y' || start == 'Y' || start == 'n' || start == 'N'); + } + } + org.snakeyaml.engine.v2.nodes.Node nodeKey = representData(key); + quote = true; + return new NodeTuple(nodeKey, representData(entry.getValue())); + } + + @Override + protected org.snakeyaml.engine.v2.nodes.Node representScalar(Tag tag, String value, ScalarStyle style) { + if (style == ScalarStyle.PLAIN) { + style = quote && tag == Tag.STR ? ScalarStyle.DOUBLE_QUOTED : this.defaultScalarStyle; + } + return new ScalarNode(tag, value, style); + } + }); + return yaml.dumpToString(mapper.convertValue(object, Object.class)); + } + + /** + * Unmarshals a stream. + *

+ * The type is assumed to be {@link KubernetesResource} + * + * @param is The {@link InputStream}. + * @param The target type. + * + * @return returns de-serialized object + */ + public T unmarshal(InputStream is) { + return unmarshal(is, new TypeReference() { + @Override + public Type getType() { + return KubernetesResource.class; + } + }); + } + + public T unmarshal(InputStream is, TypeReference type) { + try (BufferedInputStream bis = new BufferedInputStream(is)) { + bis.mark(-1); + int intch; + do { + intch = bis.read(); + } while (intch > -1 && Character.isWhitespace(intch)); + bis.reset(); + + final T result; + if (intch != '{' && intch != '[') { + result = parseYaml(bis, type); + } else { + result = mapper.readerFor(type).readValue(bis); + } + return result; + } catch (IOException e) { + throw KubernetesClientException.launderThrowable(e); + } + } + + /** + * If multiple docs exist, only non-null resources will be kept. Results spanning multiple docs + * will be returned as a List of KubernetesResource + */ + private T parseYaml(BufferedInputStream bis, TypeReference type) { + T result = null; + List listResult = null; + final Load yaml = new Load(LoadSettings.builder().build()); + final Iterable objs = yaml.loadAllFromInputStream(bis); + for (Object obj : objs) { + Object value = null; + if (obj instanceof Map) { + value = mapper.convertValue(obj, type); + } else if (obj != null) { + value = mapper.convertValue(new RawExtension(obj), type); + } + if (value != null) { + if (result == null) { + result = (T) value; + } else { + if (listResult == null) { + listResult = new ArrayList<>(); + accumulateResult(result, listResult); + } + accumulateResult(value, listResult); + } + } + } + if (listResult != null) { + return (T) listResult; + } + return result; + } + + private static void accumulateResult(T result, List listResult) { + if (result instanceof KubernetesResourceList) { + listResult.addAll(((KubernetesResourceList) result).getItems()); + } else { + listResult.add((KubernetesResource) result); + } + } + + /** + * Unmarshals a {@link String} + *

+ * The type is assumed to be {@link KubernetesResource} + * + * @param str The {@link String}. + * @param template argument denoting type + * @return returns de-serialized object + */ + public T unmarshal(String str) { + return (T) unmarshal(str, KubernetesResource.class); + } + + /** + * Unmarshals a {@link String} + * + * @param str The {@link String}. + * @param type The target type. + * @param template argument denoting type + * @return returns de-serialized object + */ + public T unmarshal(String str, final Class type) { + try (InputStream is = new ByteArrayInputStream(str.getBytes(StandardCharsets.UTF_8))) { + return unmarshal(is, type); + } catch (IOException e) { + throw KubernetesClientException.launderThrowable(e); + } + } + + /** + * Unmarshals an {@link InputStream}. + * + * @param is The {@link InputStream}. + * @param type The type. + * @param Template argument denoting type + * @return returns de-serialized object + */ + public T unmarshal(InputStream is, final Class type) { + return unmarshal(is, new TypeReference() { + @Override + public Type getType() { + return type; + } + }); + } + + /** + * Create a copy of the resource via serialization. + * + * @return a deep clone of the resource + * @throws IllegalArgumentException if the cloning cannot be performed + */ + public T clone(T resource) { + // if full serialization seems too expensive, there is also + //return (T) JSON_MAPPER.convertValue(resource, resource.getClass()); + try { + return (T) mapper.readValue( + mapper.writeValueAsString(resource), resource.getClass()); + } catch (JsonProcessingException e) { + throw new IllegalStateException(e); + } + } + + public T convertValue(Object value, Class type) { + return mapper.convertValue(value, type); + } + + public Type constructParametricType(Class parameterizedClass, Class parameterType) { + return mapper.getTypeFactory().constructParametricType(parameterizedClass, parameterType); + } + + public Class getRegisteredKind(String apiVersion, String kind) { + return this.kubernetesDeserializer.getRegisteredKind(apiVersion, kind); + } + + public UnmatchedFieldTypeModule getUnmatchedFieldTypeModule() { + return unmatchedFieldTypeModule; + } + + ObjectMapper getMapper() { + return mapper; + } + + /** + * Registers a Custom Resource Definition Kind + */ + public void registerCustomKind(String kind, Class clazz) { + registerCustomKind(null, kind, clazz); + } + + /** + * Registers a Custom Resource Definition Kind + */ + public void registerCustomKind(String apiVersion, String kind, Class clazz) { + kubernetesDeserializer.registerCustomKind(apiVersion, kind, clazz); + } + +} diff --git a/kubernetes-client-api/src/main/java/io/fabric8/kubernetes/client/utils/OpenIDConnectionUtils.java b/kubernetes-client-api/src/main/java/io/fabric8/kubernetes/client/utils/OpenIDConnectionUtils.java index cf9ce5452e7..1695a9321d4 100644 --- a/kubernetes-client-api/src/main/java/io/fabric8/kubernetes/client/utils/OpenIDConnectionUtils.java +++ b/kubernetes-client-api/src/main/java/io/fabric8/kubernetes/client/utils/OpenIDConnectionUtils.java @@ -263,7 +263,7 @@ public static boolean persistKubeConfigWithUpdatedAuthInfo(Config currentConfig, } private static Map convertJsonStringToMap(String jsonString) throws JsonProcessingException { - return Serialization.jsonMapper().readValue(jsonString, Map.class); + return Serialization.unmarshal(jsonString, Map.class); } private static HttpClient getDefaultHttpClientWithPemCert(String idpCert, HttpClient.Builder clientBuilder) { diff --git a/kubernetes-client-api/src/main/java/io/fabric8/kubernetes/client/utils/Serialization.java b/kubernetes-client-api/src/main/java/io/fabric8/kubernetes/client/utils/Serialization.java index 7cf20e013f9..a50877ac5b8 100644 --- a/kubernetes-client-api/src/main/java/io/fabric8/kubernetes/client/utils/Serialization.java +++ b/kubernetes-client-api/src/main/java/io/fabric8/kubernetes/client/utils/Serialization.java @@ -63,6 +63,8 @@ private Serialization() { private static volatile ObjectMapper YAML_MAPPER; + private static KubernetesSerialization kubernetesSerialization = new KubernetesSerialization(new ObjectMapper()); + /** * {@link ObjectMapper} singleton instance used internally by the Kubernetes client. * @@ -456,4 +458,14 @@ public static T clone(T resource) { throw new IllegalStateException(e); } } + + /** + * + * @deprecated + */ + @Deprecated + public static KubernetesSerialization getKubernetesSerialization() { + return kubernetesSerialization; + } + } diff --git a/kubernetes-client-api/src/test/java/io/fabric8/kubernetes/client/informers/cache/ReducedStateItemStoreTest.java b/kubernetes-client-api/src/test/java/io/fabric8/kubernetes/client/informers/cache/ReducedStateItemStoreTest.java index 2e73bca1977..97607a81906 100644 --- a/kubernetes-client-api/src/test/java/io/fabric8/kubernetes/client/informers/cache/ReducedStateItemStoreTest.java +++ b/kubernetes-client-api/src/test/java/io/fabric8/kubernetes/client/informers/cache/ReducedStateItemStoreTest.java @@ -17,6 +17,7 @@ import io.fabric8.kubernetes.api.model.Pod; import io.fabric8.kubernetes.api.model.PodBuilder; +import io.fabric8.kubernetes.client.utils.Serialization; import org.junit.jupiter.api.Test; import static org.junit.Assert.assertNotNull; @@ -27,8 +28,8 @@ class ReducedStateItemStoreTest { @Test void testStoreRestore() { - ReducedStateItemStore store = new ReducedStateItemStore<>(ReducedStateItemStore.UID_KEY_STATE, Pod.class, - "metadata.labels", "foo.bar"); + ReducedStateItemStore store = new ReducedStateItemStore<>(ReducedStateItemStore.UID_KEY_STATE, + Pod.class, Serialization.getKubernetesSerialization(), "metadata.labels", "foo.bar"); Pod pod = new PodBuilder().withNewSpec().endSpec().withNewMetadata().withUid("x").withName("y").addToLabels("one", "1") .addToLabels("two", "2").withResourceVersion("2").endMetadata().withNewStatus().endStatus().build(); diff --git a/kubernetes-client/src/main/java/io/fabric8/kubernetes/client/dsl/internal/AbstractWatchManager.java b/kubernetes-client/src/main/java/io/fabric8/kubernetes/client/dsl/internal/AbstractWatchManager.java index d25d66e6cda..8025747e8b2 100644 --- a/kubernetes-client/src/main/java/io/fabric8/kubernetes/client/dsl/internal/AbstractWatchManager.java +++ b/kubernetes-client/src/main/java/io/fabric8/kubernetes/client/dsl/internal/AbstractWatchManager.java @@ -30,7 +30,7 @@ import io.fabric8.kubernetes.client.WatcherException; import io.fabric8.kubernetes.client.http.HttpClient; import io.fabric8.kubernetes.client.utils.ExponentialBackoffIntervalCalculator; -import io.fabric8.kubernetes.client.utils.Serialization; +import io.fabric8.kubernetes.client.utils.KubernetesSerialization; import io.fabric8.kubernetes.client.utils.Utils; import io.fabric8.kubernetes.client.utils.internal.SerialExecutor; import org.slf4j.Logger; @@ -248,7 +248,7 @@ void eventReceived(Watcher.Action action, HasMetadata resource) { // the WatchEvent deserialization is not specifically typed // modify the type here if needed if (resource != null && !baseOperation.getType().isAssignableFrom(resource.getClass())) { - resource = Serialization.jsonMapper().convertValue(resource, baseOperation.getType()); + resource = this.baseOperation.getKubernetesSerialization().convertValue(resource, baseOperation.getType()); } @SuppressWarnings("unchecked") final T t = (T) resource; @@ -297,17 +297,20 @@ public void close() { private WatchEvent contextAwareWatchEventDeserializer(String messageSource) throws JsonProcessingException { + KubernetesSerialization kubernetesSerialization = this.baseOperation.getKubernetesSerialization(); try { - return Serialization.unmarshal(messageSource, WatchEvent.class); + return kubernetesSerialization.unmarshal(messageSource, WatchEvent.class); } catch (Exception ex1) { - JsonNode json = Serialization.jsonMapper().readTree(messageSource); + // TODO: this is not necessarily correct - it will force the object to be the expected type + // even though it is not (for example Status could be converted to the typed result) + JsonNode json = kubernetesSerialization.unmarshal(messageSource, JsonNode.class); JsonNode objectJson = null; if (json instanceof ObjectNode && json.has("object")) { objectJson = ((ObjectNode) json).remove("object"); } - WatchEvent watchEvent = Serialization.jsonMapper().treeToValue(json, WatchEvent.class); - KubernetesResource object = Serialization.jsonMapper().treeToValue(objectJson, baseOperation.getType()); + WatchEvent watchEvent = kubernetesSerialization.convertValue(json, WatchEvent.class); + KubernetesResource object = kubernetesSerialization.convertValue(objectJson, baseOperation.getType()); watchEvent.setObject(object); return watchEvent; diff --git a/kubernetes-client/src/main/java/io/fabric8/kubernetes/client/dsl/internal/BaseOperation.java b/kubernetes-client/src/main/java/io/fabric8/kubernetes/client/dsl/internal/BaseOperation.java index 3f6c9cfc692..2de72952cf8 100755 --- a/kubernetes-client/src/main/java/io/fabric8/kubernetes/client/dsl/internal/BaseOperation.java +++ b/kubernetes-client/src/main/java/io/fabric8/kubernetes/client/dsl/internal/BaseOperation.java @@ -57,7 +57,6 @@ import io.fabric8.kubernetes.client.readiness.Readiness; import io.fabric8.kubernetes.client.utils.ApiVersionUtil; import io.fabric8.kubernetes.client.utils.KubernetesResourceUtil; -import io.fabric8.kubernetes.client.utils.Serialization; import io.fabric8.kubernetes.client.utils.URLUtils; import io.fabric8.kubernetes.client.utils.URLUtils.URLBuilder; import io.fabric8.kubernetes.client.utils.Utils; @@ -164,7 +163,7 @@ public T require() { */ public T getItemOrRequireFromServer() { if (item != null) { - return Serialization.clone(item); + return getKubernetesSerialization().clone(item); } return requireFromServer(); } @@ -258,7 +257,7 @@ public BaseOperation inAnyNamespace() { @Override public R load(InputStream is) { - T unmarshal = unmarshal(is, type); + T unmarshal = this.getKubernetesSerialization().unmarshal(is, type); // if you do something like client.foo().v2().load(v1 resource) // it will parse as v2, but have a v1 apiVersion, so we need to // force the apiVersion @@ -305,7 +304,7 @@ public final T createOrReplace() { resource::create, resource::replace, m -> resource.waitUntilCondition(Objects::nonNull, 1, TimeUnit.SECONDS), - m -> resource.fromServer().get()); + m -> resource.fromServer().get(), this.getKubernetesSerialization()); return createOrReplaceHelper.createOrReplace(item); } @@ -403,7 +402,7 @@ public CompletableFuture submitList(ListOptions listOptions) { URL fetchListUrl = fetchListUrl(getNamespacedUrl(), defaultListOptions(listOptions, null)); HttpRequest.Builder requestBuilder = httpClient.newHttpRequestBuilder().url(fetchListUrl); Type refinedType = listType.equals(DefaultKubernetesResourceList.class) - ? Serialization.jsonMapper().getTypeFactory().constructParametricType(listType, type) + ? this.getKubernetesSerialization().constructParametricType(listType, type) : listType; TypeReference listTypeReference = new TypeReference() { @Override diff --git a/kubernetes-client/src/main/java/io/fabric8/kubernetes/client/dsl/internal/ExecWebSocketListener.java b/kubernetes-client/src/main/java/io/fabric8/kubernetes/client/dsl/internal/ExecWebSocketListener.java index 5a0a5dd2ec9..f94d3af2aed 100644 --- a/kubernetes-client/src/main/java/io/fabric8/kubernetes/client/dsl/internal/ExecWebSocketListener.java +++ b/kubernetes-client/src/main/java/io/fabric8/kubernetes/client/dsl/internal/ExecWebSocketListener.java @@ -16,7 +16,6 @@ package io.fabric8.kubernetes.client.dsl.internal; -import com.fasterxml.jackson.databind.ObjectMapper; import io.fabric8.kubernetes.api.model.Status; import io.fabric8.kubernetes.api.model.StatusCause; import io.fabric8.kubernetes.client.KubernetesClientException; @@ -28,7 +27,7 @@ import io.fabric8.kubernetes.client.http.WebSocket; import io.fabric8.kubernetes.client.http.WebSocketHandshakeException; import io.fabric8.kubernetes.client.utils.InputStreamPumper; -import io.fabric8.kubernetes.client.utils.Serialization; +import io.fabric8.kubernetes.client.utils.KubernetesSerialization; import io.fabric8.kubernetes.client.utils.internal.SerialExecutor; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -144,17 +143,14 @@ private void handle(ByteBuffer byteString, WebSocket webSocket) throws IOExcepti private final SerialExecutor serialExecutor; private final AtomicBoolean closed = new AtomicBoolean(false); private final CompletableFuture exitCode = new CompletableFuture<>(); - private ObjectMapper objectMapper = new ObjectMapper(); + private KubernetesSerialization serialization; public static String toString(ByteBuffer buffer) { return StandardCharsets.UTF_8.decode(buffer).toString(); } - public ExecWebSocketListener(PodOperationContext context) { - this(context, Runnable::run); - } - - public ExecWebSocketListener(PodOperationContext context, Executor executor) { + public ExecWebSocketListener(PodOperationContext context, Executor executor, KubernetesSerialization serialization) { + this.serialization = serialization; this.listener = context.getExecListener(); Integer bufferSize = context.getBufferSize(); @@ -269,7 +265,7 @@ public void onError(WebSocket webSocket, Throwable t) { if (t instanceof WebSocketHandshakeException) { response = ((WebSocketHandshakeException) t).getResponse(); if (response != null) { - Status status = OperationSupport.createStatus(response); + Status status = OperationSupport.createStatus(response, serialization); status.setMessage(t.getMessage()); t = new KubernetesClientException(status).initCause(t); } @@ -351,7 +347,7 @@ private void handleExitStatus(ByteBuffer bytes) { int code = -1; try { String stringValue = toString(bytes); - status = Serialization.unmarshal(stringValue, Status.class); + status = serialization.unmarshal(stringValue, Status.class); if (status != null) { code = parseExitCode(status); } @@ -419,7 +415,7 @@ public void resize(int cols, int rows) { Map map = new HashMap<>(4); map.put(HEIGHT, rows); map.put(WIDTH, cols); - byte[] bytes = objectMapper.writeValueAsBytes(map); + byte[] bytes = serialization.asJson(map).getBytes(StandardCharsets.UTF_8); send(bytes, 0, bytes.length, (byte) 4); } catch (Exception e) { throw KubernetesClientException.launderThrowable(e); diff --git a/kubernetes-client/src/main/java/io/fabric8/kubernetes/client/dsl/internal/HasMetadataOperation.java b/kubernetes-client/src/main/java/io/fabric8/kubernetes/client/dsl/internal/HasMetadataOperation.java index 8cff5378e81..7dcd1103660 100644 --- a/kubernetes-client/src/main/java/io/fabric8/kubernetes/client/dsl/internal/HasMetadataOperation.java +++ b/kubernetes-client/src/main/java/io/fabric8/kubernetes/client/dsl/internal/HasMetadataOperation.java @@ -28,7 +28,6 @@ import io.fabric8.kubernetes.client.dsl.base.PatchContext; import io.fabric8.kubernetes.client.dsl.base.PatchType; import io.fabric8.kubernetes.client.utils.KubernetesResourceUtil; -import io.fabric8.kubernetes.client.utils.Serialization; import io.fabric8.kubernetes.client.utils.Utils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -69,7 +68,7 @@ public T edit(UnaryOperator function) { } private T clone(T item) { - return Serialization.clone(item); + return this.getKubernetesSerialization().clone(item); } @Override diff --git a/kubernetes-client/src/main/java/io/fabric8/kubernetes/client/dsl/internal/NamespaceVisitFromServerGetWatchDeleteRecreateWaitApplicableListImpl.java b/kubernetes-client/src/main/java/io/fabric8/kubernetes/client/dsl/internal/NamespaceVisitFromServerGetWatchDeleteRecreateWaitApplicableListImpl.java index 6388c25ba68..e4e4a9d1475 100644 --- a/kubernetes-client/src/main/java/io/fabric8/kubernetes/client/dsl/internal/NamespaceVisitFromServerGetWatchDeleteRecreateWaitApplicableListImpl.java +++ b/kubernetes-client/src/main/java/io/fabric8/kubernetes/client/dsl/internal/NamespaceVisitFromServerGetWatchDeleteRecreateWaitApplicableListImpl.java @@ -15,7 +15,6 @@ */ package io.fabric8.kubernetes.client.dsl.internal; -import com.fasterxml.jackson.databind.ObjectMapper; import io.fabric8.kubernetes.api.builder.VisitableBuilder; import io.fabric8.kubernetes.api.builder.Visitor; import io.fabric8.kubernetes.api.model.DeletionPropagation; @@ -32,21 +31,17 @@ import io.fabric8.kubernetes.client.dsl.ListVisitFromServerWritable; import io.fabric8.kubernetes.client.dsl.NamespaceListVisitFromServerGetDeleteRecreateWaitApplicable; import io.fabric8.kubernetes.client.dsl.NamespaceableResource; -import io.fabric8.kubernetes.client.dsl.ParameterNamespaceListVisitFromServerGetDeleteRecreateWaitApplicable; import io.fabric8.kubernetes.client.dsl.Resource; import io.fabric8.kubernetes.client.dsl.Waitable; import io.fabric8.kubernetes.client.readiness.Readiness; -import io.fabric8.kubernetes.client.utils.Serialization; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import java.io.InputStream; import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; import java.util.Collections; import java.util.List; -import java.util.Map; import java.util.Objects; import java.util.concurrent.CompletableFuture; import java.util.concurrent.ExecutionException; @@ -58,13 +53,12 @@ import java.util.stream.Stream; public class NamespaceVisitFromServerGetWatchDeleteRecreateWaitApplicableListImpl - implements ParameterNamespaceListVisitFromServerGetDeleteRecreateWaitApplicable, + implements NamespaceListVisitFromServerGetDeleteRecreateWaitApplicable, Waitable, HasMetadata> { private static final Logger LOGGER = LoggerFactory .getLogger(NamespaceVisitFromServerGetWatchDeleteRecreateWaitApplicableListImpl.class); protected static final String EXPRESSION = "expression"; - protected static final ObjectMapper OBJECT_MAPPER = new ObjectMapper(); private OperationContext context; @@ -173,13 +167,6 @@ private static void logAsNotReady(Throwable t, HasMetadata meta) { LOGGER.debug("The error stack trace:", t); } - @Override - public NamespaceListVisitFromServerGetDeleteRecreateWaitApplicable withParameters( - Map parameters) { - Object item = Serialization.unmarshal((InputStream) context.getItem(), parameters); - return newInstance(context.withItem(item)); - } - @Override public ListVisitFromServerWritable dryRun(boolean isDryRun) { return newInstance(this.context.withDryRun(isDryRun)); diff --git a/kubernetes-client/src/main/java/io/fabric8/kubernetes/client/dsl/internal/OperationSupport.java b/kubernetes-client/src/main/java/io/fabric8/kubernetes/client/dsl/internal/OperationSupport.java index 251940af8dc..7a1181ee6ee 100644 --- a/kubernetes-client/src/main/java/io/fabric8/kubernetes/client/dsl/internal/OperationSupport.java +++ b/kubernetes-client/src/main/java/io/fabric8/kubernetes/client/dsl/internal/OperationSupport.java @@ -16,7 +16,6 @@ package io.fabric8.kubernetes.client.dsl.internal; import com.fasterxml.jackson.core.type.TypeReference; -import com.fasterxml.jackson.databind.ObjectMapper; import io.fabric8.kubernetes.api.model.DeleteOptions; import io.fabric8.kubernetes.api.model.DeletionPropagation; import io.fabric8.kubernetes.api.model.HasMetadata; @@ -37,8 +36,9 @@ import io.fabric8.kubernetes.client.http.HttpClient; import io.fabric8.kubernetes.client.http.HttpRequest; import io.fabric8.kubernetes.client.http.HttpResponse; +import io.fabric8.kubernetes.client.impl.BaseClient; import io.fabric8.kubernetes.client.utils.KubernetesResourceUtil; -import io.fabric8.kubernetes.client.utils.Serialization; +import io.fabric8.kubernetes.client.utils.KubernetesSerialization; import io.fabric8.kubernetes.client.utils.URLUtils; import io.fabric8.kubernetes.client.utils.Utils; import org.slf4j.Logger; @@ -46,7 +46,6 @@ import java.io.ByteArrayInputStream; import java.io.IOException; -import java.io.InputStream; import java.io.InterruptedIOException; import java.lang.reflect.Type; import java.net.HttpURLConnection; @@ -55,7 +54,6 @@ import java.util.ArrayList; import java.util.Collections; import java.util.List; -import java.util.Map; import java.util.Objects; import java.util.concurrent.CompletableFuture; import java.util.concurrent.ExecutionException; @@ -71,7 +69,6 @@ public class OperationSupport { public static final String STRATEGIC_MERGE_JSON_PATCH = "application/strategic-merge-patch+json"; public static final String JSON_MERGE_PATCH = "application/merge-patch+json"; - protected static final ObjectMapper JSON_MAPPER = Serialization.jsonMapper(); private static final Logger LOG = LoggerFactory.getLogger(OperationSupport.class); private static final String CLIENT_STATUS_FLAG = "CLIENT_STATUS_FLAG"; @@ -259,7 +256,7 @@ protected T correctNamespace(T item) { String itemNs = KubernetesResourceUtil.getNamespace((HasMetadata) item); if (Utils.isNotNullOrEmpty(namespace) && Utils.isNotNullOrEmpty(itemNs) && !namespace.equals(itemNs)) { - item = Serialization.clone(item); + item = getKubernetesSerialization().clone(item); KubernetesResourceUtil.setNamespace((HasMetadata) item, namespace); } return item; @@ -324,7 +321,7 @@ protected KubernetesResource handleDelete(URL requestUrl, long gracePeriodSecond } HttpRequest.Builder requestBuilder = httpClient.newHttpRequestBuilder() - .delete(JSON, JSON_MAPPER.writeValueAsString(deleteOptions)).url(requestUrl); + .delete(JSON, getKubernetesSerialization().asJson(deleteOptions)).url(requestUrl); return handleResponse(requestBuilder, KubernetesResource.class); } @@ -344,7 +341,7 @@ protected KubernetesResource handleDelete(URL requestUrl, long gracePeriodSecond protected T handleCreate(I resource, Class outputType) throws InterruptedException, IOException { resource = correctNamespace(resource); HttpRequest.Builder requestBuilder = httpClient.newHttpRequestBuilder() - .post(JSON, JSON_MAPPER.writeValueAsString(resource)) + .post(JSON, getKubernetesSerialization().asJson(resource)) .url(getResourceURLForWriteOperation(getResourceUrl(checkNamespace(resource), null))); return handleResponse(requestBuilder, outputType); } @@ -363,7 +360,7 @@ protected T handleCreate(I resource, Class outputType) throws Interrup protected T handleUpdate(T updated, Class type, boolean status) throws IOException { updated = correctNamespace(updated); HttpRequest.Builder requestBuilder = httpClient.newHttpRequestBuilder() - .put(JSON, JSON_MAPPER.writeValueAsString(updated)) + .put(JSON, getKubernetesSerialization().asJson(updated)) .url(getResourceURLForWriteOperation(getResourceUrl(checkNamespace(updated), checkName(updated), status))); return handleResponse(requestBuilder, type); } @@ -413,7 +410,7 @@ protected T handlePatch(PatchContext patchContext, T current, T updated, Cla } } } - patchForUpdate = Serialization.asJson(updated); + patchForUpdate = getKubernetesSerialization().asJson(updated); current = updated; // use the updated to determine the path } return handlePatch(patchContext, current, patchForUpdate, type, status); @@ -454,7 +451,7 @@ protected T handlePatch(PatchContext patchContext, T current, String patchFo protected T handleScale(String resourceUrl, T scale, Class scaleType) throws InterruptedException, IOException { HttpRequest.Builder requestBuilder = httpClient.newHttpRequestBuilder().uri(resourceUrl + "/scale"); if (scale != null) { - requestBuilder.put(JSON, JSON_MAPPER.writeValueAsString(scale)); + requestBuilder.put(JSON, getKubernetesSerialization().asJson(scale)); } return handleResponse(requestBuilder, scaleType); } @@ -471,7 +468,7 @@ protected T handleScale(String resourceUrl, T scale, Class scaleType) thr protected Status handleDeploymentRollback(String resourceUrl, DeploymentRollback deploymentRollback) throws InterruptedException, IOException { HttpRequest.Builder requestBuilder = httpClient.newHttpRequestBuilder().uri(resourceUrl + "/rollback").post(JSON, - JSON_MAPPER.writeValueAsString(deploymentRollback)); + getKubernetesSerialization().asJson(deploymentRollback)); return handleResponse(requestBuilder, Status.class); } @@ -483,10 +480,9 @@ protected Status handleDeploymentRollback(String resourceUrl, DeploymentRollback * @param template argument provided * * @return returns a deserialized object as api server response of provided type. - * @throws InterruptedException Interrupted Exception * @throws IOException IOException */ - protected T handleGet(URL resourceUrl, Class type) throws InterruptedException, IOException { + protected T handleGet(URL resourceUrl, Class type) throws IOException { HttpRequest.Builder requestBuilder = httpClient.newHttpRequestBuilder().url(resourceUrl); return handleResponse(requestBuilder, type); } @@ -494,7 +490,7 @@ protected T handleGet(URL resourceUrl, Class type) throws InterruptedExce protected T handleApproveOrDeny(T csr, Class type) throws IOException, InterruptedException { String uri = URLUtils.join(getResourceUrl(null, csr.getMetadata().getName(), false).toString(), "approval"); HttpRequest.Builder requestBuilder = httpClient.newHttpRequestBuilder() - .put(JSON, JSON_MAPPER.writeValueAsString(csr)).uri(uri); + .put(JSON, getKubernetesSerialization().asJson(csr)).uri(uri); return handleResponse(requestBuilder, type); } @@ -589,7 +585,7 @@ protected CompletableFuture handleResponse(HttpClient client, HttpRequest try { assertResponseCode(request, response); if (type != null && type.getType() != null) { - return Serialization.unmarshal(new ByteArrayInputStream(response.body()), type); + return getKubernetesSerialization().unmarshal(new ByteArrayInputStream(response.body()), type); } else { return null; } @@ -624,9 +620,10 @@ protected void assertResponseCode(HttpRequest request, HttpResponse response) String customMessage = config.getErrorMessages().get(statusCode); if (customMessage != null) { - throw requestFailure(request, createStatus(statusCode, combineMessages(customMessage, createStatus(response)))); + throw requestFailure(request, + createStatus(statusCode, combineMessages(customMessage, createStatus(response, getKubernetesSerialization())))); } else { - throw requestFailure(request, createStatus(response)); + throw requestFailure(request, createStatus(response, getKubernetesSerialization())); } } @@ -640,7 +637,7 @@ private String combineMessages(String customMessage, Status defaultStatus) { return customMessage; } - public static Status createStatus(HttpResponse response) { + public static Status createStatus(HttpResponse response, KubernetesSerialization kubernetesSerialization) { String statusMessage = ""; int statusCode = response != null ? response.code() : 0; if (response == null) { @@ -649,7 +646,7 @@ public static Status createStatus(HttpResponse response) { try { String bodyString = response.bodyString(); if (Utils.isNotNullOrEmpty(bodyString)) { - Status status = JSON_MAPPER.readValue(bodyString, Status.class); + Status status = kubernetesSerialization.unmarshal(bodyString, Status.class); if (status != null) { if (status.getCode() == null) { status = new StatusBuilder(status).withCode(statusCode).build(); @@ -657,7 +654,7 @@ public static Status createStatus(HttpResponse response) { return status; } } - } catch (IOException e) { + } catch (IOException | KubernetesClientException | IllegalArgumentException e) { // ignored } if (response.message() != null) { @@ -717,23 +714,6 @@ public static KubernetesClientException requestException(HttpRequest request, Ex return requestException(request, e, null); } - protected static T unmarshal(InputStream is) { - return Serialization.unmarshal(is); - } - - protected static T unmarshal(InputStream is, final Class type) { - return Serialization.unmarshal(is, type); - } - - protected static T unmarshal(InputStream is, TypeReference type) { - return Serialization.unmarshal(is, type); - } - - protected static Map getObjectValueAsMap(T object) { - return JSON_MAPPER.convertValue(object, new TypeReference>() { - }); - } - public Config getConfig() { return config; } @@ -776,4 +756,8 @@ public R1 restCall(Class result, String... path) { } } + public KubernetesSerialization getKubernetesSerialization() { + return context.getClient().adapt(BaseClient.class).getKubernetesSerialization(); + } + } diff --git a/kubernetes-client/src/main/java/io/fabric8/kubernetes/client/dsl/internal/WatchConnectionManager.java b/kubernetes-client/src/main/java/io/fabric8/kubernetes/client/dsl/internal/WatchConnectionManager.java index 327deaf67e8..35e2e065d4a 100644 --- a/kubernetes-client/src/main/java/io/fabric8/kubernetes/client/dsl/internal/WatchConnectionManager.java +++ b/kubernetes-client/src/main/java/io/fabric8/kubernetes/client/dsl/internal/WatchConnectionManager.java @@ -108,7 +108,7 @@ protected void start(URL url, Map headers, WatchRequestState sta // We do not expect a 200 in response to the websocket connection. If it occurs, we throw // an exception and try the watch via a persistent HTTP Get. // Newer Kubernetes might also return 503 Service Unavailable in case WebSockets are not supported - Status status = OperationSupport.createStatus(response); + Status status = OperationSupport.createStatus(response, this.baseOperation.getKubernetesSerialization()); if (HTTP_OK == code || HTTP_UNAVAILABLE == code) { throw OperationSupport.requestFailure(client.newHttpRequestBuilder().url(url).build(), status, "Received " + code + " on websocket"); diff --git a/kubernetes-client/src/main/java/io/fabric8/kubernetes/client/dsl/internal/apps/v1/RollableScalableResourceOperation.java b/kubernetes-client/src/main/java/io/fabric8/kubernetes/client/dsl/internal/apps/v1/RollableScalableResourceOperation.java index 1305aec67ca..66a31f20515 100644 --- a/kubernetes-client/src/main/java/io/fabric8/kubernetes/client/dsl/internal/apps/v1/RollableScalableResourceOperation.java +++ b/kubernetes-client/src/main/java/io/fabric8/kubernetes/client/dsl/internal/apps/v1/RollableScalableResourceOperation.java @@ -27,7 +27,6 @@ import io.fabric8.kubernetes.client.dsl.internal.HasMetadataOperation; import io.fabric8.kubernetes.client.dsl.internal.OperationContext; import io.fabric8.kubernetes.client.dsl.internal.PodOperationContext; -import io.fabric8.kubernetes.client.utils.Serialization; import java.util.Collections; import java.util.List; @@ -58,7 +57,7 @@ public T edit(UnaryOperator function) { return super.edit(function); } T oldObj = getItemOrRequireFromServer(); - T newObj = function.apply(Serialization.clone(oldObj)); + T newObj = function.apply(getKubernetesSerialization().clone(oldObj)); return rollingUpdater.rollUpdate(oldObj, newObj); } @@ -125,7 +124,7 @@ public T updateImage(Map containerToImageMap) { throw new KubernetesClientException("Resource doesn't exist"); } - T base = Serialization.clone(value); + T base = getKubernetesSerialization().clone(value); List containers = getContainers(value); diff --git a/kubernetes-client/src/main/java/io/fabric8/kubernetes/client/dsl/internal/apps/v1/RollingUpdater.java b/kubernetes-client/src/main/java/io/fabric8/kubernetes/client/dsl/internal/apps/v1/RollingUpdater.java index 20f40bdce0b..705050813d9 100644 --- a/kubernetes-client/src/main/java/io/fabric8/kubernetes/client/dsl/internal/apps/v1/RollingUpdater.java +++ b/kubernetes-client/src/main/java/io/fabric8/kubernetes/client/dsl/internal/apps/v1/RollingUpdater.java @@ -34,7 +34,7 @@ import io.fabric8.kubernetes.client.dsl.internal.PatchUtils; import io.fabric8.kubernetes.client.dsl.internal.PatchUtils.Format; import io.fabric8.kubernetes.client.dsl.internal.core.v1.PodOperationsImpl; -import io.fabric8.kubernetes.client.utils.Serialization; +import io.fabric8.kubernetes.client.utils.KubernetesSerialization; import io.fabric8.kubernetes.client.utils.Utils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -168,20 +168,20 @@ public T rollUpdate(T oldObj, T newObj) { } } - private static T applyPatch(Resource resource, Map map) { - return resource.patch(PatchContext.of(PatchType.STRATEGIC_MERGE), Serialization.asJson(map)); + private static T applyPatch(Resource resource, Map map, KubernetesSerialization serialization) { + return resource.patch(PatchContext.of(PatchType.STRATEGIC_MERGE), serialization.asJson(map)); } - public static T resume(Resource resource) { - return applyPatch(resource, RollingUpdater.requestPayLoadForRolloutResume()); + public static T resume(RollableScalableResourceOperation resource) { + return applyPatch(resource, RollingUpdater.requestPayLoadForRolloutResume(), resource.getKubernetesSerialization()); } - public static T pause(Resource resource) { - return applyPatch(resource, RollingUpdater.requestPayLoadForRolloutPause()); + public static T pause(RollableScalableResourceOperation resource) { + return applyPatch(resource, RollingUpdater.requestPayLoadForRolloutPause(), resource.getKubernetesSerialization()); } - public static T restart(Resource resource) { - return applyPatch(resource, RollingUpdater.requestPayLoadForRolloutRestart()); + public static T restart(RollableScalableResourceOperation resource) { + return applyPatch(resource, RollingUpdater.requestPayLoadForRolloutRestart(), resource.getKubernetesSerialization()); } public static Map requestPayLoadForRolloutPause() { diff --git a/kubernetes-client/src/main/java/io/fabric8/kubernetes/client/dsl/internal/apps/v1/StatefulSetOperationsImpl.java b/kubernetes-client/src/main/java/io/fabric8/kubernetes/client/dsl/internal/apps/v1/StatefulSetOperationsImpl.java index 5d82ebba514..15b568330a6 100644 --- a/kubernetes-client/src/main/java/io/fabric8/kubernetes/client/dsl/internal/apps/v1/StatefulSetOperationsImpl.java +++ b/kubernetes-client/src/main/java/io/fabric8/kubernetes/client/dsl/internal/apps/v1/StatefulSetOperationsImpl.java @@ -38,7 +38,6 @@ import io.fabric8.kubernetes.client.dsl.internal.HasMetadataOperationsImpl; import io.fabric8.kubernetes.client.dsl.internal.OperationContext; import io.fabric8.kubernetes.client.dsl.internal.PodOperationContext; -import io.fabric8.kubernetes.client.utils.Serialization; import io.fabric8.kubernetes.client.utils.internal.PodOperationUtil; import java.io.InputStream; @@ -150,7 +149,8 @@ public StatefulSet undo() { }); ControllerRevision previousControllerRevision = controllerRevisions.get(1); - return patch(PatchContext.of(PatchType.STRATEGIC_MERGE), Serialization.asJson(previousControllerRevision.getData())); + return patch(PatchContext.of(PatchType.STRATEGIC_MERGE), + getKubernetesSerialization().asJson(previousControllerRevision.getData())); } private ControllerRevisionList getControllerRevisionListForStatefulSet(StatefulSet statefulSet) { diff --git a/kubernetes-client/src/main/java/io/fabric8/kubernetes/client/dsl/internal/core/v1/PodOperationsImpl.java b/kubernetes-client/src/main/java/io/fabric8/kubernetes/client/dsl/internal/core/v1/PodOperationsImpl.java index a0866c186bf..9a7d73bb4ee 100644 --- a/kubernetes-client/src/main/java/io/fabric8/kubernetes/client/dsl/internal/core/v1/PodOperationsImpl.java +++ b/kubernetes-client/src/main/java/io/fabric8/kubernetes/client/dsl/internal/core/v1/PodOperationsImpl.java @@ -263,7 +263,7 @@ private boolean handleEvict(HasMetadata eviction) { URL requestUrl = new URL(URLUtils.join(getResourceUrl().toString(), "eviction")); HttpRequest.Builder requestBuilder = httpClient.newHttpRequestBuilder() - .post(JSON, JSON_MAPPER.writeValueAsString(eviction)).url(requestUrl); + .post(JSON, getKubernetesSerialization().asJson(eviction)).url(requestUrl); handleResponse(requestBuilder, null); return true; } catch (KubernetesClientException e) { @@ -376,7 +376,8 @@ private boolean hasEphemeralContainer(List containers, Strin private ExecWebSocketListener setupConnectionToPod(URI uri) { HttpClient clone = httpClient.newBuilder().readTimeout(0, TimeUnit.MILLISECONDS).build(); - ExecWebSocketListener execWebSocketListener = new ExecWebSocketListener(getContext(), this.context.getExecutor()); + ExecWebSocketListener execWebSocketListener = new ExecWebSocketListener(getContext(), this.context.getExecutor(), + this.getKubernetesSerialization()); CompletableFuture startedFuture = clone.newWebSocketBuilder() .subprotocol("v4.channel.k8s.io") .uri(uri) diff --git a/kubernetes-client/src/main/java/io/fabric8/kubernetes/client/dsl/internal/extensions/v1beta1/LegacyRollableScalableResourceOperation.java b/kubernetes-client/src/main/java/io/fabric8/kubernetes/client/dsl/internal/extensions/v1beta1/LegacyRollableScalableResourceOperation.java index f8123a34022..18741a6a8e0 100644 --- a/kubernetes-client/src/main/java/io/fabric8/kubernetes/client/dsl/internal/extensions/v1beta1/LegacyRollableScalableResourceOperation.java +++ b/kubernetes-client/src/main/java/io/fabric8/kubernetes/client/dsl/internal/extensions/v1beta1/LegacyRollableScalableResourceOperation.java @@ -44,7 +44,8 @@ public Scale scale(Scale scaleParam) { // the sticking point is mostly the conversion of the selector from a map to a single string GenericKubernetesResource scale = handleScale( Optional.ofNullable(scaleParam) - .map(s -> Serialization.unmarshal(Serialization.asYaml(s), GenericKubernetesResource.class)).map(g -> { + .map(s -> getKubernetesSerialization().unmarshal(Serialization.asYaml(s), GenericKubernetesResource.class)) + .map(g -> { g.getAdditionalProperties().put("status", null); return g; }).orElse(null), @@ -55,7 +56,7 @@ public Scale scale(Scale scaleParam) { .ifPresent(selector -> status.put("selector", selector.entrySet().stream().map(e -> e.getKey() + "=" + e.getValue()).collect(Collectors.joining(";"))))); return s; - }).map(s -> Serialization.unmarshal(Serialization.asYaml(s), Scale.class)).orElse(null); + }).map(s -> getKubernetesSerialization().unmarshal(Serialization.asYaml(s), Scale.class)).orElse(null); } } diff --git a/kubernetes-client/src/main/java/io/fabric8/kubernetes/client/impl/BaseClient.java b/kubernetes-client/src/main/java/io/fabric8/kubernetes/client/impl/BaseClient.java index b867e847297..5c10a0b145b 100644 --- a/kubernetes-client/src/main/java/io/fabric8/kubernetes/client/impl/BaseClient.java +++ b/kubernetes-client/src/main/java/io/fabric8/kubernetes/client/impl/BaseClient.java @@ -39,6 +39,7 @@ import io.fabric8.kubernetes.client.extension.SupportTestingClient; import io.fabric8.kubernetes.client.http.HttpClient; import io.fabric8.kubernetes.client.utils.ApiVersionUtil; +import io.fabric8.kubernetes.client.utils.KubernetesSerialization; import io.fabric8.kubernetes.client.utils.Utils; import java.net.MalformedURLException; @@ -81,6 +82,7 @@ public void onClose(Executor executor) { private OperationSupport operationSupport; private ExecutorSupplier executorSupplier; private Executor executor; + protected KubernetesSerialization kubernetesSerialization; private OperationContext operationContext; @@ -92,13 +94,15 @@ public void onClose(Executor executor) { this.matchingGroupPredicate = baseClient.matchingGroupPredicate; this.executorSupplier = baseClient.executorSupplier; this.executor = baseClient.executor; + this.kubernetesSerialization = baseClient.kubernetesSerialization; setDerivedFields(); if (baseClient.operationContext != null) { operationContext(baseClient.operationContext); } } - BaseClient(final HttpClient httpClient, Config config, ExecutorSupplier executorSupplier) { + BaseClient(final HttpClient httpClient, Config config, ExecutorSupplier executorSupplier, + KubernetesSerialization kubernetesSerialization) { this.config = config; this.httpClient = httpClient; this.handlers = new Handlers(); @@ -109,6 +113,7 @@ public void onClose(Executor executor) { } this.executorSupplier = executorSupplier; this.executor = executorSupplier.get(); + this.kubernetesSerialization = kubernetesSerialization; } protected void setDerivedFields() { @@ -354,4 +359,8 @@ public Executor getExecutor() { return executor; } + public KubernetesSerialization getKubernetesSerialization() { + return kubernetesSerialization; + } + } diff --git a/kubernetes-client/src/main/java/io/fabric8/kubernetes/client/impl/Handlers.java b/kubernetes-client/src/main/java/io/fabric8/kubernetes/client/impl/Handlers.java index 66c55868800..5c9cc53ce8d 100644 --- a/kubernetes-client/src/main/java/io/fabric8/kubernetes/client/impl/Handlers.java +++ b/kubernetes-client/src/main/java/io/fabric8/kubernetes/client/impl/Handlers.java @@ -21,6 +21,7 @@ import io.fabric8.kubernetes.api.model.GenericKubernetesResource; import io.fabric8.kubernetes.api.model.GenericKubernetesResourceList; import io.fabric8.kubernetes.api.model.HasMetadata; +import io.fabric8.kubernetes.api.model.KubernetesResource; import io.fabric8.kubernetes.api.model.KubernetesResourceList; import io.fabric8.kubernetes.client.Client; import io.fabric8.kubernetes.client.KubernetesClientException; @@ -30,7 +31,6 @@ import io.fabric8.kubernetes.client.dsl.internal.HasMetadataOperation; import io.fabric8.kubernetes.client.utils.ApiVersionUtil; import io.fabric8.kubernetes.client.utils.KubernetesResourceUtil; -import io.fabric8.kubernetes.client.utils.Serialization; import java.util.Arrays; import java.util.List; @@ -57,7 +57,7 @@ public void unregister(Class type) { /** * Returns a {@link ResourceHandler} for the given item. The client is optional, if it is supplied, then the server can be * consulted for resource metadata if a generic item is passed in. - * + * * @return the handler * @throws KubernetesClientException if a handler cannot be found */ @@ -65,7 +65,8 @@ public > ResourceHandler Class type = (Class) meta.getClass(); if (type.equals(GenericKubernetesResource.class)) { - ResourceDefinitionContext rdc = getResourceDefinitionContext((GenericKubernetesResource) meta, client); + GenericKubernetesResource gkr = (GenericKubernetesResource) meta; + ResourceDefinitionContext rdc = getResourceDefinitionContext(gkr.getApiVersion(), gkr.getKind(), client); if (rdc != null) { return new ResourceHandlerImpl(GenericKubernetesResource.class, GenericKubernetesResourceList.class, rdc); @@ -79,26 +80,17 @@ public > ResourceHandler return result; } - public ResourceDefinitionContext getResourceDefinitionContext(String apiVersion, String kind, BaseClient client) { - GenericKubernetesResource resource = new GenericKubernetesResource(); - resource.setKind(kind); - resource.setApiVersion(apiVersion); - return getResourceDefinitionContext(resource, client); - } - - public ResourceDefinitionContext getResourceDefinitionContext(GenericKubernetesResource meta, + public ResourceDefinitionContext getResourceDefinitionContext(String apiVersion, String kind, Client client) { // check if it's built-in - Object value = Serialization.unmarshal(Serialization.asJson(meta)); - Class parsedType = (Class) value.getClass(); + Class clazz = client.adapt(BaseClient.class).getKubernetesSerialization() + .getRegisteredKind(apiVersion, kind); ResourceDefinitionContext rdc = null; - if (!parsedType.equals(GenericKubernetesResource.class)) { - rdc = ResourceDefinitionContext.fromResourceType(parsedType); + if (clazz != null) { + rdc = ResourceDefinitionContext.fromResourceType(clazz); } else if (client != null) { // if a client has been supplied, we can try to look this up from the server - String kind = meta.getKind(); - String apiVersion = meta.getApiVersion(); if (kind == null || apiVersion == null) { return null; } diff --git a/kubernetes-client/src/main/java/io/fabric8/kubernetes/client/impl/KubernetesClientImpl.java b/kubernetes-client/src/main/java/io/fabric8/kubernetes/client/impl/KubernetesClientImpl.java index 0c693945ef9..843aa011499 100644 --- a/kubernetes-client/src/main/java/io/fabric8/kubernetes/client/impl/KubernetesClientImpl.java +++ b/kubernetes-client/src/main/java/io/fabric8/kubernetes/client/impl/KubernetesClientImpl.java @@ -72,7 +72,6 @@ import io.fabric8.kubernetes.client.ApiVisitor.ApiVisitResult; import io.fabric8.kubernetes.client.Client; import io.fabric8.kubernetes.client.Config; -import io.fabric8.kubernetes.client.ConfigBuilder; import io.fabric8.kubernetes.client.KubernetesClientBuilder.ExecutorSupplier; import io.fabric8.kubernetes.client.KubernetesClientException; import io.fabric8.kubernetes.client.NamespacedKubernetesClient; @@ -114,7 +113,6 @@ import io.fabric8.kubernetes.client.dsl.NamespaceableResource; import io.fabric8.kubernetes.client.dsl.NetworkAPIGroupDSL; import io.fabric8.kubernetes.client.dsl.NonNamespaceOperation; -import io.fabric8.kubernetes.client.dsl.ParameterNamespaceListVisitFromServerGetDeleteRecreateWaitApplicable; import io.fabric8.kubernetes.client.dsl.PodResource; import io.fabric8.kubernetes.client.dsl.PolicyAPIGroupDSL; import io.fabric8.kubernetes.client.dsl.RbacAPIGroupDSL; @@ -160,8 +158,7 @@ import io.fabric8.kubernetes.client.informers.SharedInformerFactory; import io.fabric8.kubernetes.client.informers.impl.SharedInformerFactoryImpl; import io.fabric8.kubernetes.client.utils.ApiVersionUtil; -import io.fabric8.kubernetes.client.utils.HttpClientUtils; -import io.fabric8.kubernetes.client.utils.Serialization; +import io.fabric8.kubernetes.client.utils.KubernetesSerialization; import io.fabric8.kubernetes.client.utils.Utils; import java.io.InputStream; @@ -178,24 +175,9 @@ public class KubernetesClientImpl extends BaseClient implements NamespacedKubern public static final String KUBERNETES_VERSION_ENDPOINT = "version"; - public KubernetesClientImpl() { - this(new ConfigBuilder().build()); - } - - public KubernetesClientImpl(String masterUrl) { - this(new ConfigBuilder().withMasterUrl(masterUrl).build()); - } - - public KubernetesClientImpl(Config config) { - this(HttpClientUtils.createHttpClient(config), config); - } - - public KubernetesClientImpl(HttpClient httpClient, Config config) { - this(httpClient, config, null); - } - - public KubernetesClientImpl(HttpClient httpClient, Config config, ExecutorSupplier executorSupplier) { - super(httpClient, config, executorSupplier); + public KubernetesClientImpl(HttpClient httpClient, Config config, ExecutorSupplier executorSupplier, + KubernetesSerialization kubernetesSerialization) { + super(httpClient, config, executorSupplier, kubernetesSerialization); this.getAdapters().registerClient(AppsAPIGroupDSL.class, new AppsAPIGroupClient()); this.getAdapters().registerClient(AdmissionRegistrationAPIGroupDSL.class, new AdmissionRegistrationAPIGroupClient()); @@ -310,8 +292,8 @@ public NonNamespaceOperation load(InputStream is) { - return resourceListFor(Serialization.unmarshal(is)); + public NamespaceListVisitFromServerGetDeleteRecreateWaitApplicable load(InputStream is) { + return resourceListFor(kubernetesSerialization.unmarshal(is)); } /** @@ -347,8 +329,8 @@ public NamespaceListVisitFromServerGetDeleteRecreateWaitApplicable * {@inheritDoc} */ @Override - public ParameterNamespaceListVisitFromServerGetDeleteRecreateWaitApplicable resourceList(String s) { - return resourceListFor(Serialization.unmarshal(s)); + public NamespaceListVisitFromServerGetDeleteRecreateWaitApplicable resourceList(String s) { + return resourceListFor(kubernetesSerialization.unmarshal(s)); } @Override @@ -372,7 +354,7 @@ private NamespaceableResource resource(Object resource) { */ @Override public NamespaceableResource resource(String s) { - return resource(Serialization. unmarshal(s)); + return resource(kubernetesSerialization. unmarshal(s)); } /** @@ -380,7 +362,7 @@ public NamespaceableResource resource(String s) { */ @Override public NamespaceableResource resource(InputStream is) { - return resource(Serialization. unmarshal(is)); + return resource(kubernetesSerialization. unmarshal(is)); } /** diff --git a/kubernetes-client/src/main/java/io/fabric8/kubernetes/client/osgi/ManagedKubernetesClient.java b/kubernetes-client/src/main/java/io/fabric8/kubernetes/client/osgi/ManagedKubernetesClient.java index 4caf4caeebd..9f1c3eb6dfa 100644 --- a/kubernetes-client/src/main/java/io/fabric8/kubernetes/client/osgi/ManagedKubernetesClient.java +++ b/kubernetes-client/src/main/java/io/fabric8/kubernetes/client/osgi/ManagedKubernetesClient.java @@ -17,6 +17,7 @@ import io.fabric8.kubernetes.client.ConfigBuilder; import io.fabric8.kubernetes.client.KubernetesClient; +import io.fabric8.kubernetes.client.KubernetesClientBuilder; import io.fabric8.kubernetes.client.NamespacedKubernetesClient; import io.fabric8.kubernetes.client.NamespacedKubernetesClientAdapter; import io.fabric8.kubernetes.client.OAuthTokenProvider; @@ -166,7 +167,7 @@ public void activate(Map properties) { builder.withOauthTokenProvider(provider); } - this.init(new KubernetesClientImpl(builder.build())); + this.init(new KubernetesClientBuilder().withConfig(builder.build()).build()); } @Deactivate diff --git a/kubernetes-client/src/main/java/io/fabric8/kubernetes/client/utils/internal/CreateOrReplaceHelper.java b/kubernetes-client/src/main/java/io/fabric8/kubernetes/client/utils/internal/CreateOrReplaceHelper.java index 6671516336d..7abf75db7f2 100644 --- a/kubernetes-client/src/main/java/io/fabric8/kubernetes/client/utils/internal/CreateOrReplaceHelper.java +++ b/kubernetes-client/src/main/java/io/fabric8/kubernetes/client/utils/internal/CreateOrReplaceHelper.java @@ -18,7 +18,7 @@ import io.fabric8.kubernetes.api.model.HasMetadata; import io.fabric8.kubernetes.client.KubernetesClientException; import io.fabric8.kubernetes.client.utils.KubernetesResourceUtil; -import io.fabric8.kubernetes.client.utils.Serialization; +import io.fabric8.kubernetes.client.utils.KubernetesSerialization; import java.net.HttpURLConnection; import java.util.concurrent.CompletableFuture; @@ -30,20 +30,22 @@ public class CreateOrReplaceHelper { private final UnaryOperator replaceTask; private final UnaryOperator waitTask; private final UnaryOperator reloadTask; + private final KubernetesSerialization serialization; public CreateOrReplaceHelper(UnaryOperator createTask, UnaryOperator replaceTask, UnaryOperator waitTask, - UnaryOperator reloadTask) { + UnaryOperator reloadTask, KubernetesSerialization serialization) { this.createTask = createTask; this.replaceTask = replaceTask; this.waitTask = waitTask; this.reloadTask = reloadTask; + this.serialization = serialization; } public T createOrReplace(T item) { String resourceVersion = KubernetesResourceUtil.getResourceVersion(item); final CompletableFuture future = new CompletableFuture<>(); int nTries = 0; - item = Serialization.clone(item); + item = serialization.clone(item); while (!future.isDone() && nTries < CREATE_OR_REPLACE_RETRIES) { try { // Create diff --git a/kubernetes-client/src/test/java/io/fabric8/kubernetes/client/dsl/internal/ExecWebSocketListenerTest.java b/kubernetes-client/src/test/java/io/fabric8/kubernetes/client/dsl/internal/ExecWebSocketListenerTest.java index 5e1e2f10fe0..0425d431a94 100644 --- a/kubernetes-client/src/test/java/io/fabric8/kubernetes/client/dsl/internal/ExecWebSocketListenerTest.java +++ b/kubernetes-client/src/test/java/io/fabric8/kubernetes/client/dsl/internal/ExecWebSocketListenerTest.java @@ -20,6 +20,7 @@ import io.fabric8.kubernetes.api.model.StatusCause; import io.fabric8.kubernetes.client.KubernetesClientException; import io.fabric8.kubernetes.client.http.WebSocket; +import io.fabric8.kubernetes.client.utils.Serialization; import org.junit.jupiter.api.Test; import org.mockito.Mockito; @@ -70,7 +71,7 @@ void testSendShouldTruncateAndSendFlaggedWebSocketData() { final WebSocket mockedWebSocket = Mockito.mock(WebSocket.class); Mockito.when(mockedWebSocket.send(Mockito.any())).thenReturn(true); - ExecWebSocketListener listner = new ExecWebSocketListener(new PodOperationContext()); + ExecWebSocketListener listner = newExecWebSocketListener(new PodOperationContext()); listner.onOpen(mockedWebSocket); final byte[] toSend = new byte[] { 1, 3, 3, 7, 0 }; @@ -83,7 +84,7 @@ void testSendShouldTruncateAndSendFlaggedWebSocketData() { @Test void testCheckErrorHasErrorFromMessageShouldThrowException() { - ExecWebSocketListener listener = new ExecWebSocketListener( + ExecWebSocketListener listener = newExecWebSocketListener( new PodOperationContext().toBuilder().terminateOnError(true).build()); listener.onMessage(null, ByteBuffer.wrap(new byte[] { (byte) 2, (byte) 1, (byte) 1 })); @@ -93,16 +94,20 @@ void testCheckErrorHasErrorFromMessageShouldThrowException() { @Test void testCheckErrorHasErrorFromFailureShouldThrowException() { - ExecWebSocketListener listener = new ExecWebSocketListener(new PodOperationContext()); + ExecWebSocketListener listener = newExecWebSocketListener(new PodOperationContext()); listener.onError(null, new IOException("here")); assertThrows(KubernetesClientException.class, () -> listener.checkError()); } + private ExecWebSocketListener newExecWebSocketListener(PodOperationContext context) { + return new ExecWebSocketListener(context, Runnable::run, Serialization.getKubernetesSerialization()); + } + @Test void testGracefulClose() { - ExecWebSocketListener listener = new ExecWebSocketListener(new PodOperationContext()); + ExecWebSocketListener listener = newExecWebSocketListener(new PodOperationContext()); WebSocket mock = Mockito.mock(WebSocket.class); listener.onOpen(mock); listener.close(); @@ -113,7 +118,7 @@ void testGracefulClose() { @Test void testOnClose() { - ExecWebSocketListener listener = new ExecWebSocketListener(new PodOperationContext()); + ExecWebSocketListener listener = newExecWebSocketListener(new PodOperationContext()); WebSocket mock = Mockito.mock(WebSocket.class); listener.onClose(mock, 1000, "testing"); diff --git a/kubernetes-client/src/test/java/io/fabric8/kubernetes/client/dsl/internal/HasMetadataOperationsImplTest.java b/kubernetes-client/src/test/java/io/fabric8/kubernetes/client/dsl/internal/HasMetadataOperationsImplTest.java index d6012d94dd6..c7c04a488ec 100644 --- a/kubernetes-client/src/test/java/io/fabric8/kubernetes/client/dsl/internal/HasMetadataOperationsImplTest.java +++ b/kubernetes-client/src/test/java/io/fabric8/kubernetes/client/dsl/internal/HasMetadataOperationsImplTest.java @@ -19,9 +19,9 @@ import io.fabric8.kubernetes.api.model.GenericKubernetesResource; import io.fabric8.kubernetes.api.model.KubernetesResource; import io.fabric8.kubernetes.client.CustomResource; +import io.fabric8.kubernetes.client.KubernetesClientBuilder; import io.fabric8.kubernetes.client.dsl.MixedOperation; import io.fabric8.kubernetes.client.dsl.Resource; -import io.fabric8.kubernetes.client.impl.KubernetesClientImpl; import io.fabric8.kubernetes.client.utils.Serialization; import io.fabric8.kubernetes.model.annotation.Group; import io.fabric8.kubernetes.model.annotation.Version; @@ -34,7 +34,7 @@ class HasMetadataOperationsImplTest { @Test void shouldBeAbleToReturnOperationsWithoutSpecificList() { - final MixedOperation> operation = new KubernetesClientImpl().resources(Bar.class, + final MixedOperation> operation = new KubernetesClientBuilder().build().resources(Bar.class, BarList.class); assertNotNull(operation); } diff --git a/kubernetes-client/src/test/java/io/fabric8/kubernetes/client/dsl/internal/OperationSupportTest.java b/kubernetes-client/src/test/java/io/fabric8/kubernetes/client/dsl/internal/OperationSupportTest.java index da852aae422..79395bcfaec 100644 --- a/kubernetes-client/src/test/java/io/fabric8/kubernetes/client/dsl/internal/OperationSupportTest.java +++ b/kubernetes-client/src/test/java/io/fabric8/kubernetes/client/dsl/internal/OperationSupportTest.java @@ -17,7 +17,6 @@ import io.fabric8.kubernetes.api.model.Pod; import io.fabric8.kubernetes.api.model.PodBuilder; -import io.fabric8.kubernetes.client.Client; import io.fabric8.kubernetes.client.Config; import io.fabric8.kubernetes.client.ConfigBuilder; import io.fabric8.kubernetes.client.KubernetesClientException; @@ -26,12 +25,15 @@ import io.fabric8.kubernetes.client.http.HttpResponse; import io.fabric8.kubernetes.client.http.StandardHttpRequest; import io.fabric8.kubernetes.client.http.TestHttpResponse; +import io.fabric8.kubernetes.client.impl.BaseClient; +import io.fabric8.kubernetes.client.utils.Serialization; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.Arguments; import org.junit.jupiter.params.provider.MethodSource; +import org.mockito.Mockito; import java.net.MalformedURLException; import java.net.URI; @@ -41,7 +43,6 @@ import static org.junit.jupiter.api.Assertions.assertDoesNotThrow; import static org.junit.jupiter.api.Assertions.assertThrows; import static org.junit.jupiter.params.provider.Arguments.arguments; -import static org.mockito.Mockito.RETURNS_DEEP_STUBS; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.when; @@ -51,7 +52,10 @@ class OperationSupportTest { @BeforeEach void setUp() { - final OperationContext context = new OperationContext().withClient(mock(Client.class, RETURNS_DEEP_STUBS)); + BaseClient mock = mock(BaseClient.class, Mockito.RETURNS_SELF); + Mockito.when(mock.adapt(BaseClient.class).getKubernetesSerialization()) + .thenReturn(Serialization.getKubernetesSerialization()); + final OperationContext context = new OperationContext().withClient(mock); final Config globalConfig = new ConfigBuilder(Config.empty()) .withRequestTimeout(313373) .build(); diff --git a/kubernetes-client/src/test/java/io/fabric8/kubernetes/client/impl/BaseClientTest.java b/kubernetes-client/src/test/java/io/fabric8/kubernetes/client/impl/BaseClientTest.java index 29d6c758355..009e02ba785 100644 --- a/kubernetes-client/src/test/java/io/fabric8/kubernetes/client/impl/BaseClientTest.java +++ b/kubernetes-client/src/test/java/io/fabric8/kubernetes/client/impl/BaseClientTest.java @@ -24,6 +24,7 @@ import io.fabric8.kubernetes.client.RequestConfig; import io.fabric8.kubernetes.client.dsl.internal.OperationSupport; import io.fabric8.kubernetes.client.http.HttpClient; +import io.fabric8.kubernetes.client.utils.Serialization; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; @@ -45,7 +46,7 @@ class BaseClientTest { @BeforeEach void setUp() { httpClient = mock(HttpClient.class, RETURNS_DEEP_STUBS); - baseClient = new BaseClient(httpClient, Config.empty(), () -> Runnable::run) { + baseClient = new BaseClient(httpClient, Config.empty(), () -> Runnable::run, Serialization.getKubernetesSerialization()) { @Override BaseClient copy() { diff --git a/kubernetes-client/src/test/java/io/fabric8/kubernetes/client/impl/DryRunTest.java b/kubernetes-client/src/test/java/io/fabric8/kubernetes/client/impl/DryRunTest.java index ae7504bb1eb..9d6764ed2a2 100644 --- a/kubernetes-client/src/test/java/io/fabric8/kubernetes/client/impl/DryRunTest.java +++ b/kubernetes-client/src/test/java/io/fabric8/kubernetes/client/impl/DryRunTest.java @@ -28,6 +28,7 @@ import io.fabric8.kubernetes.client.http.HttpRequest; import io.fabric8.kubernetes.client.http.HttpRequest.Builder; import io.fabric8.kubernetes.client.http.TestHttpResponse; +import io.fabric8.kubernetes.client.utils.Serialization; import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; @@ -61,7 +62,8 @@ public void setUp() throws IOException { when(mockClient.sendAsync(any(), Mockito.eq(byte[].class))) .thenReturn(CompletableFuture.completedFuture(TestHttpResponse.from(200, "{\"kind\":\"Pod\", \"apiVersion\":\"v1\"}"))); - kubernetesClient = new KubernetesClientImpl(mockClient, config); + kubernetesClient = new KubernetesClientImpl(mockClient, config, () -> Runnable::run, + Serialization.getKubernetesSerialization()); Mockito.when(mockClient.newHttpRequestBuilder()).thenAnswer(answer -> { HttpRequest.Builder result = Mockito.mock(HttpRequest.Builder.class, Mockito.RETURNS_SELF); builders.add(result); diff --git a/kubernetes-client/src/test/java/io/fabric8/kubernetes/client/impl/KubernetesClientImplTest.java b/kubernetes-client/src/test/java/io/fabric8/kubernetes/client/impl/KubernetesClientImplTest.java index 170ab23ff5b..a092ed8814d 100644 --- a/kubernetes-client/src/test/java/io/fabric8/kubernetes/client/impl/KubernetesClientImplTest.java +++ b/kubernetes-client/src/test/java/io/fabric8/kubernetes/client/impl/KubernetesClientImplTest.java @@ -24,7 +24,7 @@ import io.fabric8.kubernetes.client.KubernetesClient; import io.fabric8.kubernetes.client.KubernetesClientBuilder; import io.fabric8.kubernetes.client.KubernetesClientException; -import io.fabric8.kubernetes.client.dsl.ParameterNamespaceListVisitFromServerGetDeleteRecreateWaitApplicable; +import io.fabric8.kubernetes.client.dsl.NamespaceListVisitFromServerGetDeleteRecreateWaitApplicable; import io.fabric8.kubernetes.client.http.BasicBuilder; import io.fabric8.kubernetes.client.http.HttpRequest; import io.fabric8.kubernetes.client.utils.HttpClientUtils; @@ -62,11 +62,11 @@ class KubernetesClientImplTest { private static final String TEST_CONFIG_YML_FILE = Utils .filePath(KubernetesClientImplTest.class.getResource("/test-config.yml")); - private KubernetesClientImpl defaultKubernetesClient; + private KubernetesClient defaultKubernetesClient; @BeforeEach public void setUp() { - defaultKubernetesClient = new KubernetesClientImpl(); + defaultKubernetesClient = new KubernetesClientBuilder().build(); } @AfterEach @@ -107,7 +107,7 @@ void loadWithWindowsLineSeparatorsString() throws Exception { new File(KubernetesClientImplTest.class.getResource("/test-list.yml").getFile()).toPath(), StandardCharsets.UTF_8); final String crlfFile = String.join(" \r\n", fileLines); // When - final List result = new KubernetesClientImpl() + final List result = new KubernetesClientBuilder().build() .load(new ByteArrayInputStream(crlfFile.getBytes(StandardCharsets.UTF_8))).items(); // Then assertThat(result) @@ -127,7 +127,7 @@ void shouldInstantiateClientUsingYaml() throws Exception { @Test void shouldInstantiateClientUsingSerializeDeserialize() { - KubernetesClientImpl original = new KubernetesClientImpl(); + KubernetesClient original = new KubernetesClientBuilder().build(); String json = Serialization.asJson(original.getConfiguration()); KubernetesClient copy = new KubernetesClientBuilder().withConfig(json).build(); @@ -150,7 +150,7 @@ void shouldPropagateImpersonateSettings() { .withImpersonateExtras(extras) .build(); - final KubernetesClientImpl client = new KubernetesClientImpl(config); + final KubernetesClient client = new KubernetesClientBuilder().withConfig(config).build(); final Config currentConfig = client.getConfiguration(); assertEquals("a", currentConfig.getImpersonateUsername()); @@ -161,14 +161,14 @@ void shouldPropagateImpersonateSettings() { @Test @DisplayName("resource(String).item with HasMetadata should deserialize") void resourceFromStringWithHasMetadata() { - assertThat(new KubernetesClientImpl().resource("apiVersion: v1\nkind: Pod").item()) + assertThat(new KubernetesClientBuilder().build().resource("apiVersion: v1\nkind: Pod").item()) .isInstanceOf(Pod.class); } @Test @DisplayName("resource(String) with no HasMetadata should throwException") void resourceFromStringWithInvalid() { - final KubernetesClient kc = new KubernetesClientImpl(); + final KubernetesClient kc = new KubernetesClientBuilder().build(); assertThatExceptionOfType(KubernetesClientException.class) .isThrownBy(() -> kc.resource("NotAPod")) .withMessageStartingWith("Unable to create a valid resource from the provided object"); @@ -179,7 +179,7 @@ void resourceFromStringWithInvalid() { void resourceFromInputStreamWithHasMetadata() throws IOException { final String podYaml = "apiVersion: v1\nkind: Pod"; try (InputStream is = new ByteArrayInputStream(podYaml.getBytes(StandardCharsets.UTF_8))) { - assertThat(new KubernetesClientImpl().resource(is).item()) + assertThat(new KubernetesClientBuilder().build().resource(is).item()) .isInstanceOf(Pod.class); } } @@ -187,7 +187,7 @@ void resourceFromInputStreamWithHasMetadata() throws IOException { @Test @DisplayName("resource(InputStream) with no HasMetadata should throwException") void resourceFromInputStreamWithInvalid() throws IOException { - final KubernetesClient kc = new KubernetesClientImpl(); + final KubernetesClient kc = new KubernetesClientBuilder().build(); final String podYaml = "NotAPod"; try (InputStream is = new ByteArrayInputStream(podYaml.getBytes(StandardCharsets.UTF_8))) { assertThatExceptionOfType(KubernetesClientException.class) @@ -201,7 +201,7 @@ void resourceFromInputStreamWithInvalid() throws IOException { void loadFromInputStreamWithHasMetadata() throws IOException { final String podYaml = "apiVersion: v1\nkind: Pod"; try (InputStream is = new ByteArrayInputStream(podYaml.getBytes(StandardCharsets.UTF_8))) { - assertThat(new KubernetesClientImpl().load(is).items()) + assertThat(new KubernetesClientBuilder().build().load(is).items()) .containsExactly(new Pod()); } } @@ -211,7 +211,8 @@ void loadFromInputStreamWithHasMetadata() throws IOException { void loadFromInputStreamWithInvalid() throws IOException { final String podYaml = "NotAPod"; try (InputStream is = new ByteArrayInputStream(podYaml.getBytes(StandardCharsets.UTF_8))) { - final ParameterNamespaceListVisitFromServerGetDeleteRecreateWaitApplicable load = new KubernetesClientImpl() + final NamespaceListVisitFromServerGetDeleteRecreateWaitApplicable load = new KubernetesClientBuilder() + .build() .load(is); assertThatIllegalArgumentException() .isThrownBy(load::get) diff --git a/kubernetes-client/src/test/java/io/fabric8/kubernetes/client/impl/PatchTest.java b/kubernetes-client/src/test/java/io/fabric8/kubernetes/client/impl/PatchTest.java index dbbb7fb7268..df37733bafd 100644 --- a/kubernetes-client/src/test/java/io/fabric8/kubernetes/client/impl/PatchTest.java +++ b/kubernetes-client/src/test/java/io/fabric8/kubernetes/client/impl/PatchTest.java @@ -29,6 +29,7 @@ import io.fabric8.kubernetes.client.http.HttpRequest.Builder; import io.fabric8.kubernetes.client.http.StandardHttpRequest; import io.fabric8.kubernetes.client.http.TestHttpResponse; +import io.fabric8.kubernetes.client.utils.Serialization; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.mockito.ArgumentCaptor; @@ -62,7 +63,8 @@ public void setUp() throws IOException { when(mockClient.sendAsync(any(), Mockito.eq(byte[].class))) .thenReturn(CompletableFuture.completedFuture(TestHttpResponse.from(200, "{}"))); Config config = new ConfigBuilder().withMasterUrl("https://localhost:8443/").build(); - kubernetesClient = new KubernetesClientImpl(mockClient, config); + kubernetesClient = new KubernetesClientImpl(mockClient, config, () -> Runnable::run, + Serialization.getKubernetesSerialization()); when(mockClient.newHttpRequestBuilder()).thenAnswer(answer -> { HttpRequest.Builder result = Mockito.mock(HttpRequest.Builder.class, Mockito.RETURNS_SELF); when(result.build()).thenReturn(new StandardHttpRequest.Builder().uri("https://localhost:8443/").build()); diff --git a/kubernetes-client/src/test/java/io/fabric8/kubernetes/client/informers/SharedInformerFactoryImplTest.java b/kubernetes-client/src/test/java/io/fabric8/kubernetes/client/informers/SharedInformerFactoryImplTest.java index 1a2abc092de..c7ddf4d17ad 100644 --- a/kubernetes-client/src/test/java/io/fabric8/kubernetes/client/informers/SharedInformerFactoryImplTest.java +++ b/kubernetes-client/src/test/java/io/fabric8/kubernetes/client/informers/SharedInformerFactoryImplTest.java @@ -19,7 +19,8 @@ import io.fabric8.kubernetes.api.model.Service; import io.fabric8.kubernetes.api.model.apps.Deployment; import io.fabric8.kubernetes.client.CustomResource; -import io.fabric8.kubernetes.client.impl.KubernetesClientImpl; +import io.fabric8.kubernetes.client.KubernetesClient; +import io.fabric8.kubernetes.client.KubernetesClientBuilder; import io.fabric8.kubernetes.client.informers.impl.SharedInformerFactoryImpl; import io.fabric8.kubernetes.model.annotation.Group; import io.fabric8.kubernetes.model.annotation.Kind; @@ -33,7 +34,7 @@ class SharedInformerFactoryImplTest { public static final long RESYNC_PERIOD = 10 * 1000L; - private KubernetesClientImpl mockBaseClient; + private KubernetesClient mockBaseClient; private static class TestCustomResourceSpec { } @@ -95,7 +96,7 @@ public String toString() { @BeforeEach void init() { - this.mockBaseClient = new KubernetesClientImpl(); + this.mockBaseClient = new KubernetesClientBuilder().build(); } @Test diff --git a/kubernetes-client/src/test/java/io/fabric8/kubernetes/client/utils/internal/CreateOrReplaceHelperTest.java b/kubernetes-client/src/test/java/io/fabric8/kubernetes/client/utils/internal/CreateOrReplaceHelperTest.java index 7940721f077..aef8f57b7cc 100644 --- a/kubernetes-client/src/test/java/io/fabric8/kubernetes/client/utils/internal/CreateOrReplaceHelperTest.java +++ b/kubernetes-client/src/test/java/io/fabric8/kubernetes/client/utils/internal/CreateOrReplaceHelperTest.java @@ -19,6 +19,7 @@ import io.fabric8.kubernetes.api.model.PodBuilder; import io.fabric8.kubernetes.api.model.StatusBuilder; import io.fabric8.kubernetes.client.KubernetesClientException; +import io.fabric8.kubernetes.client.utils.Serialization; import org.junit.jupiter.api.Test; import org.mockito.Mockito; @@ -47,7 +48,7 @@ void testCreateOrReplaceShouldCreate() { createPodTask, p -> getPod(), p -> getPod(), - p -> getPod()); + p -> getPod(), Serialization.getKubernetesSerialization()); Pod p = getPod(); p.getMetadata().setResourceVersion("1"); @@ -77,7 +78,7 @@ void testCreateOrReplaceShouldReplace() { createPodTask, replacePodTask, p -> getPod(), - p -> getPod()); + p -> getPod(), Serialization.getKubernetesSerialization()); // When Pod podCreated = podCreateOrReplaceHelper.createOrReplace(getPod()); @@ -106,7 +107,7 @@ HttpURLConnection.HTTP_INTERNAL_ERROR, new StatusBuilder().withCode(HttpURLConne createPodTask, p -> getPod(), waitTask, - reloadTask); + reloadTask, Serialization.getKubernetesSerialization()); // When Pod podCreated = podCreateOrReplaceHelper.createOrReplace(getPod()); @@ -125,7 +126,7 @@ void testCreateOrReplaceThrowExceptionOnErrorCodeLessThan500() { HttpURLConnection.HTTP_BAD_REQUEST, new StatusBuilder().withCode(HttpURLConnection.HTTP_BAD_REQUEST).build()); }; CreateOrReplaceHelper podCreateOrReplaceHelper = new CreateOrReplaceHelper<>(createPodTask, - p -> getPod(), p -> getPod(), p -> getPod()); + p -> getPod(), p -> getPod(), p -> getPod(), Serialization.getKubernetesSerialization()); Pod podToCreate = getPod(); // When diff --git a/kubernetes-model-generator/kubernetes-model-core/src/main/java/io/fabric8/kubernetes/api/model/GenericKubernetesResource.java b/kubernetes-model-generator/kubernetes-model-core/src/main/java/io/fabric8/kubernetes/api/model/GenericKubernetesResource.java index 293be7fcd43..684f1a6fa27 100644 --- a/kubernetes-model-generator/kubernetes-model-core/src/main/java/io/fabric8/kubernetes/api/model/GenericKubernetesResource.java +++ b/kubernetes-model-generator/kubernetes-model-core/src/main/java/io/fabric8/kubernetes/api/model/GenericKubernetesResource.java @@ -74,6 +74,10 @@ public void setAdditionalProperty(String name, Object value) { this.additionalProperties.put(name, value); } + /** + * @deprecated use KubernetesSerialization to convert the additionalProperties + */ + @Deprecated @JsonIgnore public JsonNode getAdditionalPropertiesNode() { return MAPPER.convertValue(getAdditionalProperties(), JsonNode.class); diff --git a/kubernetes-model-generator/kubernetes-model-core/src/main/java/io/fabric8/kubernetes/internal/KubernetesDeserializer.java b/kubernetes-model-generator/kubernetes-model-core/src/main/java/io/fabric8/kubernetes/internal/KubernetesDeserializer.java index 7aa89cbfdda..a78c388c067 100644 --- a/kubernetes-model-generator/kubernetes-model-core/src/main/java/io/fabric8/kubernetes/internal/KubernetesDeserializer.java +++ b/kubernetes-model-generator/kubernetes-model-core/src/main/java/io/fabric8/kubernetes/internal/KubernetesDeserializer.java @@ -75,7 +75,7 @@ public boolean equals(Object obj) { private static final String KIND = "kind"; private static final String API_VERSION = "apiVersion"; - private static final Mapping mapping = new Mapping(); + private final Mapping mapping = new Mapping(); @Override public KubernetesResource deserialize(JsonParser jp, DeserializationContext ctxt) throws IOException { @@ -110,7 +110,7 @@ private KubernetesResource fromArrayNode(JsonParser jp, JsonNode node) throws IO return new KubernetesListBuilder().withItems(list).build(); } - private static KubernetesResource fromObjectNode(JsonParser jp, JsonNode node) throws IOException { + private KubernetesResource fromObjectNode(JsonParser jp, JsonNode node) throws IOException { TypeKey key = getKey(node); Class resourceType = mapping.getForKey(key); if (resourceType == null) { @@ -132,7 +132,7 @@ private static KubernetesResource fromObjectNode(JsonParser jp, JsonNode node) t /** * Return a string representation of the key of the type: #. */ - private static TypeKey getKey(JsonNode node) { + private TypeKey getKey(JsonNode node) { JsonNode apiVersion = node.get(API_VERSION); JsonNode kind = node.get(KIND); @@ -144,14 +144,14 @@ private static TypeKey getKey(JsonNode node) { /** * Registers a Custom Resource Definition Kind */ - public static void registerCustomKind(String kind, Class clazz) { + public void registerCustomKind(String kind, Class clazz) { registerCustomKind(null, kind, clazz); } /** * Registers a Custom Resource Definition Kind */ - public static void registerCustomKind(String apiVersion, String kind, Class clazz) { + public void registerCustomKind(String apiVersion, String kind, Class clazz) { mapping.registerKind(apiVersion, kind, clazz); } @@ -223,4 +223,8 @@ private void addMapping(Class clazz) { } } } + + public Class getRegisteredKind(String apiVersion, String kind) { + return mapping.getForKey(mapping.createKey(apiVersion, kind)); + } } diff --git a/kubernetes-tests/src/test/java/io/fabric8/kubernetes/client/mock/ClusterRoleTest.java b/kubernetes-tests/src/test/java/io/fabric8/kubernetes/client/mock/ClusterRoleTest.java index 75127d90b11..dfdd68d5b43 100644 --- a/kubernetes-tests/src/test/java/io/fabric8/kubernetes/client/mock/ClusterRoleTest.java +++ b/kubernetes-tests/src/test/java/io/fabric8/kubernetes/client/mock/ClusterRoleTest.java @@ -19,7 +19,7 @@ import io.fabric8.kubernetes.api.model.HasMetadata; import io.fabric8.kubernetes.api.model.rbac.ClusterRole; import io.fabric8.kubernetes.client.KubernetesClient; -import io.fabric8.kubernetes.client.dsl.ParameterNamespaceListVisitFromServerGetDeleteRecreateWaitApplicable; +import io.fabric8.kubernetes.client.dsl.NamespaceListVisitFromServerGetDeleteRecreateWaitApplicable; import io.fabric8.kubernetes.client.server.mock.EnableKubernetesMockClient; import org.junit.jupiter.api.Test; @@ -44,7 +44,7 @@ void testLoadFromFile() { @Test void testHandlersLoadFromFile() { - ParameterNamespaceListVisitFromServerGetDeleteRecreateWaitApplicable load = client + NamespaceListVisitFromServerGetDeleteRecreateWaitApplicable load = client .load(getClass().getResourceAsStream("/test-clusterrole.yml")); assertNotNull(load); diff --git a/kubernetes-tests/src/test/java/io/fabric8/kubernetes/client/mock/CustomResourceCrudTest.java b/kubernetes-tests/src/test/java/io/fabric8/kubernetes/client/mock/CustomResourceCrudTest.java index 00f09af4233..5fbe9d6904f 100644 --- a/kubernetes-tests/src/test/java/io/fabric8/kubernetes/client/mock/CustomResourceCrudTest.java +++ b/kubernetes-tests/src/test/java/io/fabric8/kubernetes/client/mock/CustomResourceCrudTest.java @@ -22,11 +22,11 @@ import io.fabric8.kubernetes.client.dsl.MixedOperation; import io.fabric8.kubernetes.client.dsl.NonNamespaceOperation; import io.fabric8.kubernetes.client.dsl.Resource; +import io.fabric8.kubernetes.client.impl.BaseClient; import io.fabric8.kubernetes.client.mock.crd.CronTab; import io.fabric8.kubernetes.client.mock.crd.CronTabSpec; import io.fabric8.kubernetes.client.mock.crd.CronTabStatus; import io.fabric8.kubernetes.client.server.mock.EnableKubernetesMockClient; -import io.fabric8.kubernetes.internal.KubernetesDeserializer; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; @@ -48,7 +48,8 @@ class CustomResourceCrudTest { @BeforeEach void setUp() { - KubernetesDeserializer.registerCustomKind("stable.example.com/v1", "CronTab", CronTab.class); + client.adapt(BaseClient.class).getKubernetesSerialization().registerCustomKind("stable.example.com/v1", "CronTab", + CronTab.class); cronTabCrd = client .apiextensions() .v1() diff --git a/kubernetes-tests/src/test/java/io/fabric8/kubernetes/client/mock/CustomResourceCrudWithCRDContextTest.java b/kubernetes-tests/src/test/java/io/fabric8/kubernetes/client/mock/CustomResourceCrudWithCRDContextTest.java index cdfe80b955f..cf03b8af945 100644 --- a/kubernetes-tests/src/test/java/io/fabric8/kubernetes/client/mock/CustomResourceCrudWithCRDContextTest.java +++ b/kubernetes-tests/src/test/java/io/fabric8/kubernetes/client/mock/CustomResourceCrudWithCRDContextTest.java @@ -20,11 +20,11 @@ import io.fabric8.kubernetes.client.KubernetesClient; import io.fabric8.kubernetes.client.dsl.MixedOperation; import io.fabric8.kubernetes.client.dsl.Resource; +import io.fabric8.kubernetes.client.impl.BaseClient; import io.fabric8.kubernetes.client.mock.crd.EntandoBundleRelease; import io.fabric8.kubernetes.client.mock.crd.EntandoBundleReleaseList; import io.fabric8.kubernetes.client.mock.crd.EntandoBundleReleaseSpec; import io.fabric8.kubernetes.client.server.mock.EnableKubernetesMockClient; -import io.fabric8.kubernetes.internal.KubernetesDeserializer; import org.junit.jupiter.api.Test; import static org.junit.jupiter.api.Assertions.assertEquals; @@ -38,7 +38,8 @@ class CustomResourceCrudWithCRDContextTest { @Test void testCreateAndGet() { // Given - KubernetesDeserializer.registerCustomKind("demo.fabric8.io/v1alpha1", "EntandoBundleRelease", EntandoBundleRelease.class); + client.adapt(BaseClient.class).getKubernetesSerialization().registerCustomKind("demo.fabric8.io/v1alpha1", + "EntandoBundleRelease", EntandoBundleRelease.class); MixedOperation> ebrClient = client .resources(EntandoBundleRelease.class, EntandoBundleReleaseList.class); @@ -54,7 +55,8 @@ void testCreateAndGet() { @Test void testCreateAndGetWithInferredContext() { // Given - KubernetesDeserializer.registerCustomKind("demo.fabric8.io/v1alpha1", "EntandoBundleRelease", EntandoBundleRelease.class); + client.adapt(BaseClient.class).getKubernetesSerialization().registerCustomKind("demo.fabric8.io/v1alpha1", + "EntandoBundleRelease", EntandoBundleRelease.class); MixedOperation, Resource> ebrClient = client .resources(EntandoBundleRelease.class); diff --git a/kubernetes-tests/src/test/java/io/fabric8/kubernetes/client/mock/DefaultSharedIndexInformerTest.java b/kubernetes-tests/src/test/java/io/fabric8/kubernetes/client/mock/DefaultSharedIndexInformerTest.java index 7ac7f9d0701..2ad9367592b 100644 --- a/kubernetes-tests/src/test/java/io/fabric8/kubernetes/client/mock/DefaultSharedIndexInformerTest.java +++ b/kubernetes-tests/src/test/java/io/fabric8/kubernetes/client/mock/DefaultSharedIndexInformerTest.java @@ -42,6 +42,7 @@ import io.fabric8.kubernetes.client.WatcherException; import io.fabric8.kubernetes.client.dsl.base.CustomResourceDefinitionContext; import io.fabric8.kubernetes.client.dsl.base.ResourceDefinitionContext; +import io.fabric8.kubernetes.client.impl.BaseClient; import io.fabric8.kubernetes.client.informers.ResourceEventHandler; import io.fabric8.kubernetes.client.informers.SharedIndexInformer; import io.fabric8.kubernetes.client.informers.SharedInformerFactory; @@ -58,7 +59,6 @@ import io.fabric8.kubernetes.client.utils.URLUtils; import io.fabric8.kubernetes.client.utils.URLUtils.URLBuilder; import io.fabric8.kubernetes.client.utils.Utils; -import io.fabric8.kubernetes.internal.KubernetesDeserializer; import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.DisplayName; @@ -1166,7 +1166,8 @@ void testGenericKubernetesResourceSharedIndexInformerWithAdditionalDeserializers r -> new WatchEvent(getAnimal("red-panda", "Carnivora", r), "ADDED"), null, null); // When - KubernetesDeserializer.registerCustomKind("jungle.example.com/v1", "Animal", CronTab.class); + client.adapt(BaseClient.class).getKubernetesSerialization().registerCustomKind("jungle.example.com/v1", "Animal", + CronTab.class); SharedIndexInformer animalSharedIndexInformer = client .genericKubernetesResources(animalContext) .inNamespace("ns1") diff --git a/kubernetes-tests/src/test/java/io/fabric8/kubernetes/client/mock/InformTest.java b/kubernetes-tests/src/test/java/io/fabric8/kubernetes/client/mock/InformTest.java index ea60c563b03..8b704b97f87 100644 --- a/kubernetes-tests/src/test/java/io/fabric8/kubernetes/client/mock/InformTest.java +++ b/kubernetes-tests/src/test/java/io/fabric8/kubernetes/client/mock/InformTest.java @@ -34,6 +34,7 @@ import io.fabric8.kubernetes.client.informers.cache.ReducedStateItemStore; import io.fabric8.kubernetes.client.server.mock.EnableKubernetesMockClient; import io.fabric8.kubernetes.client.server.mock.KubernetesMockServer; +import io.fabric8.kubernetes.client.utils.Serialization; import org.junit.jupiter.api.Test; import java.net.HttpURLConnection; @@ -484,7 +485,8 @@ public void onUpdate(Pod oldObj, Pod newObj) { SharedIndexInformer informer = client.pods() .runnableInformer(0) .itemStore( - new ReducedStateItemStore<>(ReducedStateItemStore.NAME_KEY_STATE, Pod.class, "metadata.ownerReferences")) + new ReducedStateItemStore<>(ReducedStateItemStore.NAME_KEY_STATE, Pod.class, + Serialization.getKubernetesSerialization(), "metadata.ownerReferences")) .removeNamespaceIndex() .addEventHandler(handler) .run(); diff --git a/kubernetes-tests/src/test/java/io/fabric8/kubernetes/client/mock/LeaderElectionTest.java b/kubernetes-tests/src/test/java/io/fabric8/kubernetes/client/mock/LeaderElectionTest.java index b68d9a50409..b90472ef0d3 100644 --- a/kubernetes-tests/src/test/java/io/fabric8/kubernetes/client/mock/LeaderElectionTest.java +++ b/kubernetes-tests/src/test/java/io/fabric8/kubernetes/client/mock/LeaderElectionTest.java @@ -69,6 +69,7 @@ void singleLeaderConfigMapLockUpdateTest() throws Exception { .withPath("/api/v1/namespaces/namespace/configmaps/name") .andReturn(200, new ConfigMapBuilder() .withNewMetadata() + .withName("name") .withResourceVersion("1") .withAnnotations(Collections.singletonMap( "control-plane.alpha.kubernetes.io/leader", diff --git a/kubernetes-tests/src/test/java/io/fabric8/openshift/client/server/mock/LoadAsTemplateTest.java b/kubernetes-tests/src/test/java/io/fabric8/openshift/client/server/mock/LoadAsTemplateTest.java index 8cf4bec5221..35f5ee7eaf3 100644 --- a/kubernetes-tests/src/test/java/io/fabric8/openshift/client/server/mock/LoadAsTemplateTest.java +++ b/kubernetes-tests/src/test/java/io/fabric8/openshift/client/server/mock/LoadAsTemplateTest.java @@ -84,13 +84,13 @@ void shouldProcessLocallyWithParametersInYaml() { @Test void shouldProcessLocallyDoubleBracedParameters() { // Given - final Map nonStringParamsToBeAbleToLoad = Collections.singletonMap("CONTAINER_PORT", "8080"); final Map localRequiredParameters = new HashMap<>(); localRequiredParameters.put("USERNAME", "notTheOneInYaml"); localRequiredParameters.put("REQUIRED", "requiredValue"); localRequiredParameters.put("REQUIRED_BOOLEAN", "true"); + localRequiredParameters.put("CONTAINER_PORT", "8080"); // When - final KubernetesList result = client.templates().withParameters(nonStringParamsToBeAbleToLoad) + final KubernetesList result = client.templates() .load(getClass().getResourceAsStream("/template-with-json-params.yml")) .processLocally(localRequiredParameters); // Then diff --git a/kubernetes-tests/src/test/resources/parameters.yml b/kubernetes-tests/src/test/resources/parameters.yml index c796e7c8d1d..bc77995943a 100644 --- a/kubernetes-tests/src/test/resources/parameters.yml +++ b/kubernetes-tests/src/test/resources/parameters.yml @@ -17,3 +17,4 @@ USERNAME: root REQUIRED: requiredValue REQUIRED_BOOLEAN: false +CONTAINER_PORT: 8080 diff --git a/kubernetes-tests/src/test/resources/template-with-json-params.yml b/kubernetes-tests/src/test/resources/template-with-json-params.yml index 37556c7887f..7568eacb055 100644 --- a/kubernetes-tests/src/test/resources/template-with-json-params.yml +++ b/kubernetes-tests/src/test/resources/template-with-json-params.yml @@ -57,3 +57,6 @@ parameters: - description: Required boolean parameter name: REQUIRED_BOOLEAN required: true +- description: container port parameter + name: CONTAINER_PORT + required: true diff --git a/openshift-client-api/src/main/java/io/fabric8/openshift/client/DefaultOpenShiftClient.java b/openshift-client-api/src/main/java/io/fabric8/openshift/client/DefaultOpenShiftClient.java index 21169f5aaa3..2e9e98ca0b1 100644 --- a/openshift-client-api/src/main/java/io/fabric8/openshift/client/DefaultOpenShiftClient.java +++ b/openshift-client-api/src/main/java/io/fabric8/openshift/client/DefaultOpenShiftClient.java @@ -22,9 +22,6 @@ import io.fabric8.kubernetes.client.http.HttpClient.Factory; import io.fabric8.kubernetes.client.http.StandardHttpClientBuilder; import io.fabric8.kubernetes.client.utils.HttpClientUtils; -import io.fabric8.kubernetes.client.utils.Serialization; - -import java.io.InputStream; /** * Class for Default Openshift Client implementing KubernetesClient interface. @@ -37,14 +34,6 @@ public class DefaultOpenShiftClient extends NamespacedOpenShiftClientAdapter { public static final String OPENSHIFT_VERSION_ENDPOINT = "version/openshift"; - public static DefaultOpenShiftClient fromConfig(String config) { - return new DefaultOpenShiftClient(Serialization.unmarshal(config, OpenShiftConfig.class)); - } - - public static DefaultOpenShiftClient fromConfig(InputStream is) { - return new DefaultOpenShiftClient(Serialization.unmarshal(is, OpenShiftConfig.class)); - } - public DefaultOpenShiftClient() { this(new OpenShiftConfigBuilder().build()); } diff --git a/openshift-client-api/src/main/java/io/fabric8/openshift/client/NamespacedOpenShiftClientAdapter.java b/openshift-client-api/src/main/java/io/fabric8/openshift/client/NamespacedOpenShiftClientAdapter.java index a4b26fdde04..686c16e066b 100644 --- a/openshift-client-api/src/main/java/io/fabric8/openshift/client/NamespacedOpenShiftClientAdapter.java +++ b/openshift-client-api/src/main/java/io/fabric8/openshift/client/NamespacedOpenShiftClientAdapter.java @@ -18,7 +18,6 @@ import io.fabric8.kubernetes.api.model.ComponentStatus; import io.fabric8.kubernetes.api.model.ComponentStatusList; -import io.fabric8.kubernetes.api.model.KubernetesList; import io.fabric8.kubernetes.client.NamespacedKubernetesClientAdapter; import io.fabric8.kubernetes.client.RequestConfig; import io.fabric8.kubernetes.client.VersionInfo; @@ -348,7 +347,7 @@ public MixedOperation> routes() { } @Override - public ParameterMixedOperation> templates() { + public ParameterMixedOperation templates() { return getClient().templates(); } diff --git a/openshift-client-api/src/main/java/io/fabric8/openshift/client/OpenShiftClient.java b/openshift-client-api/src/main/java/io/fabric8/openshift/client/OpenShiftClient.java index d492bcbb329..78ddb467ed7 100644 --- a/openshift-client-api/src/main/java/io/fabric8/openshift/client/OpenShiftClient.java +++ b/openshift-client-api/src/main/java/io/fabric8/openshift/client/OpenShiftClient.java @@ -16,13 +16,105 @@ package io.fabric8.openshift.client; -import io.fabric8.kubernetes.api.model.KubernetesList; import io.fabric8.kubernetes.client.KubernetesClient; import io.fabric8.kubernetes.client.RequestConfig; import io.fabric8.kubernetes.client.VersionInfo; -import io.fabric8.kubernetes.client.dsl.*; +import io.fabric8.kubernetes.client.dsl.AppsAPIGroupDSL; +import io.fabric8.kubernetes.client.dsl.AutoscalingAPIGroupDSL; +import io.fabric8.kubernetes.client.dsl.BatchAPIGroupDSL; +import io.fabric8.kubernetes.client.dsl.ExtensionsAPIGroupDSL; +import io.fabric8.kubernetes.client.dsl.FunctionCallable; +import io.fabric8.kubernetes.client.dsl.Gettable; +import io.fabric8.kubernetes.client.dsl.InOutCreateable; +import io.fabric8.kubernetes.client.dsl.MixedOperation; +import io.fabric8.kubernetes.client.dsl.Nameable; +import io.fabric8.kubernetes.client.dsl.Namespaceable; +import io.fabric8.kubernetes.client.dsl.NamespacedInOutCreateable; +import io.fabric8.kubernetes.client.dsl.NetworkAPIGroupDSL; +import io.fabric8.kubernetes.client.dsl.NonNamespaceOperation; +import io.fabric8.kubernetes.client.dsl.ParameterMixedOperation; +import io.fabric8.kubernetes.client.dsl.RbacAPIGroupDSL; +import io.fabric8.kubernetes.client.dsl.Resource; +import io.fabric8.kubernetes.client.dsl.SchedulingAPIGroupDSL; +import io.fabric8.kubernetes.client.dsl.StorageAPIGroupDSL; import io.fabric8.kubernetes.client.extension.SupportTestingClient; -import io.fabric8.openshift.api.model.*; +import io.fabric8.openshift.api.model.BrokerTemplateInstance; +import io.fabric8.openshift.api.model.BrokerTemplateInstanceList; +import io.fabric8.openshift.api.model.Build; +import io.fabric8.openshift.api.model.BuildConfig; +import io.fabric8.openshift.api.model.BuildConfigList; +import io.fabric8.openshift.api.model.BuildList; +import io.fabric8.openshift.api.model.ClusterNetwork; +import io.fabric8.openshift.api.model.ClusterNetworkList; +import io.fabric8.openshift.api.model.ClusterRole; +import io.fabric8.openshift.api.model.ClusterRoleBinding; +import io.fabric8.openshift.api.model.ClusterRoleBindingList; +import io.fabric8.openshift.api.model.ClusterRoleList; +import io.fabric8.openshift.api.model.DeploymentConfig; +import io.fabric8.openshift.api.model.DeploymentConfigList; +import io.fabric8.openshift.api.model.EgressNetworkPolicy; +import io.fabric8.openshift.api.model.EgressNetworkPolicyList; +import io.fabric8.openshift.api.model.Group; +import io.fabric8.openshift.api.model.GroupList; +import io.fabric8.openshift.api.model.HelmChartRepository; +import io.fabric8.openshift.api.model.HelmChartRepositoryList; +import io.fabric8.openshift.api.model.HostSubnet; +import io.fabric8.openshift.api.model.HostSubnetList; +import io.fabric8.openshift.api.model.Identity; +import io.fabric8.openshift.api.model.IdentityList; +import io.fabric8.openshift.api.model.Image; +import io.fabric8.openshift.api.model.ImageList; +import io.fabric8.openshift.api.model.ImageStream; +import io.fabric8.openshift.api.model.ImageStreamImage; +import io.fabric8.openshift.api.model.ImageStreamImport; +import io.fabric8.openshift.api.model.ImageStreamList; +import io.fabric8.openshift.api.model.ImageStreamMapping; +import io.fabric8.openshift.api.model.ImageStreamTag; +import io.fabric8.openshift.api.model.ImageStreamTagList; +import io.fabric8.openshift.api.model.ImageTag; +import io.fabric8.openshift.api.model.ImageTagList; +import io.fabric8.openshift.api.model.LocalResourceAccessReview; +import io.fabric8.openshift.api.model.LocalSubjectAccessReview; +import io.fabric8.openshift.api.model.NetNamespace; +import io.fabric8.openshift.api.model.NetNamespaceList; +import io.fabric8.openshift.api.model.OAuthAccessToken; +import io.fabric8.openshift.api.model.OAuthAccessTokenList; +import io.fabric8.openshift.api.model.OAuthAuthorizeToken; +import io.fabric8.openshift.api.model.OAuthAuthorizeTokenList; +import io.fabric8.openshift.api.model.OAuthClient; +import io.fabric8.openshift.api.model.OAuthClientAuthorization; +import io.fabric8.openshift.api.model.OAuthClientAuthorizationList; +import io.fabric8.openshift.api.model.OAuthClientList; +import io.fabric8.openshift.api.model.PodSecurityPolicyReview; +import io.fabric8.openshift.api.model.PodSecurityPolicySelfSubjectReview; +import io.fabric8.openshift.api.model.PodSecurityPolicySubjectReview; +import io.fabric8.openshift.api.model.RangeAllocation; +import io.fabric8.openshift.api.model.RangeAllocationList; +import io.fabric8.openshift.api.model.ResourceAccessReview; +import io.fabric8.openshift.api.model.ResourceAccessReviewResponse; +import io.fabric8.openshift.api.model.Role; +import io.fabric8.openshift.api.model.RoleBinding; +import io.fabric8.openshift.api.model.RoleBindingList; +import io.fabric8.openshift.api.model.RoleBindingRestriction; +import io.fabric8.openshift.api.model.RoleBindingRestrictionList; +import io.fabric8.openshift.api.model.RoleList; +import io.fabric8.openshift.api.model.Route; +import io.fabric8.openshift.api.model.RouteList; +import io.fabric8.openshift.api.model.SecurityContextConstraints; +import io.fabric8.openshift.api.model.SecurityContextConstraintsList; +import io.fabric8.openshift.api.model.SelfSubjectRulesReview; +import io.fabric8.openshift.api.model.SubjectAccessReview; +import io.fabric8.openshift.api.model.SubjectAccessReviewResponse; +import io.fabric8.openshift.api.model.SubjectRulesReview; +import io.fabric8.openshift.api.model.Template; +import io.fabric8.openshift.api.model.TemplateInstance; +import io.fabric8.openshift.api.model.TemplateInstanceList; +import io.fabric8.openshift.api.model.TemplateList; +import io.fabric8.openshift.api.model.User; +import io.fabric8.openshift.api.model.UserIdentityMapping; +import io.fabric8.openshift.api.model.UserList; +import io.fabric8.openshift.api.model.UserOAuthAccessToken; +import io.fabric8.openshift.api.model.UserOAuthAccessTokenList; import io.fabric8.openshift.api.model.miscellaneous.apiserver.v1.APIRequestCount; import io.fabric8.openshift.api.model.miscellaneous.apiserver.v1.APIRequestCountList; import io.fabric8.openshift.api.model.miscellaneous.cloudcredential.v1.CredentialsRequest; @@ -35,7 +127,26 @@ import io.fabric8.openshift.api.model.miscellaneous.network.operator.v1.EgressRouterList; import io.fabric8.openshift.api.model.miscellaneous.network.operator.v1.OperatorPKI; import io.fabric8.openshift.api.model.miscellaneous.network.operator.v1.OperatorPKIList; -import io.fabric8.openshift.client.dsl.*; +import io.fabric8.openshift.client.dsl.BuildConfigResource; +import io.fabric8.openshift.client.dsl.BuildResource; +import io.fabric8.openshift.client.dsl.DeployableScalableResource; +import io.fabric8.openshift.client.dsl.MachineConfigurationAPIGroupDSL; +import io.fabric8.openshift.client.dsl.NameableCreateOrDeleteable; +import io.fabric8.openshift.client.dsl.OpenShiftClusterAutoscalingAPIGroupDSL; +import io.fabric8.openshift.client.dsl.OpenShiftConfigAPIGroupDSL; +import io.fabric8.openshift.client.dsl.OpenShiftConsoleAPIGroupDSL; +import io.fabric8.openshift.client.dsl.OpenShiftHiveAPIGroupDSL; +import io.fabric8.openshift.client.dsl.OpenShiftMachineAPIGroupDSL; +import io.fabric8.openshift.client.dsl.OpenShiftMonitoringAPIGroupDSL; +import io.fabric8.openshift.client.dsl.OpenShiftOperatorAPIGroupDSL; +import io.fabric8.openshift.client.dsl.OpenShiftOperatorHubAPIGroupDSL; +import io.fabric8.openshift.client.dsl.OpenShiftQuotaAPIGroupDSL; +import io.fabric8.openshift.client.dsl.OpenShiftStorageVersionMigratorApiGroupDSL; +import io.fabric8.openshift.client.dsl.OpenShiftTunedAPIGroupDSL; +import io.fabric8.openshift.client.dsl.OpenShiftWhereaboutsAPIGroupDSL; +import io.fabric8.openshift.client.dsl.ProjectOperation; +import io.fabric8.openshift.client.dsl.ProjectRequestOperation; +import io.fabric8.openshift.client.dsl.TemplateResource; import java.net.URL; @@ -448,7 +559,7 @@ public interface OpenShiftClient extends KubernetesClient, SupportTestingClient * * @return {@link ParameterMixedOperation} object for Template operations */ - ParameterMixedOperation> templates(); + ParameterMixedOperation templates(); /** * API entrypoint for TemplateInstance(template.openshift.io/v1) diff --git a/openshift-client-api/src/main/java/io/fabric8/openshift/client/dsl/TemplateResource.java b/openshift-client-api/src/main/java/io/fabric8/openshift/client/dsl/TemplateResource.java index 7620a103cc4..2595562b8df 100644 --- a/openshift-client-api/src/main/java/io/fabric8/openshift/client/dsl/TemplateResource.java +++ b/openshift-client-api/src/main/java/io/fabric8/openshift/client/dsl/TemplateResource.java @@ -15,85 +15,87 @@ */ package io.fabric8.openshift.client.dsl; +import io.fabric8.kubernetes.api.model.KubernetesList; import io.fabric8.kubernetes.client.dsl.Resource; +import io.fabric8.openshift.api.model.Template; import io.fabric8.openshift.client.ParameterValue; import java.io.File; import java.io.InputStream; import java.util.Map; -public interface TemplateResource extends Resource { +public interface TemplateResource extends Resource