Skip to content

Commit e0f267c

Browse files
authored
Merge pull request #2064 from wind57/fix-1641-part-3-make-fabric8-discovery-client-cacheable
Fix 1641 part 3 : make fabric8 discovery client cacheable (3)
2 parents 252d83f + 0e51c75 commit e0f267c

File tree

16 files changed

+697
-152
lines changed

16 files changed

+697
-152
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
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.discovery;
18+
19+
import java.lang.annotation.Documented;
20+
import java.lang.annotation.ElementType;
21+
import java.lang.annotation.Inherited;
22+
import java.lang.annotation.Retention;
23+
import java.lang.annotation.RetentionPolicy;
24+
import java.lang.annotation.Target;
25+
26+
import org.springframework.boot.autoconfigure.condition.NoneNestedConditions;
27+
import org.springframework.context.annotation.Conditional;
28+
29+
/**
30+
* Reverse of {@link ConditionalOnDiscoveryCacheableBlockingEnabled}.
31+
*
32+
* @author wind57
33+
*/
34+
@Target({ ElementType.TYPE, ElementType.METHOD })
35+
@Retention(RetentionPolicy.RUNTIME)
36+
@Documented
37+
@Inherited
38+
@Conditional(ConditionalOnDiscoveryCacheableBlockingDisabled.OnDiscoveryCacheableBlockingDisabled.class)
39+
public @interface ConditionalOnDiscoveryCacheableBlockingDisabled {
40+
41+
class OnDiscoveryCacheableBlockingDisabled extends NoneNestedConditions {
42+
43+
OnDiscoveryCacheableBlockingDisabled() {
44+
super(ConfigurationPhase.REGISTER_BEAN);
45+
}
46+
47+
@ConditionalOnDiscoveryCacheableBlockingEnabled
48+
static class OnDisabled {
49+
50+
}
51+
52+
}
53+
54+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
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.discovery;
18+
19+
import java.lang.annotation.Documented;
20+
import java.lang.annotation.ElementType;
21+
import java.lang.annotation.Inherited;
22+
import java.lang.annotation.Retention;
23+
import java.lang.annotation.RetentionPolicy;
24+
import java.lang.annotation.Target;
25+
26+
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
27+
28+
/**
29+
* Provides a more succinct conditional for:
30+
* <code>spring.cloud.kubernetes.discovery.cacheable.blocking.enabled</code>. This
31+
* annotation says that caching in the blocking implementation is enabled.
32+
*
33+
* @author wind57
34+
*/
35+
@Target({ ElementType.TYPE, ElementType.METHOD })
36+
@Retention(RetentionPolicy.RUNTIME)
37+
@Documented
38+
@Inherited
39+
@ConditionalOnProperty(value = "spring.cloud.kubernetes.discovery.cacheable.blocking.enabled", havingValue = "true",
40+
matchIfMissing = false)
41+
public @interface ConditionalOnDiscoveryCacheableBlockingEnabled {
42+
43+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
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.discovery;
18+
19+
import java.lang.annotation.Documented;
20+
import java.lang.annotation.ElementType;
21+
import java.lang.annotation.Inherited;
22+
import java.lang.annotation.Retention;
23+
import java.lang.annotation.RetentionPolicy;
24+
import java.lang.annotation.Target;
25+
26+
import org.springframework.boot.autoconfigure.condition.NoneNestedConditions;
27+
import org.springframework.context.annotation.Conditional;
28+
29+
/**
30+
* Reverse of {@link ConditionalOnDiscoveryCacheableReactiveEnabled}.
31+
*
32+
* @author wind57
33+
*/
34+
@Target({ ElementType.TYPE, ElementType.METHOD })
35+
@Retention(RetentionPolicy.RUNTIME)
36+
@Documented
37+
@Inherited
38+
@Conditional(ConditionalOnDiscoveryCacheableReactiveDisabled.OnDiscoveryCacheableReactiveDisabled.class)
39+
public @interface ConditionalOnDiscoveryCacheableReactiveDisabled {
40+
41+
class OnDiscoveryCacheableReactiveDisabled extends NoneNestedConditions {
42+
43+
OnDiscoveryCacheableReactiveDisabled() {
44+
super(ConfigurationPhase.REGISTER_BEAN);
45+
}
46+
47+
@ConditionalOnDiscoveryCacheableReactiveEnabled
48+
static class OnDisabled {
49+
50+
}
51+
52+
}
53+
54+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
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.discovery;
18+
19+
import java.lang.annotation.Documented;
20+
import java.lang.annotation.ElementType;
21+
import java.lang.annotation.Inherited;
22+
import java.lang.annotation.Retention;
23+
import java.lang.annotation.RetentionPolicy;
24+
import java.lang.annotation.Target;
25+
26+
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
27+
28+
/**
29+
* Provides a more succinct conditional for:
30+
* <code>spring.cloud.kubernetes.discovery.cacheable.reactive.enabled</code>. This
31+
* annotation says that caching in the reactive implementation is enabled.
32+
*
33+
* @author wind57
34+
*/
35+
@Target({ ElementType.TYPE, ElementType.METHOD })
36+
@Retention(RetentionPolicy.RUNTIME)
37+
@Documented
38+
@Inherited
39+
@ConditionalOnProperty(value = "spring.cloud.kubernetes.discovery.cacheable.reactive.enabled", havingValue = "true",
40+
matchIfMissing = false)
41+
public @interface ConditionalOnDiscoveryCacheableReactiveEnabled {
42+
43+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,175 @@
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.discovery;
18+
19+
import java.util.ArrayList;
20+
import java.util.List;
21+
import java.util.Map;
22+
import java.util.Objects;
23+
import java.util.function.Predicate;
24+
25+
import io.fabric8.kubernetes.api.model.EndpointAddress;
26+
import io.fabric8.kubernetes.api.model.EndpointSubset;
27+
import io.fabric8.kubernetes.api.model.Endpoints;
28+
import io.fabric8.kubernetes.api.model.Service;
29+
import io.fabric8.kubernetes.client.KubernetesClient;
30+
import org.apache.commons.logging.LogFactory;
31+
32+
import org.springframework.cloud.client.ServiceInstance;
33+
import org.springframework.cloud.client.discovery.DiscoveryClient;
34+
import org.springframework.cloud.kubernetes.commons.KubernetesNamespaceProvider;
35+
import org.springframework.cloud.kubernetes.commons.discovery.KubernetesDiscoveryProperties;
36+
import org.springframework.cloud.kubernetes.commons.discovery.ServiceMetadata;
37+
import org.springframework.cloud.kubernetes.commons.discovery.ServicePortNameAndNumber;
38+
import org.springframework.cloud.kubernetes.commons.discovery.ServicePortSecureResolver;
39+
import org.springframework.core.log.LogAccessor;
40+
41+
import static org.springframework.cloud.kubernetes.commons.discovery.DiscoveryClientUtils.endpointsPort;
42+
import static org.springframework.cloud.kubernetes.commons.discovery.DiscoveryClientUtils.externalNameServiceInstance;
43+
import static org.springframework.cloud.kubernetes.commons.discovery.DiscoveryClientUtils.serviceInstance;
44+
import static org.springframework.cloud.kubernetes.commons.discovery.DiscoveryClientUtils.serviceInstanceMetadata;
45+
import static org.springframework.cloud.kubernetes.commons.discovery.KubernetesDiscoveryConstants.EXTERNAL_NAME;
46+
import static org.springframework.cloud.kubernetes.fabric8.Fabric8Utils.serviceMetadata;
47+
import static org.springframework.cloud.kubernetes.fabric8.discovery.Fabric8DiscoveryClientUtils.addresses;
48+
import static org.springframework.cloud.kubernetes.fabric8.discovery.Fabric8DiscoveryClientUtils.endpointSubsetsPortData;
49+
import static org.springframework.cloud.kubernetes.fabric8.discovery.Fabric8DiscoveryClientUtils.endpoints;
50+
import static org.springframework.cloud.kubernetes.fabric8.discovery.Fabric8DiscoveryClientUtils.services;
51+
import static org.springframework.cloud.kubernetes.fabric8.discovery.Fabric8InstanceIdHostPodNameSupplier.externalName;
52+
import static org.springframework.cloud.kubernetes.fabric8.discovery.Fabric8InstanceIdHostPodNameSupplier.nonExternalName;
53+
54+
/**
55+
* @author wind57
56+
*/
57+
abstract class Fabric8AbstractBlockingDiscoveryClient implements DiscoveryClient {
58+
59+
private static final LogAccessor LOG = new LogAccessor(
60+
LogFactory.getLog(Fabric8AbstractBlockingDiscoveryClient.class));
61+
62+
private final KubernetesDiscoveryProperties properties;
63+
64+
private final ServicePortSecureResolver servicePortSecureResolver;
65+
66+
private final KubernetesClient client;
67+
68+
private final KubernetesNamespaceProvider namespaceProvider;
69+
70+
private final Predicate<Service> predicate;
71+
72+
Fabric8AbstractBlockingDiscoveryClient(KubernetesClient client,
73+
KubernetesDiscoveryProperties kubernetesDiscoveryProperties,
74+
ServicePortSecureResolver servicePortSecureResolver, KubernetesNamespaceProvider namespaceProvider,
75+
Predicate<Service> predicate) {
76+
77+
this.client = client;
78+
this.properties = kubernetesDiscoveryProperties;
79+
this.servicePortSecureResolver = servicePortSecureResolver;
80+
this.namespaceProvider = namespaceProvider;
81+
this.predicate = predicate;
82+
}
83+
84+
public abstract String description();
85+
86+
@Override
87+
public List<ServiceInstance> getInstances(String serviceId) {
88+
Objects.requireNonNull(serviceId);
89+
90+
List<Endpoints> allEndpoints = endpoints(properties, client, namespaceProvider, "fabric8-discovery", serviceId,
91+
predicate);
92+
93+
List<ServiceInstance> instances = new ArrayList<>();
94+
for (Endpoints endpoints : allEndpoints) {
95+
// endpoints are only those that matched the serviceId
96+
instances.addAll(serviceInstances(endpoints, serviceId));
97+
}
98+
99+
if (properties.includeExternalNameServices()) {
100+
LOG.debug(() -> "Searching for 'ExternalName' type of services with serviceId : " + serviceId);
101+
List<Service> services = services(properties, client, namespaceProvider,
102+
s -> s.getSpec().getType().equals(EXTERNAL_NAME), Map.of("metadata.name", serviceId),
103+
"fabric8-discovery");
104+
for (Service service : services) {
105+
ServiceMetadata serviceMetadata = serviceMetadata(service);
106+
Map<String, String> serviceInstanceMetadata = serviceInstanceMetadata(Map.of(), serviceMetadata,
107+
properties);
108+
109+
Fabric8InstanceIdHostPodNameSupplier supplierOne = externalName(service);
110+
111+
ServiceInstance externalNameServiceInstance = externalNameServiceInstance(serviceMetadata, supplierOne,
112+
serviceInstanceMetadata);
113+
114+
instances.add(externalNameServiceInstance);
115+
}
116+
}
117+
118+
return instances;
119+
}
120+
121+
@Override
122+
public List<String> getServices() {
123+
List<String> services = services(properties, client, namespaceProvider, predicate, null, "fabric8 discovery")
124+
.stream()
125+
.map(service -> service.getMetadata().getName())
126+
.distinct()
127+
.toList();
128+
LOG.debug(() -> "will return services : " + services);
129+
return services;
130+
}
131+
132+
@Override
133+
public int getOrder() {
134+
return properties.order();
135+
}
136+
137+
private List<ServiceInstance> serviceInstances(Endpoints endpoints, String serviceId) {
138+
139+
List<EndpointSubset> subsets = endpoints.getSubsets();
140+
if (subsets.isEmpty()) {
141+
LOG.debug(() -> "serviceId : " + serviceId + " does not have any subsets");
142+
return List.of();
143+
}
144+
145+
String namespace = endpoints.getMetadata().getNamespace();
146+
List<ServiceInstance> instances = new ArrayList<>();
147+
148+
Service service = client.services().inNamespace(namespace).withName(serviceId).get();
149+
ServiceMetadata serviceMetadata = serviceMetadata(service);
150+
Map<String, Integer> portsData = endpointSubsetsPortData(subsets);
151+
152+
Map<String, String> serviceInstanceMetadata = serviceInstanceMetadata(portsData, serviceMetadata, properties);
153+
154+
for (EndpointSubset endpointSubset : subsets) {
155+
156+
Map<String, Integer> endpointsPortData = endpointSubsetsPortData(List.of(endpointSubset));
157+
ServicePortNameAndNumber portData = endpointsPort(endpointsPortData, serviceMetadata, properties);
158+
159+
List<EndpointAddress> addresses = addresses(endpointSubset, properties);
160+
for (EndpointAddress endpointAddress : addresses) {
161+
162+
Fabric8InstanceIdHostPodNameSupplier supplierOne = nonExternalName(endpointAddress, service);
163+
Fabric8PodLabelsAndAnnotationsSupplier supplierTwo = Fabric8PodLabelsAndAnnotationsSupplier
164+
.nonExternalName(client, namespace);
165+
166+
ServiceInstance serviceInstance = serviceInstance(servicePortSecureResolver, serviceMetadata,
167+
supplierOne, supplierTwo, portData, serviceInstanceMetadata, properties);
168+
instances.add(serviceInstance);
169+
}
170+
}
171+
172+
return instances;
173+
}
174+
175+
}

0 commit comments

Comments
 (0)