Merge pull request #466 from Haybu/bug/issue-465
service (for its metadata) should be queried per namespace. fixes gh-465
This commit is contained in:
@@ -0,0 +1,61 @@
|
||||
/*
|
||||
* Copyright 2012-2019 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.discovery;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import io.fabric8.kubernetes.api.model.EndpointSubset;
|
||||
|
||||
/**
|
||||
* @author Haytham Mohamed
|
||||
**/
|
||||
public class EndpointSubsetNS {
|
||||
|
||||
private String namespace;
|
||||
|
||||
private List<EndpointSubset> endpointSubset;
|
||||
|
||||
public EndpointSubsetNS() {
|
||||
endpointSubset = new ArrayList<>();
|
||||
}
|
||||
|
||||
public String getNamespace() {
|
||||
return namespace;
|
||||
}
|
||||
|
||||
public void setNamespace(String namespace) {
|
||||
this.namespace = namespace;
|
||||
}
|
||||
|
||||
public List<EndpointSubset> getEndpointSubset() {
|
||||
return endpointSubset;
|
||||
}
|
||||
|
||||
public void setEndpointSubset(List<EndpointSubset> endpointSubset) {
|
||||
this.endpointSubset = endpointSubset;
|
||||
}
|
||||
|
||||
public boolean equals(Object o) {
|
||||
return this.endpointSubset.equals(o);
|
||||
}
|
||||
|
||||
public int hashCode() {
|
||||
return this.endpointSubset.hashCode();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -101,40 +101,38 @@ public class KubernetesDiscoveryClient implements DiscoveryClient {
|
||||
public List<ServiceInstance> getInstances(String serviceId) {
|
||||
Assert.notNull(serviceId,
|
||||
"[Assertion failed] - the object argument must not be null");
|
||||
|
||||
List<Endpoints> endpointsList = this.properties.isAllNamespaces()
|
||||
? this.client.endpoints().inAnyNamespace()
|
||||
.withField("metadata.name", serviceId).list().getItems()
|
||||
: Collections
|
||||
.singletonList(this.client.endpoints().withName(serviceId).get());
|
||||
List<EndpointSubset> subsets = endpointsList.stream()
|
||||
.flatMap(endpoints -> getSubsetsFromEndpoints(endpoints).stream())
|
||||
|
||||
List<EndpointSubsetNS> subsetsNS = endpointsList.stream()
|
||||
.map(endpoints -> getSubsetsFromEndpoints(endpoints))
|
||||
.collect(Collectors.toList());
|
||||
|
||||
List<ServiceInstance> instances = new ArrayList<>();
|
||||
if (!subsetsNS.isEmpty()) {
|
||||
for (EndpointSubsetNS es : subsetsNS) {
|
||||
instances.addAll(this.getNamespaceServiceInstances(es, serviceId));
|
||||
}
|
||||
}
|
||||
|
||||
return instances;
|
||||
}
|
||||
|
||||
private List<ServiceInstance> getNamespaceServiceInstances(EndpointSubsetNS es,
|
||||
String serviceId) {
|
||||
String namespace = es.getNamespace();
|
||||
List<EndpointSubset> subsets = es.getEndpointSubset();
|
||||
List<ServiceInstance> instances = new ArrayList<>();
|
||||
if (!subsets.isEmpty()) {
|
||||
|
||||
final Service service = this.client.services().withName(serviceId).get();
|
||||
|
||||
final Map<String, String> serviceMetadata = new HashMap<>();
|
||||
final Service service = this.client.services().inNamespace(namespace)
|
||||
.withName(serviceId).get();
|
||||
final Map<String, String> serviceMetadata = this.getServiceMetadata(service);
|
||||
KubernetesDiscoveryProperties.Metadata metadataProps = this.properties
|
||||
.getMetadata();
|
||||
if (metadataProps.isAddLabels()) {
|
||||
Map<String, String> labelMetadata = getMapWithPrefixedKeys(
|
||||
service.getMetadata().getLabels(),
|
||||
metadataProps.getLabelsPrefix());
|
||||
if (log.isDebugEnabled()) {
|
||||
log.debug("Adding label metadata: " + labelMetadata);
|
||||
}
|
||||
serviceMetadata.putAll(labelMetadata);
|
||||
}
|
||||
if (metadataProps.isAddAnnotations()) {
|
||||
Map<String, String> annotationMetadata = getMapWithPrefixedKeys(
|
||||
service.getMetadata().getAnnotations(),
|
||||
metadataProps.getAnnotationsPrefix());
|
||||
if (log.isDebugEnabled()) {
|
||||
log.debug("Adding annotation metadata: " + annotationMetadata);
|
||||
}
|
||||
serviceMetadata.putAll(annotationMetadata);
|
||||
}
|
||||
|
||||
for (EndpointSubset s : subsets) {
|
||||
// Extend the service metadata map with per-endpoint port information (if
|
||||
@@ -176,6 +174,31 @@ public class KubernetesDiscoveryClient implements DiscoveryClient {
|
||||
return instances;
|
||||
}
|
||||
|
||||
private Map<String, String> getServiceMetadata(Service service) {
|
||||
final Map<String, String> serviceMetadata = new HashMap<>();
|
||||
KubernetesDiscoveryProperties.Metadata metadataProps = this.properties
|
||||
.getMetadata();
|
||||
if (metadataProps.isAddLabels()) {
|
||||
Map<String, String> labelMetadata = getMapWithPrefixedKeys(
|
||||
service.getMetadata().getLabels(), metadataProps.getLabelsPrefix());
|
||||
if (log.isDebugEnabled()) {
|
||||
log.debug("Adding label metadata: " + labelMetadata);
|
||||
}
|
||||
serviceMetadata.putAll(labelMetadata);
|
||||
}
|
||||
if (metadataProps.isAddAnnotations()) {
|
||||
Map<String, String> annotationMetadata = getMapWithPrefixedKeys(
|
||||
service.getMetadata().getAnnotations(),
|
||||
metadataProps.getAnnotationsPrefix());
|
||||
if (log.isDebugEnabled()) {
|
||||
log.debug("Adding annotation metadata: " + annotationMetadata);
|
||||
}
|
||||
serviceMetadata.putAll(annotationMetadata);
|
||||
}
|
||||
|
||||
return serviceMetadata;
|
||||
}
|
||||
|
||||
private EndpointPort findEndpointPort(EndpointSubset s) {
|
||||
List<EndpointPort> ports = s.getPorts();
|
||||
EndpointPort endpointPort;
|
||||
@@ -197,15 +220,17 @@ public class KubernetesDiscoveryClient implements DiscoveryClient {
|
||||
return endpointPort;
|
||||
}
|
||||
|
||||
private List<EndpointSubset> getSubsetsFromEndpoints(Endpoints endpoints) {
|
||||
if (endpoints == null) {
|
||||
return new ArrayList<>();
|
||||
}
|
||||
if (endpoints.getSubsets() == null) {
|
||||
return new ArrayList<>();
|
||||
private EndpointSubsetNS getSubsetsFromEndpoints(Endpoints endpoints) {
|
||||
EndpointSubsetNS es = new EndpointSubsetNS();
|
||||
es.setNamespace(this.client.getNamespace()); // start with the default that comes
|
||||
// with the client
|
||||
|
||||
if (endpoints != null && endpoints.getSubsets() != null) {
|
||||
es.setNamespace(endpoints.getMetadata().getNamespace());
|
||||
es.setEndpointSubset(endpoints.getSubsets());
|
||||
}
|
||||
|
||||
return endpoints.getSubsets();
|
||||
return es;
|
||||
}
|
||||
|
||||
// returns a new map that contain all the entries of the original map
|
||||
|
||||
@@ -27,6 +27,7 @@ import io.fabric8.kubernetes.api.model.EndpointPortBuilder;
|
||||
import io.fabric8.kubernetes.api.model.Endpoints;
|
||||
import io.fabric8.kubernetes.api.model.EndpointsBuilder;
|
||||
import io.fabric8.kubernetes.api.model.EndpointsList;
|
||||
import io.fabric8.kubernetes.api.model.ObjectMeta;
|
||||
import io.fabric8.kubernetes.api.model.Service;
|
||||
import io.fabric8.kubernetes.api.model.ServiceBuilder;
|
||||
import io.fabric8.kubernetes.api.model.ServiceList;
|
||||
@@ -48,6 +49,7 @@ import org.springframework.cloud.client.ServiceInstance;
|
||||
import static java.util.stream.Collectors.toList;
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.assertj.core.api.Assertions.entry;
|
||||
import static org.mockito.ArgumentMatchers.anyString;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
@RunWith(MockitoJUnitRunner.class)
|
||||
@@ -89,7 +91,7 @@ public class KubernetesDiscoveryClientFilterMetadataTest {
|
||||
when(this.metadata.isAddAnnotations()).thenReturn(false);
|
||||
when(this.metadata.isAddPorts()).thenReturn(false);
|
||||
|
||||
setupServiceWithLabelsAndAnnotationsAndPorts(serviceId,
|
||||
setupServiceWithLabelsAndAnnotationsAndPorts(serviceId, "ns",
|
||||
new HashMap<String, String>() {
|
||||
{
|
||||
put("l1", "lab");
|
||||
@@ -119,7 +121,7 @@ public class KubernetesDiscoveryClientFilterMetadataTest {
|
||||
when(this.metadata.isAddAnnotations()).thenReturn(false);
|
||||
when(this.metadata.isAddPorts()).thenReturn(false);
|
||||
|
||||
setupServiceWithLabelsAndAnnotationsAndPorts(serviceId,
|
||||
setupServiceWithLabelsAndAnnotationsAndPorts(serviceId, "ns",
|
||||
new HashMap<String, String>() {
|
||||
{
|
||||
put("l1", "v1");
|
||||
@@ -152,7 +154,7 @@ public class KubernetesDiscoveryClientFilterMetadataTest {
|
||||
when(this.metadata.isAddAnnotations()).thenReturn(false);
|
||||
when(this.metadata.isAddPorts()).thenReturn(false);
|
||||
|
||||
setupServiceWithLabelsAndAnnotationsAndPorts(serviceId,
|
||||
setupServiceWithLabelsAndAnnotationsAndPorts(serviceId, "ns",
|
||||
new HashMap<String, String>() {
|
||||
{
|
||||
put("l1", "v1");
|
||||
@@ -184,7 +186,7 @@ public class KubernetesDiscoveryClientFilterMetadataTest {
|
||||
when(this.metadata.isAddAnnotations()).thenReturn(true);
|
||||
when(this.metadata.isAddPorts()).thenReturn(false);
|
||||
|
||||
setupServiceWithLabelsAndAnnotationsAndPorts(serviceId,
|
||||
setupServiceWithLabelsAndAnnotationsAndPorts(serviceId, "ns",
|
||||
new HashMap<String, String>() {
|
||||
{
|
||||
put("l1", "v1");
|
||||
@@ -217,7 +219,7 @@ public class KubernetesDiscoveryClientFilterMetadataTest {
|
||||
when(this.metadata.getAnnotationsPrefix()).thenReturn("a_");
|
||||
when(this.metadata.isAddPorts()).thenReturn(false);
|
||||
|
||||
setupServiceWithLabelsAndAnnotationsAndPorts(serviceId,
|
||||
setupServiceWithLabelsAndAnnotationsAndPorts(serviceId, "ns",
|
||||
new HashMap<String, String>() {
|
||||
{
|
||||
put("l1", "v1");
|
||||
@@ -249,7 +251,7 @@ public class KubernetesDiscoveryClientFilterMetadataTest {
|
||||
when(this.metadata.isAddAnnotations()).thenReturn(false);
|
||||
when(this.metadata.isAddPorts()).thenReturn(true);
|
||||
|
||||
setupServiceWithLabelsAndAnnotationsAndPorts(serviceId,
|
||||
setupServiceWithLabelsAndAnnotationsAndPorts(serviceId, "ns",
|
||||
new HashMap<String, String>() {
|
||||
{
|
||||
put("l1", "v1");
|
||||
@@ -281,7 +283,7 @@ public class KubernetesDiscoveryClientFilterMetadataTest {
|
||||
when(this.metadata.isAddPorts()).thenReturn(true);
|
||||
when(this.metadata.getPortsPrefix()).thenReturn("p_");
|
||||
|
||||
setupServiceWithLabelsAndAnnotationsAndPorts(serviceId,
|
||||
setupServiceWithLabelsAndAnnotationsAndPorts(serviceId, "ns",
|
||||
new HashMap<String, String>() {
|
||||
{
|
||||
put("l1", "v1");
|
||||
@@ -315,7 +317,7 @@ public class KubernetesDiscoveryClientFilterMetadataTest {
|
||||
when(this.metadata.isAddPorts()).thenReturn(true);
|
||||
when(this.metadata.getPortsPrefix()).thenReturn("p_");
|
||||
|
||||
setupServiceWithLabelsAndAnnotationsAndPorts(serviceId,
|
||||
setupServiceWithLabelsAndAnnotationsAndPorts(serviceId, "ns",
|
||||
new HashMap<String, String>() {
|
||||
{
|
||||
put("l1", "la1");
|
||||
@@ -339,18 +341,24 @@ public class KubernetesDiscoveryClientFilterMetadataTest {
|
||||
}
|
||||
|
||||
private void setupServiceWithLabelsAndAnnotationsAndPorts(String serviceId,
|
||||
Map<String, String> labels, Map<String, String> annotations,
|
||||
String namespace, Map<String, String> labels, Map<String, String> annotations,
|
||||
Map<Integer, String> ports) {
|
||||
final Service service = new ServiceBuilder().withNewMetadata().withLabels(labels)
|
||||
.withAnnotations(annotations).endMetadata().withNewSpec()
|
||||
.withPorts(getServicePorts(ports)).endSpec().build();
|
||||
final Service service = new ServiceBuilder().withNewMetadata()
|
||||
.withNamespace(namespace).withLabels(labels).withAnnotations(annotations)
|
||||
.endMetadata().withNewSpec().withPorts(getServicePorts(ports)).endSpec()
|
||||
.build();
|
||||
when(this.serviceOperation.withName(serviceId)).thenReturn(this.serviceResource);
|
||||
when(this.serviceResource.get()).thenReturn(service);
|
||||
when(this.kubernetesClient.services()).thenReturn(this.serviceOperation);
|
||||
when(this.kubernetesClient.services().inNamespace(anyString()))
|
||||
.thenReturn(this.serviceOperation);
|
||||
|
||||
final Endpoints endpoints = new EndpointsBuilder().addNewSubset()
|
||||
.addAllToPorts(getEndpointPorts(ports)).addNewAddress().endAddress()
|
||||
.endSubset().build();
|
||||
ObjectMeta objectMeta = new ObjectMeta();
|
||||
objectMeta.setNamespace(namespace);
|
||||
|
||||
final Endpoints endpoints = new EndpointsBuilder().withMetadata(objectMeta)
|
||||
.addNewSubset().addAllToPorts(getEndpointPorts(ports)).addNewAddress()
|
||||
.endAddress().endSubset().build();
|
||||
|
||||
when(this.endpointsResource.get()).thenReturn(endpoints);
|
||||
when(this.endpointsOperation.withName(serviceId))
|
||||
|
||||
@@ -116,13 +116,14 @@ public class KubernetesDiscoveryClientTest {
|
||||
.andReturn(200, services).once();
|
||||
|
||||
mockServer.expect().get().withPath("/api/v1/namespaces/test/services/endpoint")
|
||||
.andReturn(200, service1).once();
|
||||
.andReturn(200, service1).always();
|
||||
|
||||
mockServer.expect().get().withPath("/api/v1/namespaces/test2/services/endpoint")
|
||||
.andReturn(200, service2).once();
|
||||
.andReturn(200, service2).always();
|
||||
|
||||
final KubernetesDiscoveryProperties properties = new KubernetesDiscoveryProperties();
|
||||
properties.setAllNamespaces(true);
|
||||
|
||||
final DiscoveryClient discoveryClient = new KubernetesDiscoveryClient(mockClient,
|
||||
properties, KubernetesClient::services,
|
||||
new DefaultIsServicePortSecureResolver(properties));
|
||||
@@ -149,16 +150,17 @@ public class KubernetesDiscoveryClientTest {
|
||||
.endAddress().addNewPort("http", 80, "TCP").endSubset().build())
|
||||
.once();
|
||||
|
||||
mockServer.expect().get().withPath("/api/v1/namespaces/test/services/endpoint")
|
||||
mockServer.expect().get().withPath("/api/v1/services/endpoint")
|
||||
.andReturn(200, new ServiceBuilder().withNewMetadata()
|
||||
.withName("endpoint").withLabels(new HashMap<String, String>() {
|
||||
{
|
||||
put("l", "v");
|
||||
}
|
||||
}).endMetadata().build())
|
||||
.once();
|
||||
.always();
|
||||
|
||||
final KubernetesDiscoveryProperties properties = new KubernetesDiscoveryProperties();
|
||||
|
||||
final DiscoveryClient discoveryClient = new KubernetesDiscoveryClient(mockClient,
|
||||
properties, KubernetesClient::services,
|
||||
new DefaultIsServicePortSecureResolver(properties));
|
||||
@@ -180,14 +182,14 @@ public class KubernetesDiscoveryClientTest {
|
||||
.addNewPort("http", 80, "TCP").endSubset().build())
|
||||
.once();
|
||||
|
||||
mockServer.expect().get().withPath("/api/v1/namespaces/test/services/endpoint")
|
||||
mockServer.expect().get().withPath("/api/v1/services/endpoint")
|
||||
.andReturn(200, new ServiceBuilder().withNewMetadata()
|
||||
.withName("endpoint").withLabels(new HashMap<String, String>() {
|
||||
{
|
||||
put("l", "v");
|
||||
}
|
||||
}).endMetadata().build())
|
||||
.once();
|
||||
.always();
|
||||
|
||||
final KubernetesDiscoveryProperties properties = new KubernetesDiscoveryProperties();
|
||||
properties.setPrimaryPortName("http");
|
||||
@@ -212,14 +214,14 @@ public class KubernetesDiscoveryClientTest {
|
||||
.endAddress().addNewPort("https", 443, "TCP").endSubset().build())
|
||||
.once();
|
||||
|
||||
mockServer.expect().get().withPath("/api/v1/namespaces/test/services/endpoint")
|
||||
mockServer.expect().get().withPath("/api/v1/services/endpoint")
|
||||
.andReturn(200, new ServiceBuilder().withNewMetadata()
|
||||
.withName("endpoint").withLabels(new HashMap<String, String>() {
|
||||
{
|
||||
put("l", "v");
|
||||
}
|
||||
}).endMetadata().build())
|
||||
.once();
|
||||
.always();
|
||||
|
||||
final KubernetesDiscoveryProperties properties = new KubernetesDiscoveryProperties();
|
||||
final DiscoveryClient discoveryClient = new KubernetesDiscoveryClient(mockClient,
|
||||
|
||||
Reference in New Issue
Block a user