Skip to content

Commit 3cce84b

Browse files
authored
Merge pull request #901 from yue9944882/refactor/set-api-type-for-filter
Require Kubernetes API type for event-filter annotation
2 parents 0f661c5 + 1ea92e9 commit 3cce84b

File tree

7 files changed

+123
-56
lines changed

7 files changed

+123
-56
lines changed

spring/src/main/java/io/kubernetes/client/spring/extended/controller/KubernetesReconcilerProcessor.java

Lines changed: 103 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -14,13 +14,18 @@
1414
import java.lang.reflect.Method;
1515
import java.time.Duration;
1616
import java.util.ArrayList;
17+
import java.util.HashMap;
18+
import java.util.HashSet;
1719
import java.util.List;
20+
import java.util.Map;
21+
import java.util.Set;
1822
import java.util.concurrent.ExecutorService;
1923
import java.util.concurrent.Executors;
2024
import java.util.function.BiPredicate;
2125
import java.util.function.Function;
2226
import java.util.function.Predicate;
2327
import java.util.function.Supplier;
28+
import org.apache.commons.lang3.StringUtils;
2429
import org.slf4j.Logger;
2530
import org.slf4j.LoggerFactory;
2631
import org.springframework.beans.BeansException;
@@ -76,38 +81,20 @@ private Controller buildController(SharedInformerFactory sharedInformerFactory,
7681
DefaultControllerBuilder builder = ControllerBuilder.defaultBuilder(sharedInformerFactory);
7782
RateLimitingQueue<Request> workQueue = new DefaultRateLimitingQueue<>();
7883
builder = builder.withWorkQueue(workQueue);
84+
Map<Class, AddFilterAdaptor> addFilters = getAddFilters(watches, r);
85+
Map<Class, UpdateFilterAdaptor> updateFilters = getUpdateFilters(watches, r);
86+
Map<Class, DeleteFilterAdaptor> deleteFilters = getDeleteFilters(watches, r);
87+
List<ReadyFuncAdaptor> readyFuncs = getReadyFuncs(r);
7988
for (KubernetesReconcilerWatch watch : watches.value()) {
8089
try {
81-
Predicate addFilter = null;
82-
BiPredicate updateFilter = null;
83-
BiPredicate deleteFilter = null;
84-
final List<Supplier<Boolean>> readyFuncs = new ArrayList<>();
8590
Function<?, Request> workQueueKeyFunc = watch.workQueueKeyFunc().newInstance();
86-
for (Method method : r.getClass().getMethods()) {
87-
if (method.isAnnotationPresent(AddWatchEventFilter.class)) {
88-
addFilter = new AddFilterAdaptor(r, method);
89-
}
90-
if (method.isAnnotationPresent(UpdateWatchEventFilter.class)) {
91-
updateFilter = new UpdateFilterAdaptor(r, method);
92-
}
93-
if (method.isAnnotationPresent(DeleteWatchEventFilter.class)) {
94-
deleteFilter = new DeleteFilterAdaptor(r, method);
95-
}
96-
if (method.isAnnotationPresent(KubernetesReconcilerReadyFunc.class)) {
97-
readyFuncs.add(new ReadyFuncAdaptor(r, method));
98-
}
99-
}
100-
101-
final Predicate finalAddFilter = addFilter;
102-
final BiPredicate finalUpdateFilter = updateFilter;
103-
final BiPredicate finalDeleteFilter = deleteFilter;
10491
builder =
10592
builder.watch(
10693
(q) -> {
10794
return ControllerBuilder.controllerWatchBuilder(watch.apiTypeClass(), q)
108-
.withOnAddFilter(finalAddFilter)
109-
.withOnUpdateFilter(finalUpdateFilter)
110-
.withOnDeleteFilter(finalDeleteFilter)
95+
.withOnAddFilter(addFilters.get(watch.apiTypeClass()))
96+
.withOnUpdateFilter(updateFilters.get(watch.apiTypeClass()))
97+
.withOnDeleteFilter(deleteFilters.get(watch.apiTypeClass()))
11198
.withWorkQueueKeyFunc(workQueueKeyFunc)
11299
.withResyncPeriod(Duration.ofMillis(watch.resyncPeriodMillis()))
113100
.build();
@@ -120,15 +107,101 @@ private Controller buildController(SharedInformerFactory sharedInformerFactory,
120107
}
121108
}
122109

123-
if (r.getClass().isAnnotationPresent(KubernetesReconcilerWorkerCount.class)) {
124-
KubernetesReconcilerWorkerCount workerCount =
125-
r.getClass().getAnnotation(KubernetesReconcilerWorkerCount.class);
126-
builder = builder.withWorkerCount(workerCount.value());
127-
}
110+
builder = builder.withWorkerCount(kubernetesReconciler.workerCount());
128111

129112
return builder.withReconciler(r).withName(reconcilerName).build();
130113
}
131114

115+
private Map<Class, AddFilterAdaptor> getAddFilters(
116+
KubernetesReconcilerWatches watches, Reconciler reconciler) {
117+
Map<Class, AddFilterAdaptor> filters = new HashMap<>();
118+
Set<Method> allAnnotatedMethods = new HashSet<>();
119+
Set<Method> adoptedMethods = new HashSet<>();
120+
for (KubernetesReconcilerWatch watch : watches.value()) {
121+
for (Method method : reconciler.getClass().getMethods()) {
122+
AddWatchEventFilter annotation = method.getAnnotation(AddWatchEventFilter.class);
123+
if (watch.apiTypeClass().equals(annotation.apiTypeClass())) {
124+
if (filters.containsKey(watch.apiTypeClass())) {
125+
log.warn(
126+
"Duplicated watch ADD event filter upon apiType {}", annotation.apiTypeClass());
127+
}
128+
filters.put(watch.apiTypeClass(), new AddFilterAdaptor(reconciler, method));
129+
adoptedMethods.add(method);
130+
}
131+
allAnnotatedMethods.add(method);
132+
}
133+
}
134+
allAnnotatedMethods.removeAll(adoptedMethods);
135+
if (allAnnotatedMethods.size() > 0) {
136+
log.warn("Dangling watch ADD event filters {}", StringUtils.join(allAnnotatedMethods, ","));
137+
}
138+
return filters;
139+
}
140+
141+
private Map<Class, UpdateFilterAdaptor> getUpdateFilters(
142+
KubernetesReconcilerWatches watches, Reconciler reconciler) {
143+
Map<Class, UpdateFilterAdaptor> filters = new HashMap<>();
144+
Set<Method> allAnnotatedMethods = new HashSet<>();
145+
Set<Method> adoptedMethods = new HashSet<>();
146+
for (KubernetesReconcilerWatch watch : watches.value()) {
147+
for (Method method : reconciler.getClass().getMethods()) {
148+
UpdateWatchEventFilter annotation = method.getAnnotation(UpdateWatchEventFilter.class);
149+
if (watch.apiTypeClass().equals(annotation.apiTypeClass())) {
150+
if (filters.containsKey(watch.apiTypeClass())) {
151+
log.warn(
152+
"Duplicated watch UPDATE event filter upon apiType {}", annotation.apiTypeClass());
153+
}
154+
filters.put(watch.apiTypeClass(), new UpdateFilterAdaptor(reconciler, method));
155+
adoptedMethods.add(method);
156+
}
157+
allAnnotatedMethods.add(method);
158+
}
159+
}
160+
allAnnotatedMethods.removeAll(adoptedMethods);
161+
if (allAnnotatedMethods.size() > 0) {
162+
log.warn(
163+
"Dangling watch UPDATE event filters {}", StringUtils.join(allAnnotatedMethods, ","));
164+
}
165+
return filters;
166+
}
167+
168+
private Map<Class, DeleteFilterAdaptor> getDeleteFilters(
169+
KubernetesReconcilerWatches watches, Reconciler reconciler) {
170+
Map<Class, DeleteFilterAdaptor> filters = new HashMap<>();
171+
Set<Method> allAnnotatedMethods = new HashSet<>();
172+
Set<Method> adoptedMethods = new HashSet<>();
173+
for (KubernetesReconcilerWatch watch : watches.value()) {
174+
for (Method method : reconciler.getClass().getMethods()) {
175+
DeleteWatchEventFilter annotation = method.getAnnotation(DeleteWatchEventFilter.class);
176+
if (watch.apiTypeClass().equals(annotation.apiTypeClass())) {
177+
if (filters.containsKey(watch.apiTypeClass())) {
178+
log.warn(
179+
"Duplicated watch DELETE event filter upon apiType {}", annotation.apiTypeClass());
180+
}
181+
filters.put(watch.apiTypeClass(), new DeleteFilterAdaptor(reconciler, method));
182+
adoptedMethods.add(method);
183+
}
184+
allAnnotatedMethods.add(method);
185+
}
186+
}
187+
allAnnotatedMethods.removeAll(adoptedMethods);
188+
if (allAnnotatedMethods.size() > 0) {
189+
log.warn(
190+
"Dangling watch DELETE event filters {}", StringUtils.join(allAnnotatedMethods, ","));
191+
}
192+
return filters;
193+
}
194+
195+
private List<ReadyFuncAdaptor> getReadyFuncs(Reconciler reconciler) {
196+
List<ReadyFuncAdaptor> readyFuncs = new ArrayList<>();
197+
for (Method method : reconciler.getClass().getMethods()) {
198+
if (method.isAnnotationPresent(KubernetesReconcilerReadyFunc.class)) {
199+
readyFuncs.add(new ReadyFuncAdaptor(reconciler, method));
200+
}
201+
}
202+
return readyFuncs;
203+
}
204+
132205
private static class AddFilterAdaptor implements Predicate {
133206
private Method method;
134207
private Object target;

spring/src/main/java/io/kubernetes/client/spring/extended/controller/annotation/AddWatchEventFilter.java

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,4 +13,6 @@
1313
*/
1414
@Target({ElementType.METHOD})
1515
@Retention(RetentionPolicy.RUNTIME)
16-
public @interface AddWatchEventFilter {}
16+
public @interface AddWatchEventFilter {
17+
Class apiTypeClass();
18+
}

spring/src/main/java/io/kubernetes/client/spring/extended/controller/annotation/DeleteWatchEventFilter.java

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,4 +15,6 @@
1515
*/
1616
@Target({ElementType.METHOD})
1717
@Retention(RetentionPolicy.RUNTIME)
18-
public @interface DeleteWatchEventFilter {}
18+
public @interface DeleteWatchEventFilter {
19+
Class apiTypeClass();
20+
}

spring/src/main/java/io/kubernetes/client/spring/extended/controller/annotation/KubernetesReconciler.java

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
package io.kubernetes.client.spring.extended.controller.annotation;
22

3+
import io.kubernetes.client.extended.controller.builder.Constants;
34
import java.lang.annotation.ElementType;
45
import java.lang.annotation.Retention;
56
import java.lang.annotation.RetentionPolicy;
@@ -31,4 +32,11 @@
3132
* @return the kubernetes reconciler watches
3233
*/
3334
KubernetesReconcilerWatches watches();
35+
36+
/**
37+
* The number of workers.
38+
*
39+
* @return the int
40+
*/
41+
int workerCount() default Constants.DEFAULT_WORKER_COUNT;
3442
}

spring/src/main/java/io/kubernetes/client/spring/extended/controller/annotation/KubernetesReconcilerWorkerCount.java

Lines changed: 0 additions & 19 deletions
This file was deleted.

spring/src/main/java/io/kubernetes/client/spring/extended/controller/annotation/UpdateWatchEventFilter.java

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,4 +16,6 @@
1616
*/
1717
@Target({ElementType.METHOD})
1818
@Retention(RetentionPolicy.RUNTIME)
19-
public @interface UpdateWatchEventFilter {}
19+
public @interface UpdateWatchEventFilter {
20+
Class apiTypeClass();
21+
}

spring/src/test/java/io/kubernetes/client/spring/extended/controller/KubernetesReconcilerCreatorTest.java

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,6 @@ public TestReconciler podReconciler() {
4949
resyncPeriodMillis = 60 * 1000L // resync every 60s
5050
)
5151
}))
52-
@KubernetesReconcilerWorkerCount(4)
5352
static class TestReconciler implements Reconciler {
5453

5554
private int observedPodCount;
@@ -64,17 +63,17 @@ public Result reconcile(Request request) {
6463
return new Result(false);
6564
}
6665

67-
@AddWatchEventFilter
66+
@AddWatchEventFilter(apiTypeClass = V1Pod.class)
6867
private boolean onAddFilter(V1Pod pod) {
6968
return true;
7069
}
7170

72-
@UpdateWatchEventFilter
71+
@UpdateWatchEventFilter(apiTypeClass = V1Pod.class)
7372
private boolean onUpdateFilter(V1Pod oldPod, V1Pod newPod) {
7473
return true;
7574
}
7675

77-
@DeleteWatchEventFilter
76+
@DeleteWatchEventFilter(apiTypeClass = V1Pod.class)
7877
private boolean onDeleteFilter(V1Pod pod) {
7978
return true;
8079
}

0 commit comments

Comments
 (0)