Clean fabric8 discovery 1 (#1183)

This commit is contained in:
erabii
2023-01-12 16:55:36 +02:00
committed by GitHub
parent 6913f2c5b8
commit 8260df5c8e
6 changed files with 628 additions and 72 deletions

View File

@@ -48,7 +48,20 @@
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
<!-- in favor of mockito-inline -->
<exclusions>
<exclusion>
<groupId>org.mockito</groupId>
<artifactId>mockito-core</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.mockito</groupId>
<artifactId>mockito-inline</artifactId>
</dependency>
<dependency>
<groupId>org.junit.vintage</groupId>
<artifactId>junit-vintage-engine</artifactId>

View File

@@ -0,0 +1,92 @@
/*
* Copyright 2012-2022 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.fabric8.discovery;
import java.util.ArrayList;
import java.util.List;
import java.util.Optional;
import java.util.function.Function;
import java.util.function.Predicate;
import io.fabric8.kubernetes.api.model.Service;
import io.fabric8.kubernetes.client.KubernetesClient;
import org.springframework.cloud.kubernetes.commons.discovery.KubernetesDiscoveryProperties;
import org.springframework.expression.Expression;
import org.springframework.expression.spel.standard.SpelExpressionParser;
import org.springframework.expression.spel.support.SimpleEvaluationContext;
/**
* Adapts a {@link KubernetesClientServicesFunction} to a Function that takes a
* KubernetesClient as input and returns a List of Services(s), plus adds functionality
* not supported by it.
*
* @author wind57
*/
final class Fabric8DiscoveryServicesAdapter implements Function<KubernetesClient, List<Service>> {
private static final SpelExpressionParser PARSER = new SpelExpressionParser();
private static final SimpleEvaluationContext EVALUATION_CONTEXT = SimpleEvaluationContext.forReadOnlyDataBinding()
.withInstanceMethods().build();
private final KubernetesClientServicesFunction function;
private final KubernetesDiscoveryProperties properties;
private final Predicate<Service> filter;
Fabric8DiscoveryServicesAdapter(KubernetesClientServicesFunction function, KubernetesDiscoveryProperties properties,
Predicate<Service> filter) {
this.function = function;
this.properties = properties;
if (filter == null) {
this.filter = filter();
}
else {
this.filter = filter;
}
}
@Override
public List<Service> apply(KubernetesClient client) {
if (!properties.namespaces().isEmpty()) {
List<Service> services = new ArrayList<>();
properties.namespaces().forEach(namespace -> services.addAll(client.services().inNamespace(namespace)
.withLabels(properties.serviceLabels()).list().getItems().stream().filter(filter).toList()));
return services;
}
return function.apply(client).list().getItems().stream().filter(filter).toList();
}
Predicate<Service> filter() {
String spelExpression = properties.filter();
Predicate<Service> predicate;
if (spelExpression == null || spelExpression.isEmpty()) {
predicate = service -> true;
}
else {
Expression filterExpr = PARSER.parseExpression(spelExpression);
predicate = service -> {
Boolean include = filterExpr.getValue(EVALUATION_CONTEXT, service, Boolean.class);
return Optional.ofNullable(include).orElse(false);
};
}
return predicate;
}
}

View File

@@ -36,9 +36,6 @@ import org.springframework.cloud.client.ServiceInstance;
import org.springframework.cloud.client.discovery.DiscoveryClient;
import org.springframework.cloud.kubernetes.commons.discovery.DefaultKubernetesServiceInstance;
import org.springframework.cloud.kubernetes.commons.discovery.KubernetesDiscoveryProperties;
import org.springframework.expression.Expression;
import org.springframework.expression.spel.standard.SpelExpressionParser;
import org.springframework.expression.spel.support.SimpleEvaluationContext;
import org.springframework.util.Assert;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;
@@ -61,14 +58,11 @@ public class KubernetesDiscoveryClient implements DiscoveryClient {
private final KubernetesDiscoveryProperties properties;
private final ServicePortSecureResolver servicePortSecureResolver;
private final KubernetesClientServicesFunction kubernetesClientServicesFunction;
private final SpelExpressionParser parser = new SpelExpressionParser();
private final ServicePortSecureResolver servicePortSecureResolver;
private final SimpleEvaluationContext evalCtxt = SimpleEvaluationContext.forReadOnlyDataBinding()
.withInstanceMethods().build();
private final Fabric8DiscoveryServicesAdapter adapter;
private KubernetesClient client;
@@ -76,18 +70,20 @@ public class KubernetesDiscoveryClient implements DiscoveryClient {
KubernetesDiscoveryProperties kubernetesDiscoveryProperties,
KubernetesClientServicesFunction kubernetesClientServicesFunction) {
this(client, kubernetesDiscoveryProperties, kubernetesClientServicesFunction,
this(client, kubernetesDiscoveryProperties, kubernetesClientServicesFunction, null,
new ServicePortSecureResolver(kubernetesDiscoveryProperties));
}
KubernetesDiscoveryClient(KubernetesClient client, KubernetesDiscoveryProperties kubernetesDiscoveryProperties,
KubernetesClientServicesFunction kubernetesClientServicesFunction,
KubernetesClientServicesFunction kubernetesClientServicesFunction, Predicate<Service> filter,
ServicePortSecureResolver servicePortSecureResolver) {
this.client = client;
this.properties = kubernetesDiscoveryProperties;
this.kubernetesClientServicesFunction = kubernetesClientServicesFunction;
this.servicePortSecureResolver = servicePortSecureResolver;
this.kubernetesClientServicesFunction = kubernetesClientServicesFunction;
this.adapter = new Fabric8DiscoveryServicesAdapter(kubernetesClientServicesFunction,
kubernetesDiscoveryProperties, filter);
}
public KubernetesClient getClient() {
@@ -291,35 +287,13 @@ public class KubernetesDiscoveryClient implements DiscoveryClient {
@Override
public List<String> getServices() {
String spelExpression = this.properties.filter();
Predicate<Service> filteredServices;
if (spelExpression == null || spelExpression.isEmpty()) {
filteredServices = (Service instance) -> true;
}
else {
Expression filterExpr = this.parser.parseExpression(spelExpression);
filteredServices = (Service instance) -> {
Boolean include = filterExpr.getValue(this.evalCtxt, instance, Boolean.class);
if (include == null) {
return false;
}
return include;
};
}
return getServices(filteredServices);
return adapter.apply(client).stream().map(s -> s.getMetadata().getName()).toList();
}
@Deprecated(forRemoval = true)
public List<String> getServices(Predicate<Service> filter) {
if (properties.namespaces().isEmpty()) {
return this.kubernetesClientServicesFunction.apply(this.client).list().getItems().stream().filter(filter)
.map(s -> s.getMetadata().getName()).collect(Collectors.toList());
}
List<String> services = new ArrayList<>();
for (String ns : properties.namespaces()) {
services.addAll(getClient().services().inNamespace(ns).list().getItems().stream().filter(filter)
.map(s -> s.getMetadata().getName()).toList());
}
return services;
return new Fabric8DiscoveryServicesAdapter(kubernetesClientServicesFunction, properties, filter).apply(client)
.stream().map(s -> s.getMetadata().getName()).toList();
}
@Override

View File

@@ -31,14 +31,17 @@ import org.springframework.cloud.client.ConditionalOnBlockingDiscoveryEnabled;
import org.springframework.cloud.client.ConditionalOnDiscoveryEnabled;
import org.springframework.cloud.client.ConditionalOnDiscoveryHealthIndicatorEnabled;
import org.springframework.cloud.client.discovery.simple.SimpleDiscoveryClientAutoConfiguration;
import org.springframework.cloud.kubernetes.commons.KubernetesNamespaceProvider;
import org.springframework.cloud.kubernetes.commons.PodUtils;
import org.springframework.cloud.kubernetes.commons.discovery.ConditionalOnKubernetesDiscoveryEnabled;
import org.springframework.cloud.kubernetes.commons.discovery.KubernetesDiscoveryClientHealthIndicatorInitializer;
import org.springframework.cloud.kubernetes.commons.discovery.KubernetesDiscoveryProperties;
import org.springframework.cloud.kubernetes.fabric8.Fabric8AutoConfiguration;
import org.springframework.cloud.kubernetes.fabric8.Fabric8Utils;
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.env.Environment;
/**
* Auto configuration for discovery clients.
@@ -55,23 +58,18 @@ import org.springframework.context.annotation.Configuration;
public class KubernetesDiscoveryClientAutoConfiguration {
@Bean
public KubernetesClientServicesFunction servicesFunction(KubernetesDiscoveryProperties properties) {
if (properties.serviceLabels().isEmpty()) {
if (properties.allNamespaces()) {
return (client) -> client.services().inAnyNamespace();
}
else {
return KubernetesClient::services;
}
}
else {
if (properties.allNamespaces()) {
return (client) -> client.services().inAnyNamespace().withLabels(properties.serviceLabels());
}
else {
return (client) -> client.services().withLabels(properties.serviceLabels());
}
public KubernetesClientServicesFunction servicesFunction(KubernetesDiscoveryProperties properties,
Environment environment) {
if (properties.allNamespaces()) {
return (client) -> client.services().inAnyNamespace().withLabels(properties.serviceLabels());
}
return client -> {
String namespace = Fabric8Utils.getApplicationNamespace(client, null, "discovery-service",
new KubernetesNamespaceProvider(environment));
return client.services().inNamespace(namespace).withLabels(properties.serviceLabels());
};
}
@ConditionalOnClass({ HealthIndicator.class })
@@ -82,7 +80,7 @@ public class KubernetesDiscoveryClientAutoConfiguration {
@Bean
public KubernetesDiscoveryClientHealthIndicatorInitializer indicatorInitializer(
ApplicationEventPublisher applicationEventPublisher, PodUtils podUtils) {
ApplicationEventPublisher applicationEventPublisher, PodUtils<?> podUtils) {
return new KubernetesDiscoveryClientHealthIndicatorInitializer(podUtils, applicationEventPublisher);
}
@@ -98,7 +96,7 @@ public class KubernetesDiscoveryClientAutoConfiguration {
public KubernetesDiscoveryClient kubernetesDiscoveryClient(KubernetesClient client,
KubernetesDiscoveryProperties properties,
KubernetesClientServicesFunction kubernetesClientServicesFunction) {
return new KubernetesDiscoveryClient(client, properties, kubernetesClientServicesFunction,
return new KubernetesDiscoveryClient(client, properties, kubernetesClientServicesFunction, null,
new ServicePortSecureResolver(properties));
}

View File

@@ -0,0 +1,479 @@
/*
* Copyright 2012-2022 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.fabric8.discovery;
import java.util.Comparator;
import java.util.List;
import java.util.Map;
import java.util.Set;
import io.fabric8.kubernetes.api.model.Service;
import io.fabric8.kubernetes.api.model.ServiceBuilder;
import io.fabric8.kubernetes.client.KubernetesClient;
import io.fabric8.kubernetes.client.server.mock.EnableKubernetesMockClient;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.mockito.MockedStatic;
import org.mockito.Mockito;
import org.springframework.cloud.kubernetes.commons.KubernetesNamespaceProvider;
import org.springframework.cloud.kubernetes.commons.discovery.KubernetesDiscoveryProperties;
import org.springframework.cloud.kubernetes.fabric8.Fabric8Utils;
import org.springframework.mock.env.MockEnvironment;
/**
* @author wind57
*/
@EnableKubernetesMockClient(crud = true, https = false)
class Fabric8DiscoveryServicesAdapterTests {
private static KubernetesClient client;
private static MockedStatic<Fabric8Utils> utils;
@BeforeEach
void beforeEach() {
utils = Mockito.mockStatic(Fabric8Utils.class);
}
@AfterEach
void afterEach() {
client.services().inAnyNamespace().delete();
utils.close();
}
/**
* <pre>
* - all-namespaces = true
* - labels = {}
* - filter = null
*
* - serviceA exists in namespaceA with labels = {color=red}
* - serviceB exists in namespaceB with labels = {color=blue}
*
* - we get both services as a result.
* </pre>
*/
@Test
void testAllNamespacesWithoutLabelsWithoutFilter() {
boolean allNamespaces = true;
Map<String, String> labels = Map.of();
String spelFilter = null;
MockEnvironment environment = new MockEnvironment();
KubernetesDiscoveryProperties properties = new KubernetesDiscoveryProperties(false, allNamespaces, Set.of(),
true, 60L, false, spelFilter, Set.of(), labels, null, null, 0, false);
Fabric8DiscoveryServicesAdapter adapter = new Fabric8DiscoveryServicesAdapter(
new KubernetesDiscoveryClientAutoConfiguration().servicesFunction(properties, environment), properties,
null);
service("namespaceA", "serviceA", Map.of("color", "red"));
service("namespaceB", "serviceB", Map.of("color", "blue"));
List<Service> result = adapter.apply(client);
Assertions.assertEquals(result.size(), 2);
Assertions.assertEquals(result.get(0).getMetadata().getName(), "serviceA");
Assertions.assertEquals(result.get(0).getMetadata().getNamespace(), "namespaceA");
Assertions.assertEquals(result.get(1).getMetadata().getName(), "serviceB");
Assertions.assertEquals(result.get(1).getMetadata().getNamespace(), "namespaceB");
}
/**
* <pre>
* - all-namespaces = true
* - labels = {color=red}
* - filter = null
*
* - serviceA exists in namespaceA with labels = {color=red}
* - serviceB exists in namespaceB with labels = {color=blue}
*
* - we get only serviceA as a result.
* </pre>
*/
@Test
void testAllNamespacesWithLabelsWithoutFilter() {
boolean allNamespaces = true;
Map<String, String> labels = Map.of("color", "red");
String spelFilter = null;
MockEnvironment environment = new MockEnvironment();
KubernetesDiscoveryProperties properties = new KubernetesDiscoveryProperties(false, allNamespaces, Set.of(),
true, 60L, false, spelFilter, Set.of(), labels, null, null, 0, false);
Fabric8DiscoveryServicesAdapter adapter = new Fabric8DiscoveryServicesAdapter(
new KubernetesDiscoveryClientAutoConfiguration().servicesFunction(properties, environment), properties,
null);
service("namespaceA", "serviceA", Map.of("color", "red"));
service("namespaceB", "serviceB", Map.of("color", "blue"));
List<Service> result = adapter.apply(client);
Assertions.assertEquals(result.size(), 1);
Assertions.assertEquals(result.get(0).getMetadata().getName(), "serviceA");
Assertions.assertEquals(result.get(0).getMetadata().getNamespace(), "namespaceA");
}
/**
* <pre>
* - all-namespaces = true
* - labels = {}
* - filter = "#root.metadata.namespace matches '^.+A$'"
* (ends in A)
*
* - serviceA exists in namespaceA with labels = {color=red}
* - serviceB exists in namespaceB with labels = {color=blue}
*
* - we get only serviceA as a result.
* </pre>
*/
@Test
void testAllNamespacesWithoutLabelsWithNamespaceFilter() {
boolean allNamespaces = true;
Map<String, String> labels = Map.of();
String spelFilter = """
#root.metadata.namespace matches "^.+A$"
""";
MockEnvironment environment = new MockEnvironment();
KubernetesDiscoveryProperties properties = new KubernetesDiscoveryProperties(false, allNamespaces, Set.of(),
true, 60L, false, spelFilter, Set.of(), labels, null, null, 0, false);
Fabric8DiscoveryServicesAdapter adapter = new Fabric8DiscoveryServicesAdapter(
new KubernetesDiscoveryClientAutoConfiguration().servicesFunction(properties, environment), properties,
null);
service("namespaceA", "serviceA", Map.of("color", "red"));
service("namespaceB", "serviceB", Map.of("color", "blue"));
List<Service> result = adapter.apply(client);
Assertions.assertEquals(result.size(), 1);
Assertions.assertEquals(result.get(0).getMetadata().getName(), "serviceA");
Assertions.assertEquals(result.get(0).getMetadata().getNamespace(), "namespaceA");
}
/**
* <pre>
* - all-namespaces = true
* - labels = {}
* - filter = "#root.metadata.namespace matches '^namespace[A|B]$'"
* (namespaceA or namespaceB)
*
* - serviceA exists in namespaceA with labels = {color=red}
* - serviceB exists in namespaceB with labels = {color=blue}
* - serviceC exists in namespaceC with labels = {color=purple}
*
* - we get only serviceA and serviceB as a result.
* </pre>
*/
@Test
void testAllNamespacesWithoutLabelsWithNamespacesFilter() {
boolean allNamespaces = true;
Map<String, String> labels = Map.of();
String spelFilter = """
#root.metadata.namespace matches "^namespace[A|B]$"
""";
MockEnvironment environment = new MockEnvironment();
KubernetesDiscoveryProperties properties = new KubernetesDiscoveryProperties(false, allNamespaces, Set.of(),
true, 60L, false, spelFilter, Set.of(), labels, null, null, 0, false);
Fabric8DiscoveryServicesAdapter adapter = new Fabric8DiscoveryServicesAdapter(
new KubernetesDiscoveryClientAutoConfiguration().servicesFunction(properties, environment), properties,
null);
service("namespaceA", "serviceA", Map.of("color", "red"));
service("namespaceB", "serviceB", Map.of("color", "blue"));
service("namespaceC", "serviceC", Map.of("color", "purple"));
List<Service> result = adapter.apply(client);
Assertions.assertEquals(result.size(), 2);
Assertions.assertEquals(result.get(0).getMetadata().getName(), "serviceA");
Assertions.assertEquals(result.get(0).getMetadata().getNamespace(), "namespaceA");
Assertions.assertEquals(result.get(1).getMetadata().getName(), "serviceB");
Assertions.assertEquals(result.get(1).getMetadata().getNamespace(), "namespaceB");
}
/**
* <pre>
* - all-namespaces = false
* - specific namespace = namespaceA
* - labels = {}
*
* - serviceA exists in namespaceA with labels = {color=red}
* - serviceB exists in namespaceB with labels = {color=blue}
*
* - we get only serviceA as a result.
* </pre>
*/
@Test
void testSpecificNamespaceWithoutLabelsWithoutFilter() {
boolean allNamespaces = false;
Map<String, String> labels = Map.of();
String spelFilter = null;
MockEnvironment environment = new MockEnvironment();
KubernetesDiscoveryProperties properties = new KubernetesDiscoveryProperties(false, allNamespaces, Set.of(),
true, 60L, false, spelFilter, Set.of(), labels, null, null, 0, false);
Fabric8DiscoveryServicesAdapter adapter = new Fabric8DiscoveryServicesAdapter(
new KubernetesDiscoveryClientAutoConfiguration().servicesFunction(properties, environment), properties,
null);
utils.when(() -> Fabric8Utils.getApplicationNamespace(Mockito.any(KubernetesClient.class),
Mockito.nullable(String.class), Mockito.anyString(), Mockito.any(KubernetesNamespaceProvider.class)))
.thenReturn("namespaceA");
service("namespaceA", "serviceA", Map.of("color", "red"));
service("namespaceB", "serviceB", Map.of("color", "blue"));
List<Service> result = adapter.apply(client);
Assertions.assertEquals(result.size(), 1);
Assertions.assertEquals(result.get(0).getMetadata().getName(), "serviceA");
Assertions.assertEquals(result.get(0).getMetadata().getNamespace(), "namespaceA");
}
/**
* <pre>
* - all-namespaces = false
* - specific namespace = namespaceA
* - labels = {color = purple}
*
* - serviceA exists in namespaceA with labels = {color=red}
* - serviceB exists in namespaceA with labels = {color=purple}
* - serviceC exists in namespaceC with labels = {color=purple}
*
* - we get only serviceB as a result, even if such labels are also
* present on a different service (but it's in a different namespace).
* </pre>
*/
@Test
void testSpecificNamespaceWithLabelsWithoutFilter() {
boolean allNamespaces = false;
Map<String, String> labels = Map.of("color", "purple");
String spelFilter = null;
MockEnvironment environment = new MockEnvironment();
KubernetesDiscoveryProperties properties = new KubernetesDiscoveryProperties(false, allNamespaces, Set.of(),
true, 60L, false, spelFilter, Set.of(), labels, null, null, 0, false);
Fabric8DiscoveryServicesAdapter adapter = new Fabric8DiscoveryServicesAdapter(
new KubernetesDiscoveryClientAutoConfiguration().servicesFunction(properties, environment), properties,
null);
utils.when(() -> Fabric8Utils.getApplicationNamespace(Mockito.any(KubernetesClient.class),
Mockito.nullable(String.class), Mockito.anyString(), Mockito.any(KubernetesNamespaceProvider.class)))
.thenReturn("namespaceA");
service("namespaceA", "serviceA", Map.of("color", "red"));
service("namespaceA", "serviceB", Map.of("color", "purple"));
service("namespaceC", "serviceC", Map.of("color", "purple"));
List<Service> result = adapter.apply(client);
Assertions.assertEquals(result.size(), 1);
Assertions.assertEquals(result.get(0).getMetadata().getName(), "serviceB");
Assertions.assertEquals(result.get(0).getMetadata().getNamespace(), "namespaceA");
}
/**
* <pre>
* - all-namespaces = false
* - specific namespace = namespaceA
* - labels = {}
* - filter = "#root.metadata.labels.containsKey("number")"
* (namespaceA or namespaceB)
*
* - serviceA exists in namespaceA with labels = {color=red, number=1}
* - serviceB exists in namespaceA with labels = {color=purple, cycle=create}
* - serviceC exists in namespaceC with labels = {color=purple, number=1}
*
* - we get only serviceB as a result (because of the filter) even if such labels are also
* present on a different service (but it's in a different namespace).
* </pre>
*/
@Test
void testSpecificNamespaceWithoutLabelsWithFilter() {
boolean allNamespaces = false;
Map<String, String> labels = Map.of();
String spelFilter = """
#root.metadata.labels.containsKey("number")
""".stripLeading();
MockEnvironment environment = new MockEnvironment();
KubernetesDiscoveryProperties properties = new KubernetesDiscoveryProperties(false, allNamespaces, Set.of(),
true, 60L, false, spelFilter, Set.of(), labels, null, null, 0, false);
Fabric8DiscoveryServicesAdapter adapter = new Fabric8DiscoveryServicesAdapter(
new KubernetesDiscoveryClientAutoConfiguration().servicesFunction(properties, environment), properties,
null);
utils.when(() -> Fabric8Utils.getApplicationNamespace(Mockito.any(KubernetesClient.class),
Mockito.nullable(String.class), Mockito.anyString(), Mockito.any(KubernetesNamespaceProvider.class)))
.thenReturn("namespaceA");
service("namespaceA", "serviceA", Map.of("color", "red", "number", "1"));
service("namespaceA", "serviceB", Map.of("color", "purple", "cycle", "create"));
service("namespaceC", "serviceC", Map.of("color", "purple", "number", "1"));
List<Service> result = adapter.apply(client);
Assertions.assertEquals(result.size(), 1);
Assertions.assertEquals(result.get(0).getMetadata().getName(), "serviceA");
Assertions.assertEquals(result.get(0).getMetadata().getNamespace(), "namespaceA");
Assertions.assertEquals(result.get(0).getMetadata().getLabels(), Map.of("color", "red", "number", "1"));
}
/**
* <pre>
* - all-namespaces = false
* - some namespaces = [namespaceA, namespaceB]
* - labels = {}
* - filter = null
*
* - serviceA exists in namespaceA with labels = {}
* - serviceB exists in namespaceB with labels = {}
* - serviceC exists in namespaceC with labels = {}
*
* - we get serviceA and serviceB as a result, because their namespaces match.
* </pre>
*/
@Test
void testSomeNamespacesWithoutLabelsWithoutFilter() {
boolean allNamespaces = false;
Set<String> someNamespaces = Set.of("namespaceA", "namespaceB");
Map<String, String> labels = Map.of();
String spelFilter = null;
MockEnvironment environment = new MockEnvironment();
KubernetesDiscoveryProperties properties = new KubernetesDiscoveryProperties(false, allNamespaces,
someNamespaces, true, 60L, false, spelFilter, Set.of(), labels, null, null, 0, false);
Fabric8DiscoveryServicesAdapter adapter = new Fabric8DiscoveryServicesAdapter(
new KubernetesDiscoveryClientAutoConfiguration().servicesFunction(properties, environment), properties,
null);
service("namespaceA", "serviceA", Map.of());
service("namespaceB", "serviceB", Map.of());
service("namespaceC", "serviceC", Map.of());
List<Service> result = adapter.apply(client);
Assertions.assertEquals(result.size(), 2);
result = result.stream().sorted(Comparator.comparing(x -> x.getMetadata().getName())).toList();
Assertions.assertEquals(result.get(0).getMetadata().getName(), "serviceA");
Assertions.assertEquals(result.get(0).getMetadata().getNamespace(), "namespaceA");
Assertions.assertEquals(result.get(1).getMetadata().getName(), "serviceB");
Assertions.assertEquals(result.get(1).getMetadata().getNamespace(), "namespaceB");
}
/**
* <pre>
* - all-namespaces = false
* - some namespaces = [namespaceA, namespaceB]
* - labels = {color=purple}
* - filter = null
*
* - serviceA exists in namespaceA with labels = {color=purple}
* - serviceB exists in namespaceB with labels = {color=red}
* - serviceC exists in namespaceC with labels = {color=purple}
*
* - we get serviceA as a result
* </pre>
*/
@Test
void testSomeNamespacesWithLabelsWithoutFilter() {
boolean allNamespaces = false;
Set<String> someNamespaces = Set.of("namespaceA", "namespaceB");
Map<String, String> labels = Map.of("color", "purple");
String spelFilter = null;
MockEnvironment environment = new MockEnvironment();
KubernetesDiscoveryProperties properties = new KubernetesDiscoveryProperties(false, allNamespaces,
someNamespaces, true, 60L, false, spelFilter, Set.of(), labels, null, null, 0, false);
Fabric8DiscoveryServicesAdapter adapter = new Fabric8DiscoveryServicesAdapter(
new KubernetesDiscoveryClientAutoConfiguration().servicesFunction(properties, environment), properties,
null);
service("namespaceA", "serviceA", Map.of("color", "purple"));
service("namespaceB", "serviceB", Map.of("color", "red"));
service("namespaceC", "serviceC", Map.of("color", "purple"));
List<Service> result = adapter.apply(client);
Assertions.assertEquals(result.size(), 1);
Assertions.assertEquals(result.get(0).getMetadata().getName(), "serviceA");
Assertions.assertEquals(result.get(0).getMetadata().getNamespace(), "namespaceA");
}
/**
* <pre>
* - all-namespaces = false
* - some namespaces = [namespaceA, namespaceB]
* - labels = {color=purple}
* - filter = #root.metadata.labels.containsKey("number")
*
* - serviceA exists in namespaceA with labels = {color=purple}
* - serviceB exists in namespaceB with labels = {color=red}
* - serviceC exists in namespaceC with labels = {color=purple}
*
* - we get serviceA as a result
* </pre>
*/
@Test
void testSomeNamespacesWithLabelsWithFilter() {
boolean allNamespaces = false;
Set<String> someNamespaces = Set.of("namespaceA", "namespaceB");
Map<String, String> labels = Map.of("color", "purple");
String spelFilter = """
#root.metadata.labels.containsKey("number")
""".stripLeading();
MockEnvironment environment = new MockEnvironment();
KubernetesDiscoveryProperties properties = new KubernetesDiscoveryProperties(false, allNamespaces,
someNamespaces, true, 60L, false, spelFilter, Set.of(), labels, null, null, 0, false);
Fabric8DiscoveryServicesAdapter adapter = new Fabric8DiscoveryServicesAdapter(
new KubernetesDiscoveryClientAutoConfiguration().servicesFunction(properties, environment), properties,
null);
service("namespaceA", "serviceA", Map.of("color", "purple", "number", "1"));
service("namespaceB", "serviceB", Map.of("color", "purple", "cycle", "create"));
service("namespaceC", "serviceC", Map.of("color", "purple", "number", "1"));
List<Service> result = adapter.apply(client);
Assertions.assertEquals(result.size(), 1);
Assertions.assertEquals(result.get(0).getMetadata().getName(), "serviceA");
Assertions.assertEquals(result.get(0).getMetadata().getNamespace(), "namespaceA");
}
private void service(String namespace, String name, Map<String, String> labels) {
client.services().inNamespace(namespace)
.resource(new ServiceBuilder().withNewMetadata().withName(name).withLabels(labels).and().build())
.create();
}
}

View File

@@ -85,7 +85,7 @@ public class KubernetesDiscoveryClientTest {
mockClient.services().inNamespace("test").resource(service).create();
final DiscoveryClient discoveryClient = new KubernetesDiscoveryClient(mockClient,
KubernetesDiscoveryProperties.DEFAULT, KubernetesClient::services,
KubernetesDiscoveryProperties.DEFAULT, KubernetesClient::services, null,
new ServicePortSecureResolver(KubernetesDiscoveryProperties.DEFAULT));
final List<ServiceInstance> instances = discoveryClient.getInstances("endpoint");
@@ -115,7 +115,7 @@ public class KubernetesDiscoveryClientTest {
60, false, null, Set.of(), labels, "http_tcp", Metadata.DEFAULT, 0, true);
final DiscoveryClient discoveryClient = new KubernetesDiscoveryClient(mockClient, properties,
KubernetesClient::services, new ServicePortSecureResolver(properties));
KubernetesClient::services, null, new ServicePortSecureResolver(properties));
final List<ServiceInstance> instances = discoveryClient.getInstances("endpoint");
@@ -137,7 +137,7 @@ public class KubernetesDiscoveryClientTest {
mockClient.endpoints().inNamespace("test").resource(endPoint).create();
final KubernetesDiscoveryClient discoveryClient = new KubernetesDiscoveryClient(mockClient,
KubernetesDiscoveryProperties.DEFAULT, KubernetesClient::services,
KubernetesDiscoveryProperties.DEFAULT, KubernetesClient::services, null,
new ServicePortSecureResolver(KubernetesDiscoveryProperties.DEFAULT));
final List<Endpoints> result_endpoints = discoveryClient.getEndPointsList("endpoint");
@@ -164,7 +164,7 @@ public class KubernetesDiscoveryClientTest {
60, false, null, Set.of(), Map.of(), null, KubernetesDiscoveryProperties.Metadata.DEFAULT, 0, false);
final KubernetesDiscoveryClient discoveryClient = new KubernetesDiscoveryClient(mockClient, properties,
KubernetesClient::services, new ServicePortSecureResolver(properties));
KubernetesClient::services, null, new ServicePortSecureResolver(properties));
final List<Endpoints> result_endpoints = discoveryClient.getEndPointsList("endpoint");
@@ -194,7 +194,7 @@ public class KubernetesDiscoveryClientTest {
KubernetesDiscoveryProperties.Metadata.DEFAULT, 0, false);
final KubernetesDiscoveryClient discoveryClient = new KubernetesDiscoveryClient(mockClient, properties,
KubernetesClient::services, new ServicePortSecureResolver(properties));
KubernetesClient::services, null, new ServicePortSecureResolver(properties));
final List<Endpoints> result_endpoints = discoveryClient.getEndPointsList("endpoint");
@@ -226,7 +226,7 @@ public class KubernetesDiscoveryClientTest {
60, false, null, Set.of(443, 8443), labels, null, metadata, 0, true);
final DiscoveryClient discoveryClient = new KubernetesDiscoveryClient(mockClient, properties,
KubernetesClient::services, new ServicePortSecureResolver(properties));
KubernetesClient::services, null, new ServicePortSecureResolver(properties));
final List<ServiceInstance> instances = discoveryClient.getInstances("endpoint");
@@ -254,7 +254,7 @@ public class KubernetesDiscoveryClientTest {
mockClient.services().inNamespace("test").resource(service3).create();
final DiscoveryClient discoveryClient = new KubernetesDiscoveryClient(mockClient,
KubernetesDiscoveryProperties.DEFAULT, KubernetesClient::services,
KubernetesDiscoveryProperties.DEFAULT, KubernetesClient::services, null,
new ServicePortSecureResolver(KubernetesDiscoveryProperties.DEFAULT));
final List<String> services = discoveryClient.getServices();
@@ -280,7 +280,7 @@ public class KubernetesDiscoveryClientTest {
final DiscoveryClient discoveryClient = new KubernetesDiscoveryClient(mockClient,
KubernetesDiscoveryProperties.DEFAULT,
client -> client.services().withLabels(Collections.singletonMap("label", "value")),
client -> client.services().withLabels(Collections.singletonMap("label", "value")), null,
new ServicePortSecureResolver(KubernetesDiscoveryProperties.DEFAULT));
final List<String> services = discoveryClient.getServices();
@@ -313,7 +313,7 @@ public class KubernetesDiscoveryClientTest {
KubernetesDiscoveryProperties.Metadata.DEFAULT, 0, false);
final DiscoveryClient discoveryClient = new KubernetesDiscoveryClient(mockClient, properties,
KubernetesClient::services, new ServicePortSecureResolver(properties));
KubernetesClient::services, null, new ServicePortSecureResolver(properties));
final List<String> services = discoveryClient.getServices();
@@ -346,7 +346,7 @@ public class KubernetesDiscoveryClientTest {
60, false, null, Set.of(), Map.of(), null, Metadata.DEFAULT, 0, true);
final DiscoveryClient discoveryClient = new KubernetesDiscoveryClient(mockClient, properties,
KubernetesClient::services, new ServicePortSecureResolver(properties));
KubernetesClient::services, null, new ServicePortSecureResolver(properties));
final List<ServiceInstance> instances = discoveryClient.getInstances("endpoint");
@@ -369,7 +369,7 @@ public class KubernetesDiscoveryClientTest {
mockClient.endpoints().inNamespace("test").resource(endPoint).create();
final KubernetesDiscoveryClient discoveryClient = new KubernetesDiscoveryClient(mockClient,
KubernetesDiscoveryProperties.DEFAULT, KubernetesClient::services,
KubernetesDiscoveryProperties.DEFAULT, KubernetesClient::services, null,
new ServicePortSecureResolver(KubernetesDiscoveryProperties.DEFAULT));
final List<ServiceInstance> instances = discoveryClient.getInstances("endpoint1");
@@ -398,7 +398,7 @@ public class KubernetesDiscoveryClientTest {
60, false, null, Set.of(443, 8443), Map.of(), null, Metadata.DEFAULT, 0, true);
final DiscoveryClient discoveryClient = new KubernetesDiscoveryClient(mockClient, properties,
KubernetesClient::services, new ServicePortSecureResolver(properties));
KubernetesClient::services, null, new ServicePortSecureResolver(properties));
final List<ServiceInstance> instances = discoveryClient.getInstances("endpoint2");
@@ -429,7 +429,7 @@ public class KubernetesDiscoveryClientTest {
60, false, null, Set.of(443, 8443), Map.of(), null, Metadata.DEFAULT, 0, true);
final DiscoveryClient discoveryClient = new KubernetesDiscoveryClient(mockClient, properties,
KubernetesClient::services, new ServicePortSecureResolver(properties));
KubernetesClient::services, null, new ServicePortSecureResolver(properties));
final List<ServiceInstance> instances = discoveryClient.getInstances("endpoint3");
@@ -459,7 +459,7 @@ public class KubernetesDiscoveryClientTest {
60, false, null, Set.of(443, 8443), Map.of(), "oops", Metadata.DEFAULT, 0, true);
final DiscoveryClient discoveryClient = new KubernetesDiscoveryClient(mockClient, properties,
KubernetesClient::services, new ServicePortSecureResolver(properties));
KubernetesClient::services, null, new ServicePortSecureResolver(properties));
final List<ServiceInstance> instances = discoveryClient.getInstances("endpoint4");
@@ -488,7 +488,7 @@ public class KubernetesDiscoveryClientTest {
60, false, null, Set.of(443, 8443), Map.of(), null, Metadata.DEFAULT, 0, true);
final DiscoveryClient discoveryClient = new KubernetesDiscoveryClient(mockClient, properties,
KubernetesClient::services, new ServicePortSecureResolver(properties));
KubernetesClient::services, null, new ServicePortSecureResolver(properties));
final List<ServiceInstance> instances = discoveryClient.getInstances("endpoint5");
@@ -515,7 +515,7 @@ public class KubernetesDiscoveryClientTest {
mockClient.services().inNamespace("test").resource(service).create();
final DiscoveryClient discoveryClient = new KubernetesDiscoveryClient(mockClient,
KubernetesDiscoveryProperties.DEFAULT, KubernetesClient::services,
KubernetesDiscoveryProperties.DEFAULT, KubernetesClient::services, null,
new ServicePortSecureResolver(KubernetesDiscoveryProperties.DEFAULT));
final List<ServiceInstance> instances = discoveryClient.getInstances("endpoint5");
@@ -545,7 +545,7 @@ public class KubernetesDiscoveryClientTest {
60, true, null, Set.of(443, 8443), Map.of(), null, Metadata.DEFAULT, 0, true);
final DiscoveryClient discoveryClient = new KubernetesDiscoveryClient(mockClient, properties,
KubernetesClient::services, new ServicePortSecureResolver(properties));
KubernetesClient::services, null, new ServicePortSecureResolver(properties));
final List<ServiceInstance> instances = discoveryClient.getInstances("endpoint5");