Move endpoints ports to commons (#1395)
This commit is contained in:
@@ -17,14 +17,21 @@
|
||||
package org.springframework.cloud.kubernetes.commons.discovery;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
|
||||
import org.springframework.core.log.LogAccessor;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
import static org.springframework.cloud.kubernetes.commons.config.ConfigUtils.keysWithPrefix;
|
||||
import static org.springframework.cloud.kubernetes.commons.discovery.KubernetesDiscoveryConstants.HTTP;
|
||||
import static org.springframework.cloud.kubernetes.commons.discovery.KubernetesDiscoveryConstants.HTTPS;
|
||||
import static org.springframework.cloud.kubernetes.commons.discovery.KubernetesDiscoveryConstants.NAMESPACE_METADATA_KEY;
|
||||
import static org.springframework.cloud.kubernetes.commons.discovery.KubernetesDiscoveryConstants.PRIMARY_PORT_NAME_LABEL_KEY;
|
||||
import static org.springframework.cloud.kubernetes.commons.discovery.KubernetesDiscoveryConstants.SERVICE_TYPE;
|
||||
|
||||
/**
|
||||
@@ -77,4 +84,95 @@ public final class DiscoveryClientUtils {
|
||||
return serviceMetadata;
|
||||
}
|
||||
|
||||
public static ServicePortNameAndNumber endpointsPort(LinkedHashMap<String, Integer> endpointsPorts,
|
||||
String serviceId, KubernetesDiscoveryProperties properties, Map<String, String> serviceLabels) {
|
||||
|
||||
if (endpointsPorts.size() == 0) {
|
||||
LOG.debug(() -> "no ports found for service : " + serviceId + ", will return zero");
|
||||
return new ServicePortNameAndNumber(0, "http");
|
||||
}
|
||||
|
||||
if (endpointsPorts.size() == 1) {
|
||||
Map.Entry<String, Integer> single = endpointsPorts.entrySet().iterator().next();
|
||||
LOG.debug(() -> "endpoint ports has a single entry, using port : " + single.getValue());
|
||||
return new ServicePortNameAndNumber(single.getValue(), single.getKey());
|
||||
}
|
||||
|
||||
else {
|
||||
|
||||
Optional<ServicePortNameAndNumber> portData;
|
||||
String primaryPortName = primaryPortName(properties, serviceLabels, serviceId);
|
||||
|
||||
Map<String, Integer> existingPorts = endpointsPorts.entrySet().stream()
|
||||
.filter(entry -> StringUtils.hasText(entry.getKey()))
|
||||
.collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue));
|
||||
|
||||
portData = fromMap(existingPorts, primaryPortName, "found primary-port-name (with value: '"
|
||||
+ primaryPortName + "') via properties or service labels to match port");
|
||||
if (portData.isPresent()) {
|
||||
return portData.get();
|
||||
}
|
||||
|
||||
portData = fromMap(existingPorts, HTTPS, "found primary-port-name via 'https' to match port");
|
||||
if (portData.isPresent()) {
|
||||
return portData.get();
|
||||
}
|
||||
|
||||
portData = fromMap(existingPorts, HTTP, "found primary-port-name via 'http' to match port");
|
||||
if (portData.isPresent()) {
|
||||
return portData.get();
|
||||
}
|
||||
|
||||
logWarnings();
|
||||
Map.Entry<String, Integer> first = endpointsPorts.entrySet().iterator().next();
|
||||
return new ServicePortNameAndNumber(first.getValue(), first.getKey());
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* take primary-port-name from service label "PRIMARY_PORT_NAME_LABEL_KEY" if it
|
||||
* exists, otherwise from KubernetesDiscoveryProperties if it exists, otherwise null.
|
||||
*/
|
||||
static String primaryPortName(KubernetesDiscoveryProperties properties, Map<String, String> serviceLabels,
|
||||
String serviceId) {
|
||||
String primaryPortNameFromProperties = properties.primaryPortName();
|
||||
|
||||
// the value from labels takes precedence over the one from properties
|
||||
String primaryPortName = Optional
|
||||
.ofNullable(Optional.ofNullable(serviceLabels).orElse(Map.of()).get(PRIMARY_PORT_NAME_LABEL_KEY))
|
||||
.orElse(primaryPortNameFromProperties);
|
||||
|
||||
if (primaryPortName == null) {
|
||||
LOG.debug(
|
||||
() -> "did not find a primary-port-name in neither properties nor service labels for service with ID : "
|
||||
+ serviceId);
|
||||
return null;
|
||||
}
|
||||
|
||||
LOG.debug(() -> "will use primaryPortName : " + primaryPortName + " for service with ID = " + serviceId);
|
||||
return primaryPortName;
|
||||
}
|
||||
|
||||
private static Optional<ServicePortNameAndNumber> fromMap(Map<String, Integer> existingPorts, String key,
|
||||
String message) {
|
||||
Integer fromPrimaryPortName = existingPorts.get(key);
|
||||
if (fromPrimaryPortName == null) {
|
||||
LOG.debug(() -> "not " + message);
|
||||
return Optional.empty();
|
||||
}
|
||||
else {
|
||||
LOG.debug(() -> message + " : " + fromPrimaryPortName);
|
||||
return Optional.of(new ServicePortNameAndNumber(fromPrimaryPortName, key));
|
||||
}
|
||||
}
|
||||
|
||||
private static void logWarnings() {
|
||||
LOG.warn(() -> """
|
||||
Make sure that either the primary-port-name label has been added to the service,
|
||||
or spring.cloud.kubernetes.discovery.primary-port-name has been configured.
|
||||
Alternatively name the primary port 'https' or 'http'
|
||||
An incorrect configuration may result in non-deterministic behaviour.""");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2012-2023 the original author or authors.
|
||||
* Copyright 2019-2023 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.
|
||||
@@ -14,10 +14,10 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.cloud.kubernetes.fabric8.discovery;
|
||||
package org.springframework.cloud.kubernetes.commons.discovery;
|
||||
|
||||
/**
|
||||
* @author wind57
|
||||
*/
|
||||
record Fabric8ServicePortData(int portNumber, String portName) {
|
||||
public record ServicePortNameAndNumber(int portNumber, String portName) {
|
||||
}
|
||||
@@ -16,6 +16,7 @@
|
||||
|
||||
package org.springframework.cloud.kubernetes.commons.discovery;
|
||||
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.stream.Collectors;
|
||||
@@ -27,6 +28,8 @@ import org.junit.jupiter.api.extension.ExtendWith;
|
||||
import org.springframework.boot.test.system.CapturedOutput;
|
||||
import org.springframework.boot.test.system.OutputCaptureExtension;
|
||||
|
||||
import static org.springframework.cloud.kubernetes.commons.discovery.KubernetesDiscoveryConstants.PRIMARY_PORT_NAME_LABEL_KEY;
|
||||
|
||||
/**
|
||||
* @author wind57
|
||||
*/
|
||||
@@ -347,6 +350,282 @@ class DiscoveryClientUtilsTests {
|
||||
.contains("Adding port metadata: {prefix-http=8081, prefix-https=8080} for serviceId : my-service"));
|
||||
}
|
||||
|
||||
/**
|
||||
* <pre>
|
||||
* - properties do not have primary-port-name set
|
||||
* - service labels do not have primary-port-name set
|
||||
*
|
||||
* As such null is returned.
|
||||
* </pre>
|
||||
*/
|
||||
@Test
|
||||
void testPrimaryPortNameNotFound(CapturedOutput output) {
|
||||
KubernetesDiscoveryProperties properties = KubernetesDiscoveryProperties.DEFAULT;
|
||||
|
||||
Map<String, String> serviceLabels = Map.of();
|
||||
|
||||
String result = DiscoveryClientUtils.primaryPortName(properties, serviceLabels, "abc");
|
||||
Assertions.assertNull(result);
|
||||
Assertions.assertTrue(output.getOut().contains(
|
||||
"did not find a primary-port-name in neither properties nor service labels for service with ID : abc"));
|
||||
}
|
||||
|
||||
/**
|
||||
* <pre>
|
||||
* - properties do have primary-port-name set to "https"
|
||||
* - service labels do not have primary-port-name set
|
||||
*
|
||||
* As such "https" is returned.
|
||||
* </pre>
|
||||
*/
|
||||
@Test
|
||||
void testPrimaryPortNameFoundInProperties(CapturedOutput output) {
|
||||
String primaryPortName = "https";
|
||||
KubernetesDiscoveryProperties properties = new KubernetesDiscoveryProperties(true, true, Set.of(), true, 60L,
|
||||
true, "", Set.of(), Map.of(), primaryPortName, null, 0, false);
|
||||
|
||||
Map<String, String> serviceLabels = Map.of();
|
||||
|
||||
String result = DiscoveryClientUtils.primaryPortName(properties, serviceLabels, "abc");
|
||||
Assertions.assertNotNull(result);
|
||||
Assertions.assertEquals(result, primaryPortName);
|
||||
Assertions.assertTrue(output.getOut().contains("will use primaryPortName : https for service with ID = abc"));
|
||||
}
|
||||
|
||||
/**
|
||||
* <pre>
|
||||
* - properties do not have primary-port-name set
|
||||
* - service labels do have primary-port-name set to "https"
|
||||
*
|
||||
* As such "https" is returned.
|
||||
* </pre>
|
||||
*/
|
||||
@Test
|
||||
void testPrimaryPortNameFoundInLabels(CapturedOutput output) {
|
||||
Map<String, String> serviceLabels = Map.of(PRIMARY_PORT_NAME_LABEL_KEY, "https");
|
||||
KubernetesDiscoveryProperties properties = KubernetesDiscoveryProperties.DEFAULT;
|
||||
|
||||
String result = DiscoveryClientUtils.primaryPortName(properties, serviceLabels, "abc");
|
||||
Assertions.assertNotNull(result);
|
||||
Assertions.assertEquals(result, "https");
|
||||
Assertions.assertTrue(output.getOut().contains("will use primaryPortName : https for service with ID = abc"));
|
||||
}
|
||||
|
||||
/**
|
||||
* <pre>
|
||||
* - properties do have primary-port-name set to "https"
|
||||
* - service labels do have primary-port-name set to "http"
|
||||
*
|
||||
* As such "http" is returned (labels win).
|
||||
* </pre>
|
||||
*/
|
||||
@Test
|
||||
void testPrimaryPortNameFoundInBothPropertiesAndLabels(CapturedOutput output) {
|
||||
String primaryPortName = "https";
|
||||
Map<String, String> serviceLabels = Map.of(PRIMARY_PORT_NAME_LABEL_KEY, "http");
|
||||
KubernetesDiscoveryProperties properties = new KubernetesDiscoveryProperties(true, true, Set.of(), true, 60L,
|
||||
true, "", Set.of(), Map.of(), primaryPortName, null, 0, false);
|
||||
|
||||
String result = DiscoveryClientUtils.primaryPortName(properties, serviceLabels, "abc");
|
||||
Assertions.assertNotNull(result);
|
||||
Assertions.assertEquals(result, "http");
|
||||
Assertions.assertTrue(output.getOut().contains("will use primaryPortName : http for service with ID = abc"));
|
||||
}
|
||||
|
||||
/**
|
||||
* <pre>
|
||||
* - EndpointSubset has no ports.
|
||||
* </pre>
|
||||
*/
|
||||
@Test
|
||||
void testEndpointsPortNoPorts(CapturedOutput output) {
|
||||
String serviceId = "spring-k8s";
|
||||
KubernetesDiscoveryProperties properties = KubernetesDiscoveryProperties.DEFAULT;
|
||||
|
||||
LinkedHashMap<String, Integer> endpointsPorts = new LinkedHashMap<>();
|
||||
Map<String, String> serviceLabels = Map.of();
|
||||
|
||||
ServicePortNameAndNumber portData = DiscoveryClientUtils.endpointsPort(endpointsPorts, serviceId, properties,
|
||||
serviceLabels);
|
||||
Assertions.assertEquals(portData.portNumber(), 0);
|
||||
Assertions.assertEquals(portData.portName(), "http");
|
||||
Assertions.assertTrue(output.getOut().contains("no ports found for service : spring-k8s, will return zero"));
|
||||
}
|
||||
|
||||
/**
|
||||
* <pre>
|
||||
* - EndpointSubset has a single entry in getPorts.
|
||||
* </pre>
|
||||
*/
|
||||
@Test
|
||||
void testEndpointsPortSinglePort(CapturedOutput output) {
|
||||
String serviceId = "spring-k8s";
|
||||
KubernetesDiscoveryProperties properties = KubernetesDiscoveryProperties.DEFAULT;
|
||||
|
||||
LinkedHashMap<String, Integer> endpointsPorts = new LinkedHashMap<>();
|
||||
endpointsPorts.put("http", 8080);
|
||||
Map<String, String> serviceLabels = Map.of();
|
||||
|
||||
ServicePortNameAndNumber portData = DiscoveryClientUtils.endpointsPort(endpointsPorts, serviceId, properties,
|
||||
serviceLabels);
|
||||
Assertions.assertEquals(portData.portNumber(), 8080);
|
||||
Assertions.assertEquals(portData.portName(), "http");
|
||||
Assertions.assertTrue(output.getOut().contains("endpoint ports has a single entry, using port : 8080"));
|
||||
}
|
||||
|
||||
/**
|
||||
* <pre>
|
||||
* - primary-port-name is null.
|
||||
* </pre>
|
||||
*/
|
||||
@Test
|
||||
void testEndpointsPortNullPrimaryPortName(CapturedOutput output) {
|
||||
String serviceId = "spring-k8s";
|
||||
KubernetesDiscoveryProperties properties = KubernetesDiscoveryProperties.DEFAULT;
|
||||
|
||||
LinkedHashMap<String, Integer> endpointsPorts = new LinkedHashMap<>();
|
||||
endpointsPorts.put(null, 8080);
|
||||
endpointsPorts.put("not-http-or-https", 8081);
|
||||
Map<String, String> serviceLabels = Map.of();
|
||||
|
||||
ServicePortNameAndNumber portData = DiscoveryClientUtils.endpointsPort(endpointsPorts, serviceId, properties,
|
||||
serviceLabels);
|
||||
Assertions.assertEquals(portData.portNumber(), 8080);
|
||||
Assertions.assertNull(portData.portName());
|
||||
Assertions.assertTrue(output.getOut().contains(
|
||||
"did not find a primary-port-name in neither properties nor service labels for service with ID : spring-k8s"));
|
||||
Assertions.assertTrue(output.getOut()
|
||||
.contains("not found primary-port-name (with value: 'null') via properties or service labels"));
|
||||
Assertions.assertTrue(output.getOut().contains("not found primary-port-name via 'https' to match port"));
|
||||
Assertions.assertTrue(output.getOut().contains("not found primary-port-name via 'http' to match port"));
|
||||
Assertions.assertTrue(output.getOut().contains("""
|
||||
Make sure that either the primary-port-name label has been added to the service,
|
||||
or spring.cloud.kubernetes.discovery.primary-port-name has been configured.
|
||||
Alternatively name the primary port 'https' or 'http'
|
||||
An incorrect configuration may result in non-deterministic behaviour."""));
|
||||
}
|
||||
|
||||
/**
|
||||
* <pre>
|
||||
* - primary-port-name is "three", such a port name does not exist.
|
||||
* </pre>
|
||||
*/
|
||||
@Test
|
||||
void testEndpointsPortPrimaryPortNameIsPresentButNotFound(CapturedOutput output) {
|
||||
String serviceId = "spring-k8s";
|
||||
String primaryPortName = "three";
|
||||
KubernetesDiscoveryProperties properties = new KubernetesDiscoveryProperties(true, true, Set.of(), true, 60L,
|
||||
true, "", Set.of(), Map.of(), primaryPortName, null, 0, false);
|
||||
|
||||
LinkedHashMap<String, Integer> endpointsPorts = new LinkedHashMap<>();
|
||||
endpointsPorts.put("one", 8080);
|
||||
endpointsPorts.put("two", 8081);
|
||||
Map<String, String> serviceLabels = Map.of();
|
||||
|
||||
ServicePortNameAndNumber portData = DiscoveryClientUtils.endpointsPort(endpointsPorts, serviceId, properties,
|
||||
serviceLabels);
|
||||
Assertions.assertEquals(portData.portNumber(), 8080);
|
||||
Assertions.assertEquals(portData.portName(), "one");
|
||||
Assertions.assertTrue(
|
||||
output.getOut().contains("will use primaryPortName : three for service with ID = spring-k8s"));
|
||||
Assertions.assertTrue(output.getOut()
|
||||
.contains("not found primary-port-name (with value: 'three') via properties or service labels"));
|
||||
Assertions.assertTrue(output.getOut().contains("not found primary-port-name via 'https' to match port"));
|
||||
Assertions.assertTrue(output.getOut().contains("not found primary-port-name via 'http' to match port"));
|
||||
Assertions.assertTrue(output.getOut().contains("""
|
||||
Make sure that either the primary-port-name label has been added to the service,
|
||||
or spring.cloud.kubernetes.discovery.primary-port-name has been configured.
|
||||
Alternatively name the primary port 'https' or 'http'
|
||||
An incorrect configuration may result in non-deterministic behaviour."""));
|
||||
}
|
||||
|
||||
/**
|
||||
* <pre>
|
||||
* - primary-port-name is "two", such a port name exists and matches 8081
|
||||
* </pre>
|
||||
*/
|
||||
@Test
|
||||
void testEndpointsPortPrimaryPortNameFound(CapturedOutput output) {
|
||||
String serviceId = "spring-k8s";
|
||||
String primaryPortName = "two";
|
||||
KubernetesDiscoveryProperties properties = new KubernetesDiscoveryProperties(true, true, Set.of(), true, 60L,
|
||||
true, "", Set.of(), Map.of(), primaryPortName, null, 0, false);
|
||||
|
||||
LinkedHashMap<String, Integer> endpointsPorts = new LinkedHashMap<>();
|
||||
endpointsPorts.put("one", 8080);
|
||||
endpointsPorts.put("two", 8081);
|
||||
Map<String, String> serviceLabels = Map.of();
|
||||
|
||||
ServicePortNameAndNumber portData = DiscoveryClientUtils.endpointsPort(endpointsPorts, serviceId, properties,
|
||||
serviceLabels);
|
||||
Assertions.assertEquals(portData.portNumber(), 8081);
|
||||
Assertions.assertEquals(portData.portName(), "two");
|
||||
Assertions.assertTrue(
|
||||
output.getOut().contains("will use primaryPortName : two for service with ID = spring-k8s"));
|
||||
Assertions.assertTrue(output.getOut().contains(
|
||||
"found primary-port-name (with value: 'two') via properties or service labels to match port : 8081"));
|
||||
}
|
||||
|
||||
/**
|
||||
* <pre>
|
||||
* - primary-port-name is "three", such a port name does not exist.
|
||||
* - https port exists and this one is returned
|
||||
* </pre>
|
||||
*/
|
||||
@Test
|
||||
void testEndpointsPortPrimaryPortHttps(CapturedOutput output) {
|
||||
String serviceId = "spring-k8s";
|
||||
String primaryPortName = "three";
|
||||
KubernetesDiscoveryProperties properties = new KubernetesDiscoveryProperties(true, true, Set.of(), true, 60L,
|
||||
true, "", Set.of(), Map.of(), primaryPortName, null, 0, false, false);
|
||||
|
||||
LinkedHashMap<String, Integer> endpointsPorts = new LinkedHashMap<>();
|
||||
endpointsPorts.put("one", 8080);
|
||||
endpointsPorts.put("two", 8081);
|
||||
endpointsPorts.put("https", 8082);
|
||||
Map<String, String> serviceLabels = Map.of();
|
||||
|
||||
ServicePortNameAndNumber portData = DiscoveryClientUtils.endpointsPort(endpointsPorts, serviceId, properties,
|
||||
serviceLabels);
|
||||
Assertions.assertEquals(portData.portNumber(), 8082);
|
||||
Assertions.assertEquals(portData.portName(), "https");
|
||||
Assertions.assertTrue(
|
||||
output.getOut().contains("will use primaryPortName : three for service with ID = spring-k8s"));
|
||||
Assertions.assertTrue(output.getOut().contains(
|
||||
"not found primary-port-name (with value: 'three') via properties or service labels to match port"));
|
||||
Assertions.assertTrue(output.getOut().contains("found primary-port-name via 'https' to match port : 8082"));
|
||||
}
|
||||
|
||||
/**
|
||||
* <pre>
|
||||
* - primary-port-name is "three", such a port name does not exist.
|
||||
* - http port exists and this one is returned
|
||||
* </pre>
|
||||
*/
|
||||
@Test
|
||||
void testEndpointsPortPrimaryPortHttp(CapturedOutput output) {
|
||||
String serviceId = "spring-k8s";
|
||||
String primaryPortName = "three";
|
||||
KubernetesDiscoveryProperties properties = new KubernetesDiscoveryProperties(true, true, Set.of(), true, 60L,
|
||||
true, "", Set.of(), Map.of(), primaryPortName, null, 0, false);
|
||||
|
||||
LinkedHashMap<String, Integer> endpointsPorts = new LinkedHashMap<>();
|
||||
endpointsPorts.put("one", 8080);
|
||||
endpointsPorts.put("two", 8081);
|
||||
endpointsPorts.put("http", 8082);
|
||||
Map<String, String> serviceLabels = Map.of();
|
||||
|
||||
ServicePortNameAndNumber portData = DiscoveryClientUtils.endpointsPort(endpointsPorts, serviceId, properties,
|
||||
serviceLabels);
|
||||
Assertions.assertEquals(portData.portNumber(), 8082);
|
||||
Assertions.assertEquals(portData.portName(), "http");
|
||||
Assertions.assertTrue(
|
||||
output.getOut().contains("will use primaryPortName : three for service with ID = spring-k8s"));
|
||||
Assertions.assertTrue(output.getOut().contains(
|
||||
"not found primary-port-name (with value: 'three') via properties or service labels to match port"));
|
||||
Assertions.assertTrue(output.getOut().contains("found primary-port-name via 'http' to match port : 8082"));
|
||||
}
|
||||
|
||||
private String filterOnK8sNamespaceAndType(Map<String, String> result) {
|
||||
return result.entrySet().stream().filter(en -> !en.getKey().contains("k8s_namespace"))
|
||||
.filter(en -> !en.getKey().equals("type"))
|
||||
|
||||
@@ -0,0 +1,18 @@
|
||||
<configuration>
|
||||
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
|
||||
<encoder>
|
||||
<pattern>%d{HH:mm:ss.SSS} [%thread] %-5level %logger - %msg%n</pattern>
|
||||
</encoder>
|
||||
</appender>
|
||||
|
||||
<root level="info">
|
||||
<appender-ref ref="STDOUT"/>
|
||||
</root>
|
||||
|
||||
<logger name="org.testcontainers" level="INFO"/>
|
||||
<logger name="com.github.dockerjava" level="WARN"/>
|
||||
|
||||
<!-- needed for CapturedOutput -->
|
||||
<logger name="org.springframework.cloud.kubernetes.commons.discovery" level="DEBUG"/>
|
||||
|
||||
</configuration>
|
||||
@@ -18,6 +18,7 @@ package org.springframework.cloud.kubernetes.fabric8.discovery;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
@@ -47,14 +48,13 @@ import org.springframework.cloud.client.ServiceInstance;
|
||||
import org.springframework.cloud.kubernetes.commons.KubernetesNamespaceProvider;
|
||||
import org.springframework.cloud.kubernetes.commons.discovery.DefaultKubernetesServiceInstance;
|
||||
import org.springframework.cloud.kubernetes.commons.discovery.KubernetesDiscoveryProperties;
|
||||
import org.springframework.cloud.kubernetes.commons.discovery.ServicePortNameAndNumber;
|
||||
import org.springframework.cloud.kubernetes.fabric8.Fabric8Utils;
|
||||
import org.springframework.core.log.LogAccessor;
|
||||
import org.springframework.util.CollectionUtils;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
import static org.springframework.cloud.kubernetes.commons.discovery.KubernetesDiscoveryConstants.EXTERNAL_NAME;
|
||||
import static org.springframework.cloud.kubernetes.commons.discovery.KubernetesDiscoveryConstants.HTTP;
|
||||
import static org.springframework.cloud.kubernetes.commons.discovery.KubernetesDiscoveryConstants.HTTPS;
|
||||
import static org.springframework.cloud.kubernetes.commons.discovery.KubernetesDiscoveryConstants.PRIMARY_PORT_NAME_LABEL_KEY;
|
||||
import static org.springframework.cloud.kubernetes.commons.discovery.KubernetesDiscoveryConstants.SERVICE_TYPE;
|
||||
import static org.springframework.cloud.kubernetes.fabric8.discovery.ServicePortSecureResolver.Input;
|
||||
@@ -77,54 +77,6 @@ final class Fabric8KubernetesDiscoveryClientUtils {
|
||||
return new EndpointSubsetNS(endpoints.getMetadata().getNamespace(), endpoints.getSubsets());
|
||||
}
|
||||
|
||||
static Fabric8ServicePortData endpointsPort(EndpointSubset endpointSubset, String serviceId,
|
||||
KubernetesDiscoveryProperties properties, Service service) {
|
||||
|
||||
List<EndpointPort> endpointPorts = endpointSubset.getPorts();
|
||||
|
||||
if (endpointPorts.size() == 0) {
|
||||
LOG.debug(() -> "no ports found for service : " + serviceId + ", will return zero");
|
||||
return new Fabric8ServicePortData(0, "http");
|
||||
}
|
||||
|
||||
if (endpointPorts.size() == 1) {
|
||||
EndpointPort single = endpointPorts.get(0);
|
||||
int port = single.getPort();
|
||||
LOG.debug(() -> "endpoint ports has a single entry, using port : " + port);
|
||||
return new Fabric8ServicePortData(single.getPort(), single.getName());
|
||||
}
|
||||
|
||||
else {
|
||||
|
||||
Optional<Fabric8ServicePortData> portData;
|
||||
String primaryPortName = primaryPortName(properties, service, serviceId);
|
||||
|
||||
Map<String, Integer> existingPorts = endpointPorts.stream()
|
||||
.filter(endpointPort -> StringUtils.hasText(endpointPort.getName()))
|
||||
.collect(Collectors.toMap(EndpointPort::getName, EndpointPort::getPort));
|
||||
|
||||
portData = fromMap(existingPorts, primaryPortName, "found primary-port-name (with value: '"
|
||||
+ primaryPortName + "') via properties or service labels to match port");
|
||||
if (portData.isPresent()) {
|
||||
return portData.get();
|
||||
}
|
||||
|
||||
portData = fromMap(existingPorts, HTTPS, "found primary-port-name via 'https' to match port");
|
||||
if (portData.isPresent()) {
|
||||
return portData.get();
|
||||
}
|
||||
|
||||
portData = fromMap(existingPorts, HTTP, "found primary-port-name via 'http' to match port");
|
||||
if (portData.isPresent()) {
|
||||
return portData.get();
|
||||
}
|
||||
|
||||
logWarnings();
|
||||
return new Fabric8ServicePortData(endpointPorts.get(0).getPort(), endpointPorts.get(0).getName());
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* take primary-port-name from service label "PRIMARY_PORT_NAME_LABEL_KEY" if it
|
||||
* exists, otherwise from KubernetesDiscoveryProperties if it exists, otherwise null.
|
||||
@@ -244,7 +196,7 @@ final class Fabric8KubernetesDiscoveryClientUtils {
|
||||
}
|
||||
|
||||
static ServiceInstance serviceInstance(@Nullable ServicePortSecureResolver servicePortSecureResolver,
|
||||
Service service, @Nullable EndpointAddress endpointAddress, Fabric8ServicePortData portData,
|
||||
Service service, @Nullable EndpointAddress endpointAddress, ServicePortNameAndNumber portData,
|
||||
String serviceId, Map<String, String> serviceMetadata, String namespace,
|
||||
KubernetesDiscoveryProperties properties, KubernetesClient client) {
|
||||
// instanceId is usually the pod-uid as seen in the .metadata.uid
|
||||
@@ -336,6 +288,26 @@ final class Fabric8KubernetesDiscoveryClientUtils {
|
||||
.collect(Collectors.toMap(EndpointPort::getName, port -> Integer.toString(port.getPort())));
|
||||
}
|
||||
|
||||
static LinkedHashMap<String, Integer> endpointSubsetPortsData(EndpointSubset endpointSubset) {
|
||||
LinkedHashMap<String, Integer> result = new LinkedHashMap<>();
|
||||
List<EndpointPort> endpointPorts = endpointSubset.getPorts();
|
||||
|
||||
// this is most probably not a needed if statement, but it preserves the
|
||||
// previous logic before I refactored the code. In particular, this takes care of the fact
|
||||
// that an EndpointsPort name could be missing.
|
||||
if (endpointPorts.size() == 1) {
|
||||
result.put(endpointPorts.get(0).getName(), endpointPorts.get(0).getPort());
|
||||
return result;
|
||||
}
|
||||
|
||||
endpointSubset.getPorts().forEach(port -> {
|
||||
if (StringUtils.hasText(port.getName())) {
|
||||
result.put(port.getName(), port.getPort());
|
||||
}
|
||||
});
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* serviceName can be null, in which case, such a filter will not be applied.
|
||||
*/
|
||||
@@ -355,25 +327,4 @@ final class Fabric8KubernetesDiscoveryClientUtils {
|
||||
|
||||
}
|
||||
|
||||
private static Optional<Fabric8ServicePortData> fromMap(Map<String, Integer> existingPorts, String key,
|
||||
String message) {
|
||||
Integer fromPrimaryPortName = existingPorts.get(key);
|
||||
if (fromPrimaryPortName == null) {
|
||||
LOG.debug(() -> "not " + message);
|
||||
return Optional.empty();
|
||||
}
|
||||
else {
|
||||
LOG.debug(() -> message + " : " + fromPrimaryPortName);
|
||||
return Optional.of(new Fabric8ServicePortData(fromPrimaryPortName, key));
|
||||
}
|
||||
}
|
||||
|
||||
private static void logWarnings() {
|
||||
LOG.warn(() -> """
|
||||
Make sure that either the primary-port-name label has been added to the service,
|
||||
or spring.cloud.kubernetes.discovery.primary-port-name has been configured.
|
||||
Alternatively name the primary port 'https' or 'http'
|
||||
An incorrect configuration may result in non-deterministic behaviour.""");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -35,14 +35,15 @@ import org.springframework.cloud.client.discovery.DiscoveryClient;
|
||||
import org.springframework.cloud.kubernetes.commons.KubernetesNamespaceProvider;
|
||||
import org.springframework.cloud.kubernetes.commons.discovery.DiscoveryClientUtils;
|
||||
import org.springframework.cloud.kubernetes.commons.discovery.KubernetesDiscoveryProperties;
|
||||
import org.springframework.cloud.kubernetes.commons.discovery.ServicePortNameAndNumber;
|
||||
import org.springframework.context.EnvironmentAware;
|
||||
import org.springframework.core.env.Environment;
|
||||
import org.springframework.core.log.LogAccessor;
|
||||
|
||||
import static org.springframework.cloud.kubernetes.commons.discovery.KubernetesDiscoveryConstants.EXTERNAL_NAME;
|
||||
import static org.springframework.cloud.kubernetes.fabric8.discovery.Fabric8KubernetesDiscoveryClientUtils.addresses;
|
||||
import static org.springframework.cloud.kubernetes.fabric8.discovery.Fabric8KubernetesDiscoveryClientUtils.endpointSubsetPortsData;
|
||||
import static org.springframework.cloud.kubernetes.fabric8.discovery.Fabric8KubernetesDiscoveryClientUtils.endpoints;
|
||||
import static org.springframework.cloud.kubernetes.fabric8.discovery.Fabric8KubernetesDiscoveryClientUtils.endpointsPort;
|
||||
import static org.springframework.cloud.kubernetes.fabric8.discovery.Fabric8KubernetesDiscoveryClientUtils.portsData;
|
||||
import static org.springframework.cloud.kubernetes.fabric8.discovery.Fabric8KubernetesDiscoveryClientUtils.serviceInstance;
|
||||
import static org.springframework.cloud.kubernetes.fabric8.discovery.Fabric8KubernetesDiscoveryClientUtils.services;
|
||||
@@ -127,7 +128,7 @@ public class KubernetesDiscoveryClient implements DiscoveryClient, EnvironmentAw
|
||||
serviceMetadata.getNamespace(), service.getSpec().getType());
|
||||
|
||||
ServiceInstance externalNameServiceInstance = serviceInstance(null, service, null,
|
||||
new Fabric8ServicePortData(-1, null), serviceId, result, service.getMetadata().getNamespace(),
|
||||
new ServicePortNameAndNumber(-1, null), serviceId, result, service.getMetadata().getNamespace(),
|
||||
properties, client);
|
||||
instances.add(externalNameServiceInstance);
|
||||
}
|
||||
@@ -159,7 +160,10 @@ public class KubernetesDiscoveryClient implements DiscoveryClient, EnvironmentAw
|
||||
service.getSpec().getType());
|
||||
|
||||
for (EndpointSubset endpointSubset : subsets) {
|
||||
Fabric8ServicePortData portData = endpointsPort(endpointSubset, serviceId, properties, service);
|
||||
|
||||
ServicePortNameAndNumber portData = DiscoveryClientUtils.endpointsPort(
|
||||
endpointSubsetPortsData(endpointSubset), serviceId, properties, service.getMetadata().getLabels());
|
||||
|
||||
List<EndpointAddress> addresses = addresses(endpointSubset, properties);
|
||||
for (EndpointAddress endpointAddress : addresses) {
|
||||
ServiceInstance serviceInstance = serviceInstance(servicePortSecureResolver, service, endpointAddress,
|
||||
|
||||
@@ -23,6 +23,7 @@ import java.util.Set;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
|
||||
import org.springframework.cloud.kubernetes.commons.discovery.KubernetesDiscoveryProperties;
|
||||
import org.springframework.cloud.kubernetes.commons.discovery.ServicePortNameAndNumber;
|
||||
import org.springframework.core.log.LogAccessor;
|
||||
|
||||
import static org.springframework.cloud.kubernetes.commons.discovery.KubernetesDiscoveryConstants.SECURED;
|
||||
@@ -53,7 +54,7 @@ class ServicePortSecureResolver {
|
||||
boolean resolve(Input input) {
|
||||
|
||||
String serviceName = input.serviceName();
|
||||
Fabric8ServicePortData portData = input.portData();
|
||||
ServicePortNameAndNumber portData = input.portData();
|
||||
|
||||
Optional<String> securedLabelValue = Optional.ofNullable(input.serviceLabels().get(SECURED));
|
||||
if (securedLabelValue.isPresent() && TRUTHY_STRINGS.contains(securedLabelValue.get())) {
|
||||
@@ -89,10 +90,10 @@ class ServicePortSecureResolver {
|
||||
/**
|
||||
* @author wind57
|
||||
*/
|
||||
record Input(Fabric8ServicePortData portData, String serviceName, Map<String, String> serviceLabels,
|
||||
record Input(ServicePortNameAndNumber portData, String serviceName, Map<String, String> serviceLabels,
|
||||
Map<String, String> serviceAnnotations) {
|
||||
|
||||
Input(Fabric8ServicePortData portData, String serviceName, Map<String, String> serviceLabels,
|
||||
Input(ServicePortNameAndNumber portData, String serviceName, Map<String, String> serviceLabels,
|
||||
Map<String, String> serviceAnnotations) {
|
||||
this.portData = portData;
|
||||
this.serviceName = serviceName;
|
||||
|
||||
@@ -36,13 +36,11 @@ import org.junit.jupiter.api.Assertions;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.api.extension.ExtendWith;
|
||||
|
||||
import org.springframework.boot.test.system.CapturedOutput;
|
||||
import org.springframework.boot.test.system.OutputCaptureExtension;
|
||||
import org.springframework.cloud.client.ServiceInstance;
|
||||
import org.springframework.cloud.kubernetes.commons.discovery.DefaultKubernetesServiceInstance;
|
||||
import org.springframework.cloud.kubernetes.commons.discovery.KubernetesDiscoveryProperties;
|
||||
|
||||
import static org.springframework.cloud.kubernetes.commons.discovery.KubernetesDiscoveryConstants.PRIMARY_PORT_NAME_LABEL_KEY;
|
||||
import org.springframework.cloud.kubernetes.commons.discovery.ServicePortNameAndNumber;
|
||||
|
||||
/**
|
||||
* @author wind57
|
||||
@@ -74,288 +72,6 @@ class KubernetesDiscoveryClientUtilsTests {
|
||||
Assertions.assertEquals(result.namespace(), "default");
|
||||
}
|
||||
|
||||
/**
|
||||
* <pre>
|
||||
* - properties do not have primary-port-name set
|
||||
* - service labels do not have primary-port-name set
|
||||
*
|
||||
* As such null is returned.
|
||||
* </pre>
|
||||
*/
|
||||
@Test
|
||||
void testPrimaryPortNameNotFound(CapturedOutput output) {
|
||||
KubernetesDiscoveryProperties properties = KubernetesDiscoveryProperties.DEFAULT;
|
||||
Service service = new ServiceBuilder().withMetadata(new ObjectMeta()).build();
|
||||
|
||||
String result = Fabric8KubernetesDiscoveryClientUtils.primaryPortName(properties, service, "abc");
|
||||
Assertions.assertNull(result);
|
||||
Assertions.assertTrue(output.getOut().contains(
|
||||
"did not find a primary-port-name in neither properties nor service labels for service with ID : abc"));
|
||||
}
|
||||
|
||||
/**
|
||||
* <pre>
|
||||
* - properties do have primary-port-name set to "https"
|
||||
* - service labels do not have primary-port-name set
|
||||
*
|
||||
* As such "https" is returned.
|
||||
* </pre>
|
||||
*/
|
||||
@Test
|
||||
void testPrimaryPortNameFoundInProperties(CapturedOutput output) {
|
||||
String primaryPortName = "https";
|
||||
KubernetesDiscoveryProperties properties = new KubernetesDiscoveryProperties(true, true, Set.of(), true, 60L,
|
||||
true, "", Set.of(), Map.of(), primaryPortName, null, 0, false);
|
||||
Service service = new ServiceBuilder().withMetadata(new ObjectMeta()).build();
|
||||
|
||||
String result = Fabric8KubernetesDiscoveryClientUtils.primaryPortName(properties, service, "abc");
|
||||
Assertions.assertNotNull(result);
|
||||
Assertions.assertEquals(result, primaryPortName);
|
||||
Assertions.assertTrue(output.getOut().contains("will use primaryPortName : https for service with ID = abc"));
|
||||
}
|
||||
|
||||
/**
|
||||
* <pre>
|
||||
* - properties do not have primary-port-name set
|
||||
* - service labels do have primary-port-name set to "https"
|
||||
*
|
||||
* As such "https" is returned.
|
||||
* </pre>
|
||||
*/
|
||||
@Test
|
||||
void testPrimaryPortNameFoundInLabels(CapturedOutput output) {
|
||||
Map<String, String> labels = Map.of(PRIMARY_PORT_NAME_LABEL_KEY, "https");
|
||||
KubernetesDiscoveryProperties properties = KubernetesDiscoveryProperties.DEFAULT;
|
||||
Service service = new ServiceBuilder().withMetadata(new ObjectMetaBuilder().withLabels(labels).build()).build();
|
||||
|
||||
String result = Fabric8KubernetesDiscoveryClientUtils.primaryPortName(properties, service, "abc");
|
||||
Assertions.assertNotNull(result);
|
||||
Assertions.assertEquals(result, "https");
|
||||
Assertions.assertTrue(output.getOut().contains("will use primaryPortName : https for service with ID = abc"));
|
||||
}
|
||||
|
||||
/**
|
||||
* <pre>
|
||||
* - properties do have primary-port-name set to "https"
|
||||
* - service labels do have primary-port-name set to "http"
|
||||
*
|
||||
* As such "http" is returned (labels win).
|
||||
* </pre>
|
||||
*/
|
||||
@Test
|
||||
void testPrimaryPortNameFoundInBothPropertiesAndLabels(CapturedOutput output) {
|
||||
String primaryPortName = "https";
|
||||
Map<String, String> labels = Map.of(PRIMARY_PORT_NAME_LABEL_KEY, "http");
|
||||
KubernetesDiscoveryProperties properties = new KubernetesDiscoveryProperties(true, true, Set.of(), true, 60L,
|
||||
true, "", Set.of(), Map.of(), primaryPortName, null, 0, false);
|
||||
Service service = new ServiceBuilder().withMetadata(new ObjectMetaBuilder().withLabels(labels).build()).build();
|
||||
|
||||
String result = Fabric8KubernetesDiscoveryClientUtils.primaryPortName(properties, service, "abc");
|
||||
Assertions.assertNotNull(result);
|
||||
Assertions.assertEquals(result, "http");
|
||||
Assertions.assertTrue(output.getOut().contains("will use primaryPortName : http for service with ID = abc"));
|
||||
}
|
||||
|
||||
/**
|
||||
* <pre>
|
||||
* - EndpointSubset has no ports.
|
||||
* </pre>
|
||||
*/
|
||||
@Test
|
||||
void testEndpointsPortNoPorts(CapturedOutput output) {
|
||||
EndpointSubset endpointSubset = new EndpointSubsetBuilder().build();
|
||||
String serviceId = "spring-k8s";
|
||||
KubernetesDiscoveryProperties properties = KubernetesDiscoveryProperties.DEFAULT;
|
||||
Service service = new ServiceBuilder().build();
|
||||
|
||||
Fabric8ServicePortData portData = Fabric8KubernetesDiscoveryClientUtils.endpointsPort(endpointSubset, serviceId,
|
||||
properties, service);
|
||||
Assertions.assertEquals(portData.portNumber(), 0);
|
||||
Assertions.assertEquals(portData.portName(), "http");
|
||||
Assertions.assertTrue(output.getOut().contains("no ports found for service : spring-k8s, will return zero"));
|
||||
}
|
||||
|
||||
/**
|
||||
* <pre>
|
||||
* - EndpointSubset has a single entry in getPorts.
|
||||
* </pre>
|
||||
*/
|
||||
@Test
|
||||
void testEndpointsPortSinglePort(CapturedOutput output) {
|
||||
EndpointSubset endpointSubset = new EndpointSubsetBuilder()
|
||||
.withPorts(new EndpointPortBuilder().withPort(8080).withName("http").build()).build();
|
||||
String serviceId = "spring-k8s";
|
||||
KubernetesDiscoveryProperties properties = KubernetesDiscoveryProperties.DEFAULT;
|
||||
Service service = new ServiceBuilder().build();
|
||||
|
||||
Fabric8ServicePortData portData = Fabric8KubernetesDiscoveryClientUtils.endpointsPort(endpointSubset, serviceId,
|
||||
properties, service);
|
||||
Assertions.assertEquals(portData.portNumber(), 8080);
|
||||
Assertions.assertEquals(portData.portName(), "http");
|
||||
Assertions.assertTrue(output.getOut().contains("endpoint ports has a single entry, using port : 8080"));
|
||||
}
|
||||
|
||||
/**
|
||||
* <pre>
|
||||
* - primary-port-name is null.
|
||||
* </pre>
|
||||
*/
|
||||
@Test
|
||||
void testEndpointsPortNullPrimaryPortName(CapturedOutput output) {
|
||||
EndpointSubset endpointSubset = new EndpointSubsetBuilder()
|
||||
.withPorts(new EndpointPortBuilder().withPort(8080).build(),
|
||||
new EndpointPortBuilder().withPort(8081).build())
|
||||
.build();
|
||||
String serviceId = "spring-k8s";
|
||||
KubernetesDiscoveryProperties properties = KubernetesDiscoveryProperties.DEFAULT;
|
||||
Service service = new ServiceBuilder().withMetadata(new ObjectMeta()).build();
|
||||
|
||||
Fabric8ServicePortData portData = Fabric8KubernetesDiscoveryClientUtils.endpointsPort(endpointSubset, serviceId,
|
||||
properties, service);
|
||||
Assertions.assertEquals(portData.portNumber(), 8080);
|
||||
Assertions.assertNull(portData.portName());
|
||||
Assertions.assertTrue(output.getOut().contains(
|
||||
"did not find a primary-port-name in neither properties nor service labels for service with ID : spring-k8s"));
|
||||
Assertions.assertTrue(output.getOut()
|
||||
.contains("not found primary-port-name (with value: 'null') via properties or service labels"));
|
||||
Assertions.assertTrue(output.getOut().contains("not found primary-port-name via 'https' to match port"));
|
||||
Assertions.assertTrue(output.getOut().contains("not found primary-port-name via 'http' to match port"));
|
||||
Assertions.assertTrue(output.getOut().contains("""
|
||||
Make sure that either the primary-port-name label has been added to the service,
|
||||
or spring.cloud.kubernetes.discovery.primary-port-name has been configured.
|
||||
Alternatively name the primary port 'https' or 'http'
|
||||
An incorrect configuration may result in non-deterministic behaviour."""));
|
||||
}
|
||||
|
||||
/**
|
||||
* <pre>
|
||||
* - primary-port-name is "three", such a port name does not exist.
|
||||
* </pre>
|
||||
*/
|
||||
@Test
|
||||
void testEndpointsPortPrimaryPortNameIsPresentButNotFound(CapturedOutput output) {
|
||||
EndpointSubset endpointSubset = new EndpointSubsetBuilder()
|
||||
.withPorts(new EndpointPortBuilder().withPort(8080).withName("one").build(),
|
||||
new EndpointPortBuilder().withPort(8081).withName("two").build())
|
||||
.build();
|
||||
String serviceId = "spring-k8s";
|
||||
|
||||
String primaryPortName = "three";
|
||||
KubernetesDiscoveryProperties properties = new KubernetesDiscoveryProperties(true, true, Set.of(), true, 60L,
|
||||
true, "", Set.of(), Map.of(), primaryPortName, null, 0, false);
|
||||
|
||||
Service service = new ServiceBuilder().withMetadata(new ObjectMeta()).build();
|
||||
|
||||
Fabric8ServicePortData portData = Fabric8KubernetesDiscoveryClientUtils.endpointsPort(endpointSubset, serviceId,
|
||||
properties, service);
|
||||
Assertions.assertEquals(portData.portNumber(), 8080);
|
||||
Assertions.assertEquals(portData.portName(), "one");
|
||||
Assertions.assertTrue(
|
||||
output.getOut().contains("will use primaryPortName : three for service with ID = spring-k8s"));
|
||||
Assertions.assertTrue(output.getOut()
|
||||
.contains("not found primary-port-name (with value: 'three') via properties or service labels"));
|
||||
Assertions.assertTrue(output.getOut().contains("not found primary-port-name via 'https' to match port"));
|
||||
Assertions.assertTrue(output.getOut().contains("not found primary-port-name via 'http' to match port"));
|
||||
Assertions.assertTrue(output.getOut().contains("""
|
||||
Make sure that either the primary-port-name label has been added to the service,
|
||||
or spring.cloud.kubernetes.discovery.primary-port-name has been configured.
|
||||
Alternatively name the primary port 'https' or 'http'
|
||||
An incorrect configuration may result in non-deterministic behaviour."""));
|
||||
}
|
||||
|
||||
/**
|
||||
* <pre>
|
||||
* - primary-port-name is "two", such a port name exists and matches 8081
|
||||
* </pre>
|
||||
*/
|
||||
@Test
|
||||
void testEndpointsPortPrimaryPortNameFound(CapturedOutput output) {
|
||||
EndpointSubset endpointSubset = new EndpointSubsetBuilder()
|
||||
.withPorts(new EndpointPortBuilder().withPort(8080).withName("one").build(),
|
||||
new EndpointPortBuilder().withPort(8081).withName("two").build())
|
||||
.build();
|
||||
String serviceId = "spring-k8s";
|
||||
|
||||
String primaryPortName = "two";
|
||||
KubernetesDiscoveryProperties properties = new KubernetesDiscoveryProperties(true, true, Set.of(), true, 60L,
|
||||
true, "", Set.of(), Map.of(), primaryPortName, null, 0, false);
|
||||
|
||||
Service service = new ServiceBuilder().withMetadata(new ObjectMeta()).build();
|
||||
|
||||
Fabric8ServicePortData portData = Fabric8KubernetesDiscoveryClientUtils.endpointsPort(endpointSubset, serviceId,
|
||||
properties, service);
|
||||
Assertions.assertEquals(portData.portNumber(), 8081);
|
||||
Assertions.assertEquals(portData.portName(), "two");
|
||||
Assertions.assertTrue(
|
||||
output.getOut().contains("will use primaryPortName : two for service with ID = spring-k8s"));
|
||||
Assertions.assertTrue(output.getOut().contains(
|
||||
"found primary-port-name (with value: 'two') via properties or service labels to match port : 8081"));
|
||||
}
|
||||
|
||||
/**
|
||||
* <pre>
|
||||
* - primary-port-name is "three", such a port name does not exist.
|
||||
* - https port exists and this one is returned
|
||||
* </pre>
|
||||
*/
|
||||
@Test
|
||||
void testEndpointsPortPrimaryPortHttps(CapturedOutput output) {
|
||||
EndpointSubset endpointSubset = new EndpointSubsetBuilder()
|
||||
.withPorts(new EndpointPortBuilder().withPort(8080).withName("one").build(),
|
||||
new EndpointPortBuilder().withPort(8081).withName("two").build(),
|
||||
new EndpointPortBuilder().withPort(8082).withName("https").build())
|
||||
.build();
|
||||
String serviceId = "spring-k8s";
|
||||
|
||||
String primaryPortName = "three";
|
||||
KubernetesDiscoveryProperties properties = new KubernetesDiscoveryProperties(true, true, Set.of(), true, 60L,
|
||||
true, "", Set.of(), Map.of(), primaryPortName, null, 0, false, false);
|
||||
|
||||
Service service = new ServiceBuilder().withMetadata(new ObjectMeta()).build();
|
||||
|
||||
Fabric8ServicePortData portData = Fabric8KubernetesDiscoveryClientUtils.endpointsPort(endpointSubset, serviceId,
|
||||
properties, service);
|
||||
Assertions.assertEquals(portData.portNumber(), 8082);
|
||||
Assertions.assertEquals(portData.portName(), "https");
|
||||
Assertions.assertTrue(
|
||||
output.getOut().contains("will use primaryPortName : three for service with ID = spring-k8s"));
|
||||
Assertions.assertTrue(output.getOut().contains(
|
||||
"not found primary-port-name (with value: 'three') via properties or service labels to match port"));
|
||||
Assertions.assertTrue(output.getOut().contains("found primary-port-name via 'https' to match port : 8082"));
|
||||
}
|
||||
|
||||
/**
|
||||
* <pre>
|
||||
* - primary-port-name is "three", such a port name does not exist.
|
||||
* - http port exists and this one is returned
|
||||
* </pre>
|
||||
*/
|
||||
@Test
|
||||
void testEndpointsPortPrimaryPortHttp(CapturedOutput output) {
|
||||
EndpointSubset endpointSubset = new EndpointSubsetBuilder()
|
||||
.withPorts(new EndpointPortBuilder().withPort(8080).withName("one").build(),
|
||||
new EndpointPortBuilder().withPort(8081).withName("two").build(),
|
||||
new EndpointPortBuilder().withPort(8082).withName("http").build())
|
||||
.build();
|
||||
String serviceId = "spring-k8s";
|
||||
|
||||
String primaryPortName = "three";
|
||||
KubernetesDiscoveryProperties properties = new KubernetesDiscoveryProperties(true, true, Set.of(), true, 60L,
|
||||
true, "", Set.of(), Map.of(), primaryPortName, null, 0, false);
|
||||
|
||||
Service service = new ServiceBuilder().withMetadata(new ObjectMeta()).build();
|
||||
|
||||
Fabric8ServicePortData portData = Fabric8KubernetesDiscoveryClientUtils.endpointsPort(endpointSubset, serviceId,
|
||||
properties, service);
|
||||
Assertions.assertEquals(portData.portNumber(), 8082);
|
||||
Assertions.assertEquals(portData.portName(), "http");
|
||||
Assertions.assertTrue(
|
||||
output.getOut().contains("will use primaryPortName : three for service with ID = spring-k8s"));
|
||||
Assertions.assertTrue(output.getOut().contains(
|
||||
"not found primary-port-name (with value: 'three') via properties or service labels to match port"));
|
||||
Assertions.assertTrue(output.getOut().contains("found primary-port-name via 'http' to match port : 8082"));
|
||||
}
|
||||
|
||||
/**
|
||||
* <pre>
|
||||
* - ready addresses are empty
|
||||
@@ -442,7 +158,7 @@ class KubernetesDiscoveryClientUtilsTests {
|
||||
EndpointAddress address = new EndpointAddressBuilder().withNewTargetRef().withUid("123").endTargetRef()
|
||||
.withIp("127.0.0.1").build();
|
||||
|
||||
Fabric8ServicePortData portData = new Fabric8ServicePortData(8080, "http");
|
||||
ServicePortNameAndNumber portData = new ServicePortNameAndNumber(8080, "http");
|
||||
ServiceInstance serviceInstance = Fabric8KubernetesDiscoveryClientUtils.serviceInstance(resolver, service,
|
||||
address, portData, "my-service", Map.of("a", "b"), "k8s", properties, null);
|
||||
Assertions.assertTrue(serviceInstance instanceof DefaultKubernetesServiceInstance);
|
||||
@@ -465,7 +181,7 @@ class KubernetesDiscoveryClientUtilsTests {
|
||||
.withSpec(new ServiceSpecBuilder().withExternalName("spring.io").withType("ExternalName").build())
|
||||
.withMetadata(new ObjectMetaBuilder().withUid("123").build()).build();
|
||||
|
||||
Fabric8ServicePortData portData = new Fabric8ServicePortData(-1, "http");
|
||||
ServicePortNameAndNumber portData = new ServicePortNameAndNumber(-1, "http");
|
||||
ServiceInstance serviceInstance = Fabric8KubernetesDiscoveryClientUtils.serviceInstance(null, service, null,
|
||||
portData, "my-service", Map.of("a", "b"), "k8s", KubernetesDiscoveryProperties.DEFAULT, null);
|
||||
Assertions.assertTrue(serviceInstance instanceof DefaultKubernetesServiceInstance);
|
||||
@@ -489,7 +205,7 @@ class KubernetesDiscoveryClientUtilsTests {
|
||||
|
||||
EndpointAddress endpointAddress = new EndpointAddressBuilder().withIp("127.0.0.1").build();
|
||||
|
||||
Fabric8ServicePortData portData = new Fabric8ServicePortData(0, "http");
|
||||
ServicePortNameAndNumber portData = new ServicePortNameAndNumber(0, "http");
|
||||
ServiceInstance serviceInstance = Fabric8KubernetesDiscoveryClientUtils.serviceInstance(null, service,
|
||||
endpointAddress, portData, "my-service", Map.of("a", "b"), "k8s", KubernetesDiscoveryProperties.DEFAULT,
|
||||
null);
|
||||
@@ -507,4 +223,42 @@ class KubernetesDiscoveryClientUtilsTests {
|
||||
Assertions.assertNull(defaultInstance.getCluster());
|
||||
}
|
||||
|
||||
/**
|
||||
* endpoints ports are empty.
|
||||
*/
|
||||
@Test
|
||||
void testEndpointSubsetPortsDataOne() {
|
||||
EndpointSubset endpointSubset = new EndpointSubsetBuilder().build();
|
||||
Map<String, Integer> result = Fabric8KubernetesDiscoveryClientUtils.endpointSubsetPortsData(endpointSubset);
|
||||
Assertions.assertTrue(result.isEmpty());
|
||||
}
|
||||
|
||||
/**
|
||||
* endpoints ports has one entry.
|
||||
*/
|
||||
@Test
|
||||
void testEndpointSubsetPortsDataTwo() {
|
||||
EndpointSubset endpointSubset = new EndpointSubsetBuilder()
|
||||
.withPorts(new EndpointPortBuilder().withPort(8080).withName("http").build()).build();
|
||||
Map<String, Integer> result = Fabric8KubernetesDiscoveryClientUtils.endpointSubsetPortsData(endpointSubset);
|
||||
Assertions.assertEquals(result.size(), 1);
|
||||
Assertions.assertEquals(result.get("http"), 8080);
|
||||
}
|
||||
|
||||
/**
|
||||
* endpoints ports has three entries, only two are picked up.
|
||||
*/
|
||||
@Test
|
||||
void testEndpointSubsetPortsDataThree() {
|
||||
EndpointSubset endpointSubset = new EndpointSubsetBuilder()
|
||||
.withPorts(new EndpointPortBuilder().withPort(8080).withName("http").build(),
|
||||
new EndpointPortBuilder().withPort(8081).build(),
|
||||
new EndpointPortBuilder().withPort(8082).withName("https").build())
|
||||
.build();
|
||||
Map<String, Integer> result = Fabric8KubernetesDiscoveryClientUtils.endpointSubsetPortsData(endpointSubset);
|
||||
Assertions.assertEquals(result.size(), 2);
|
||||
Assertions.assertEquals(result.get("http"), 8080);
|
||||
Assertions.assertEquals(result.get("https"), 8082);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -26,6 +26,7 @@ import org.junit.jupiter.api.extension.ExtendWith;
|
||||
import org.springframework.boot.test.system.CapturedOutput;
|
||||
import org.springframework.boot.test.system.OutputCaptureExtension;
|
||||
import org.springframework.cloud.kubernetes.commons.discovery.KubernetesDiscoveryProperties;
|
||||
import org.springframework.cloud.kubernetes.commons.discovery.ServicePortNameAndNumber;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.springframework.cloud.kubernetes.fabric8.discovery.ServicePortSecureResolver.Input;
|
||||
@@ -42,16 +43,16 @@ class ServicePortSecureResolverTest {
|
||||
private static final Map<String, String> SECURED_ON_MAP = Collections.singletonMap("secured", "on");
|
||||
|
||||
private static final ServicePortSecureResolver.Input SECURED_TRUE = new ServicePortSecureResolver.Input(
|
||||
new Fabric8ServicePortData(8080, "http"), "dummy", SECURED_TRUE_MAP, Collections.emptyMap());
|
||||
new ServicePortNameAndNumber(8080, "http"), "dummy", SECURED_TRUE_MAP, Collections.emptyMap());
|
||||
|
||||
private static final ServicePortSecureResolver.Input SECURED_1 = new ServicePortSecureResolver.Input(
|
||||
new Fabric8ServicePortData(1234, "http"), "dummy", SECURED_1_MAP, Collections.emptyMap());
|
||||
new ServicePortNameAndNumber(1234, "http"), "dummy", SECURED_1_MAP, Collections.emptyMap());
|
||||
|
||||
private static final ServicePortSecureResolver.Input SECURED_YES = new ServicePortSecureResolver.Input(
|
||||
new Fabric8ServicePortData(4321, "http"), "dummy", SECURED_YES_MAP, Collections.emptyMap());
|
||||
new ServicePortNameAndNumber(4321, "http"), "dummy", SECURED_YES_MAP, Collections.emptyMap());
|
||||
|
||||
private static final ServicePortSecureResolver.Input SECURED_ON = new ServicePortSecureResolver.Input(
|
||||
new Fabric8ServicePortData(4321, "http"), "dummy", SECURED_ON_MAP, Collections.emptyMap());
|
||||
new ServicePortNameAndNumber(4321, "http"), "dummy", SECURED_ON_MAP, Collections.emptyMap());
|
||||
|
||||
@Test
|
||||
void testPortNumbersOnly() {
|
||||
@@ -61,20 +62,18 @@ class ServicePortSecureResolverTest {
|
||||
|
||||
ServicePortSecureResolver secureResolver = new ServicePortSecureResolver(properties);
|
||||
|
||||
assertThat(
|
||||
secureResolver.resolve(new Input(new Fabric8ServicePortData(-1, "http"), "dummy", Map.of(), Map.of())))
|
||||
.isFalse();
|
||||
assertThat(secureResolver
|
||||
.resolve(new Input(new Fabric8ServicePortData(8080, "http"), "dummy", Map.of(), Map.of()))).isFalse();
|
||||
.resolve(new Input(new ServicePortNameAndNumber(-1, "http"), "dummy", Map.of(), Map.of()))).isFalse();
|
||||
assertThat(secureResolver
|
||||
.resolve(new Input(new Fabric8ServicePortData(1234, "http"), "dummy", Map.of(), Map.of()))).isFalse();
|
||||
assertThat(
|
||||
secureResolver.resolve(new Input(new Fabric8ServicePortData(443, "http"), "dummy", Map.of(), Map.of())))
|
||||
.isTrue();
|
||||
.resolve(new Input(new ServicePortNameAndNumber(8080, "http"), "dummy", Map.of(), Map.of()))).isFalse();
|
||||
assertThat(secureResolver
|
||||
.resolve(new Input(new Fabric8ServicePortData(8443, "http"), "dummy", Map.of(), Map.of()))).isTrue();
|
||||
.resolve(new Input(new ServicePortNameAndNumber(1234, "http"), "dummy", Map.of(), Map.of()))).isFalse();
|
||||
assertThat(secureResolver
|
||||
.resolve(new Input(new Fabric8ServicePortData(12345, "http"), "dummy", Map.of(), Map.of()))).isTrue();
|
||||
.resolve(new Input(new ServicePortNameAndNumber(443, "http"), "dummy", Map.of(), Map.of()))).isTrue();
|
||||
assertThat(secureResolver
|
||||
.resolve(new Input(new ServicePortNameAndNumber(8443, "http"), "dummy", Map.of(), Map.of()))).isTrue();
|
||||
assertThat(secureResolver
|
||||
.resolve(new Input(new ServicePortNameAndNumber(12345, "http"), "dummy", Map.of(), Map.of()))).isTrue();
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -93,7 +92,7 @@ class ServicePortSecureResolverTest {
|
||||
false, null, Set.of(443, 8443, 12345), Map.of(), null, KubernetesDiscoveryProperties.Metadata.DEFAULT,
|
||||
0, true);
|
||||
ServicePortSecureResolver secureResolver = new ServicePortSecureResolver(properties);
|
||||
Fabric8ServicePortData portData = new Fabric8ServicePortData(8080, "http");
|
||||
ServicePortNameAndNumber portData = new ServicePortNameAndNumber(8080, "http");
|
||||
Input input = new Input(portData, "dummy", Map.of(), Map.of());
|
||||
|
||||
boolean result = secureResolver.resolve(input);
|
||||
@@ -107,7 +106,7 @@ class ServicePortSecureResolverTest {
|
||||
false, null, Set.of(443, 8443), Map.of(), null, KubernetesDiscoveryProperties.Metadata.DEFAULT, 0,
|
||||
true);
|
||||
ServicePortSecureResolver secureResolver = new ServicePortSecureResolver(properties);
|
||||
Fabric8ServicePortData portData = new Fabric8ServicePortData(8080, "http");
|
||||
ServicePortNameAndNumber portData = new ServicePortNameAndNumber(8080, "http");
|
||||
Input input = new Input(portData, "dummy", Map.of("secured", "right"), Map.of());
|
||||
|
||||
boolean result = secureResolver.resolve(input);
|
||||
@@ -121,7 +120,7 @@ class ServicePortSecureResolverTest {
|
||||
false, null, Set.of(443, 8443), Map.of(), null, KubernetesDiscoveryProperties.Metadata.DEFAULT, 0,
|
||||
true);
|
||||
ServicePortSecureResolver secureResolver = new ServicePortSecureResolver(properties);
|
||||
Fabric8ServicePortData portData = new Fabric8ServicePortData(8080, "http");
|
||||
ServicePortNameAndNumber portData = new ServicePortNameAndNumber(8080, "http");
|
||||
Input input = new Input(portData, "dummy", Map.of("secured", "true"), Map.of());
|
||||
|
||||
boolean result = secureResolver.resolve(input);
|
||||
@@ -136,7 +135,7 @@ class ServicePortSecureResolverTest {
|
||||
false, null, Set.of(443, 8443), Map.of(), null, KubernetesDiscoveryProperties.Metadata.DEFAULT, 0,
|
||||
true);
|
||||
ServicePortSecureResolver secureResolver = new ServicePortSecureResolver(properties);
|
||||
Fabric8ServicePortData portData = new Fabric8ServicePortData(8080, "http");
|
||||
ServicePortNameAndNumber portData = new ServicePortNameAndNumber(8080, "http");
|
||||
Input input = new Input(portData, "dummy", Map.of(), Map.of("secured", "right"));
|
||||
|
||||
boolean result = secureResolver.resolve(input);
|
||||
@@ -150,7 +149,7 @@ class ServicePortSecureResolverTest {
|
||||
false, null, Set.of(443, 8443), Map.of(), null, KubernetesDiscoveryProperties.Metadata.DEFAULT, 0,
|
||||
true);
|
||||
ServicePortSecureResolver secureResolver = new ServicePortSecureResolver(properties);
|
||||
Fabric8ServicePortData portData = new Fabric8ServicePortData(8080, "http");
|
||||
ServicePortNameAndNumber portData = new ServicePortNameAndNumber(8080, "http");
|
||||
Input input = new Input(portData, "dummy", Map.of(), Map.of("secured", "true"));
|
||||
|
||||
boolean result = secureResolver.resolve(input);
|
||||
@@ -164,7 +163,7 @@ class ServicePortSecureResolverTest {
|
||||
KubernetesDiscoveryProperties properties = new KubernetesDiscoveryProperties(true, true, Set.of(), true, 60,
|
||||
false, null, Set.of(8080), Map.of(), null, KubernetesDiscoveryProperties.Metadata.DEFAULT, 0, true);
|
||||
ServicePortSecureResolver secureResolver = new ServicePortSecureResolver(properties);
|
||||
Fabric8ServicePortData portData = new Fabric8ServicePortData(8080, "http");
|
||||
ServicePortNameAndNumber portData = new ServicePortNameAndNumber(8080, "http");
|
||||
Input input = new Input(portData, "dummy", Map.of(), Map.of());
|
||||
|
||||
boolean result = secureResolver.resolve(input);
|
||||
@@ -178,7 +177,7 @@ class ServicePortSecureResolverTest {
|
||||
KubernetesDiscoveryProperties properties = new KubernetesDiscoveryProperties(true, true, Set.of(), true, 60,
|
||||
false, null, Set.of(8081), Map.of(), null, KubernetesDiscoveryProperties.Metadata.DEFAULT, 0, true);
|
||||
ServicePortSecureResolver secureResolver = new ServicePortSecureResolver(properties);
|
||||
Fabric8ServicePortData portData = new Fabric8ServicePortData(8080, "https");
|
||||
ServicePortNameAndNumber portData = new ServicePortNameAndNumber(8080, "https");
|
||||
Input input = new Input(portData, "dummy", Map.of(), Map.of());
|
||||
|
||||
boolean result = secureResolver.resolve(input);
|
||||
|
||||
Reference in New Issue
Block a user