Merge branch '3.0.x'

This commit is contained in:
Ryan Baxter
2023-12-19 14:11:37 -05:00
9 changed files with 70 additions and 40 deletions

View File

@@ -0,0 +1,26 @@
/*
* 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.List;
/**
* Use for discovery service implementation.
* @author wind57
*/
public record Service(String name, List<DefaultKubernetesServiceInstance> serviceInstances) {
}

View File

@@ -16,13 +16,13 @@
package org.springframework.cloud.kubernetes.discoveryserver;
import java.util.List;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;
import org.springframework.cloud.client.ServiceInstance;
import org.springframework.cloud.kubernetes.client.discovery.reactive.KubernetesInformerReactiveDiscoveryClient;
import org.springframework.cloud.kubernetes.commons.discovery.DefaultKubernetesServiceInstance;
import org.springframework.cloud.kubernetes.commons.discovery.Service;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RestController;
@@ -41,8 +41,10 @@ public class DiscoveryServerController {
@GetMapping("/apps")
public Flux<Service> apps() {
return reactiveDiscoveryClient.getServices().flatMap(service -> reactiveDiscoveryClient.getInstances(service)
.collectList().flatMap(serviceInstances -> Mono.just(new Service(service, serviceInstances))));
return reactiveDiscoveryClient.getServices()
.flatMap(service -> reactiveDiscoveryClient.getInstances(service).collectList()
.flatMap(serviceInstances -> Mono.just(new Service(service,
serviceInstances.stream().map(x -> (DefaultKubernetesServiceInstance) x).toList()))));
}
@GetMapping("/apps/{name}")
@@ -56,8 +58,4 @@ public class DiscoveryServerController {
.filter(serviceInstance -> serviceInstance.getInstanceId().equals(instanceId)).singleOrEmpty();
}
record Service(String name, List<ServiceInstance> serviceInstances) {
}
}

View File

@@ -29,7 +29,7 @@ import reactor.test.StepVerifier;
import org.springframework.cloud.client.ServiceInstance;
import org.springframework.cloud.kubernetes.client.discovery.reactive.KubernetesInformerReactiveDiscoveryClient;
import org.springframework.cloud.kubernetes.commons.discovery.DefaultKubernetesServiceInstance;
import org.springframework.cloud.kubernetes.commons.discovery.KubernetesServiceInstance;
import org.springframework.cloud.kubernetes.commons.discovery.Service;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.mock;
@@ -40,26 +40,26 @@ import static org.mockito.Mockito.when;
*/
class DiscoveryServerControllerTests {
private static final KubernetesServiceInstance SERVICE_A_INSTANCE_1 = new DefaultKubernetesServiceInstance(
private static final DefaultKubernetesServiceInstance SERVICE_A_INSTANCE_1 = new DefaultKubernetesServiceInstance(
"serviceAInstance1", "serviceAInstance1", "2.2.2.2", 8080, Map.of(), false, "namespace1", null);
private static final KubernetesServiceInstance SERVICE_A_INSTANCE_2 = new DefaultKubernetesServiceInstance(
private static final DefaultKubernetesServiceInstance SERVICE_A_INSTANCE_2 = new DefaultKubernetesServiceInstance(
"serviceAInstance2", "serviceAInstance2", "2.2.2.2", 8080, Map.of(), false, "namespace1", null);
private static final KubernetesServiceInstance SERVICE_A_INSTANCE_3 = new DefaultKubernetesServiceInstance(
private static final DefaultKubernetesServiceInstance SERVICE_A_INSTANCE_3 = new DefaultKubernetesServiceInstance(
"serviceAInstance3", "serviceAInstance3", "2.2.2.2", 8080, Map.of(), false, "namespace2", null);
private static final KubernetesServiceInstance SERVICE_B_INSTANCE_1 = new DefaultKubernetesServiceInstance(
private static final DefaultKubernetesServiceInstance SERVICE_B_INSTANCE_1 = new DefaultKubernetesServiceInstance(
"serviceBInstance1", "serviceBInstance1", "2.2.2.2", 8080, Map.of(), false, "namespace1", null);
private static final KubernetesServiceInstance SERVICE_C_INSTANCE_1 = new DefaultKubernetesServiceInstance(
private static final DefaultKubernetesServiceInstance SERVICE_C_INSTANCE_1 = new DefaultKubernetesServiceInstance(
"serviceCInstance1", "serviceCInstance1", "2.2.2.2", 8080, Map.of(), false, "namespace2", null);
private static DiscoveryServerController.Service serviceA;
private static Service serviceA;
private static DiscoveryServerController.Service serviceB;
private static Service serviceB;
private static DiscoveryServerController.Service serviceC;
private static Service serviceC;
private static KubernetesInformerReactiveDiscoveryClient discoveryClient;
@@ -67,17 +67,17 @@ class DiscoveryServerControllerTests {
static void beforeAll() {
Flux<String> services = Flux.just("serviceA", "serviceB", "serviceC");
List<ServiceInstance> serviceAInstanceList = new ArrayList<>();
List<DefaultKubernetesServiceInstance> serviceAInstanceList = new ArrayList<>();
serviceAInstanceList.add(SERVICE_A_INSTANCE_1);
serviceAInstanceList.add(SERVICE_A_INSTANCE_2);
serviceAInstanceList.add(SERVICE_A_INSTANCE_3);
Flux<ServiceInstance> serviceAInstances = Flux.fromIterable(serviceAInstanceList);
List<ServiceInstance> serviceBInstanceList = Collections.singletonList(SERVICE_B_INSTANCE_1);
List<DefaultKubernetesServiceInstance> serviceBInstanceList = Collections.singletonList(SERVICE_B_INSTANCE_1);
Flux<ServiceInstance> serviceBInstances = Flux.fromIterable(serviceBInstanceList);
List<ServiceInstance> serviceCInstanceList = Collections.singletonList(SERVICE_C_INSTANCE_1);
List<DefaultKubernetesServiceInstance> serviceCInstanceList = Collections.singletonList(SERVICE_C_INSTANCE_1);
Flux<ServiceInstance> serviceCInstances = Flux.fromIterable(serviceCInstanceList);
discoveryClient = mock(KubernetesInformerReactiveDiscoveryClient.class);
@@ -87,9 +87,9 @@ class DiscoveryServerControllerTests {
when(discoveryClient.getInstances(eq("serviceC"))).thenReturn(serviceCInstances);
when(discoveryClient.getInstances(eq("serviceD"))).thenReturn(Flux.empty());
serviceA = new DiscoveryServerController.Service("serviceA", serviceAInstanceList);
serviceB = new DiscoveryServerController.Service("serviceB", serviceBInstanceList);
serviceC = new DiscoveryServerController.Service("serviceC", serviceCInstanceList);
serviceA = new Service("serviceA", serviceAInstanceList);
serviceB = new Service("serviceB", serviceBInstanceList);
serviceC = new Service("serviceC", serviceCInstanceList);
}

View File

@@ -23,7 +23,9 @@ import java.util.stream.Collectors;
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.cloud.kubernetes.commons.discovery.Service;
import org.springframework.util.StringUtils;
import org.springframework.web.client.RestTemplate;
@@ -68,8 +70,9 @@ public class KubernetesDiscoveryClient implements DiscoveryClient {
@Override
public List<ServiceInstance> getInstances(String serviceId) {
KubernetesServiceInstance[] responseBody = rest
.getForEntity(discoveryServerUrl + "/apps/" + serviceId, KubernetesServiceInstance[].class).getBody();
DefaultKubernetesServiceInstance[] responseBody = rest
.getForEntity(discoveryServerUrl + "/apps/" + serviceId, DefaultKubernetesServiceInstance[].class)
.getBody();
if (responseBody != null && responseBody.length > 0) {
return Arrays.stream(responseBody).filter(this::matchNamespaces).collect(Collectors.toList());
}
@@ -80,18 +83,18 @@ public class KubernetesDiscoveryClient implements DiscoveryClient {
public List<String> getServices() {
Service[] services = rest.getForEntity(discoveryServerUrl + "/apps", Service[].class).getBody();
if (services != null && services.length > 0) {
return Arrays.stream(services).filter(this::matchNamespaces).map(Service::getName).toList();
return Arrays.stream(services).filter(this::matchNamespaces).map(Service::name).toList();
}
return List.of();
}
private boolean matchNamespaces(KubernetesServiceInstance kubernetesServiceInstance) {
private boolean matchNamespaces(DefaultKubernetesServiceInstance kubernetesServiceInstance) {
return emptyNamespaces || namespaces.contains(kubernetesServiceInstance.getNamespace());
}
private boolean matchNamespaces(Service service) {
return service.getServiceInstances().isEmpty()
|| service.getServiceInstances().stream().anyMatch(this::matchNamespaces);
return service.serviceInstances().isEmpty()
|| service.serviceInstances().stream().anyMatch(this::matchNamespaces);
}
}

View File

@@ -21,7 +21,9 @@ import reactor.core.publisher.Flux;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.cloud.client.ServiceInstance;
import org.springframework.cloud.client.discovery.ReactiveDiscoveryClient;
import org.springframework.cloud.kubernetes.commons.discovery.DefaultKubernetesServiceInstance;
import org.springframework.cloud.kubernetes.commons.discovery.KubernetesDiscoveryProperties;
import org.springframework.cloud.kubernetes.commons.discovery.Service;
import org.springframework.util.StringUtils;
import org.springframework.web.reactive.function.client.WebClient;
@@ -57,14 +59,14 @@ public class KubernetesReactiveDiscoveryClient implements ReactiveDiscoveryClien
@Cacheable("serviceinstances")
public Flux<ServiceInstance> getInstances(String serviceId) {
return webClient.get().uri("/apps/" + serviceId)
.exchangeToFlux(clientResponse -> clientResponse.bodyToFlux(KubernetesServiceInstance.class));
.exchangeToFlux(clientResponse -> clientResponse.bodyToFlux(DefaultKubernetesServiceInstance.class));
}
@Override
@Cacheable("services")
public Flux<String> getServices() {
return webClient.get().uri("/apps").exchangeToFlux(
clientResponse -> clientResponse.bodyToFlux(Service.class).map(service -> service.getName()));
return webClient.get().uri("/apps")
.exchangeToFlux(clientResponse -> clientResponse.bodyToFlux(Service.class).map(Service::name));
}
}

View File

@@ -25,6 +25,7 @@ import org.springframework.cloud.client.ServiceInstance;
/**
* @author Ryan Baxter
*/
@Deprecated(forRemoval = true)
public class KubernetesServiceInstance implements ServiceInstance {
private String instanceId;

View File

@@ -21,6 +21,7 @@ import java.util.List;
/**
* @author Ryan Baxter
*/
@Deprecated(forRemoval = true)
public class Service {
private String name;

View File

@@ -16,7 +16,6 @@
package org.springframework.cloud.kubernetes.discovery;
import java.net.URI;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
@@ -33,6 +32,7 @@ import org.junit.jupiter.params.provider.MethodSource;
import org.springframework.boot.web.client.RestTemplateBuilder;
import org.springframework.cloud.client.ServiceInstance;
import org.springframework.cloud.kubernetes.commons.discovery.DefaultKubernetesServiceInstance;
import org.springframework.cloud.kubernetes.commons.discovery.KubernetesDiscoveryProperties;
import org.springframework.web.client.RestTemplate;
@@ -133,9 +133,8 @@ class KubernetesDiscoveryClientTests {
metadata.put("spring", "true");
metadata.put("http", "8080");
metadata.put("k8s", "true");
assertThat(discoveryClient.getInstances("test-svc-3"))
.contains(new KubernetesServiceInstance("uid2", "test-svc-3", "2.2.2.2", 8080, false,
URI.create("http://2.2.2.2:8080"), metadata, "http", "namespace2"));
assertThat(discoveryClient.getInstances("test-svc-3")).contains(new DefaultKubernetesServiceInstance("uid2",
"test-svc-3", "2.2.2.2", 8080, metadata, false, "namespace2", null, null));
assertThat(discoveryClient.getInstances("does-not-exist")).isEmpty();
}

View File

@@ -16,7 +16,6 @@
package org.springframework.cloud.kubernetes.discovery;
import java.net.URI;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
@@ -27,6 +26,7 @@ import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.Test;
import reactor.test.StepVerifier;
import org.springframework.cloud.kubernetes.commons.discovery.DefaultKubernetesServiceInstance;
import org.springframework.cloud.kubernetes.commons.discovery.KubernetesDiscoveryProperties;
import org.springframework.web.reactive.function.client.WebClient;
@@ -127,11 +127,11 @@ class KubernetesReactiveDiscoveryClientTests {
metadata.put("spring", "true");
metadata.put("http", "8080");
metadata.put("k8s", "true");
StepVerifier.create(discoveryClient.getInstances("test-svc-3"))
.expectNext(new KubernetesServiceInstance("uid2", "test-svc-3", "2.2.2.2", 8080, false,
URI.create("http://2.2.2.2:8080"), metadata, "http", "namespace1"))
.expectNext(new DefaultKubernetesServiceInstance("uid2", "test-svc-3", "2.2.2.2", 8080, metadata, false,
"namespace1", null, null))
.verifyComplete();
StepVerifier.create(discoveryClient.getInstances("test-svc-3")).expectNextCount(0);
}
}