diff --git a/spring-cloud-kubernetes-fabric8-autoconfig/src/main/java/org/springframework/cloud/kubernetes/fabric8/Fabric8InfoContributor.java b/spring-cloud-kubernetes-fabric8-autoconfig/src/main/java/org/springframework/cloud/kubernetes/fabric8/Fabric8InfoContributor.java index 59c1b5b7..73752ceb 100644 --- a/spring-cloud-kubernetes-fabric8-autoconfig/src/main/java/org/springframework/cloud/kubernetes/fabric8/Fabric8InfoContributor.java +++ b/spring-cloud-kubernetes-fabric8-autoconfig/src/main/java/org/springframework/cloud/kubernetes/fabric8/Fabric8InfoContributor.java @@ -16,7 +16,7 @@ package org.springframework.cloud.kubernetes.fabric8; -import java.util.HashMap; +import java.util.Collections; import java.util.Map; import io.fabric8.kubernetes.api.model.Pod; @@ -24,6 +24,7 @@ import io.fabric8.kubernetes.api.model.Pod; import org.springframework.boot.actuate.info.InfoContributor; import org.springframework.cloud.kubernetes.commons.AbstractKubernetesInfoContributor; import org.springframework.cloud.kubernetes.commons.PodUtils; +import org.springframework.util.CollectionUtils; /** * Kubernetes implementation of {@link InfoContributor}. @@ -32,7 +33,7 @@ import org.springframework.cloud.kubernetes.commons.PodUtils; */ public class Fabric8InfoContributor extends AbstractKubernetesInfoContributor { - private PodUtils utils; + private final PodUtils utils; public Fabric8InfoContributor(PodUtils utils) { this.utils = utils; @@ -41,18 +42,19 @@ public class Fabric8InfoContributor extends AbstractKubernetesInfoContributor { @Override public Map getDetails() { Pod current = this.utils.currentPod().get(); - Map details = new HashMap<>(); - boolean inside = current != null; - details.put(INSIDE, inside); - if (inside) { + + if (current != null) { + Map details = CollectionUtils.newHashMap(7); + details.put(INSIDE, true); details.put(NAMESPACE, current.getMetadata().getNamespace()); details.put(POD_NAME, current.getMetadata().getName()); details.put(POD_IP, current.getStatus().getPodIP()); details.put(SERVICE_ACCOUNT, current.getSpec().getServiceAccountName()); details.put(NODE_NAME, current.getSpec().getNodeName()); details.put(HOST_IP, current.getStatus().getHostIP()); + return details; } - return details; + return Collections.singletonMap(INSIDE, false); } } diff --git a/spring-cloud-kubernetes-fabric8-autoconfig/src/test/java/org/springframework/cloud/kubernetes/Fabric8InsideInfoContributorTest.java b/spring-cloud-kubernetes-fabric8-autoconfig/src/test/java/org/springframework/cloud/kubernetes/Fabric8InsideInfoContributorTest.java new file mode 100644 index 00000000..371a5229 --- /dev/null +++ b/spring-cloud-kubernetes-fabric8-autoconfig/src/test/java/org/springframework/cloud/kubernetes/Fabric8InsideInfoContributorTest.java @@ -0,0 +1,134 @@ +/* + * Copyright 2013-2019 the original author or authors. + * + * 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 + * + * https://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 org.springframework.cloud.kubernetes; + +import java.util.Map; + +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.core.type.TypeReference; +import com.fasterxml.jackson.databind.ObjectMapper; +import io.fabric8.kubernetes.api.model.Pod; +import io.fabric8.kubernetes.api.model.PodBuilder; +import io.fabric8.kubernetes.api.model.PodSpec; +import io.fabric8.kubernetes.api.model.PodStatus; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; +import org.mockito.Mockito; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.cloud.kubernetes.commons.PodUtils; +import org.springframework.cloud.kubernetes.example.App; +import org.springframework.cloud.kubernetes.fabric8.Fabric8InfoContributor; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.context.annotation.Import; +import org.springframework.context.annotation.Primary; +import org.springframework.http.MediaType; +import org.springframework.test.web.reactive.server.WebTestClient; + +/** + * @author wind57 + * + * test proper fields being set in /actuator/info + */ + +@Import(Fabric8InsideInfoContributorTest.InfoContributorTestConfig.class) +@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT, classes = App.class, + properties = { "management.endpoint.health.show-details=always", "management.info.kubernetes.enabled=false" }) +public class Fabric8InsideInfoContributorTest { + + @Autowired + private WebTestClient webClient; + + @Value("${local.server.port}") + private int port; + + @Test + public void test() { + this.webClient.get().uri("http://localhost:{port}/actuator/info", this.port).accept(MediaType.APPLICATION_JSON) + .exchange().expectStatus().isOk().expectBody(String.class) + .value(Fabric8InsideInfoContributorTest::validateInfo); + } + + private static Pod stubPod() { + + PodStatus status = new PodStatus(); + status.setPodIP("10.1.1.1"); + status.setHostIP("192.160.10.3"); + + PodSpec spec = new PodSpec(); + spec.setServiceAccountName("serviceAccountName"); + spec.setNodeName("nodeName"); + + return new PodBuilder().withNewMetadata().withName("pod").withNamespace("namespace").endMetadata() + .withStatus(status).withSpec(spec).build(); + } + + /** + *
+	 * {
+	 *   "kubernetes": {
+	 *     "nodeName": "nodeName",
+	 *     "podIp": "10.1.1.1",
+	 *     "hostIp": "192.160.10.3",
+	 *     "namespace": "namespace",
+	 *     "podName": "pod",
+	 *     "serviceAccount": "serviceAccountName",
+	 *     "inside": true
+	 *   }
+	 * }
+	 *  
+ */ + @SuppressWarnings("unchecked") + private static void validateInfo(String input) { + try { + Map map = new ObjectMapper().readValue(input, new TypeReference>() { + + }); + Map infoProperties = (Map) map.get("kubernetes"); + + Assertions.assertEquals("nodeName", infoProperties.get("nodeName")); + Assertions.assertEquals("10.1.1.1", infoProperties.get("podIp")); + Assertions.assertEquals("192.160.10.3", infoProperties.get("hostIp")); + Assertions.assertEquals("namespace", infoProperties.get("namespace")); + Assertions.assertEquals("pod", infoProperties.get("podName")); + Assertions.assertEquals("serviceAccountName", infoProperties.get("serviceAccount")); + Assertions.assertTrue((Boolean) infoProperties.get("inside")); + + } + catch (JsonProcessingException e) { + throw new RuntimeException(e); + } + } + + @Configuration + static class InfoContributorTestConfig { + + @Bean + @Primary + public Fabric8InfoContributor testInfoContributor() { + @SuppressWarnings("unchecked") + PodUtils utils = Mockito.mock(PodUtils.class); + Mockito.when(utils.currentPod()).thenReturn(Fabric8InsideInfoContributorTest::stubPod); + return new Fabric8InfoContributor(utils); + } + + } + +} diff --git a/spring-cloud-kubernetes-fabric8-autoconfig/src/test/java/org/springframework/cloud/kubernetes/InfoContributorTest.java b/spring-cloud-kubernetes-fabric8-autoconfig/src/test/java/org/springframework/cloud/kubernetes/Fabric8NotInsideInfoContributorTest.java similarity index 63% rename from spring-cloud-kubernetes-fabric8-autoconfig/src/test/java/org/springframework/cloud/kubernetes/InfoContributorTest.java rename to spring-cloud-kubernetes-fabric8-autoconfig/src/test/java/org/springframework/cloud/kubernetes/Fabric8NotInsideInfoContributorTest.java index 79e7fdfa..d6c99d7e 100644 --- a/spring-cloud-kubernetes-fabric8-autoconfig/src/test/java/org/springframework/cloud/kubernetes/InfoContributorTest.java +++ b/spring-cloud-kubernetes-fabric8-autoconfig/src/test/java/org/springframework/cloud/kubernetes/Fabric8NotInsideInfoContributorTest.java @@ -16,29 +16,28 @@ package org.springframework.cloud.kubernetes; -import io.fabric8.kubernetes.client.Config; +import java.util.Map; + +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.core.type.TypeReference; +import com.fasterxml.jackson.databind.ObjectMapper; import io.fabric8.kubernetes.client.KubernetesClient; import io.fabric8.kubernetes.server.mock.KubernetesServer; -import org.junit.BeforeClass; -import org.junit.ClassRule; -import org.junit.Test; -import org.junit.runner.RunWith; +import org.junit.jupiter.api.AfterAll; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.Test; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Value; import org.springframework.boot.test.context.SpringBootTest; import org.springframework.cloud.kubernetes.example.App; import org.springframework.http.MediaType; -import org.springframework.test.context.junit4.SpringRunner; import org.springframework.test.web.reactive.server.WebTestClient; -import static org.hamcrest.Matchers.containsString; - -@RunWith(SpringRunner.class) @SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT, classes = App.class) -public class InfoContributorTest { +public class Fabric8NotInsideInfoContributorTest { - @ClassRule public static KubernetesServer server = new KubernetesServer(); private static KubernetesClient mockClient; @@ -49,23 +48,36 @@ public class InfoContributorTest { @Value("${local.server.port}") private int port; - @BeforeClass + @BeforeAll public static void setUpBeforeClass() { + server.before(); mockClient = server.getClient(); + } - // Configure the kubernetes master url to point to the mock server - System.setProperty(Config.KUBERNETES_MASTER_SYSTEM_PROPERTY, mockClient.getConfiguration().getMasterUrl()); - System.setProperty(Config.KUBERNETES_TRUST_CERT_SYSTEM_PROPERTY, "true"); - System.setProperty(Config.KUBERNETES_AUTH_TRYKUBECONFIG_SYSTEM_PROPERTY, "false"); - System.setProperty(Config.KUBERNETES_AUTH_TRYSERVICEACCOUNT_SYSTEM_PROPERTY, "false"); - System.setProperty(Config.KUBERNETES_NAMESPACE_SYSTEM_PROPERTY, "test"); - System.setProperty(Config.KUBERNETES_HTTP2_DISABLE, "true"); + @AfterAll + public static void afterAll() { + server.after(); } @Test public void infoEndpointShouldContainKubernetes() { this.webClient.get().uri("http://localhost:{port}/actuator/info", this.port).accept(MediaType.APPLICATION_JSON) - .exchange().expectStatus().isOk().expectBody(String.class).value(containsString("kubernetes")); + .exchange().expectStatus().isOk().expectBody(String.class).value(this::validateInfo); + } + + // {"kubernetes":{"inside":false}} + @SuppressWarnings("unchecked") + private void validateInfo(String input) { + try { + Map map = new ObjectMapper().readValue(input, new TypeReference>() { + + }); + Map kubernetesProperties = (Map) map.get("kubernetes"); + Assertions.assertFalse((Boolean) kubernetesProperties.get("inside")); + } + catch (JsonProcessingException e) { + throw new RuntimeException(e); + } } }