Skip to content

Commit 0b1f7a8

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

File tree

5 files changed

+154
-0
lines changed

5 files changed

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

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)