Skip to content

Commit 595f3e1

Browse files
committed
feature: support namespace-scoped informer
1 parent 3cf16a9 commit 595f3e1

File tree

13 files changed

+214
-92
lines changed

13 files changed

+214
-92
lines changed

pom.xml

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -306,6 +306,12 @@
306306
<version>4.0.3</version>
307307
<scope>test</scope>
308308
</dependency>
309+
<dependency>
310+
<groupId>org.assertj</groupId>
311+
<artifactId>assertj-core</artifactId>
312+
<version>3.18.1</version>
313+
<scope>test</scope>
314+
</dependency>
309315

310316
</dependencies>
311317
</dependencyManagement>

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

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -24,14 +24,14 @@
2424
import org.slf4j.Logger;
2525
import org.slf4j.LoggerFactory;
2626
import org.springframework.beans.BeansException;
27+
import org.springframework.beans.factory.annotation.Autowired;
2728
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
2829
import org.springframework.beans.factory.support.AbstractBeanDefinition;
2930
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
3031
import org.springframework.beans.factory.support.BeanDefinitionRegistryPostProcessor;
3132
import org.springframework.beans.factory.support.RootBeanDefinition;
3233
import org.springframework.core.Ordered;
3334
import org.springframework.core.ResolvableType;
34-
import org.springframework.stereotype.Component;
3535

3636
/**
3737
* The type Kubernetes informer factory processor which basically does the following things:
@@ -41,7 +41,6 @@
4141
* io.kubernetes.client.spring.extended.controller.annotation.KubernetesInformers}, instantiates and
4242
* injects informers to spring context with the underlying constructing process hidden from users.
4343
*/
44-
@Component
4544
public class KubernetesInformerFactoryProcessor
4645
implements BeanDefinitionRegistryPostProcessor, Ordered {
4746

@@ -55,6 +54,7 @@ public class KubernetesInformerFactoryProcessor
5554
private final ApiClient apiClient;
5655
private final SharedInformerFactory sharedInformerFactory;
5756

57+
@Autowired
5858
public KubernetesInformerFactoryProcessor(
5959
ApiClient apiClient, SharedInformerFactory sharedInformerFactory) {
6060
this.apiClient = apiClient;
@@ -85,7 +85,10 @@ public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory)
8585
apiClient);
8686
SharedIndexInformer sharedIndexInformer =
8787
sharedInformerFactory.sharedIndexInformerFor(
88-
api, kubernetesInformer.apiTypeClass(), kubernetesInformer.resyncPeriodMillis());
88+
api,
89+
kubernetesInformer.apiTypeClass(),
90+
kubernetesInformer.resyncPeriodMillis(),
91+
kubernetesInformer.namespace());
8992
ResolvableType informerType =
9093
ResolvableType.forClassWithGenerics(
9194
SharedInformer.class, kubernetesInformer.apiTypeClass());

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

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,6 @@
2626
import org.springframework.beans.factory.config.BeanFactoryPostProcessor;
2727
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
2828
import org.springframework.core.Ordered;
29-
import org.springframework.stereotype.Component;
3029

3130
/**
3231
* Scans and processes {@link
@@ -35,7 +34,6 @@
3534
* <p>It will create a {@link io.kubernetes.client.extended.controller.Controller} for every
3635
* reconciler instances registered in the spring bean-factory.
3736
*/
38-
@Component
3937
public class KubernetesReconcilerProcessor implements BeanFactoryPostProcessor, Ordered {
4038

4139
private static final Logger log = LoggerFactory.getLogger(KubernetesReconcilerProcessor.class);

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

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
import io.kubernetes.client.common.KubernetesObject;
1717
import io.kubernetes.client.openapi.models.V1Namespace;
1818
import io.kubernetes.client.openapi.models.V1NamespaceList;
19+
import io.kubernetes.client.util.Namespaces;
1920
import java.lang.annotation.ElementType;
2021
import java.lang.annotation.Retention;
2122
import java.lang.annotation.RetentionPolicy;
@@ -58,4 +59,11 @@
5859
* @return the long
5960
*/
6061
long resyncPeriodMillis() default 0;
62+
63+
/**
64+
* Target namespace to list-watch, by default it will be cluster-scoped.
65+
*
66+
* @return the string
67+
*/
68+
String namespace() default Namespaces.NAMESPACE_ALL;
6169
}

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

Lines changed: 11 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -43,21 +43,21 @@
4343
import org.junit.Test;
4444
import org.junit.runner.RunWith;
4545
import org.springframework.beans.factory.annotation.Autowired;
46+
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
47+
import org.springframework.boot.autoconfigure.SpringBootApplication;
4648
import org.springframework.boot.test.context.SpringBootTest;
47-
import org.springframework.boot.test.context.TestConfiguration;
4849
import org.springframework.context.annotation.Bean;
49-
import org.springframework.context.annotation.Import;
5050
import org.springframework.test.context.junit4.SpringRunner;
5151

5252
@RunWith(SpringRunner.class)
53-
@SpringBootTest
54-
@Import(KubernetesInformerCreatorTest.TestConfig.class)
53+
@SpringBootTest(classes = {KubernetesInformerCreatorTest.App.class})
5554
public class KubernetesInformerCreatorTest {
5655

5756
@Rule public WireMockRule wireMockRule = new WireMockRule(8188);
5857

59-
@TestConfiguration
60-
static class TestConfig {
58+
@SpringBootApplication
59+
@EnableAutoConfiguration
60+
static class App {
6161

6262
@Bean
6363
public ApiClient testingApiClient() {
@@ -70,12 +70,6 @@ public SharedInformerFactory sharedInformerFactory() {
7070
return new TestSharedInformerFactory();
7171
}
7272

73-
@Bean
74-
public KubernetesInformerConfigurer kubernetesInformerConfigurer(
75-
ApiClient apiClient, SharedInformerFactory sharedInformerFactory) {
76-
return new KubernetesInformerConfigurer(apiClient, sharedInformerFactory);
77-
}
78-
7973
@KubernetesInformers({
8074
@KubernetesInformer(
8175
apiTypeClass = V1Pod.class,
@@ -85,6 +79,7 @@ public KubernetesInformerConfigurer kubernetesInformerConfigurer(
8579
@KubernetesInformer(
8680
apiTypeClass = V1ConfigMap.class,
8781
apiListTypeClass = V1ConfigMapList.class,
82+
namespace = "default",
8883
groupVersionResource =
8984
@GroupVersionResource(
9085
apiGroup = "",
@@ -138,7 +133,7 @@ public void testInformerInjection() throws InterruptedException {
138133
.willReturn(aResponse().withStatus(200).withBody("{}")));
139134

140135
wireMockRule.stubFor(
141-
get(urlMatching("^/api/v1/configmaps.*"))
136+
get(urlMatching("^/api/v1/namespaces/default/configmaps.*"))
142137
.withQueryParam("watch", equalTo("false"))
143138
.willReturn(
144139
aResponse()
@@ -150,7 +145,7 @@ public void testInformerInjection() throws InterruptedException {
150145
.metadata(new V1ListMeta().resourceVersion("0"))
151146
.items(Arrays.asList(bar1))))));
152147
wireMockRule.stubFor(
153-
get(urlMatching("^/api/v1/configmaps.*"))
148+
get(urlMatching("^/api/v1/namespaces/default/configmaps.*"))
154149
.withQueryParam("watch", equalTo("true"))
155150
.willReturn(aResponse().withStatus(200).withBody("{}")));
156151

@@ -165,10 +160,10 @@ public void testInformerInjection() throws InterruptedException {
165160
getRequestedFor(urlPathEqualTo("/api/v1/pods")).withQueryParam("watch", equalTo("true")));
166161
verify(
167162
1,
168-
getRequestedFor(urlPathEqualTo("/api/v1/configmaps"))
163+
getRequestedFor(urlPathEqualTo("/api/v1/namespaces/default/configmaps"))
169164
.withQueryParam("watch", equalTo("false")));
170165
verify(
171-
getRequestedFor(urlPathEqualTo("/api/v1/configmaps"))
166+
getRequestedFor(urlPathEqualTo("/api/v1/namespaces/default/configmaps"))
172167
.withQueryParam("watch", equalTo("true")));
173168

174169
assertEquals(1, podLister.list().size());

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

Lines changed: 45 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -12,10 +12,6 @@
1212
*/
1313
package io.kubernetes.client.spring.extended.controller;
1414

15-
import static org.junit.Assert.assertEquals;
16-
import static org.junit.Assert.assertNotNull;
17-
import static org.junit.Assert.fail;
18-
1915
import com.github.tomakehurst.wiremock.junit.WireMockRule;
2016
import io.kubernetes.client.common.KubernetesObject;
2117
import io.kubernetes.client.extended.controller.Controller;
@@ -29,41 +25,77 @@
2925
import io.kubernetes.client.informer.cache.DeltaFIFO;
3026
import io.kubernetes.client.informer.cache.Lister;
3127
import io.kubernetes.client.informer.impl.DefaultSharedIndexInformer;
28+
import io.kubernetes.client.openapi.ApiClient;
3229
import io.kubernetes.client.openapi.models.V1ConfigMap;
30+
import io.kubernetes.client.openapi.models.V1ConfigMapList;
3331
import io.kubernetes.client.openapi.models.V1ObjectMeta;
3432
import io.kubernetes.client.openapi.models.V1Pod;
3533
import io.kubernetes.client.openapi.models.V1PodList;
3634
import io.kubernetes.client.spring.extended.controller.annotation.AddWatchEventFilter;
3735
import io.kubernetes.client.spring.extended.controller.annotation.DeleteWatchEventFilter;
36+
import io.kubernetes.client.spring.extended.controller.annotation.GroupVersionResource;
37+
import io.kubernetes.client.spring.extended.controller.annotation.KubernetesInformer;
38+
import io.kubernetes.client.spring.extended.controller.annotation.KubernetesInformers;
3839
import io.kubernetes.client.spring.extended.controller.annotation.KubernetesReconciler;
3940
import io.kubernetes.client.spring.extended.controller.annotation.KubernetesReconcilerReadyFunc;
4041
import io.kubernetes.client.spring.extended.controller.annotation.KubernetesReconcilerWatch;
4142
import io.kubernetes.client.spring.extended.controller.annotation.KubernetesReconcilerWatches;
4243
import io.kubernetes.client.spring.extended.controller.annotation.UpdateWatchEventFilter;
4344
import io.kubernetes.client.spring.extended.controller.factory.KubernetesControllerFactory;
44-
import java.util.LinkedList;
45-
import java.util.function.Function;
46-
import javax.annotation.Resource;
45+
import io.kubernetes.client.util.ClientBuilder;
4746
import org.apache.commons.lang3.tuple.MutablePair;
4847
import org.junit.Rule;
4948
import org.junit.Test;
5049
import org.junit.runner.RunWith;
5150
import org.springframework.beans.factory.annotation.Autowired;
51+
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
52+
import org.springframework.boot.autoconfigure.SpringBootApplication;
5253
import org.springframework.boot.test.context.SpringBootTest;
53-
import org.springframework.boot.test.context.TestConfiguration;
5454
import org.springframework.context.annotation.Bean;
55-
import org.springframework.context.annotation.Import;
5655
import org.springframework.test.context.junit4.SpringRunner;
5756

57+
import javax.annotation.Resource;
58+
import java.util.LinkedList;
59+
import java.util.function.Function;
60+
61+
import static org.junit.Assert.*;
62+
5863
@RunWith(SpringRunner.class)
59-
@SpringBootTest
60-
@Import(KubernetesInformerCreatorTest.TestConfig.class)
64+
@SpringBootTest(classes = {KubernetesReconcilerCreatorTest.App.class})
6165
public class KubernetesReconcilerCreatorTest {
6266

6367
@Rule public WireMockRule wireMockRule = new WireMockRule(8189);
6468

65-
@TestConfiguration
66-
static class TestConfig {
69+
@SpringBootApplication
70+
@EnableAutoConfiguration
71+
static class App {
72+
@Bean
73+
public ApiClient testingApiClient() {
74+
ApiClient apiClient = new ClientBuilder().setBasePath("http://localhost:" + 8188).build();
75+
return apiClient;
76+
}
77+
78+
@Bean
79+
public SharedInformerFactory sharedInformerFactory() {
80+
return new KubernetesInformerCreatorTest.App.TestSharedInformerFactory();
81+
}
82+
83+
@KubernetesInformers({
84+
@KubernetesInformer(
85+
apiTypeClass = V1Pod.class,
86+
apiListTypeClass = V1PodList.class,
87+
groupVersionResource =
88+
@GroupVersionResource(apiGroup = "", apiVersion = "v1", resourcePlural = "pods")),
89+
@KubernetesInformer(
90+
apiTypeClass = V1ConfigMap.class,
91+
apiListTypeClass = V1ConfigMapList.class,
92+
groupVersionResource =
93+
@GroupVersionResource(
94+
apiGroup = "",
95+
apiVersion = "v1",
96+
resourcePlural = "configmaps")),
97+
})
98+
static class TestSharedInformerFactory extends SharedInformerFactory {}
6799

68100
@Bean
69101
public TestReconciler testReconciler() {

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

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

util/pom.xml

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -110,6 +110,11 @@
110110
<artifactId>awaitility</artifactId>
111111
<scope>test</scope>
112112
</dependency>
113+
<dependency>
114+
<groupId>org.assertj</groupId>
115+
<artifactId>assertj-core</artifactId>
116+
<scope>test</scope>
117+
</dependency>
113118

114119
</dependencies>
115120
<build>

0 commit comments

Comments
 (0)