From 61d83681c2e8256524af76006256a0d6281495ad Mon Sep 17 00:00:00 2001 From: erabii Date: Wed, 2 Aug 2023 21:05:06 +0300 Subject: [PATCH] Move service data to commons (#1394) --- .../discovery/DiscoveryClientUtils.java | 80 ++++ .../discovery/DiscoveryClientUtilsTests.java | 356 ++++++++++++++++++ ...Fabric8KubernetesDiscoveryClientUtils.java | 52 +-- .../discovery/KubernetesDiscoveryClient.java | 23 +- ...c8KubernetesDiscoveryClientUtilsTests.java | 30 ++ .../KubernetesDiscoveryClientUtilsTests.java | 296 --------------- 6 files changed, 488 insertions(+), 349 deletions(-) create mode 100644 spring-cloud-kubernetes-commons/src/main/java/org/springframework/cloud/kubernetes/commons/discovery/DiscoveryClientUtils.java create mode 100644 spring-cloud-kubernetes-commons/src/test/java/org/springframework/cloud/kubernetes/commons/discovery/DiscoveryClientUtilsTests.java diff --git a/spring-cloud-kubernetes-commons/src/main/java/org/springframework/cloud/kubernetes/commons/discovery/DiscoveryClientUtils.java b/spring-cloud-kubernetes-commons/src/main/java/org/springframework/cloud/kubernetes/commons/discovery/DiscoveryClientUtils.java new file mode 100644 index 00000000..140c05fb --- /dev/null +++ b/spring-cloud-kubernetes-commons/src/main/java/org/springframework/cloud/kubernetes/commons/discovery/DiscoveryClientUtils.java @@ -0,0 +1,80 @@ +/* + * 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. + * 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.commons.discovery; + +import java.util.HashMap; +import java.util.Map; + +import org.apache.commons.logging.LogFactory; + +import org.springframework.core.log.LogAccessor; + +import static org.springframework.cloud.kubernetes.commons.config.ConfigUtils.keysWithPrefix; +import static org.springframework.cloud.kubernetes.commons.discovery.KubernetesDiscoveryConstants.NAMESPACE_METADATA_KEY; +import static org.springframework.cloud.kubernetes.commons.discovery.KubernetesDiscoveryConstants.SERVICE_TYPE; + +/** + * @author wind57 + */ +public final class DiscoveryClientUtils { + + private static final LogAccessor LOG = new LogAccessor(LogFactory.getLog(DiscoveryClientUtils.class)); + + private DiscoveryClientUtils() { + throw new AssertionError("no instance provided"); + } + + /** + * This adds the following metadata.
+	 *     - labels (if requested)
+	 *     - annotations (if requested)
+	 *     - ports (if requested)
+	 *     - namespace
+	 *     - service type
+	 * 
+ */ + public static Map serviceMetadata(String serviceId, Map serviceLabels, + Map serviceAnnotations, Map portsData, + KubernetesDiscoveryProperties properties, String namespace, String serviceType) { + Map serviceMetadata = new HashMap<>(); + KubernetesDiscoveryProperties.Metadata metadataProps = properties.metadata(); + if (metadataProps.addLabels()) { + Map labelMetadata = keysWithPrefix(serviceLabels, metadataProps.labelsPrefix()); + LOG.debug(() -> "Adding labels metadata: " + labelMetadata + " for serviceId: " + serviceId); + serviceMetadata.putAll(labelMetadata); + } + if (metadataProps.addAnnotations()) { + Map annotationMetadata = keysWithPrefix(serviceAnnotations, + metadataProps.annotationsPrefix()); + LOG.debug(() -> "Adding annotations metadata: " + annotationMetadata + " for serviceId: " + serviceId); + serviceMetadata.putAll(annotationMetadata); + } + + if (metadataProps.addPorts()) { + Map portMetadata = keysWithPrefix(portsData, properties.metadata().portsPrefix()); + if (!portMetadata.isEmpty()) { + LOG.debug(() -> "Adding port metadata: " + portMetadata + " for serviceId : " + serviceId); + } + serviceMetadata.putAll(portMetadata); + } + + serviceMetadata.put(NAMESPACE_METADATA_KEY, namespace); + serviceMetadata.put(SERVICE_TYPE, serviceType); + return serviceMetadata; + } + +} diff --git a/spring-cloud-kubernetes-commons/src/test/java/org/springframework/cloud/kubernetes/commons/discovery/DiscoveryClientUtilsTests.java b/spring-cloud-kubernetes-commons/src/test/java/org/springframework/cloud/kubernetes/commons/discovery/DiscoveryClientUtilsTests.java new file mode 100644 index 00000000..cf6d923a --- /dev/null +++ b/spring-cloud-kubernetes-commons/src/test/java/org/springframework/cloud/kubernetes/commons/discovery/DiscoveryClientUtilsTests.java @@ -0,0 +1,356 @@ +/* + * Copyright 2013-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. + * 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.commons.discovery; + +import java.util.Map; +import java.util.Set; +import java.util.stream.Collectors; + +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; + +/** + * @author wind57 + */ +@ExtendWith(OutputCaptureExtension.class) +class DiscoveryClientUtilsTests { + + /** + *
+	 *     - labels are not added
+	 *     - annotations are not added
+	 * 
+ */ + @Test + void testServiceMetadataEmpty() { + boolean addLabels = false; + String labelsPrefix = ""; + boolean addAnnotations = false; + String annotationsPrefix = ""; + boolean addPorts = false; + String portsPrefix = ""; + String namespace = "default"; + + Map serviceLabels = Map.of(); + Map serviceAnnotations = Map.of(); + Map portsData = Map.of(); + + KubernetesDiscoveryProperties.Metadata metadata = new KubernetesDiscoveryProperties.Metadata(addLabels, + labelsPrefix, addAnnotations, annotationsPrefix, addPorts, portsPrefix); + KubernetesDiscoveryProperties properties = new KubernetesDiscoveryProperties(true, true, Set.of(), true, 60L, + true, "", Set.of(), Map.of(), "", metadata, 0, false, false); + + Map result = DiscoveryClientUtils.serviceMetadata("my-service", serviceLabels, + serviceAnnotations, portsData, properties, namespace, "ClusterIP"); + Assertions.assertEquals(result.size(), 2); + Assertions.assertEquals(result, Map.of("k8s_namespace", "default", "type", "ClusterIP")); + } + + /** + *
+	 *     - labels are not added, though they are not empty
+	 *     - annotations are not added, though they are not empty
+	 * 
+ */ + @Test + void testServiceMetadataNotEmptyNotTaken() { + boolean addLabels = false; + String labelsPrefix = ""; + boolean addAnnotations = false; + String annotationsPrefix = ""; + boolean addPorts = false; + String portsPrefix = ""; + String namespace = "default"; + + Map serviceLabels = Map.of("a", "1"); + Map serviceAnnotations = Map.of("b", "2"); + Map portsData = Map.of("c", "3"); + + KubernetesDiscoveryProperties.Metadata metadata = new KubernetesDiscoveryProperties.Metadata(addLabels, + labelsPrefix, addAnnotations, annotationsPrefix, addPorts, portsPrefix); + KubernetesDiscoveryProperties properties = new KubernetesDiscoveryProperties(true, true, Set.of(), true, 60L, + true, "", Set.of(), Map.of(), "", metadata, 0, false, false); + + Map result = DiscoveryClientUtils.serviceMetadata("my-service", serviceLabels, + serviceAnnotations, portsData, properties, namespace, "ClusterIP"); + Assertions.assertEquals(result.size(), 2); + Assertions.assertEquals(result, Map.of("k8s_namespace", "default", "type", "ClusterIP")); + } + + /** + *
+	 *     - labels are added without a prefix
+	 *     - annotations are not added
+	 * 
+ */ + @Test + void testServiceMetadataAddLabelsNoPrefix(CapturedOutput output) { + boolean addLabels = true; + String labelsPrefix = ""; + boolean addAnnotations = false; + String annotationsPrefix = ""; + boolean addPorts = false; + String portsPrefix = ""; + String namespace = "default"; + + Map serviceLabels = Map.of("a", "b"); + Map serviceAnnotations = Map.of("c", "2"); + Map portsData = Map.of("d", "3"); + + KubernetesDiscoveryProperties.Metadata metadata = new KubernetesDiscoveryProperties.Metadata(addLabels, + labelsPrefix, addAnnotations, annotationsPrefix, addPorts, portsPrefix); + KubernetesDiscoveryProperties properties = new KubernetesDiscoveryProperties(true, true, Set.of(), true, 60L, + true, "", Set.of(), Map.of(), "", metadata, 0, false, false); + + Map result = DiscoveryClientUtils.serviceMetadata("my-service", serviceLabels, + serviceAnnotations, portsData, properties, namespace, "ClusterIP"); + + Assertions.assertEquals(result.size(), 3); + Assertions.assertEquals(result, Map.of("a", "b", "k8s_namespace", "default", "type", "ClusterIP")); + String labelsMetadata = filterOnK8sNamespaceAndType(result); + Assertions.assertTrue( + output.getOut().contains("Adding labels metadata: " + labelsMetadata + " for serviceId: my-service")); + } + + /** + *
+	 *     - labels are added with prefix
+	 *     - annotations are not added
+	 * 
+ */ + @Test + void testServiceMetadataAddLabelsWithPrefix(CapturedOutput output) { + boolean addLabels = true; + String labelsPrefix = "prefix-"; + boolean addAnnotations = false; + String annotationsPrefix = ""; + boolean addPorts = false; + String portsPrefix = ""; + String namespace = "default"; + + Map serviceLabels = Map.of("a", "b", "c", "d"); + Map serviceAnnotations = Map.of("c", "2"); + Map portsData = Map.of("d", "3"); + + KubernetesDiscoveryProperties.Metadata metadata = new KubernetesDiscoveryProperties.Metadata(addLabels, + labelsPrefix, addAnnotations, annotationsPrefix, addPorts, portsPrefix); + KubernetesDiscoveryProperties properties = new KubernetesDiscoveryProperties(true, true, Set.of(), true, 60L, + true, "", Set.of(), Map.of(), "", metadata, 0, false, false); + + Map result = DiscoveryClientUtils.serviceMetadata("my-service", serviceLabels, + serviceAnnotations, portsData, properties, namespace, "ClusterIP"); + + Assertions.assertEquals(result.size(), 4); + Assertions.assertEquals(result, + Map.of("prefix-a", "b", "prefix-c", "d", "k8s_namespace", "default", "type", "ClusterIP")); + // so that result is deterministic in assertion + String labelsMetadata = filterOnK8sNamespaceAndType(result); + Assertions.assertTrue( + output.getOut().contains("Adding labels metadata: " + labelsMetadata + " for serviceId: my-service")); + } + + /** + *
+	 *     - labels are not added
+	 *     - annotations are added without prefix
+	 * 
+ */ + @Test + void testServiceMetadataAddAnnotationsNoPrefix(CapturedOutput output) { + boolean addLabels = false; + String labelsPrefix = ""; + boolean addAnnotations = true; + String annotationsPrefix = ""; + boolean addPorts = false; + String portsPrefix = ""; + String namespace = "default"; + + Map serviceLabels = Map.of("a", "b"); + Map serviceAnnotations = Map.of("aa", "bb"); + Map portsData = Map.of("d", "3"); + + KubernetesDiscoveryProperties.Metadata metadata = new KubernetesDiscoveryProperties.Metadata(addLabels, + labelsPrefix, addAnnotations, annotationsPrefix, addPorts, portsPrefix); + KubernetesDiscoveryProperties properties = new KubernetesDiscoveryProperties(true, true, Set.of(), true, 60L, + true, "", Set.of(), Map.of(), "", metadata, 0, false, false); + + Map result = DiscoveryClientUtils.serviceMetadata("my-service", serviceLabels, + serviceAnnotations, portsData, properties, namespace, "ClusterIP"); + + Assertions.assertEquals(result.size(), 3); + Assertions.assertEquals(result, Map.of("aa", "bb", "k8s_namespace", "default", "type", "ClusterIP")); + Assertions + .assertTrue(output.getOut().contains("Adding annotations metadata: {aa=bb} for serviceId: my-service")); + } + + /** + *
+	 *     - labels are not added
+	 *     - annotations are added with prefix
+	 * 
+ */ + @Test + void testServiceMetadataAddAnnotationsWithPrefix(CapturedOutput output) { + boolean addLabels = false; + String labelsPrefix = ""; + boolean addAnnotations = true; + String annotationsPrefix = "prefix-"; + boolean addPorts = false; + String portsPrefix = ""; + String namespace = "default"; + + Map serviceLabels = Map.of("a", "b"); + Map serviceAnnotations = Map.of("aa", "bb", "cc", "dd"); + Map portsData = Map.of("d", "3"); + + KubernetesDiscoveryProperties.Metadata metadata = new KubernetesDiscoveryProperties.Metadata(addLabels, + labelsPrefix, addAnnotations, annotationsPrefix, addPorts, portsPrefix); + KubernetesDiscoveryProperties properties = new KubernetesDiscoveryProperties(true, true, Set.of(), true, 60L, + true, "", Set.of(), Map.of(), "", metadata, 0, false, false); + + Map result = DiscoveryClientUtils.serviceMetadata("my-service", serviceLabels, + serviceAnnotations, portsData, properties, namespace, "ClusterIP"); + + Assertions.assertEquals(result.size(), 4); + Assertions.assertEquals(result, + Map.of("prefix-aa", "bb", "prefix-cc", "dd", "k8s_namespace", "default", "type", "ClusterIP")); + // so that result is deterministic in assertion + String annotations = filterOnK8sNamespaceAndType(result); + Assertions.assertTrue( + output.getOut().contains("Adding annotations metadata: " + annotations + " for serviceId: my-service")); + } + + /** + *
+	 *     - labels are added with prefix
+	 *     - annotations are added with prefix
+	 * 
+ */ + @Test + void testServiceMetadataAddLabelsAndAnnotationsWithPrefix(CapturedOutput output) { + boolean addLabels = true; + String labelsPrefix = "label-"; + boolean addAnnotations = true; + String annotationsPrefix = "annotation-"; + boolean addPorts = false; + String portsPrefix = ""; + String namespace = "default"; + + Map serviceLabels = Map.of("a", "b", "c", "d"); + Map serviceAnnotations = Map.of("aa", "bb", "cc", "dd"); + Map portsData = Map.of("d", "3"); + + KubernetesDiscoveryProperties.Metadata metadata = new KubernetesDiscoveryProperties.Metadata(addLabels, + labelsPrefix, addAnnotations, annotationsPrefix, addPorts, portsPrefix); + KubernetesDiscoveryProperties properties = new KubernetesDiscoveryProperties(true, true, Set.of(), true, 60L, + true, "", Set.of(), Map.of(), "", metadata, 0, false, false); + + Map result = DiscoveryClientUtils.serviceMetadata("my-service", serviceLabels, + serviceAnnotations, portsData, properties, namespace, "ClusterIP"); + + Assertions.assertEquals(result.size(), 6); + Assertions.assertEquals(result, Map.of("annotation-aa", "bb", "annotation-cc", "dd", "label-a", "b", "label-c", + "d", "k8s_namespace", "default", "type", "ClusterIP")); + // so that result is deterministic in assertion + String labels = result.entrySet().stream().filter(en -> en.getKey().contains("label")) + .collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue)).toString(); + String annotations = result.entrySet().stream().filter(en -> en.getKey().contains("annotation")) + .collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue)).toString(); + Assertions.assertTrue( + output.getOut().contains("Adding labels metadata: " + labels + " for serviceId: my-service")); + Assertions.assertTrue( + output.getOut().contains("Adding annotations metadata: " + annotations + " for serviceId: my-service")); + } + + /** + *
+	 *     - ports without prefix are added
+	 * 
+ */ + @Test + void testServiceMetadataAddPortsWithoutPrefix(CapturedOutput output) { + boolean addLabels = false; + String labelsPrefix = ""; + boolean addAnnotations = false; + String annotationsPrefix = "prefix-"; + boolean addPorts = true; + String portsPrefix = ""; + String namespace = "default"; + + Map serviceLabels = Map.of("a", "b"); + Map serviceAnnotations = Map.of("aa", "bb", "cc", "dd"); + Map portsData = Map.of("https", "8080"); + + KubernetesDiscoveryProperties.Metadata metadata = new KubernetesDiscoveryProperties.Metadata(addLabels, + labelsPrefix, addAnnotations, annotationsPrefix, addPorts, portsPrefix); + KubernetesDiscoveryProperties properties = new KubernetesDiscoveryProperties(true, true, Set.of(), true, 60L, + true, "", Set.of(), Map.of(), "", metadata, 0, false, false); + + Map result = DiscoveryClientUtils.serviceMetadata("my-service", serviceLabels, + serviceAnnotations, portsData, properties, namespace, "ClusterIP"); + + Assertions.assertEquals(result.size(), 3); + Assertions.assertEquals(result, Map.of("https", "8080", "k8s_namespace", "default", "type", "ClusterIP")); + Assertions + .assertTrue(output.getOut().contains("Adding port metadata: {https=8080} for serviceId : my-service")); + } + + /** + *
+	 *     - ports without prefix are added
+	 * 
+ */ + @Test + void testServiceMetadataAddPortsWithPrefix(CapturedOutput output) { + boolean addLabels = false; + String labelsPrefix = ""; + boolean addAnnotations = false; + String annotationsPrefix = "prefix-"; + boolean addPorts = true; + String portsPrefix = "prefix-"; + String namespace = "default"; + + Map serviceLabels = Map.of("a", "b"); + Map serviceAnnotations = Map.of("aa", "bb", "cc", "dd"); + Map portsData = Map.of("http", "8081", "https", "8080"); + + KubernetesDiscoveryProperties.Metadata metadata = new KubernetesDiscoveryProperties.Metadata(addLabels, + labelsPrefix, addAnnotations, annotationsPrefix, addPorts, portsPrefix); + KubernetesDiscoveryProperties properties = new KubernetesDiscoveryProperties(true, true, Set.of(), true, 60L, + true, "", Set.of(), Map.of(), "", metadata, 0, false, false); + + Map result = DiscoveryClientUtils.serviceMetadata("my-service", serviceLabels, + serviceAnnotations, portsData, properties, namespace, "ClusterIP"); + + Assertions.assertEquals(result.size(), 4); + Assertions.assertEquals(result, + Map.of("prefix-https", "8080", "prefix-http", "8081", "k8s_namespace", "default", "type", "ClusterIP")); + Assertions.assertTrue(output.getOut() + .contains("Adding port metadata: {prefix-http=8081, prefix-https=8080} for serviceId : my-service")); + } + + private String filterOnK8sNamespaceAndType(Map result) { + return result.entrySet().stream().filter(en -> !en.getKey().contains("k8s_namespace")) + .filter(en -> !en.getKey().equals("type")) + .collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue)).toString(); + } + +} diff --git a/spring-cloud-kubernetes-fabric8-discovery/src/main/java/org/springframework/cloud/kubernetes/fabric8/discovery/Fabric8KubernetesDiscoveryClientUtils.java b/spring-cloud-kubernetes-fabric8-discovery/src/main/java/org/springframework/cloud/kubernetes/fabric8/discovery/Fabric8KubernetesDiscoveryClientUtils.java index 591eb8fa..4df970d2 100644 --- a/spring-cloud-kubernetes-fabric8-discovery/src/main/java/org/springframework/cloud/kubernetes/fabric8/discovery/Fabric8KubernetesDiscoveryClientUtils.java +++ b/spring-cloud-kubernetes-fabric8-discovery/src/main/java/org/springframework/cloud/kubernetes/fabric8/discovery/Fabric8KubernetesDiscoveryClientUtils.java @@ -52,12 +52,9 @@ import org.springframework.core.log.LogAccessor; import org.springframework.util.CollectionUtils; import org.springframework.util.StringUtils; -import static java.util.stream.Collectors.toMap; -import static org.springframework.cloud.kubernetes.commons.config.ConfigUtils.keysWithPrefix; 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.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; import static org.springframework.cloud.kubernetes.fabric8.discovery.ServicePortSecureResolver.Input; @@ -152,49 +149,6 @@ final class Fabric8KubernetesDiscoveryClientUtils { return primaryPortName; } - /** - * This adds the following metadata.
-	 *     - labels (if requested)
-	 *     - annotations (if requested)
-	 *     - ports (if requested)
-	 *     - namespace
-	 *     - service type
-	 * 
- */ - static Map serviceMetadata(String serviceId, Service service, - KubernetesDiscoveryProperties properties, List endpointSubsets, String namespace) { - Map serviceMetadata = new HashMap<>(); - KubernetesDiscoveryProperties.Metadata metadataProps = properties.metadata(); - if (metadataProps.addLabels()) { - Map labelMetadata = keysWithPrefix(service.getMetadata().getLabels(), - metadataProps.labelsPrefix()); - LOG.debug(() -> "Adding labels metadata: " + labelMetadata + " for serviceId: " + serviceId); - serviceMetadata.putAll(labelMetadata); - } - if (metadataProps.addAnnotations()) { - Map annotationMetadata = keysWithPrefix(service.getMetadata().getAnnotations(), - metadataProps.annotationsPrefix()); - LOG.debug(() -> "Adding annotations metadata: " + annotationMetadata + " for serviceId: " + serviceId); - serviceMetadata.putAll(annotationMetadata); - } - - if (metadataProps.addPorts()) { - Map ports = endpointSubsets.stream() - .flatMap(endpointSubset -> endpointSubset.getPorts().stream()) - .filter(port -> StringUtils.hasText(port.getName())) - .collect(toMap(EndpointPort::getName, port -> Integer.toString(port.getPort()))); - Map portMetadata = keysWithPrefix(ports, properties.metadata().portsPrefix()); - if (!portMetadata.isEmpty()) { - LOG.debug(() -> "Adding port metadata: " + portMetadata + " for serviceId : " + serviceId); - } - serviceMetadata.putAll(portMetadata); - } - - serviceMetadata.put(NAMESPACE_METADATA_KEY, namespace); - serviceMetadata.put(SERVICE_TYPE, service.getSpec().getType()); - return serviceMetadata; - } - static List endpoints(KubernetesDiscoveryProperties properties, KubernetesClient client, KubernetesNamespaceProvider namespaceProvider, String target, @Nullable String serviceName, Predicate filter) { @@ -376,6 +330,12 @@ final class Fabric8KubernetesDiscoveryClientUtils { return Map.of(); } + static Map portsData(List endpointSubsets) { + return endpointSubsets.stream().flatMap(endpointSubset -> endpointSubset.getPorts().stream()) + .filter(port -> StringUtils.hasText(port.getName())) + .collect(Collectors.toMap(EndpointPort::getName, port -> Integer.toString(port.getPort()))); + } + /** * serviceName can be null, in which case, such a filter will not be applied. */ diff --git a/spring-cloud-kubernetes-fabric8-discovery/src/main/java/org/springframework/cloud/kubernetes/fabric8/discovery/KubernetesDiscoveryClient.java b/spring-cloud-kubernetes-fabric8-discovery/src/main/java/org/springframework/cloud/kubernetes/fabric8/discovery/KubernetesDiscoveryClient.java index 031cdc6f..149d0679 100644 --- a/spring-cloud-kubernetes-fabric8-discovery/src/main/java/org/springframework/cloud/kubernetes/fabric8/discovery/KubernetesDiscoveryClient.java +++ b/spring-cloud-kubernetes-fabric8-discovery/src/main/java/org/springframework/cloud/kubernetes/fabric8/discovery/KubernetesDiscoveryClient.java @@ -25,6 +25,7 @@ import java.util.function.Predicate; import io.fabric8.kubernetes.api.model.EndpointAddress; import io.fabric8.kubernetes.api.model.EndpointSubset; import io.fabric8.kubernetes.api.model.Endpoints; +import io.fabric8.kubernetes.api.model.ObjectMeta; import io.fabric8.kubernetes.api.model.Service; import io.fabric8.kubernetes.client.KubernetesClient; import org.apache.commons.logging.LogFactory; @@ -32,6 +33,7 @@ import org.apache.commons.logging.LogFactory; import org.springframework.cloud.client.ServiceInstance; 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.context.EnvironmentAware; import org.springframework.core.env.Environment; @@ -41,8 +43,8 @@ import static org.springframework.cloud.kubernetes.commons.discovery.KubernetesD import static org.springframework.cloud.kubernetes.fabric8.discovery.Fabric8KubernetesDiscoveryClientUtils.addresses; 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.serviceMetadata; import static org.springframework.cloud.kubernetes.fabric8.discovery.Fabric8KubernetesDiscoveryClientUtils.services; /** @@ -119,11 +121,14 @@ public class KubernetesDiscoveryClient implements DiscoveryClient, EnvironmentAw s -> s.getSpec().getType().equals(EXTERNAL_NAME), Map.of("metadata.name", serviceId), "fabric8-discovery"); for (Service service : services) { - Map serviceMetadata = serviceMetadata(serviceId, service, properties, List.of(), - service.getMetadata().getNamespace()); + ObjectMeta serviceMetadata = service.getMetadata(); + Map result = DiscoveryClientUtils.serviceMetadata(serviceId, + serviceMetadata.getLabels(), serviceMetadata.getAnnotations(), Map.of(), properties, + serviceMetadata.getNamespace(), service.getSpec().getType()); + ServiceInstance externalNameServiceInstance = serviceInstance(null, service, null, - new Fabric8ServicePortData(-1, null), serviceId, serviceMetadata, - service.getMetadata().getNamespace(), properties, client); + new Fabric8ServicePortData(-1, null), serviceId, result, service.getMetadata().getNamespace(), + properties, client); instances.add(externalNameServiceInstance); } } @@ -147,14 +152,18 @@ public class KubernetesDiscoveryClient implements DiscoveryClient, EnvironmentAw List instances = new ArrayList<>(); Service service = client.services().inNamespace(namespace).withName(serviceId).get(); - Map serviceMetadata = serviceMetadata(serviceId, service, properties, subsets, namespace); + ObjectMeta serviceMetadata = service.getMetadata(); + + Map result = DiscoveryClientUtils.serviceMetadata(serviceId, serviceMetadata.getLabels(), + serviceMetadata.getAnnotations(), portsData(subsets), properties, serviceMetadata.getNamespace(), + service.getSpec().getType()); for (EndpointSubset endpointSubset : subsets) { Fabric8ServicePortData portData = endpointsPort(endpointSubset, serviceId, properties, service); List addresses = addresses(endpointSubset, properties); for (EndpointAddress endpointAddress : addresses) { ServiceInstance serviceInstance = serviceInstance(servicePortSecureResolver, service, endpointAddress, - portData, serviceId, serviceMetadata, namespace, properties, client); + portData, serviceId, result, namespace, properties, client); instances.add(serviceInstance); } } diff --git a/spring-cloud-kubernetes-fabric8-discovery/src/test/java/org/springframework/cloud/kubernetes/fabric8/discovery/Fabric8KubernetesDiscoveryClientUtilsTests.java b/spring-cloud-kubernetes-fabric8-discovery/src/test/java/org/springframework/cloud/kubernetes/fabric8/discovery/Fabric8KubernetesDiscoveryClientUtilsTests.java index cce2a443..7199f1bb 100644 --- a/spring-cloud-kubernetes-fabric8-discovery/src/test/java/org/springframework/cloud/kubernetes/fabric8/discovery/Fabric8KubernetesDiscoveryClientUtilsTests.java +++ b/spring-cloud-kubernetes-fabric8-discovery/src/test/java/org/springframework/cloud/kubernetes/fabric8/discovery/Fabric8KubernetesDiscoveryClientUtilsTests.java @@ -20,6 +20,9 @@ import java.util.List; import java.util.Map; import java.util.Set; +import io.fabric8.kubernetes.api.model.EndpointPortBuilder; +import io.fabric8.kubernetes.api.model.EndpointSubset; +import io.fabric8.kubernetes.api.model.EndpointSubsetBuilder; import io.fabric8.kubernetes.api.model.Service; import io.fabric8.kubernetes.api.model.ServiceBuilder; import io.fabric8.kubernetes.api.model.ServiceSpecBuilder; @@ -280,6 +283,33 @@ class Fabric8KubernetesDiscoveryClientUtilsTests { Assertions.assertEquals(result.get(0).getMetadata().getName(), "external-name-service"); } + @Test + void testPortsDataOne() { + List endpointSubsets = List.of( + new EndpointSubsetBuilder().withPorts(new EndpointPortBuilder().withPort(8081).withName("").build()) + .build(), + new EndpointSubsetBuilder() + .withPorts(new EndpointPortBuilder().withPort(8080).withName("https").build()).build()); + + Map portsData = Fabric8KubernetesDiscoveryClientUtils.portsData(endpointSubsets); + Assertions.assertEquals(portsData.size(), 1); + Assertions.assertEquals(portsData.get("https"), "8080"); + } + + @Test + void testPortsDataTwo() { + List endpointSubsets = List.of( + new EndpointSubsetBuilder().withPorts(new EndpointPortBuilder().withPort(8081).withName("http").build()) + .build(), + new EndpointSubsetBuilder() + .withPorts(new EndpointPortBuilder().withPort(8080).withName("https").build()).build()); + + Map portsData = Fabric8KubernetesDiscoveryClientUtils.portsData(endpointSubsets); + Assertions.assertEquals(portsData.size(), 2); + Assertions.assertEquals(portsData.get("https"), "8080"); + Assertions.assertEquals(portsData.get("http"), "8081"); + } + private void service(String name, String namespace, Map labels) { Service service = new ServiceBuilder().withNewMetadata().withName(name).withLabels(labels) .withNamespace(namespace).and().build(); diff --git a/spring-cloud-kubernetes-fabric8-discovery/src/test/java/org/springframework/cloud/kubernetes/fabric8/discovery/KubernetesDiscoveryClientUtilsTests.java b/spring-cloud-kubernetes-fabric8-discovery/src/test/java/org/springframework/cloud/kubernetes/fabric8/discovery/KubernetesDiscoveryClientUtilsTests.java index 366ca511..8a42ef27 100644 --- a/spring-cloud-kubernetes-fabric8-discovery/src/test/java/org/springframework/cloud/kubernetes/fabric8/discovery/KubernetesDiscoveryClientUtilsTests.java +++ b/spring-cloud-kubernetes-fabric8-discovery/src/test/java/org/springframework/cloud/kubernetes/fabric8/discovery/KubernetesDiscoveryClientUtilsTests.java @@ -19,7 +19,6 @@ package org.springframework.cloud.kubernetes.fabric8.discovery; import java.util.List; import java.util.Map; import java.util.Set; -import java.util.stream.Collectors; import io.fabric8.kubernetes.api.model.EndpointAddress; import io.fabric8.kubernetes.api.model.EndpointAddressBuilder; @@ -357,295 +356,6 @@ class KubernetesDiscoveryClientUtilsTests { Assertions.assertTrue(output.getOut().contains("found primary-port-name via 'http' to match port : 8082")); } - /** - *
-	 *     - labels are not added
-	 *     - annotations are not added
-	 * 
- */ - @Test - void testServiceMetadataEmpty() { - boolean addLabels = false; - String labelsPrefix = ""; - boolean addAnnotations = false; - String annotationsPrefix = ""; - boolean addPorts = false; - String portsPrefix = ""; - - String namespace = "default"; - - KubernetesDiscoveryProperties.Metadata metadata = new KubernetesDiscoveryProperties.Metadata(addLabels, - labelsPrefix, addAnnotations, annotationsPrefix, addPorts, portsPrefix); - KubernetesDiscoveryProperties properties = new KubernetesDiscoveryProperties(true, true, Set.of(), true, 60L, - true, "", Set.of(), Map.of(), "", metadata, 0, false, false); - Service service = new ServiceBuilder().withSpec(new ServiceSpecBuilder().withType("ClusterIP").build()).build(); - - Map result = Fabric8KubernetesDiscoveryClientUtils.serviceMetadata("my-service", service, - properties, List.of(), namespace); - Assertions.assertEquals(result.size(), 2); - Assertions.assertEquals(result, Map.of("k8s_namespace", "default", "type", "ClusterIP")); - } - - /** - *
-	 *     - labels are added without a prefix
-	 *     - annotations are not added
-	 * 
- */ - @Test - void testServiceMetadataAddLabelsNoPrefix(CapturedOutput output) { - boolean addLabels = true; - String labelsPrefix = ""; - boolean addAnnotations = false; - String annotationsPrefix = ""; - boolean addPorts = false; - String portsPrefix = ""; - - String namespace = "default"; - - KubernetesDiscoveryProperties.Metadata metadata = new KubernetesDiscoveryProperties.Metadata(addLabels, - labelsPrefix, addAnnotations, annotationsPrefix, addPorts, portsPrefix); - KubernetesDiscoveryProperties properties = new KubernetesDiscoveryProperties(true, true, Set.of(), true, 60L, - true, "", Set.of(), Map.of(), "", metadata, 0, false, false); - Service service = new ServiceBuilder().withSpec(new ServiceSpecBuilder().withType("ClusterIP").build()) - .withMetadata(new ObjectMetaBuilder().withLabels(Map.of("a", "b")).build()).build(); - - Map result = Fabric8KubernetesDiscoveryClientUtils.serviceMetadata("my-service", service, - properties, List.of(), namespace); - Assertions.assertEquals(result.size(), 3); - Assertions.assertEquals(result, Map.of("a", "b", "k8s_namespace", "default", "type", "ClusterIP")); - String labelsMetadata = filterOnK8sNamespaceAndType(result); - Assertions.assertTrue( - output.getOut().contains("Adding labels metadata: " + labelsMetadata + " for serviceId: my-service")); - } - - /** - *
-	 *     - labels are added with prefix
-	 *     - annotations are not added
-	 * 
- */ - @Test - void testServiceMetadataAddLabelsWithPrefix(CapturedOutput output) { - boolean addLabels = true; - String labelsPrefix = "prefix-"; - boolean addAnnotations = false; - String annotationsPrefix = ""; - boolean addPorts = false; - String portsPrefix = ""; - - String namespace = "default"; - - KubernetesDiscoveryProperties.Metadata metadata = new KubernetesDiscoveryProperties.Metadata(addLabels, - labelsPrefix, addAnnotations, annotationsPrefix, addPorts, portsPrefix); - KubernetesDiscoveryProperties properties = new KubernetesDiscoveryProperties(true, true, Set.of(), true, 60L, - true, "", Set.of(), Map.of(), "", metadata, 0, false, false); - Service service = new ServiceBuilder().withSpec(new ServiceSpecBuilder().withType("ClusterIP").build()) - .withMetadata(new ObjectMetaBuilder().withLabels(Map.of("a", "b", "c", "d")).build()).build(); - - Map result = Fabric8KubernetesDiscoveryClientUtils.serviceMetadata("my-service", service, - properties, List.of(), namespace); - Assertions.assertEquals(result.size(), 4); - Assertions.assertEquals(result, - Map.of("prefix-a", "b", "prefix-c", "d", "k8s_namespace", "default", "type", "ClusterIP")); - // so that result is deterministic in assertion - String labelsMetadata = filterOnK8sNamespaceAndType(result); - Assertions.assertTrue( - output.getOut().contains("Adding labels metadata: " + labelsMetadata + " for serviceId: my-service")); - } - - /** - *
-	 *     - labels are not added
-	 *     - annotations are added without prefix
-	 * 
- */ - @Test - void testServiceMetadataAddAnnotationsNoPrefix(CapturedOutput output) { - boolean addLabels = false; - String labelsPrefix = ""; - boolean addAnnotations = true; - String annotationsPrefix = ""; - boolean addPorts = false; - String portsPrefix = ""; - - String namespace = "default"; - - KubernetesDiscoveryProperties.Metadata metadata = new KubernetesDiscoveryProperties.Metadata(addLabels, - labelsPrefix, addAnnotations, annotationsPrefix, addPorts, portsPrefix); - KubernetesDiscoveryProperties properties = new KubernetesDiscoveryProperties(true, true, Set.of(), true, 60L, - true, "", Set.of(), Map.of(), "", metadata, 0, false, false); - Service service = new ServiceBuilder().withSpec(new ServiceSpecBuilder().withType("ClusterIP").build()) - .withMetadata(new ObjectMetaBuilder().withAnnotations(Map.of("aa", "bb")).withLabels(Map.of("a", "b")) - .build()) - .build(); - - Map result = Fabric8KubernetesDiscoveryClientUtils.serviceMetadata("my-service", service, - properties, List.of(), namespace); - Assertions.assertEquals(result.size(), 3); - Assertions.assertEquals(result, Map.of("aa", "bb", "k8s_namespace", "default", "type", "ClusterIP")); - Assertions - .assertTrue(output.getOut().contains("Adding annotations metadata: {aa=bb} for serviceId: my-service")); - } - - /** - *
-	 *     - labels are not added
-	 *     - annotations are added with prefix
-	 * 
- */ - @Test - void testServiceMetadataAddAnnotationsWithPrefix(CapturedOutput output) { - boolean addLabels = false; - String labelsPrefix = ""; - boolean addAnnotations = true; - String annotationsPrefix = "prefix-"; - boolean addPorts = false; - String portsPrefix = ""; - - String namespace = "default"; - - KubernetesDiscoveryProperties.Metadata metadata = new KubernetesDiscoveryProperties.Metadata(addLabels, - labelsPrefix, addAnnotations, annotationsPrefix, addPorts, portsPrefix); - KubernetesDiscoveryProperties properties = new KubernetesDiscoveryProperties(true, true, Set.of(), true, 60L, - true, "", Set.of(), Map.of(), "", metadata, 0, false, false); - Service service = new ServiceBuilder().withSpec(new ServiceSpecBuilder().withType("ClusterIP").build()) - .withMetadata(new ObjectMetaBuilder().withAnnotations(Map.of("aa", "bb", "cc", "dd")) - .withLabels(Map.of("a", "b")).build()) - .build(); - - Map result = Fabric8KubernetesDiscoveryClientUtils.serviceMetadata("my-service", service, - properties, List.of(), namespace); - Assertions.assertEquals(result.size(), 4); - Assertions.assertEquals(result, - Map.of("prefix-aa", "bb", "prefix-cc", "dd", "k8s_namespace", "default", "type", "ClusterIP")); - // so that result is deterministic in assertion - String annotations = filterOnK8sNamespaceAndType(result); - Assertions.assertTrue( - output.getOut().contains("Adding annotations metadata: " + annotations + " for serviceId: my-service")); - } - - /** - *
-	 *     - labels are added with prefix
-	 *     - annotations are added with prefix
-	 * 
- */ - @Test - void testServiceMetadataAddLabelsAndAnnotationsWithPrefix(CapturedOutput output) { - boolean addLabels = true; - String labelsPrefix = "label-"; - boolean addAnnotations = true; - String annotationsPrefix = "annotation-"; - boolean addPorts = false; - String portsPrefix = ""; - - String namespace = "default"; - - KubernetesDiscoveryProperties.Metadata metadata = new KubernetesDiscoveryProperties.Metadata(addLabels, - labelsPrefix, addAnnotations, annotationsPrefix, addPorts, portsPrefix); - KubernetesDiscoveryProperties properties = new KubernetesDiscoveryProperties(true, true, Set.of(), true, 60L, - true, "", Set.of(), Map.of(), "", metadata, 0, false, false); - Service service = new ServiceBuilder() - .withSpec(new ServiceSpecBuilder().withType("ClusterIP").build()).withMetadata(new ObjectMetaBuilder() - .withAnnotations(Map.of("aa", "bb", "cc", "dd")).withLabels(Map.of("a", "b", "c", "d")).build()) - .build(); - - Map result = Fabric8KubernetesDiscoveryClientUtils.serviceMetadata("my-service", service, - properties, List.of(), namespace); - Assertions.assertEquals(result.size(), 6); - Assertions.assertEquals(result, Map.of("annotation-aa", "bb", "annotation-cc", "dd", "label-a", "b", "label-c", - "d", "k8s_namespace", "default", "type", "ClusterIP")); - // so that result is deterministic in assertion - String labels = result.entrySet().stream().filter(en -> en.getKey().contains("label")) - .collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue)).toString(); - String annotations = result.entrySet().stream().filter(en -> en.getKey().contains("annotation")) - .collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue)).toString(); - Assertions.assertTrue( - output.getOut().contains("Adding labels metadata: " + labels + " for serviceId: my-service")); - Assertions.assertTrue( - output.getOut().contains("Adding annotations metadata: " + annotations + " for serviceId: my-service")); - } - - /** - *
-	 *     - ports without prefix are added
-	 * 
- */ - @Test - void testServiceMetadataAddPortsWithoutPrefix(CapturedOutput output) { - boolean addLabels = false; - String labelsPrefix = ""; - boolean addAnnotations = false; - String annotationsPrefix = "prefix-"; - boolean addPorts = true; - String portsPrefix = ""; - - String namespace = "default"; - - KubernetesDiscoveryProperties.Metadata metadata = new KubernetesDiscoveryProperties.Metadata(addLabels, - labelsPrefix, addAnnotations, annotationsPrefix, addPorts, portsPrefix); - KubernetesDiscoveryProperties properties = new KubernetesDiscoveryProperties(true, true, Set.of(), true, 60L, - true, "", Set.of(), Map.of(), "", metadata, 0, false, false); - Service service = new ServiceBuilder().withSpec(new ServiceSpecBuilder().withType("ClusterIP").build()) - .withMetadata(new ObjectMetaBuilder().withAnnotations(Map.of("aa", "bb", "cc", "dd")) - .withLabels(Map.of("a", "b")).build()) - .build(); - - List endpointSubsets = List.of( - new EndpointSubsetBuilder().withPorts(new EndpointPortBuilder().withPort(8081).withName("").build()) - .build(), - new EndpointSubsetBuilder() - .withPorts(new EndpointPortBuilder().withPort(8080).withName("https").build()).build()); - - Map result = Fabric8KubernetesDiscoveryClientUtils.serviceMetadata("my-service", service, - properties, endpointSubsets, namespace); - Assertions.assertEquals(result.size(), 3); - Assertions.assertEquals(result, Map.of("https", "8080", "k8s_namespace", "default", "type", "ClusterIP")); - Assertions - .assertTrue(output.getOut().contains("Adding port metadata: {https=8080} for serviceId : my-service")); - } - - /** - *
-	 *     - ports without prefix are added
-	 * 
- */ - @Test - void testServiceMetadataAddPortsWithPrefix(CapturedOutput output) { - boolean addLabels = false; - String labelsPrefix = ""; - boolean addAnnotations = false; - String annotationsPrefix = "prefix-"; - boolean addPorts = true; - String portsPrefix = "prefix-"; - - String namespace = "default"; - - KubernetesDiscoveryProperties.Metadata metadata = new KubernetesDiscoveryProperties.Metadata(addLabels, - labelsPrefix, addAnnotations, annotationsPrefix, addPorts, portsPrefix); - KubernetesDiscoveryProperties properties = new KubernetesDiscoveryProperties(true, true, Set.of(), true, 60L, - true, "", Set.of(), Map.of(), "", metadata, 0, false, false); - Service service = new ServiceBuilder().withSpec(new ServiceSpecBuilder().withType("ClusterIP").build()) - .withMetadata(new ObjectMetaBuilder().withAnnotations(Map.of("aa", "bb", "cc", "dd")) - .withLabels(Map.of("a", "b")).build()) - .build(); - - List endpointSubsets = List.of( - new EndpointSubsetBuilder().withPorts(new EndpointPortBuilder().withPort(8081).withName("http").build()) - .build(), - new EndpointSubsetBuilder() - .withPorts(new EndpointPortBuilder().withPort(8080).withName("https").build()).build()); - - Map result = Fabric8KubernetesDiscoveryClientUtils.serviceMetadata("my-service", service, - properties, endpointSubsets, namespace); - Assertions.assertEquals(result.size(), 4); - Assertions.assertEquals(result, - Map.of("prefix-https", "8080", "prefix-http", "8081", "k8s_namespace", "default", "type", "ClusterIP")); - Assertions.assertTrue(output.getOut() - .contains("Adding port metadata: {prefix-http=8081, prefix-https=8080} for serviceId : my-service")); - } - /** *
 	 *      - ready addresses are empty
@@ -797,10 +507,4 @@ class KubernetesDiscoveryClientUtilsTests {
 		Assertions.assertNull(defaultInstance.getCluster());
 	}
 
-	private String filterOnK8sNamespaceAndType(Map result) {
-		return result.entrySet().stream().filter(en -> !en.getKey().contains("k8s_namespace"))
-				.filter(en -> !en.getKey().equals("type"))
-				.collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue)).toString();
-	}
-
 }