-
Notifications
You must be signed in to change notification settings - Fork 1k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Fix wrong labels and annotations in kubernetes discovery native client #1282
Changes from all commits
032014e
c3d0ad2
10889fd
8f0375a
96ebf42
db8403e
90a5345
b041c00
9580444
a34ac47
6613f78
1b3eae9
4275382
618f25a
100a9cd
4b9056b
315a85b
ed3c264
446d630
6821a28
9e95a8a
02840b1
7e31d65
926f4d7
344e1d4
e91ac12
ba6e088
002c975
06c5465
63ce5ad
335a6f7
49025e8
266e7b4
a647bb3
0bf3fd1
962d350
16b09ab
c6acd76
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -47,6 +47,7 @@ | |
import org.springframework.util.StringUtils; | ||
|
||
import static org.springframework.cloud.kubernetes.client.discovery.KubernetesDiscoveryClientUtils.matchesServiceLabels; | ||
import static org.springframework.cloud.kubernetes.client.discovery.KubernetesDiscoveryClientUtils.serviceMetadata; | ||
import static org.springframework.cloud.kubernetes.commons.discovery.KubernetesDiscoveryConstants.HTTP; | ||
import static org.springframework.cloud.kubernetes.commons.discovery.KubernetesDiscoveryConstants.HTTPS; | ||
import static org.springframework.cloud.kubernetes.commons.discovery.KubernetesDiscoveryConstants.PRIMARY_PORT_NAME_LABEL_KEY; | ||
|
@@ -114,27 +115,7 @@ public List<ServiceInstance> getInstances(String serviceId) { | |
} | ||
|
||
private Stream<ServiceInstance> getServiceInstanceDetails(V1Service service, String serviceId) { | ||
Map<String, String> svcMetadata = new HashMap<>(); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. this PR fixes an issue, imo. if you look at this piece of code:
it says that we are going to take only annotations that start with As such, I removed this code and fixed the bug in the utils class, where the code is the same as in the fabric8 implementation. Also added tests. |
||
if (properties.metadata() != null) { | ||
if (properties.metadata().addLabels()) { | ||
if (service.getMetadata() != null && service.getMetadata().getLabels() != null) { | ||
String labelPrefix = properties.metadata().labelsPrefix() != null | ||
? properties.metadata().labelsPrefix() : ""; | ||
service.getMetadata().getLabels().entrySet().stream() | ||
.filter(e -> e.getKey().startsWith(labelPrefix)) | ||
.forEach(e -> svcMetadata.put(e.getKey(), e.getValue())); | ||
} | ||
} | ||
if (properties.metadata().addAnnotations()) { | ||
if (service.getMetadata() != null && service.getMetadata().getAnnotations() != null) { | ||
String annotationPrefix = properties.metadata().annotationsPrefix() != null | ||
? properties.metadata().annotationsPrefix() : ""; | ||
service.getMetadata().getAnnotations().entrySet().stream() | ||
.filter(e -> e.getKey().startsWith(annotationPrefix)) | ||
.forEach(e -> svcMetadata.put(e.getKey(), e.getValue())); | ||
} | ||
} | ||
} | ||
Map<String, String> serviceMetadata = serviceMetadata(properties, service, serviceId); | ||
|
||
V1Endpoints ep = endpointsLister.namespace(service.getMetadata().getNamespace()) | ||
.get(service.getMetadata().getName()); | ||
|
@@ -154,7 +135,7 @@ private Stream<ServiceInstance> getServiceInstanceDetails(V1Service service, Str | |
|
||
return ep.getSubsets().stream().filter(subset -> subset.getPorts() != null && subset.getPorts().size() > 0) // safeguard | ||
.flatMap(subset -> { | ||
Map<String, String> metadata = new HashMap<>(svcMetadata); | ||
Map<String, String> metadata = new HashMap<>(serviceMetadata); | ||
List<CoreV1EndpointPort> endpointPorts = subset.getPorts(); | ||
if (properties.metadata() != null && properties.metadata().addPorts()) { | ||
endpointPorts.forEach( | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,233 @@ | ||
/* | ||
* 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.client.discovery; | ||
|
||
import java.util.Map; | ||
import java.util.Set; | ||
import java.util.stream.Collectors; | ||
|
||
import io.kubernetes.client.openapi.models.V1ObjectMeta; | ||
import io.kubernetes.client.openapi.models.V1Service; | ||
import io.kubernetes.client.openapi.models.V1ServiceSpec; | ||
import org.junit.jupiter.api.Assertions; | ||
import org.junit.jupiter.api.Test; | ||
import org.junit.jupiter.api.extension.ExtendWith; | ||
|
||
import org.springframework.boot.test.system.CapturedOutput; | ||
import org.springframework.boot.test.system.OutputCaptureExtension; | ||
import org.springframework.cloud.kubernetes.commons.discovery.KubernetesDiscoveryProperties; | ||
|
||
/** | ||
* @author wind57 | ||
*/ | ||
@ExtendWith(OutputCaptureExtension.class) | ||
class KubernetesDiscoveryClientServiceMetadataTests { | ||
|
||
/** | ||
* <pre> | ||
* - labels are not added | ||
* - annotations are not added | ||
* </pre> | ||
*/ | ||
@Test | ||
void testServiceMetadataEmpty() { | ||
boolean addLabels = false; | ||
String labelsPrefix = ""; | ||
boolean addAnnotations = false; | ||
String annotationsPrefix = ""; | ||
boolean addPorts = false; | ||
String portsPrefix = ""; | ||
|
||
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); | ||
V1Service service = new V1Service().spec(new V1ServiceSpec().type("ClusterIP")) | ||
.metadata(new V1ObjectMeta().namespace("default")); | ||
|
||
Map<String, String> result = KubernetesDiscoveryClientUtils.serviceMetadata(properties, service, "my-service"); | ||
Assertions.assertEquals(result.size(), 2); | ||
Assertions.assertEquals(result, Map.of("k8s_namespace", "default", "type", "ClusterIP")); | ||
} | ||
|
||
/** | ||
* <pre> | ||
* - labels are added without a prefix | ||
* - annotations are not added | ||
* </pre> | ||
*/ | ||
@Test | ||
void testServiceMetadataAddLabelsNoPrefix(CapturedOutput output) { | ||
boolean addLabels = true; | ||
String labelsPrefix = ""; | ||
boolean addAnnotations = false; | ||
String annotationsPrefix = ""; | ||
boolean addPorts = false; | ||
String portsPrefix = ""; | ||
|
||
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); | ||
V1Service service = new V1Service().spec(new V1ServiceSpec().type("ClusterIP")) | ||
.metadata(new V1ObjectMeta().namespace("default").labels(Map.of("a", "b"))); | ||
|
||
Map<String, String> result = KubernetesDiscoveryClientUtils.serviceMetadata(properties, service, "my-service"); | ||
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")); | ||
} | ||
|
||
/** | ||
* <pre> | ||
* - labels are added with prefix | ||
* - annotations are not added | ||
* </pre> | ||
*/ | ||
@Test | ||
void testServiceMetadataAddLabelsWithPrefix(CapturedOutput output) { | ||
boolean addLabels = true; | ||
String labelsPrefix = "prefix-"; | ||
boolean addAnnotations = false; | ||
String annotationsPrefix = ""; | ||
boolean addPorts = false; | ||
String portsPrefix = ""; | ||
|
||
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); | ||
V1Service service = new V1Service().spec(new V1ServiceSpec().type("ClusterIP")) | ||
.metadata(new V1ObjectMeta().namespace("default").labels(Map.of("a", "b", "c", "d"))); | ||
|
||
Map<String, String> result = KubernetesDiscoveryClientUtils.serviceMetadata(properties, service, "my-service"); | ||
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")); | ||
} | ||
|
||
/** | ||
* <pre> | ||
* - labels are not added | ||
* - annotations are added without prefix | ||
* </pre> | ||
*/ | ||
@Test | ||
void testServiceMetadataAddAnnotationsNoPrefix(CapturedOutput output) { | ||
boolean addLabels = false; | ||
String labelsPrefix = ""; | ||
boolean addAnnotations = true; | ||
String annotationsPrefix = ""; | ||
boolean addPorts = false; | ||
String portsPrefix = ""; | ||
|
||
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); | ||
V1Service service = new V1Service().spec(new V1ServiceSpec().type("ClusterIP")).metadata( | ||
new V1ObjectMeta().namespace("default").labels(Map.of("a", "b")).annotations(Map.of("aa", "bb"))); | ||
|
||
Map<String, String> result = KubernetesDiscoveryClientUtils.serviceMetadata(properties, service, "my-service"); | ||
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")); | ||
} | ||
|
||
/** | ||
* <pre> | ||
* - labels are not added | ||
* - annotations are added with prefix | ||
* </pre> | ||
*/ | ||
@Test | ||
void testServiceMetadataAddAnnotationsWithPrefix(CapturedOutput output) { | ||
boolean addLabels = false; | ||
String labelsPrefix = ""; | ||
boolean addAnnotations = true; | ||
String annotationsPrefix = "prefix-"; | ||
boolean addPorts = false; | ||
String portsPrefix = ""; | ||
|
||
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); | ||
V1Service service = new V1Service().spec(new V1ServiceSpec().type("ClusterIP")).metadata(new V1ObjectMeta() | ||
.namespace("default").labels(Map.of("a", "b")).annotations(Map.of("aa", "bb", "cc", "dd"))); | ||
|
||
Map<String, String> result = KubernetesDiscoveryClientUtils.serviceMetadata(properties, service, "my-service"); | ||
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")); | ||
} | ||
|
||
/** | ||
* <pre> | ||
* - labels are added with prefix | ||
* - annotations are added with prefix | ||
* </pre> | ||
*/ | ||
@Test | ||
void testServiceMetadataAddLabelsAndAnnotationsWithPrefix(CapturedOutput output) { | ||
boolean addLabels = true; | ||
String labelsPrefix = "label-"; | ||
boolean addAnnotations = true; | ||
String annotationsPrefix = "annotation-"; | ||
boolean addPorts = false; | ||
String portsPrefix = ""; | ||
|
||
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); | ||
V1Service service = new V1Service().spec(new V1ServiceSpec().type("ClusterIP")).metadata(new V1ObjectMeta() | ||
.namespace("default").labels(Map.of("a", "b", "c", "d")).annotations(Map.of("aa", "bb", "cc", "dd"))); | ||
|
||
Map<String, String> result = KubernetesDiscoveryClientUtils.serviceMetadata(properties, service, "my-service"); | ||
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")); | ||
} | ||
|
||
private String filterOnK8sNamespaceAndType(Map<String, String> 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(); | ||
} | ||
|
||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
metadata now includes two more fields, just like we do in the fabric8 implementation.