Skip to content

Commit

Permalink
merge main
Browse files Browse the repository at this point in the history
  • Loading branch information
wind57 committed Mar 26, 2024
2 parents 593b22b + 3f1a180 commit eea75ca
Show file tree
Hide file tree
Showing 17 changed files with 728 additions and 239 deletions.
14 changes: 0 additions & 14 deletions docs/modules/ROOT/pages/spring-cloud-kubernetes.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -35,20 +35,6 @@ To see the list of all Kubernetes related configuration properties please check
Click https://docs.spring.io/spring-cloud-build/reference/building.html[here] for basic building instructions.


[[building-docker-images-on-arm64]]
=== Building Docker Images On ARM64

If you run the Spring Cloud Kuberentes build on an ARM64 machine the docker images
used for the integration tests will fail to run due to using the wrong architecture.
This is because the Paketo build pack does not yet support ARM64. To work around this you
can run the build by passing `-Dspring-boot.build-image.builder=dashaun/builder:tiny` to Maven.

For example:
```
./mvnw clean install -Dspring-boot.build-image.builder=dashaun/builder:tiny
```


[[contributing]]
== Contributing

Expand Down
13 changes: 13 additions & 0 deletions pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -376,5 +376,18 @@
</plugins>
</build>
</profile>
<!-- Workaround until Paketo build packs support arm64 a.k.a. aarch64
See https://github.com/buildpacks/pack/issues?q=is%3Aissue+is%3Aopen+arm64 -->
<profile>
<id>build-image-aarch64</id>
<activation>
<os>
<arch>aarch64</arch>
</os>
</activation>
<properties>
<spring-boot.build-image.builder>dashaun/builder:tiny</spring-boot.build-image.builder>
</properties>
</profile>
</profiles>
</project>
2 changes: 1 addition & 1 deletion spring-cloud-kubernetes-dependencies/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@
<properties>
<hoverfly.version>0.13.0</hoverfly.version>
<kubernetes-fabric8-client.version>6.9.2</kubernetes-fabric8-client.version>
<kubernetes-native-client.version>19.0.0</kubernetes-native-client.version>
<kubernetes-native-client.version>19.0.1</kubernetes-native-client.version>
<wiremock.version>3.4.2</wiremock.version>
<commons.collections4.version>4.4</commons.collections4.version>
</properties>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,12 +16,16 @@

package org.springframework.cloud.kubernetes.fabric8;

import io.fabric8.kubernetes.api.model.ObjectMeta;
import io.fabric8.kubernetes.api.model.Service;
import io.fabric8.kubernetes.api.model.ServiceSpec;
import io.fabric8.kubernetes.client.KubernetesClient;
import jakarta.annotation.Nullable;
import org.apache.commons.logging.LogFactory;

import org.springframework.cloud.kubernetes.commons.KubernetesNamespaceProvider;
import org.springframework.cloud.kubernetes.commons.config.NamespaceResolutionFailedException;
import org.springframework.cloud.kubernetes.commons.discovery.ServiceMetadata;
import org.springframework.core.log.LogAccessor;
import org.springframework.util.StringUtils;

Expand All @@ -37,6 +41,13 @@ private Fabric8Utils() {

}

public static ServiceMetadata serviceMetadata(Service service) {
ObjectMeta metadata = service.getMetadata();
ServiceSpec serviceSpec = service.getSpec();
return new ServiceMetadata(metadata.getName(), metadata.getNamespace(), serviceSpec.getType(),
metadata.getLabels(), metadata.getAnnotations());
}

private static final LogAccessor LOG = new LogAccessor(LogFactory.getLog(Fabric8Utils.class));

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,10 +29,8 @@
import io.fabric8.kubernetes.api.model.EndpointSubset;
import io.fabric8.kubernetes.api.model.Endpoints;
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.ServiceList;
import io.fabric8.kubernetes.api.model.ServiceSpec;
import io.fabric8.kubernetes.client.KubernetesClient;
import io.fabric8.kubernetes.client.dsl.FilterNested;
import io.fabric8.kubernetes.client.dsl.FilterWatchListDeletable;
Expand All @@ -43,7 +41,6 @@

import org.springframework.cloud.kubernetes.commons.KubernetesNamespaceProvider;
import org.springframework.cloud.kubernetes.commons.discovery.KubernetesDiscoveryProperties;
import org.springframework.cloud.kubernetes.commons.discovery.ServiceMetadata;
import org.springframework.cloud.kubernetes.fabric8.Fabric8Utils;
import org.springframework.core.log.LogAccessor;
import org.springframework.util.CollectionUtils;
Expand Down Expand Up @@ -198,13 +195,6 @@ static Map<String, Integer> endpointSubsetsPortData(List<EndpointSubset> endpoin
EndpointPort::getPort));
}

static ServiceMetadata serviceMetadata(Service service) {
ObjectMeta metadata = service.getMetadata();
ServiceSpec serviceSpec = service.getSpec();
return new ServiceMetadata(metadata.getName(), metadata.getNamespace(), serviceSpec.getType(),
metadata.getLabels(), metadata.getAnnotations());
}

/**
* serviceName can be null, in which case, such a filter will not be applied.
*/
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -44,12 +44,12 @@
import static org.springframework.cloud.kubernetes.commons.discovery.DiscoveryClientUtils.serviceInstance;
import static org.springframework.cloud.kubernetes.commons.discovery.DiscoveryClientUtils.serviceInstanceMetadata;
import static org.springframework.cloud.kubernetes.commons.discovery.KubernetesDiscoveryConstants.EXTERNAL_NAME;
import static org.springframework.cloud.kubernetes.fabric8.Fabric8Utils.serviceMetadata;
import static org.springframework.cloud.kubernetes.fabric8.discovery.Fabric8InstanceIdHostPodNameSupplier.externalName;
import static org.springframework.cloud.kubernetes.fabric8.discovery.Fabric8InstanceIdHostPodNameSupplier.nonExternalName;
import static org.springframework.cloud.kubernetes.fabric8.discovery.Fabric8KubernetesDiscoveryClientUtils.addresses;
import static org.springframework.cloud.kubernetes.fabric8.discovery.Fabric8KubernetesDiscoveryClientUtils.endpointSubsetsPortData;
import static org.springframework.cloud.kubernetes.fabric8.discovery.Fabric8KubernetesDiscoveryClientUtils.endpoints;
import static org.springframework.cloud.kubernetes.fabric8.discovery.Fabric8KubernetesDiscoveryClientUtils.serviceMetadata;
import static org.springframework.cloud.kubernetes.fabric8.discovery.Fabric8KubernetesDiscoveryClientUtils.services;
import static org.springframework.cloud.kubernetes.fabric8.discovery.Fabric8PodLabelsAndAnnotationsSupplier.externalName;
import static org.springframework.cloud.kubernetes.fabric8.discovery.Fabric8PodLabelsAndAnnotationsSupplier.nonExternalName;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,6 @@

package org.springframework.cloud.kubernetes.fabric8.loadbalancer;

import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Optional;
Expand All @@ -27,10 +26,13 @@
import io.fabric8.kubernetes.client.utils.Utils;

import org.springframework.cloud.kubernetes.commons.discovery.DefaultKubernetesServiceInstance;
import org.springframework.cloud.kubernetes.commons.discovery.DiscoveryClientUtils;
import org.springframework.cloud.kubernetes.commons.discovery.KubernetesDiscoveryProperties;
import org.springframework.cloud.kubernetes.commons.discovery.KubernetesServiceInstance;
import org.springframework.cloud.kubernetes.commons.discovery.ServiceMetadata;
import org.springframework.cloud.kubernetes.commons.loadbalancer.KubernetesLoadBalancerProperties;
import org.springframework.cloud.kubernetes.commons.loadbalancer.KubernetesServiceInstanceMapper;
import org.springframework.cloud.kubernetes.fabric8.Fabric8Utils;

/**
* Class for mapping Kubernetes Service object into {@link KubernetesServiceInstance}.
Expand All @@ -39,6 +41,11 @@
*/
public class Fabric8ServiceInstanceMapper implements KubernetesServiceInstanceMapper<Service> {

/**
* empty on purpose, load balancer implementation does not need them.
*/
private static final Map<String, Integer> PORTS_DATA = Map.of();

private final KubernetesLoadBalancerProperties properties;

private final KubernetesDiscoveryProperties discoveryProperties;
Expand All @@ -57,7 +64,7 @@ public KubernetesServiceInstance map(Service service) {
if (ports.size() == 1) {
port = ports.get(0);
}
else if (ports.size() > 1 && Utils.isNotNullOrEmpty(this.properties.getPortName())) {
else if (ports.size() > 1 && Utils.isNotNullOrEmpty(properties.getPortName())) {
Optional<ServicePort> optPort = ports.stream().filter(it -> properties.getPortName().endsWith(it.getName()))
.findAny();
if (optPort.isPresent()) {
Expand All @@ -72,24 +79,12 @@ else if (ports.size() > 1 && Utils.isNotNullOrEmpty(this.properties.getPortName(
boolean secure = KubernetesServiceInstanceMapper.isSecure(service.getMetadata().getLabels(),
service.getMetadata().getAnnotations(), port.getName(), port.getPort());
return new DefaultKubernetesServiceInstance(meta.getUid(), meta.getName(), host, port.getPort(),
getServiceMetadata(service), secure);
serviceMetadata(service), secure);
}

private Map<String, String> getServiceMetadata(Service service) {
Map<String, String> serviceMetadata = new HashMap<>();
KubernetesDiscoveryProperties.Metadata metadataProps = this.discoveryProperties.metadata();
if (metadataProps.addLabels()) {
Map<String, String> labelMetadata = KubernetesServiceInstanceMapper
.getMapWithPrefixedKeys(service.getMetadata().getLabels(), metadataProps.labelsPrefix());
serviceMetadata.putAll(labelMetadata);
}
if (metadataProps.addAnnotations()) {
Map<String, String> annotationMetadata = KubernetesServiceInstanceMapper
.getMapWithPrefixedKeys(service.getMetadata().getAnnotations(), metadataProps.annotationsPrefix());
serviceMetadata.putAll(annotationMetadata);
}

return serviceMetadata;
Map<String, String> serviceMetadata(Service service) {
ServiceMetadata serviceMetadata = Fabric8Utils.serviceMetadata(service);
return DiscoveryClientUtils.serviceInstanceMetadata(PORTS_DATA, serviceMetadata, discoveryProperties);
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@
import org.springframework.cloud.client.ServiceInstance;
import org.springframework.cloud.kubernetes.commons.KubernetesNamespaceProvider;
import org.springframework.cloud.kubernetes.commons.discovery.KubernetesDiscoveryProperties;
import org.springframework.cloud.kubernetes.commons.loadbalancer.KubernetesServiceInstanceMapper;
import org.springframework.cloud.kubernetes.commons.loadbalancer.KubernetesServicesListSupplier;
import org.springframework.cloud.kubernetes.fabric8.Fabric8Utils;
import org.springframework.cloud.loadbalancer.core.ServiceInstanceListSupplier;
Expand Down Expand Up @@ -64,15 +65,30 @@ public Flux<List<ServiceInstance>> get() {
LOG.debug(() -> "discovering services in all namespaces");
List<Service> services = kubernetesClient.services().inAnyNamespace()
.withField("metadata.name", serviceName).list().getItems();
services.forEach(service -> result.add(mapper.map(service)));
services.forEach(service -> addMappedService(mapper, result, service));
}
else if (!discoveryProperties.namespaces().isEmpty()) {
List<String> selectiveNamespaces = discoveryProperties.namespaces().stream().sorted().toList();
LOG.debug(() -> "discovering services in selective namespaces : " + selectiveNamespaces);
selectiveNamespaces.forEach(selectiveNamespace -> {
Service service = kubernetesClient.services().inNamespace(selectiveNamespace).withName(serviceName)
.get();
if (service != null) {
addMappedService(mapper, result, service);
}
else {
LOG.debug(() -> "did not find service with name : " + serviceName + " in namespace : "
+ selectiveNamespace);
}
});
}
else {
String namespace = Fabric8Utils.getApplicationNamespace(kubernetesClient, null, "loadbalancer-service",
namespaceProvider);
LOG.debug(() -> "discovering services in namespace : " + namespace);
Service service = kubernetesClient.services().inNamespace(namespace).withName(serviceName).get();
if (service != null) {
result.add(mapper.map(service));
addMappedService(mapper, result, service);
}
else {
LOG.debug(() -> "did not find service with name : " + serviceName + " in namespace : " + namespace);
Expand All @@ -83,4 +99,9 @@ public Flux<List<ServiceInstance>> get() {
return Flux.defer(() -> Flux.just(result));
}

private void addMappedService(KubernetesServiceInstanceMapper<Service> mapper, List<ServiceInstance> services,
Service service) {
services.add(mapper.map(service));
}

}
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright 2013-2023 the original author or authors.
* Copyright 2013-2024 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.
Expand Down Expand Up @@ -38,7 +38,7 @@ class Fabric8ServiceInstanceMapperTests {
@Test
void testMapperSimple() {
KubernetesLoadBalancerProperties properties = new KubernetesLoadBalancerProperties();
Service service = buildService("test", "abc", 8080, null, Map.of());
Service service = buildService("test", "test-namespace", "abc", 8080, null, Map.of());
KubernetesServiceInstance instance = new Fabric8ServiceInstanceMapper(properties,
KubernetesDiscoveryProperties.DEFAULT).map(service);
Assertions.assertNotNull(instance);
Expand All @@ -53,7 +53,7 @@ void testMapperMultiplePorts() {
List<ServicePort> ports = new ArrayList<>();
ports.add(new ServicePortBuilder().withPort(8080).withName("web").build());
ports.add(new ServicePortBuilder().withPort(9000).withName("http").build());
Service service = buildService("test", "abc", ports, Map.of());
Service service = buildService("test", "test-namespace", "abc", ports, Map.of());
KubernetesServiceInstance instance = new Fabric8ServiceInstanceMapper(properties,
KubernetesDiscoveryProperties.DEFAULT).map(service);
Assertions.assertNotNull(instance);
Expand All @@ -65,7 +65,7 @@ void testMapperMultiplePorts() {
@Test
void testMapperSecure() {
KubernetesLoadBalancerProperties properties = new KubernetesLoadBalancerProperties();
Service service = buildService("test", "abc", 443, null, Map.of());
Service service = buildService("test", "test-namespace", "abc", 443, null, Map.of());
KubernetesServiceInstance instance = new Fabric8ServiceInstanceMapper(properties,
KubernetesDiscoveryProperties.DEFAULT).map(service);
Assertions.assertNotNull(instance);
Expand All @@ -82,7 +82,7 @@ void testMapperSecureNullLabelsAndAnnotations() {
false);
List<ServicePort> ports = new ArrayList<>();
ports.add(new ServicePortBuilder().withPort(443).build());
Service service = buildService("test", "abc", ports, null, null);
Service service = buildService("test", "test-namespace", "abc", ports, null, null);
KubernetesServiceInstance instance = new Fabric8ServiceInstanceMapper(properties, discoveryProperties)
.map(service);
Assertions.assertNotNull(instance);
Expand All @@ -95,29 +95,56 @@ void testMapperSecureNullLabelsAndAnnotations() {
void testMapperSecureWithLabels() {
KubernetesLoadBalancerProperties properties = new KubernetesLoadBalancerProperties();
Map<String, String> labels = Map.of("secured", "true", "label1", "123");
Service service = buildService("test", "abc", 8080, null, labels);
Service service = buildService("test", "test-namespace", "abc", 8080, null, labels);
KubernetesServiceInstance instance = new Fabric8ServiceInstanceMapper(properties,
KubernetesDiscoveryProperties.DEFAULT).map(service);
Assertions.assertNotNull(instance);
Assertions.assertEquals("test", instance.getServiceId());
Assertions.assertEquals("abc", instance.getInstanceId());
Assertions.assertTrue(instance.isSecure());
Assertions.assertEquals(2, instance.getMetadata().keySet().size());
Assertions.assertEquals(4, instance.getMetadata().keySet().size());
}

private Service buildService(String name, String uid, int port, String portName, Map<String, String> labels) {
@Test
void serviceMetadataTest() {

KubernetesLoadBalancerProperties loadBalancerProperties = new KubernetesLoadBalancerProperties();
KubernetesDiscoveryProperties discoveryProperties = new KubernetesDiscoveryProperties(true, false, Set.of(),
true, 60, false, null, Set.of(), Map.of(), null, KubernetesDiscoveryProperties.Metadata.DEFAULT, 0,
true);

List<ServicePort> ports = new ArrayList<>();
ports.add(new ServicePortBuilder().withPort(443).build());

Map<String, String> labels = Map.of("one", "1");
Map<String, String> annotations = Map.of("two", "2");

Service service = buildService("test", "test-namespace", "abc", ports, labels, annotations);
Map<String, String> result = new Fabric8ServiceInstanceMapper(loadBalancerProperties, discoveryProperties)
.serviceMetadata(service);
Assertions.assertEquals(result.size(), 4);
Assertions.assertEquals(result.get("k8s_namespace"), "test-namespace");
Assertions.assertEquals(result.get("type"), "ClusterIP");
Assertions.assertEquals(result.get("one"), "1");
Assertions.assertEquals(result.get("two"), "2");
}

private Service buildService(String name, String namespace, String uid, int port, String portName,
Map<String, String> labels) {
ServicePort servicePort = new ServicePortBuilder().withPort(port).withName(portName).build();
return buildService(name, uid, Collections.singletonList(servicePort), labels);
return buildService(name, namespace, uid, Collections.singletonList(servicePort), labels);
}

private Service buildService(String name, String uid, List<ServicePort> ports, Map<String, String> labels,
Map<String, String> annotations) {
return new ServiceBuilder().withNewMetadata().withName(name).withUid(uid).addToLabels(labels)
.withAnnotations(annotations).endMetadata().withNewSpec().addAllToPorts(ports).endSpec().build();
private Service buildService(String name, String namespace, String uid, List<ServicePort> ports,
Map<String, String> labels, Map<String, String> annotations) {
return new ServiceBuilder().withNewMetadata().withNamespace(namespace).withName(name).withUid(uid)
.addToLabels(labels).withAnnotations(annotations).endMetadata().withNewSpec().addAllToPorts(ports)
.withType("ClusterIP").endSpec().build();
}

private Service buildService(String name, String uid, List<ServicePort> ports, Map<String, String> labels) {
return buildService(name, uid, ports, labels, Map.of());
private Service buildService(String name, String namespace, String uid, List<ServicePort> ports,
Map<String, String> labels) {
return buildService(name, namespace, uid, ports, labels, Map.of());
}

}
Loading

0 comments on commit eea75ca

Please sign in to comment.