Skip to content

Commit 1d9a5b4

Browse files
committed
spring controller example
1 parent 0ec02e4 commit 1d9a5b4

File tree

5 files changed

+153
-0
lines changed

5 files changed

+153
-0
lines changed

README.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -102,6 +102,8 @@ We prepared a few examples for common use-cases which are shown below:
102102
Build a controller reconciling the state of world by list-watching one or multiple resources.
103103
- ([6.0.0+](https://github.com/kubernetes-client/java/tree/client-java-parent-6.0.0)) [LeaderElectionExample](https://github.com/kubernetes-client/java/blob/master/examples/src/main/java/io/kubernetes/client/examples/LeaderElectionExample.java):
104104
Leader election utilities to help implement HA controllers.
105+
- ([9.0.0+](https://github.com/kubernetes-client/java/tree/client-java-parent-9.0.0)) [SpringIntegrationControllerExample](https://github.com/kubernetes-client/java/blob/master/examples/src/main/java/io/kubernetes/client/examples/SpringControllerExample.java):
106+
Building a kubernetes controller based on spring framework's bean injection.
105107

106108

107109
__list all pods__:

examples/pom.xml

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,11 @@
2626
<artifactId>client-java-extended</artifactId>
2727
<version>${project.version}</version>
2828
</dependency>
29+
<dependency>
30+
<groupId>io.kubernetes</groupId>
31+
<artifactId>client-java-spring-integration</artifactId>
32+
<version>${project.version}</version>
33+
</dependency>
2934
<dependency>
3035
<groupId>io.kubernetes</groupId>
3136
<artifactId>client-java-proto</artifactId>
Lines changed: 138 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,138 @@
1+
package io.kubernetes.client.examples;
2+
3+
import io.kubernetes.client.extended.controller.Controller;
4+
import io.kubernetes.client.extended.controller.reconciler.Reconciler;
5+
import io.kubernetes.client.extended.controller.reconciler.Request;
6+
import io.kubernetes.client.extended.controller.reconciler.Result;
7+
import io.kubernetes.client.informer.SharedInformer;
8+
import io.kubernetes.client.informer.SharedInformerFactory;
9+
import io.kubernetes.client.informer.cache.Lister;
10+
import io.kubernetes.client.openapi.ApiClient;
11+
import io.kubernetes.client.openapi.models.V1Node;
12+
import io.kubernetes.client.openapi.models.V1NodeList;
13+
import io.kubernetes.client.openapi.models.V1Pod;
14+
import io.kubernetes.client.openapi.models.V1PodList;
15+
import io.kubernetes.client.spring.extended.controller.annotation.*;
16+
import io.kubernetes.client.util.ClientBuilder;
17+
import java.io.IOException;
18+
import java.time.Duration;
19+
import org.springframework.beans.factory.annotation.Qualifier;
20+
import org.springframework.boot.CommandLineRunner;
21+
import org.springframework.boot.SpringApplication;
22+
import org.springframework.boot.autoconfigure.SpringBootApplication;
23+
import org.springframework.context.ApplicationContext;
24+
import org.springframework.context.annotation.Bean;
25+
import org.springframework.context.annotation.ComponentScan;
26+
import org.springframework.context.annotation.Configuration;
27+
28+
@SpringBootApplication
29+
public class SpringControllerExample {
30+
31+
public static void main(String[] args) {
32+
SpringApplication.run(SpringControllerExample.class, args);
33+
}
34+
35+
@Configuration
36+
@ComponentScan(
37+
basePackages = "io.kubernetes.client.spring.extended.controller"
38+
) // Scanning beans under this package is *REQUIRED* for informers/reconciler injections.
39+
public static class AppConfig {
40+
41+
@Bean
42+
public CommandLineRunner commandLineRunner(
43+
SharedInformerFactory sharedInformerFactory,
44+
@Qualifier("node-printing-controller") Controller nodePrintingController) {
45+
return args -> {
46+
System.out.println("starting informers..");
47+
sharedInformerFactory.startAllRegisteredInformers();
48+
49+
System.out.println("running controller..");
50+
nodePrintingController.run();
51+
};
52+
}
53+
54+
// *OPTIONAL*
55+
// Injecting and customize your ApiClient, if not specified, fallbacks to {@link
56+
// io.kubernetes.client.util.ClientBuilder#standard}
57+
@Bean
58+
public ApiClient myApiClient() throws IOException {
59+
ApiClient apiClient = ClientBuilder.standard().build();
60+
return apiClient.setHttpClient(
61+
apiClient.getHttpClient().newBuilder().readTimeout(Duration.ZERO).build());
62+
}
63+
64+
// *REQUIRED*
65+
// Injecting your SharedInformerFactory class annotated `@KubernetesInformers`
66+
@Bean("sharedInformerFactory")
67+
public SharedInformerFactory sharedInformerFactory() {
68+
return new MySharedInformerFactory();
69+
}
70+
71+
@Bean
72+
public NodePrintingReconciler nodePrintingReconciler(
73+
Lister<V1Pod> podLister, Lister<V1Node> nodeLister, SharedInformer<V1Node> nodeInformer) {
74+
return new NodePrintingReconciler(podLister, nodeLister, nodeInformer);
75+
}
76+
}
77+
78+
@KubernetesInformers({ // Defining what resources is the informer-factory actually watching.
79+
@KubernetesInformer(
80+
apiTypeClass = V1Node.class,
81+
apiListTypeClass = V1NodeList.class,
82+
groupVersionResource =
83+
@GroupVersionResource(apiGroup = "", apiVersion = "v1", resourcePlural = "nodes"),
84+
resyncPeriodMillis = 60 * 1000L
85+
),
86+
@KubernetesInformer(
87+
apiTypeClass = V1Pod.class,
88+
apiListTypeClass = V1PodList.class,
89+
groupVersionResource =
90+
@GroupVersionResource(apiGroup = "", apiVersion = "v1", resourcePlural = "pods")
91+
),
92+
})
93+
public static class MySharedInformerFactory extends SharedInformerFactory {}
94+
95+
// As long as a reconciler bean attached `@KubernetesReconciler` detected in the context, we will
96+
// be automatically creating a conresponding controller bean implementing {@link
97+
// io.kubernetes.client.extended.controller.Controller}
98+
// with the name specified and registering it to the spring bean-factory.
99+
@KubernetesReconciler(
100+
value = "node-printing-controller",
101+
watches =
102+
@KubernetesReconcilerWatches({
103+
@KubernetesReconcilerWatch(
104+
apiTypeClass = V1Node.class,
105+
resyncPeriodMillis = 60 * 1000L // fully resync every 1 minute
106+
),
107+
})
108+
)
109+
public static class NodePrintingReconciler implements Reconciler {
110+
111+
public NodePrintingReconciler(
112+
Lister<V1Pod> podLister, Lister<V1Node> nodeLister, SharedInformer<V1Node> nodeInformer) {
113+
this.nodeLister = nodeLister;
114+
this.podLister = podLister;
115+
this.nodeInformer = nodeInformer;
116+
}
117+
118+
private SharedInformer<V1Node> nodeInformer;
119+
120+
private Lister<V1Node> nodeLister;
121+
122+
private Lister<V1Pod> podLister;
123+
124+
// *OPTIONAL*
125+
// If you feed like hold the controller from running util some condition..
126+
@KubernetesReconcilerReadyFunc
127+
boolean informerReady() {
128+
return nodeInformer.hasSynced();
129+
}
130+
131+
@Override
132+
public Result reconcile(Request request) {
133+
V1Node node = nodeLister.get(request.getName());
134+
System.out.println("triggered reconciling " + node.getMetadata().getName());
135+
return new Result(false);
136+
}
137+
}
138+
}

spring/pom.xml

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,11 @@
2929
<artifactId>spring-boot</artifactId>
3030
<version>${spring.boot.version}</version>
3131
</dependency>
32+
<dependency>
33+
<groupId>org.springframework.boot</groupId>
34+
<artifactId>spring-boot-autoconfigure</artifactId>
35+
<version>${spring.boot.version}</version>
36+
</dependency>
3237

3338
<dependency>
3439
<groupId>junit</groupId>

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

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
import io.kubernetes.client.util.ClientBuilder;
1717
import io.kubernetes.client.util.Watchable;
1818
import java.io.IOException;
19+
import java.time.Duration;
1920
import java.util.Map;
2021
import java.util.Optional;
2122
import org.slf4j.Logger;
@@ -85,6 +86,8 @@ public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory)
8586
return;
8687
}
8788
}
89+
apiClient.setHttpClient(
90+
apiClient.getHttpClient().newBuilder().readTimeout(Duration.ZERO).build());
8891

8992
SharedInformerFactory sharedInformerFactory = beanFactory.getBean(SharedInformerFactory.class);
9093
KubernetesInformers kubernetesInformers =

0 commit comments

Comments
 (0)