Skip to content

Commit f2697e3

Browse files
committed
fix-1965: first commit
Signed-off-by: wind57 <eugen.rabii@gmail.com>
1 parent 5e00f3c commit f2697e3

File tree

7 files changed

+330
-3
lines changed

7 files changed

+330
-3
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
/*
2+
* Copyright 2013-present the original author or authors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* https://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package org.springframework.cloud.kubernetes.commons.loadbalancer;
18+
19+
import java.lang.annotation.ElementType;
20+
import java.lang.annotation.Retention;
21+
import java.lang.annotation.RetentionPolicy;
22+
import java.lang.annotation.Target;
23+
24+
import org.springframework.context.annotation.Conditional;
25+
26+
/**
27+
* @author wind57
28+
*/
29+
@Conditional(OnServiceMatchingStrategyCondition.class)
30+
@Retention(RetentionPolicy.RUNTIME)
31+
@Target({ ElementType.TYPE, ElementType.METHOD })
32+
public @interface ConditionalOnServiceMatchingStrategyCondition {
33+
34+
LoadBalancerServiceMatchingStrategy value();
35+
36+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
/*
2+
* Copyright 2013-present the original author or authors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* https://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package org.springframework.cloud.kubernetes.commons.loadbalancer;
18+
19+
/**
20+
* @author wind57
21+
*/
22+
public enum LoadBalancerServiceMatchingStrategy {
23+
24+
/**
25+
* Loadbalancer services discovery happens based on 'metadata.name'.
26+
*/
27+
NAME,
28+
29+
/**
30+
* Loadbalancer services discovery happens based on labels.
31+
*/
32+
LABELS
33+
34+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
/*
2+
* Copyright 2013-present the original author or authors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* https://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package org.springframework.cloud.kubernetes.commons.loadbalancer;
18+
19+
import org.springframework.boot.autoconfigure.condition.ConditionOutcome;
20+
import org.springframework.boot.autoconfigure.condition.SpringBootCondition;
21+
import org.springframework.context.annotation.ConditionContext;
22+
import org.springframework.core.type.AnnotatedTypeMetadata;
23+
24+
import static org.springframework.cloud.kubernetes.commons.loadbalancer.LoadBalancerServiceMatchingStrategy.NAME;
25+
26+
/**
27+
* @author wind57
28+
*/
29+
final class OnServiceMatchingStrategyCondition extends SpringBootCondition {
30+
31+
private static final String CLASS_NAME = ConditionalOnServiceMatchingStrategyCondition.class.getName();
32+
33+
@Override
34+
public ConditionOutcome getMatchOutcome(ConditionContext context, AnnotatedTypeMetadata metadata) {
35+
36+
// default value is NAME, so if nothing is set we will use that strategy
37+
LoadBalancerServiceMatchingStrategy fromEnvironment = context.getEnvironment()
38+
.getProperty("spring.cloud.kubernetes.loadbalancer.service-matching-strategy",
39+
LoadBalancerServiceMatchingStrategy.class, NAME);
40+
41+
LoadBalancerServiceMatchingStrategy fromAnnotation = (LoadBalancerServiceMatchingStrategy) metadata
42+
.getAnnotationAttributes(CLASS_NAME)
43+
.get("value");
44+
45+
if (fromEnvironment.equals(fromAnnotation)) {
46+
return ConditionOutcome.match("Strategy matched: " + fromAnnotation);
47+
}
48+
return ConditionOutcome.noMatch("Strategy did not match : " + fromEnvironment + " for : " + fromAnnotation);
49+
}
50+
51+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,110 @@
1+
/*
2+
* Copyright 2013-present the original author or authors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* https://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package org.springframework.cloud.kubernetes.fabric8.loadbalancer;
18+
19+
import java.util.ArrayList;
20+
import java.util.List;
21+
import java.util.Map;
22+
23+
import io.fabric8.kubernetes.api.model.Service;
24+
import io.fabric8.kubernetes.client.KubernetesClient;
25+
import reactor.core.publisher.Flux;
26+
27+
import org.springframework.cloud.client.ServiceInstance;
28+
import org.springframework.cloud.kubernetes.commons.KubernetesNamespaceProvider;
29+
import org.springframework.cloud.kubernetes.commons.discovery.KubernetesDiscoveryProperties;
30+
import org.springframework.cloud.loadbalancer.core.ServiceInstanceListSupplier;
31+
import org.springframework.core.env.Environment;
32+
import org.springframework.core.log.LogAccessor;
33+
34+
import static org.springframework.cloud.kubernetes.fabric8.Fabric8Utils.getApplicationNamespace;
35+
36+
/**
37+
* Implementation of {@link ServiceInstanceListSupplier} for load balancer in SERVICE mode
38+
* based on labels filtering.
39+
*
40+
* @author wind57
41+
*/
42+
class Fabric8LabelBasedServicesListSupplier extends AbstractFabric8ServicesListSupplier {
43+
44+
private static final LogAccessor LOG = new LogAccessor(Fabric8LabelBasedServicesListSupplier.class);
45+
46+
private static final String FIELD_NAME = "metadata.labels";
47+
48+
private final Map<String, String> serviceLabels;
49+
50+
private final KubernetesClient kubernetesClient;
51+
52+
private final KubernetesNamespaceProvider namespaceProvider;
53+
54+
Fabric8LabelBasedServicesListSupplier(Environment environment, KubernetesClient kubernetesClient,
55+
Fabric8ServiceInstanceMapper mapper, KubernetesDiscoveryProperties discoveryProperties) {
56+
super(environment, mapper, discoveryProperties);
57+
this.kubernetesClient = kubernetesClient;
58+
namespaceProvider = new KubernetesNamespaceProvider(environment);
59+
this.serviceLabels = discoveryProperties.serviceLabels();
60+
}
61+
62+
@Override
63+
public Flux<List<ServiceInstance>> get() {
64+
return Flux.defer(() -> {
65+
List<ServiceInstance> serviceInstances = new ArrayList<>();
66+
String serviceName = getServiceId();
67+
LOG.debug(() -> "loadbalancer serviceID : " + serviceName);
68+
69+
if (discoveryProperties.allNamespaces()) {
70+
LOG.debug(() -> "discovering services in all namespaces");
71+
List<Service> services = kubernetesClient.services()
72+
.inAnyNamespace()
73+
.withLabels(serviceLabels)
74+
.list()
75+
.getItems();
76+
77+
addMappedServices(serviceInstances, services, null, FIELD_NAME, serviceName);
78+
}
79+
else if (!discoveryProperties.namespaces().isEmpty()) {
80+
List<String> selectiveNamespaces = discoveryProperties.namespaces().stream().sorted().toList();
81+
LOG.debug(() -> "discovering services in selective namespaces : " + selectiveNamespaces);
82+
selectiveNamespaces.forEach(selectiveNamespace -> {
83+
List<Service> services = kubernetesClient.services()
84+
.inNamespace(selectiveNamespace)
85+
.withLabels(serviceLabels)
86+
.list()
87+
.getItems();
88+
89+
addMappedServices(serviceInstances, services, selectiveNamespace, FIELD_NAME, serviceName);
90+
});
91+
}
92+
else {
93+
String namespace = getApplicationNamespace(kubernetesClient, null, "loadbalancer-service",
94+
namespaceProvider);
95+
LOG.debug(() -> "discovering services in namespace : " + namespace);
96+
List<Service> services = kubernetesClient.services()
97+
.inNamespace(namespace)
98+
.withLabels(serviceLabels)
99+
.list()
100+
.getItems();
101+
102+
addMappedServices(serviceInstances, services, namespace, FIELD_NAME, serviceName);
103+
}
104+
105+
LOG.debug(() -> "found services : " + serviceInstances);
106+
return Flux.just(serviceInstances);
107+
});
108+
}
109+
110+
}

spring-cloud-kubernetes-fabric8-loadbalancer/src/main/java/org/springframework/cloud/kubernetes/fabric8/loadbalancer/Fabric8LoadBalancerClientConfiguration.java

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,11 +20,15 @@
2020

2121
import org.springframework.cloud.kubernetes.commons.discovery.KubernetesDiscoveryProperties;
2222
import org.springframework.cloud.kubernetes.commons.loadbalancer.ConditionalOnKubernetesLoadBalancerServiceModeEnabled;
23+
import org.springframework.cloud.kubernetes.commons.loadbalancer.ConditionalOnServiceMatchingStrategyCondition;
2324
import org.springframework.cloud.loadbalancer.core.ServiceInstanceListSupplier;
2425
import org.springframework.context.ConfigurableApplicationContext;
2526
import org.springframework.context.annotation.Bean;
2627
import org.springframework.core.env.Environment;
2728

29+
import static org.springframework.cloud.kubernetes.commons.loadbalancer.LoadBalancerServiceMatchingStrategy.LABELS;
30+
import static org.springframework.cloud.kubernetes.commons.loadbalancer.LoadBalancerServiceMatchingStrategy.NAME;
31+
2832
/**
2933
* Kubernetes load balancer client configuration.
3034
*
@@ -34,7 +38,8 @@ public class Fabric8LoadBalancerClientConfiguration {
3438

3539
@Bean
3640
@ConditionalOnKubernetesLoadBalancerServiceModeEnabled
37-
ServiceInstanceListSupplier kubernetesServicesListSupplier(Environment environment,
41+
@ConditionalOnServiceMatchingStrategyCondition(NAME)
42+
ServiceInstanceListSupplier kubernetesNameBasedServicesListSupplier(Environment environment,
3843
KubernetesClient kubernetesClient, Fabric8ServiceInstanceMapper mapper,
3944
KubernetesDiscoveryProperties discoveryProperties, ConfigurableApplicationContext context) {
4045
return ServiceInstanceListSupplier.builder()
@@ -43,4 +48,17 @@ ServiceInstanceListSupplier kubernetesServicesListSupplier(Environment environme
4348
.build(context);
4449
}
4550

51+
@Bean
52+
@ConditionalOnKubernetesLoadBalancerServiceModeEnabled
53+
@ConditionalOnServiceMatchingStrategyCondition(LABELS)
54+
ServiceInstanceListSupplier kubernetesLabelsBasedServicesListSupplier(Environment environment,
55+
KubernetesClient kubernetesClient, Fabric8ServiceInstanceMapper mapper,
56+
KubernetesDiscoveryProperties discoveryProperties, ConfigurableApplicationContext context) {
57+
return ServiceInstanceListSupplier.builder()
58+
.withBase(new Fabric8LabelBasedServicesListSupplier(environment, kubernetesClient, mapper,
59+
discoveryProperties))
60+
.withCaching()
61+
.build(context);
62+
}
63+
4664
}

spring-cloud-kubernetes-fabric8-loadbalancer/src/main/java/org/springframework/cloud/kubernetes/fabric8/loadbalancer/Fabric8ServicesListSupplier.java

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,6 @@
2121

2222
import io.fabric8.kubernetes.api.model.Service;
2323
import io.fabric8.kubernetes.client.KubernetesClient;
24-
import org.apache.commons.logging.LogFactory;
2524
import reactor.core.publisher.Flux;
2625

2726
import org.springframework.cloud.client.ServiceInstance;
@@ -41,7 +40,7 @@
4140
*/
4241
public class Fabric8ServicesListSupplier extends AbstractFabric8ServicesListSupplier {
4342

44-
private static final LogAccessor LOG = new LogAccessor(LogFactory.getLog(Fabric8ServicesListSupplier.class));
43+
private static final LogAccessor LOG = new LogAccessor(Fabric8ServicesListSupplier.class);
4544

4645
private static final String FIELD_NAME = "metadata.name";
4746

0 commit comments

Comments
 (0)