Skip to content

Commit 2ab6665

Browse files
committed
spring controller example
1 parent 0ec02e4 commit 2ab6665

File tree

5 files changed

+152
-0
lines changed

5 files changed

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

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)