From dcd3e04c177320f03123b2f777b1a0d294986e5f Mon Sep 17 00:00:00 2001 From: Rohan Kumar Date: Fri, 12 Jul 2024 10:00:39 +0200 Subject: [PATCH] feat(api): add DSL entrypoint `getAPIVersions()` in Client interface Add DSL entrypoint `getAPIVersions()` in Client interface Signed-off-by: Rohan Kumar (cherry picked from commit 093d8cd04b52ebdc9d5fd180f1cf2b1ef7f8f9e9) Signed-off-by: Marc Nuri --- CHANGELOG.md | 5 ++ .../io/fabric8/kubernetes/client/Client.java | 10 +++ .../client/extension/ClientAdapter.java | 6 ++ .../kubernetes/client/impl/BaseClient.java | 7 ++ .../client/impl/APIVersionsTest.java | 80 +++++++++++++++++++ .../io/fabric8/kubernetes/APIVersionsIT.java | 46 +++++++++++ 6 files changed, 154 insertions(+) create mode 100644 kubernetes-client/src/test/java/io/fabric8/kubernetes/client/impl/APIVersionsTest.java create mode 100644 kubernetes-itests/src/test/java/io/fabric8/kubernetes/APIVersionsIT.java diff --git a/CHANGELOG.md b/CHANGELOG.md index a77bd4cfbff..6237be1130e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,10 @@ ## CHANGELOG +### 6.13.2 (2024-08-09) + +#### Bugs +* Fix #6066: Added support for missing `v1.APIVersions` in KubernetesClient + ### 6.13.1 (2024-07-02) #### Bugs diff --git a/kubernetes-client-api/src/main/java/io/fabric8/kubernetes/client/Client.java b/kubernetes-client-api/src/main/java/io/fabric8/kubernetes/client/Client.java index bf9a2839b04..fef95d5e022 100644 --- a/kubernetes-client-api/src/main/java/io/fabric8/kubernetes/client/Client.java +++ b/kubernetes-client-api/src/main/java/io/fabric8/kubernetes/client/Client.java @@ -18,6 +18,7 @@ import io.fabric8.kubernetes.api.model.APIGroup; import io.fabric8.kubernetes.api.model.APIGroupList; import io.fabric8.kubernetes.api.model.APIResourceList; +import io.fabric8.kubernetes.api.model.APIVersions; import io.fabric8.kubernetes.api.model.HasMetadata; import io.fabric8.kubernetes.api.model.KubernetesResource; import io.fabric8.kubernetes.api.model.KubernetesResourceList; @@ -108,6 +109,15 @@ public interface Client extends Closeable { @Override void close(); + /** + * Get the available APIversions. APIVersions lists the versions that are available, + * to allow clients to discover the API at /api, which is the root path of the + * legacy v1 API. + * + * @return the {@link APIVersions} object + */ + APIVersions getAPIVersions(); + /** * Returns the api groups. This does not include the core/legacy v1 apiVersion. * diff --git a/kubernetes-client-api/src/main/java/io/fabric8/kubernetes/client/extension/ClientAdapter.java b/kubernetes-client-api/src/main/java/io/fabric8/kubernetes/client/extension/ClientAdapter.java index 149d72e230b..b6064e865cf 100644 --- a/kubernetes-client-api/src/main/java/io/fabric8/kubernetes/client/extension/ClientAdapter.java +++ b/kubernetes-client-api/src/main/java/io/fabric8/kubernetes/client/extension/ClientAdapter.java @@ -18,6 +18,7 @@ import io.fabric8.kubernetes.api.model.APIGroup; import io.fabric8.kubernetes.api.model.APIGroupList; import io.fabric8.kubernetes.api.model.APIResourceList; +import io.fabric8.kubernetes.api.model.APIVersions; import io.fabric8.kubernetes.api.model.HasMetadata; import io.fabric8.kubernetes.api.model.KubernetesResource; import io.fabric8.kubernetes.api.model.KubernetesResourceList; @@ -117,6 +118,11 @@ public APIGroupList getApiGroups() { return client.getApiGroups(); } + @Override + public APIVersions getAPIVersions() { + return client.getAPIVersions(); + } + @Override public APIGroup getApiGroup(String name) { return client.getApiGroup(name); 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 d29602b0327..45b0da8550e 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 @@ -18,6 +18,7 @@ import io.fabric8.kubernetes.api.model.APIGroup; import io.fabric8.kubernetes.api.model.APIGroupList; import io.fabric8.kubernetes.api.model.APIResourceList; +import io.fabric8.kubernetes.api.model.APIVersions; import io.fabric8.kubernetes.api.model.GenericKubernetesResource; import io.fabric8.kubernetes.api.model.HasMetadata; import io.fabric8.kubernetes.api.model.KubernetesResource; @@ -79,6 +80,7 @@ public void onClose(Executor executor) { }; public static final String APIS = "/apis"; + private static final String API = "/api"; private URL masterUrl; private String apiVersion; @@ -297,6 +299,11 @@ public APIGroup getApiGroup(String name) { return getOperationSupport().restCall(APIGroup.class, APIS, name); } + @Override + public APIVersions getAPIVersions() { + return getOperationSupport().restCall(APIVersions.class, API); + } + private OperationSupport getOperationSupport() { if (operationSupport == null) { this.operationSupport = new OperationSupport(this); diff --git a/kubernetes-client/src/test/java/io/fabric8/kubernetes/client/impl/APIVersionsTest.java b/kubernetes-client/src/test/java/io/fabric8/kubernetes/client/impl/APIVersionsTest.java new file mode 100644 index 00000000000..70f95a6514d --- /dev/null +++ b/kubernetes-client/src/test/java/io/fabric8/kubernetes/client/impl/APIVersionsTest.java @@ -0,0 +1,80 @@ +/* + * 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.impl; + +import io.fabric8.kubernetes.client.Config; +import io.fabric8.kubernetes.client.ConfigBuilder; +import io.fabric8.kubernetes.client.KubernetesClient; +import io.fabric8.kubernetes.client.http.HttpClient; +import io.fabric8.kubernetes.client.http.HttpRequest; +import io.fabric8.kubernetes.client.http.TestHttpResponse; +import io.fabric8.kubernetes.client.utils.KubernetesSerialization; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.mockito.ArgumentCaptor; +import org.mockito.Mockito; + +import java.io.IOException; +import java.util.ArrayList; +import java.util.List; +import java.util.concurrent.CompletableFuture; + +import static org.assertj.core.api.AssertionsForInterfaceTypes.assertThat; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + +class APIVersionsTest { + private HttpClient mockClient; + private KubernetesClient kubernetesClient; + private List builders; + + @BeforeEach + public void setUp() throws IOException { + builders = new ArrayList<>(); + this.mockClient = Mockito.mock(HttpClient.class, Mockito.RETURNS_DEEP_STUBS); + Config config = new ConfigBuilder().withMasterUrl("https://localhost:8443/").build(); + when(mockClient.sendAsync(any(), Mockito.eq(byte[].class))) + .thenReturn(CompletableFuture.completedFuture(TestHttpResponse.from(200, + "{\"kind\":\"Pod\", \"apiVersion\":\"v1\"}"))); + kubernetesClient = new KubernetesClientImpl(mockClient, config, () -> Runnable::run, + new KubernetesSerialization()); + Mockito.when(mockClient.newHttpRequestBuilder()).thenAnswer(answer -> { + HttpRequest.Builder result = Mockito.mock(HttpRequest.Builder.class, Mockito.RETURNS_SELF); + builders.add(result); + return result; + }); + } + + @AfterEach + void tearDown() { + kubernetesClient.close(); + kubernetesClient = null; + } + + @Test + void getApiVersions() { + // When + kubernetesClient.getAPIVersions(); + // Then + verify(mockClient).sendAsync(any(), any()); + ArgumentCaptor stringCaptor = ArgumentCaptor.forClass(String.class); + verify(builders.get(0)).uri(stringCaptor.capture()); + assertThat(stringCaptor.getValue()) + .isEqualTo("https://localhost:8443/api"); + } +} diff --git a/kubernetes-itests/src/test/java/io/fabric8/kubernetes/APIVersionsIT.java b/kubernetes-itests/src/test/java/io/fabric8/kubernetes/APIVersionsIT.java new file mode 100644 index 00000000000..da719ee11f9 --- /dev/null +++ b/kubernetes-itests/src/test/java/io/fabric8/kubernetes/APIVersionsIT.java @@ -0,0 +1,46 @@ +/* + * Copyright (C) 2015 Red Hat, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package io.fabric8.kubernetes; + +import io.fabric8.kubernetes.api.model.APIVersions; +import io.fabric8.kubernetes.api.model.ServerAddressByClientCIDR; +import io.fabric8.kubernetes.client.KubernetesClient; +import org.assertj.core.api.InstanceOfAssertFactories; +import org.junit.jupiter.api.Test; + +import java.util.Collections; + +import static org.assertj.core.api.AssertionsForClassTypes.assertThat; + +class APIVersionsIT { + KubernetesClient client; + + @Test + void testApiVersions() { + // Given + When + APIVersions apiVersions = client.getAPIVersions(); + // Then + assertThat(apiVersions) + .isNotNull() + .hasFieldOrPropertyWithValue("versions", Collections.singletonList("v1")) + .extracting(APIVersions::getServerAddressByClientCIDRs) + .asInstanceOf(InstanceOfAssertFactories.list(ServerAddressByClientCIDR.class)) + .singleElement() + .hasFieldOrPropertyWithValue("clientCIDR", "0.0.0.0/0") + .hasFieldOrPropertyWithValue("serverAddress", + String.format("%s:%d", client.getMasterUrl().getHost(), client.getMasterUrl().getPort())); + } +}