#54: Fix handling of endpoints with multiple addresses.
This commit is contained in:
11
pom.xml
11
pom.xml
@@ -89,6 +89,7 @@
|
||||
|
||||
<!-- Maven Plugin Versions -->
|
||||
<maven-compiler-plugin.version>3.5</maven-compiler-plugin.version>
|
||||
<maven-surefire-plugin.version>2.19.1</maven-surefire-plugin.version>
|
||||
<gmavenplus-plugin.version>1.2</gmavenplus-plugin.version>
|
||||
<sundrio-plugin.vesion>0.3.4</sundrio-plugin.vesion>
|
||||
</properties>
|
||||
@@ -262,6 +263,16 @@
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-surefire-plugin</artifactId>
|
||||
<version>${maven-surefire-plugin.version}</version>
|
||||
<inherited>true</inherited>
|
||||
<configuration>
|
||||
<forkCount>1</forkCount>
|
||||
<reuseForks>false</reuseForks>
|
||||
</configuration>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>io.sundr</groupId>
|
||||
<artifactId>sundr-maven-plugin</artifactId>
|
||||
|
||||
@@ -51,6 +51,38 @@
|
||||
<artifactId>spring-cloud-context</artifactId>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
|
||||
<!-- Testing Dependencies -->
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-test</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-web</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>io.fabric8</groupId>
|
||||
<artifactId>kubernetes-client</artifactId>
|
||||
<type>test-jar</type>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>io.fabric8</groupId>
|
||||
<artifactId>mockwebserver</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.spockframework</groupId>
|
||||
<artifactId>spock-spring</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
</project>
|
||||
@@ -67,7 +67,10 @@ public class KubernetesDiscoveryClient implements DiscoveryClient {
|
||||
return endpoints.getSubsets()
|
||||
.stream()
|
||||
.filter(s -> s.getAddresses().get(0).getTargetRef().getName().equals(podName))
|
||||
.map(s -> (ServiceInstance) new KubernetesServiceInstance(serviceName, s.getPorts().iterator().next().getName(), s, false))
|
||||
.map(s -> (ServiceInstance) new KubernetesServiceInstance(serviceName,
|
||||
s.getAddresses().stream().findFirst().orElseThrow(IllegalStateException::new),
|
||||
s.getPorts().stream().findFirst().orElseThrow(IllegalStateException::new),
|
||||
false))
|
||||
.findFirst().orElse(defaultInstance);
|
||||
} catch (Throwable t) {
|
||||
return defaultInstance;
|
||||
@@ -79,7 +82,8 @@ public class KubernetesDiscoveryClient implements DiscoveryClient {
|
||||
Assert.notNull(serviceId, "[Assertion failed] - the object argument must be null");
|
||||
return Optional.ofNullable(client.endpoints().withName(serviceId).get()).orElse(new Endpoints())
|
||||
.getSubsets()
|
||||
.stream().map(s -> new KubernetesServiceInstance(serviceId, s.getPorts().iterator().next().getName(), s, false))
|
||||
.stream()
|
||||
.flatMap(s -> s.getAddresses().stream().map(a -> (ServiceInstance) new KubernetesServiceInstance(serviceId, a ,s.getPorts().stream().findFirst().orElseThrow(IllegalStateException::new), false)))
|
||||
.collect(Collectors.toList());
|
||||
|
||||
}
|
||||
|
||||
@@ -16,14 +16,13 @@
|
||||
|
||||
package io.fabric8.spring.cloud.discovery;
|
||||
|
||||
import io.fabric8.kubernetes.api.model.EndpointAddress;
|
||||
import io.fabric8.kubernetes.api.model.EndpointPort;
|
||||
import io.fabric8.kubernetes.api.model.EndpointSubset;
|
||||
import org.springframework.cloud.client.ServiceInstance;
|
||||
|
||||
import java.net.URI;
|
||||
import java.net.URISyntaxException;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import static io.fabric8.kubernetes.client.utils.Utils.isNotNullOrEmpty;
|
||||
@@ -36,14 +35,14 @@ public class KubernetesServiceInstance implements ServiceInstance {
|
||||
private static final String COLN = ":";
|
||||
|
||||
private final String serviceId;
|
||||
private final String portName;
|
||||
private final EndpointSubset subset;
|
||||
private final EndpointAddress endpointAddress;
|
||||
private final EndpointPort endpointPort;
|
||||
private final Boolean secure;
|
||||
|
||||
public KubernetesServiceInstance(String serviceId, String portName, EndpointSubset subset, Boolean secure) {
|
||||
public KubernetesServiceInstance(String serviceId, EndpointAddress endpointAddress, EndpointPort endpointPort, Boolean secure) {
|
||||
this.serviceId = serviceId;
|
||||
this.portName = portName;
|
||||
this.subset = subset;
|
||||
this.endpointAddress = endpointAddress;
|
||||
this.endpointPort = endpointPort;
|
||||
this.secure = secure;
|
||||
}
|
||||
|
||||
@@ -54,26 +53,12 @@ public class KubernetesServiceInstance implements ServiceInstance {
|
||||
|
||||
@Override
|
||||
public String getHost() {
|
||||
if (subset.getAddresses().isEmpty()) {
|
||||
throw new IllegalStateException("Endpoint subset has no addresses.");
|
||||
}
|
||||
return subset.getAddresses().get(0).getIp();
|
||||
return endpointAddress.getIp();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getPort() {
|
||||
if (subset.getPorts().isEmpty()) {
|
||||
throw new IllegalStateException("Endpoint subset has no ports.");
|
||||
} else if (isNullOrEmpty(portName) && subset.getPorts().size() == 1) {
|
||||
return subset.getPorts().get(0).getPort();
|
||||
} else if (isNotNullOrEmpty(portName)) {
|
||||
for (EndpointPort port : subset.getPorts()) {
|
||||
if (portName.endsWith(port.getName())) {
|
||||
return port.getPort();
|
||||
}
|
||||
}
|
||||
}
|
||||
throw new IllegalStateException("Endpoint subset has no matching ports.");
|
||||
return endpointPort.getPort();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -0,0 +1,84 @@
|
||||
package io.fabric8.spring.cloud.discovery
|
||||
|
||||
import io.fabric8.kubernetes.api.model.EndpointsBuilder
|
||||
import io.fabric8.kubernetes.client.Config
|
||||
import io.fabric8.kubernetes.client.KubernetesClient
|
||||
import io.fabric8.kubernetes.server.mock.KubernetesMockServer
|
||||
import org.springframework.cloud.client.ServiceInstance
|
||||
import org.springframework.cloud.client.discovery.DiscoveryClient
|
||||
import spock.lang.Specification
|
||||
|
||||
class KubernetesDiscoveryClientTest extends Specification {
|
||||
|
||||
private static KubernetesMockServer mockServer = new KubernetesMockServer()
|
||||
private static KubernetesClient mockClient
|
||||
|
||||
|
||||
def setupSpec() {
|
||||
mockServer.init()
|
||||
mockClient = mockServer.createClient()
|
||||
|
||||
//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")
|
||||
}
|
||||
|
||||
def cleanupSpec() {
|
||||
mockServer.destroy();
|
||||
}
|
||||
|
||||
def "Should be able to handle endpoints single address"() {
|
||||
given:
|
||||
mockServer.expect().get().withPath("/api/v1/namespaces/test/endpoints/endpoint").andReturn(200, new EndpointsBuilder()
|
||||
.withNewMetadata()
|
||||
.withName("endpoint")
|
||||
.endMetadata()
|
||||
.addNewSubset()
|
||||
.addNewAddress()
|
||||
.withIp("ip1")
|
||||
.endAddress()
|
||||
.addNewPort("http",80,"TCP")
|
||||
.endSubset()
|
||||
.build()).once()
|
||||
|
||||
DiscoveryClient discoveryClient = new KubernetesDiscoveryClient(mockClient, new KubernetesDiscoveryProperties())
|
||||
when:
|
||||
List<ServiceInstance> instances = discoveryClient.getInstances("endpoint")
|
||||
then:
|
||||
instances != null
|
||||
instances.size() == 1
|
||||
instances.find({s -> s.host == "ip1"})
|
||||
}
|
||||
|
||||
|
||||
|
||||
def "Should be able to handle endpoints multiple addresses"() {
|
||||
given:
|
||||
mockServer.expect().get().withPath("/api/v1/namespaces/test/endpoints/endpoint").andReturn(200, new EndpointsBuilder()
|
||||
.withNewMetadata()
|
||||
.withName("endpoint")
|
||||
.endMetadata()
|
||||
.addNewSubset()
|
||||
.addNewAddress()
|
||||
.withIp("ip1")
|
||||
.endAddress()
|
||||
.addNewAddress()
|
||||
.withIp("ip2")
|
||||
.endAddress()
|
||||
.addNewPort("http",80,"TCP")
|
||||
.endSubset()
|
||||
.build()).once()
|
||||
|
||||
DiscoveryClient discoveryClient = new KubernetesDiscoveryClient(mockClient, new KubernetesDiscoveryProperties())
|
||||
when:
|
||||
List<ServiceInstance> instances = discoveryClient.getInstances("endpoint")
|
||||
then:
|
||||
instances != null
|
||||
instances.size() == 2
|
||||
instances.find({s -> s.host == "ip1"})
|
||||
instances.find({s -> s.host == "ip2"})
|
||||
|
||||
}
|
||||
}
|
||||
@@ -72,7 +72,7 @@ public class ZipkinKubernetesAutoConfiguration {
|
||||
.orElse(new Endpoints())
|
||||
.getSubsets()
|
||||
.stream()
|
||||
.map(s -> new KubernetesServiceInstance(name, s.getPorts().iterator().next().getName(), s, false))
|
||||
.flatMap(s -> s.getAddresses().stream().map(a -> (ServiceInstance) new KubernetesServiceInstance(name, a ,s.getPorts().stream().findFirst().orElseThrow(IllegalStateException::new), false)))
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user