From 4da625ec8a3854c1480127d622b320b56ea4ba92 Mon Sep 17 00:00:00 2001 From: Rohan Kumar Date: Fri, 21 Jun 2024 10:38:19 +0530 Subject: [PATCH] test(common): kubernetes mock server config can be exported to a valid .kube/config file fix (jkube-kit/common) : Update `KubernetesHelper.exportKubernetesClientConfigToFile` to add opinionated Cluster Context When using KubernetesClient with Kubernetes Mock Server, `kubernetesClient.getConfiguration()` returns a Config object with no context set. Handle this case in KubernetesMockServerUtil to create opinionated Context until this gets fixed in KubernetesMockServer Signed-off-by: Rohan Kumar --- review: KubernetesMockServerUtil is chained to KubernetesHelper Signed-off-by: Marc Nuri --- .../kit/common/util/KubernetesHelper.java | 5 +- .../kit/common/util/KubernetesHelperTest.java | 32 +++++++++++++ .../common/util/KubernetesMockServerUtil.java | 46 +++++++++++++++++++ 3 files changed, 81 insertions(+), 2 deletions(-) create mode 100644 jkube-kit/common/src/test/java/org/eclipse/jkube/kit/common/util/KubernetesMockServerUtil.java diff --git a/jkube-kit/common/src/main/java/org/eclipse/jkube/kit/common/util/KubernetesHelper.java b/jkube-kit/common/src/main/java/org/eclipse/jkube/kit/common/util/KubernetesHelper.java index 308812edee..977459fab2 100644 --- a/jkube-kit/common/src/main/java/org/eclipse/jkube/kit/common/util/KubernetesHelper.java +++ b/jkube-kit/common/src/main/java/org/eclipse/jkube/kit/common/util/KubernetesHelper.java @@ -13,12 +13,10 @@ */ package org.eclipse.jkube.kit.common.util; - import java.io.File; import java.io.IOException; import java.net.UnknownHostException; import java.nio.charset.StandardCharsets; -import java.nio.file.Files; import java.nio.file.Path; import java.time.Instant; import java.time.format.DateTimeFormatter; @@ -860,6 +858,9 @@ private static NamedCluster createKubeConfigClusterFromClient(io.fabric8.kuberne if (StringUtils.isNotBlank(kubernetesClientConfig.getCaCertData())) { clusterBuilder.withCertificateAuthorityData(kubernetesClientConfig.getCaCertData()); } + if (kubernetesClientConfig.isTrustCerts()) { + clusterBuilder.withInsecureSkipTlsVerify(true); + } return new NamedClusterBuilder().withName(Optional.ofNullable(kubernetesClientConfig.getCurrentContext()) .map(NamedContext::getContext) .map(Context::getCluster) diff --git a/jkube-kit/common/src/test/java/org/eclipse/jkube/kit/common/util/KubernetesHelperTest.java b/jkube-kit/common/src/test/java/org/eclipse/jkube/kit/common/util/KubernetesHelperTest.java index fa63ca1cc4..df2a7049aa 100644 --- a/jkube-kit/common/src/test/java/org/eclipse/jkube/kit/common/util/KubernetesHelperTest.java +++ b/jkube-kit/common/src/test/java/org/eclipse/jkube/kit/common/util/KubernetesHelperTest.java @@ -72,6 +72,7 @@ import io.fabric8.openshift.api.model.Template; import org.eclipse.jkube.kit.common.TestHttpStaticServer; import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.io.TempDir; import org.junit.jupiter.params.ParameterizedTest; @@ -454,6 +455,7 @@ void extractPodLabelSelector_withJobWithNoSelector_shouldReturnTemplateLabels() @Test + @DisplayName("when invalid target kubeconfig file provided, then thrown exception") void exportKubernetesClientConfigToFile_whenInvalidFileProvided_thenThrowException(@TempDir Path temporaryFolder) { // Given io.fabric8.kubernetes.client.Config kubernetesClientConfig = createKubernetesClientConfig(); @@ -465,6 +467,36 @@ void exportKubernetesClientConfigToFile_whenInvalidFileProvided_thenThrowExcepti } @Test + @DisplayName("should work with KubernetesClient config provided by KubernetesMockServer") + void exportKubernetesClientConfigToFile_worksWithKubernetesMockServer(@TempDir Path temporaryFolder) throws IOException { + // When + final Path result = KubernetesMockServerUtil.exportKubernetesClientConfigToFile(mockServer, temporaryFolder.resolve("config")); + // Then + final io.fabric8.kubernetes.api.model.Config kc = Serialization + .unmarshal(result.toFile(), io.fabric8.kubernetes.api.model.Config.class); + assertThat(kc) + .hasFieldOrPropertyWithValue("currentContext", "mock-server") + .satisfies(c -> assertThat(c.getContexts()) + .singleElement(InstanceOfAssertFactories.type(NamedContext.class)) + .hasFieldOrPropertyWithValue("name", "mock-server") + .hasFieldOrPropertyWithValue("context.namespace", "test") + .hasFieldOrPropertyWithValue("context.user", "mock-server-user") + .extracting("context.cluster").asString() + .matches("localhost:\\d+") + ) + .satisfies(c -> assertThat(c.getClusters()) + .singleElement(InstanceOfAssertFactories.type(NamedCluster.class)) + .hasFieldOrPropertyWithValue("cluster.insecureSkipTlsVerify", true) + .extracting("cluster.server", "name") + .allMatch(s -> s.toString().matches("(https://)?localhost:\\d+/?")) + ) + .satisfies(c -> assertThat(c.getUsers()) + .singleElement(InstanceOfAssertFactories.type(NamedAuthInfo.class)) + .hasFieldOrPropertyWithValue("name", "mock-server-user")); + } + + @Test + @DisplayName("should work with valid kube config") void exportKubernetesClientConfigToFile_whenValidTargetFile_thenWriteKubeConfigToFile(@TempDir Path temporaryFolder) throws IOException { // Given io.fabric8.kubernetes.client.Config kubernetesClientConfig = createKubernetesClientConfig(); diff --git a/jkube-kit/common/src/test/java/org/eclipse/jkube/kit/common/util/KubernetesMockServerUtil.java b/jkube-kit/common/src/test/java/org/eclipse/jkube/kit/common/util/KubernetesMockServerUtil.java new file mode 100644 index 0000000000..2023ddce00 --- /dev/null +++ b/jkube-kit/common/src/test/java/org/eclipse/jkube/kit/common/util/KubernetesMockServerUtil.java @@ -0,0 +1,46 @@ +/* + * Copyright (c) 2019 Red Hat, Inc. + * This program and the accompanying materials are made + * available under the terms of the Eclipse Public License 2.0 + * which is available at: + * + * https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * Red Hat, Inc. - initial API and implementation + */ +package org.eclipse.jkube.kit.common.util; + +import io.fabric8.kubernetes.api.model.NamedContext; +import io.fabric8.kubernetes.api.model.NamedContextBuilder; +import io.fabric8.kubernetes.client.Config; +import io.fabric8.kubernetes.client.ConfigBuilder; +import io.fabric8.kubernetes.client.KubernetesClient; +import io.fabric8.kubernetes.client.server.mock.KubernetesMockServer; + +import java.nio.file.Path; + +public class KubernetesMockServerUtil { + + private KubernetesMockServerUtil() { } + + // TODO: Remove after https://github.com/fabric8io/kubernetes-client/issues/6068 is fixed + public static Path exportKubernetesClientConfigToFile(KubernetesMockServer mockServer, Path targetKubeConfig) { + final KubernetesClient client = mockServer.createClient(); + final NamedContext mockServerContext = new NamedContextBuilder() + .withName("mock-server") + .withNewContext() + .withNamespace(client.getNamespace()) + .withCluster(String.format("%s:%d", mockServer.getHostName(), mockServer.getPort())) + .withUser("mock-server-user") + .endContext() + .build(); + final Config kubernetesClientConfig = new ConfigBuilder(client.getConfiguration()) + .addToContexts(mockServerContext) + .withCurrentContext(mockServerContext) + .build(); + return KubernetesHelper.exportKubernetesClientConfigToFile(kubernetesClientConfig, targetKubeConfig); + } +}