diff --git a/spring-cloud-kubernetes-integration-tests/load-balancer/pom.xml b/spring-cloud-kubernetes-integration-tests/load-balancer/pom.xml new file mode 100644 index 00000000..4f69d13b --- /dev/null +++ b/spring-cloud-kubernetes-integration-tests/load-balancer/pom.xml @@ -0,0 +1,36 @@ + + + + spring-cloud-kubernetes-integration-tests + org.springframework.cloud + 2.0.0-SNAPSHOT + + 4.0.0 + + load-balancer + + + + org.springframework.cloud + spring-cloud-starter-kubernetes-all + + + org.springframework.boot + spring-boot-starter-web + + + org.springframework.boot + spring-boot-starter-test + test + + + io.fabric8 + kubernetes-server-mock + 4.10.2 + test + + + + diff --git a/spring-cloud-kubernetes-integration-tests/load-balancer/src/main/java/org/spring/framework/kubernetes/loadbalancer/SimpleLoadBalancerApp.java b/spring-cloud-kubernetes-integration-tests/load-balancer/src/main/java/org/spring/framework/kubernetes/loadbalancer/SimpleLoadBalancerApp.java new file mode 100644 index 00000000..84ef41c8 --- /dev/null +++ b/spring-cloud-kubernetes-integration-tests/load-balancer/src/main/java/org/spring/framework/kubernetes/loadbalancer/SimpleLoadBalancerApp.java @@ -0,0 +1,31 @@ +package org.spring.framework.kubernetes.loadbalancer; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.boot.web.client.RestTemplateBuilder; +import org.springframework.cloud.client.loadbalancer.LoadBalanced; +import org.springframework.context.annotation.Bean; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RestController; +import org.springframework.web.client.RestTemplate; + +@SpringBootApplication +@RestController +public class SimpleLoadBalancerApp { + + public static void main(String[] args) { + SpringApplication.run(SimpleLoadBalancerApp.class, args); + } + + @Bean + @LoadBalanced + RestTemplate restTemplate() { + return new RestTemplateBuilder().build(); + } + + @GetMapping("/greeting") + public String greeting() { + return "greeting"; + } + +} diff --git a/spring-cloud-kubernetes-integration-tests/load-balancer/src/test/java/org/springframework/kubernetes/loadbalancer/LoadBalancerAllNamespacesTest.java b/spring-cloud-kubernetes-integration-tests/load-balancer/src/test/java/org/springframework/kubernetes/loadbalancer/LoadBalancerAllNamespacesTest.java new file mode 100644 index 00000000..e9533cb8 --- /dev/null +++ b/spring-cloud-kubernetes-integration-tests/load-balancer/src/test/java/org/springframework/kubernetes/loadbalancer/LoadBalancerAllNamespacesTest.java @@ -0,0 +1,71 @@ +package org.springframework.kubernetes.loadbalancer; + +import java.util.List; + +import io.fabric8.kubernetes.api.model.Endpoints; +import io.fabric8.kubernetes.api.model.ServicePortBuilder; +import io.fabric8.kubernetes.api.model.ServiceSpecBuilder; +import io.fabric8.kubernetes.client.Config; +import io.fabric8.kubernetes.client.KubernetesClient; +import io.fabric8.kubernetes.client.server.mock.KubernetesServer; +import org.junit.BeforeClass; +import org.junit.ClassRule; +import org.junit.Test; +import org.junit.jupiter.api.Assertions; +import org.junit.runner.RunWith; +import org.spring.framework.kubernetes.loadbalancer.SimpleLoadBalancerApp; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.test.context.junit4.SpringRunner; +import org.springframework.web.client.RestTemplate; + +@SpringBootTest(classes = {SimpleLoadBalancerApp.class}, webEnvironment = SpringBootTest.WebEnvironment.DEFINED_PORT, + properties = {"spring.cloud.kubernetes.discovery.all-namespaces=true"}) +@RunWith(SpringRunner.class) +public class LoadBalancerAllNamespacesTest { + + @Autowired + RestTemplate restTemplate; + @ClassRule + public static KubernetesServer server = new KubernetesServer(true, true); + + private static KubernetesClient client; + + @BeforeClass + public static void setup() { + client = server.getClient(); + + System.setProperty(Config.KUBERNETES_MASTER_SYSTEM_PROPERTY, client.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_HTTP2_DISABLE, "true"); + System.setProperty(Config.KUBERNETES_NAMESPACE_SYSTEM_PROPERTY, "test"); + } + + @Test + public void testLoadBalancerDifferentNamespace() { + createTestData("service-b", "b"); + String response = restTemplate.getForObject("http://service-b/greeting", String.class); + Assertions.assertNotNull(response); + Assertions.assertEquals("greeting", response); + } + + private void createTestData(String name, String namespace) { + client.services().inNamespace(namespace).createNew() + .withNewMetadata().withName(name).withNamespace(namespace).endMetadata() + .withSpec(new ServiceSpecBuilder() + .withPorts(new ServicePortBuilder().withProtocol("TCP").withPort(8080).build()) + .build()) + .done(); + client.endpoints().inNamespace(namespace).createNew() + .withNewMetadata().withName("service-a").withNamespace(namespace).endMetadata() + .addNewSubset() + .addNewAddress().withIp("localhost").endAddress() + .addNewPort().withName("http").withPort(8080).endPort() + .endSubset() + .done(); + } + +} diff --git a/spring-cloud-kubernetes-integration-tests/load-balancer/src/test/java/org/springframework/kubernetes/loadbalancer/LoadBalancerTest.java b/spring-cloud-kubernetes-integration-tests/load-balancer/src/test/java/org/springframework/kubernetes/loadbalancer/LoadBalancerTest.java new file mode 100644 index 00000000..09f24730 --- /dev/null +++ b/spring-cloud-kubernetes-integration-tests/load-balancer/src/test/java/org/springframework/kubernetes/loadbalancer/LoadBalancerTest.java @@ -0,0 +1,74 @@ +package org.springframework.kubernetes.loadbalancer; + +import io.fabric8.kubernetes.api.model.ServicePortBuilder; +import io.fabric8.kubernetes.api.model.ServiceSpecBuilder; +import io.fabric8.kubernetes.client.Config; +import io.fabric8.kubernetes.client.KubernetesClient; +import io.fabric8.kubernetes.client.server.mock.KubernetesServer; +import org.junit.BeforeClass; +import org.junit.ClassRule; +import org.junit.Test; +import org.junit.jupiter.api.Assertions; +import org.junit.runner.RunWith; +import org.spring.framework.kubernetes.loadbalancer.SimpleLoadBalancerApp; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.test.context.junit4.SpringRunner; +import org.springframework.web.client.RestTemplate; + +@SpringBootTest(classes = {SimpleLoadBalancerApp.class}, webEnvironment = SpringBootTest.WebEnvironment.DEFINED_PORT) +@RunWith(SpringRunner.class) +public class LoadBalancerTest { + + @Autowired + RestTemplate restTemplate; + @ClassRule + public static KubernetesServer server = new KubernetesServer(true, true); + + private static KubernetesClient client; + + @BeforeClass + public static void setup() { + client = server.getClient(); + + System.setProperty(Config.KUBERNETES_MASTER_SYSTEM_PROPERTY, client.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_HTTP2_DISABLE, "true"); + System.setProperty(Config.KUBERNETES_NAMESPACE_SYSTEM_PROPERTY, "test"); + } + + @Test + public void testLoadBalancerSameNamespace() { + createTestData("service-a", "test"); + String response = restTemplate.getForObject("http://service-a/greeting", String.class); + Assertions.assertNotNull(response); + Assertions.assertEquals("greeting", response); + } + + @Test + public void testLoadBalancerDifferentNamespace() { + createTestData("service-b", "b"); + Assertions.assertThrows(IllegalStateException.class, () -> restTemplate + .getForObject("http://service-b/greeting", String.class)); + } + + private void createTestData(String name, String namespace) { + client.services().inNamespace(namespace).createNew() + .withNewMetadata().withName(name).endMetadata() + .withSpec(new ServiceSpecBuilder() + .withPorts(new ServicePortBuilder().withProtocol("TCP").withPort(8080).build()) + .build()) + .done(); + client.endpoints().inNamespace(namespace).createNew() + .withNewMetadata().withName("service-a").endMetadata() + .addNewSubset() + .addNewAddress().withIp("localhost").endAddress() + .addNewPort().withName("http").withPort(8080).endPort() + .endSubset() + .done(); + } + +} diff --git a/spring-cloud-kubernetes-integration-tests/pom.xml b/spring-cloud-kubernetes-integration-tests/pom.xml index c666a61e..fcbd148b 100644 --- a/spring-cloud-kubernetes-integration-tests/pom.xml +++ b/spring-cloud-kubernetes-integration-tests/pom.xml @@ -133,6 +133,7 @@ simple-configmap discovery + load-balancer diff --git a/spring-cloud-starter-kubernetes-all/pom.xml b/spring-cloud-starter-kubernetes-all/pom.xml index b0d46cb5..fd9567f0 100644 --- a/spring-cloud-starter-kubernetes-all/pom.xml +++ b/spring-cloud-starter-kubernetes-all/pom.xml @@ -46,6 +46,11 @@ spring-cloud-kubernetes-discovery + + org.springframework.cloud + spring-cloud-starter-loadbalancer + +