Skip to content

Commit 985f1ba

Browse files
authored
Merge pull request #83 from ContainerSolutions/spring-boot-support
Spring boot auto configuration support
2 parents bb3eea0 + ebd75dd commit 985f1ba

File tree

19 files changed

+481
-42
lines changed

19 files changed

+481
-42
lines changed

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ The Controller only contains the logic to create, update and delete the actual r
1212

1313
Feature we would like to implement and invite the community to help us implement in the future:
1414

15-
* ~~Spring Boot sample~~
15+
* ~~Spring Boot support~~
1616
* Class generation from CRD to POJO
1717
* GraalVM / Quarkus support
1818

pom.xml

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,9 +36,11 @@
3636

3737
<modules>
3838
<module>operator-framework</module>
39+
<module>spring-boot-starter</module>
3940
<module>samples</module>
4041
</modules>
4142

43+
4244
<dependencyManagement>
4345
<dependencies>
4446
<dependency>
@@ -73,6 +75,12 @@
7375
<version>3.0.0</version>
7476
<scope>test</scope>
7577
</dependency>
78+
<dependency>
79+
<groupId>org.springframework</groupId>
80+
<artifactId>spring-core</artifactId>
81+
<version>5.2.5.RELEASE</version>
82+
<scope>compile</scope>
83+
</dependency>
7684
</dependencies>
7785
</dependencyManagement>
7886

samples/basic/spring-boot/pom.xml

Lines changed: 3 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -25,16 +25,11 @@
2525
<groupId>com.github.containersolutions</groupId>
2626
<artifactId>operator-framework-samples-common</artifactId>
2727
<version>${project.version}</version>
28-
<exclusions>
29-
<exclusion>
30-
<groupId>org.apache.logging.log4j</groupId>
31-
<artifactId>log4j-slf4j-impl</artifactId>
32-
</exclusion>
33-
</exclusions>
3428
</dependency>
3529
<dependency>
36-
<groupId>org.springframework.boot</groupId>
37-
<artifactId>spring-boot-starter</artifactId>
30+
<groupId>com.github.containersolutions</groupId>
31+
<artifactId>spring-boot-operator-framework-starter</artifactId>
32+
<version>${project.version}</version>
3833
</dependency>
3934
</dependencies>
4035

samples/basic/spring-boot/src/main/java/com/github/containersolutions/operator/sample/Config.java

Lines changed: 0 additions & 33 deletions
This file was deleted.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
package com.github.containersolutions.operator.sample;
2+
3+
import com.github.containersolutions.operator.Operator;
4+
import io.fabric8.kubernetes.client.KubernetesClient;
5+
import org.springframework.stereotype.Component;
6+
7+
/**
8+
* This component just showcases what beans are registered.
9+
*/
10+
@Component
11+
public class SampleComponent {
12+
13+
private final Operator operator;
14+
15+
private final KubernetesClient kubernetesClient;
16+
17+
private final CustomServiceController customServiceController;
18+
19+
public SampleComponent(Operator operator, KubernetesClient kubernetesClient,
20+
CustomServiceController customServiceController) {
21+
this.operator = operator;
22+
this.kubernetesClient = kubernetesClient;
23+
this.customServiceController = customServiceController;
24+
}
25+
}

samples/basic/spring-boot/src/main/java/com/github/containersolutions/operator/sample/SpringBootStarterSampleApplication.java

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,16 @@
11
package com.github.containersolutions.operator.sample;
22

3+
import com.github.containersolutions.operator.api.Controller;
34
import org.springframework.boot.SpringApplication;
45
import org.springframework.boot.autoconfigure.SpringBootApplication;
6+
import org.springframework.context.annotation.ComponentScan;
7+
import org.springframework.context.annotation.FilterType;
58

9+
/**
10+
* Note that we have multiple options here either we can add this component scan as seen below. Or annotate controllers
11+
* with @Component or @Service annotation or just register the bean within a spring "@Configuration".
12+
*/
13+
@ComponentScan(includeFilters = {@ComponentScan.Filter(type = FilterType.ANNOTATION, value = Controller.class)})
614
@SpringBootApplication
715
public class SpringBootStarterSampleApplication {
816

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
operator.controller.retry:
2+
maxAttempts: 3

spring-boot-starter/pom.xml

Lines changed: 96 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,96 @@
1+
<?xml version="1.0" encoding="UTF-8"?>
2+
<project xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://maven.apache.org/POM/4.0.0"
3+
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
4+
<modelVersion>4.0.0</modelVersion>
5+
6+
<parent>
7+
<groupId>com.github.containersolutions</groupId>
8+
<artifactId>java-operator-sdk</artifactId>
9+
<version>1.0.1-SNAPSHOT</version>
10+
</parent>
11+
12+
<artifactId>spring-boot-operator-framework-starter</artifactId>
13+
<name>Operator SDK - Spring Boot Starter</name>
14+
<description>Spring Boot starter for framework</description>
15+
<packaging>jar</packaging>
16+
17+
<properties>
18+
<junit-jupiter.version>5.3.2</junit-jupiter.version>
19+
<java.version>8</java.version>
20+
<maven.compiler.source>1.8</maven.compiler.source>
21+
<maven.compiler.target>1.8</maven.compiler.target>
22+
</properties>
23+
24+
<build>
25+
<plugins>
26+
<plugin>
27+
<groupId>org.apache.maven.plugins</groupId>
28+
<artifactId>maven-surefire-plugin</artifactId>
29+
<version>2.22.2</version>
30+
</plugin>
31+
<plugin>
32+
<groupId>org.springframework.boot</groupId>
33+
<artifactId>spring-boot-maven-plugin</artifactId>
34+
</plugin>
35+
</plugins>
36+
</build>
37+
38+
<dependencyManagement>
39+
<dependencies>
40+
<dependency>
41+
<groupId>org.springframework.boot</groupId>
42+
<artifactId>spring-boot-dependencies</artifactId>
43+
<version>2.2.6.RELEASE</version>
44+
<type>pom</type>
45+
<scope>import</scope>
46+
</dependency>
47+
</dependencies>
48+
</dependencyManagement>
49+
<dependencies>
50+
<dependency>
51+
<groupId>org.springframework.boot</groupId>
52+
<artifactId>spring-boot-autoconfigure-processor</artifactId>
53+
<optional>true</optional>
54+
</dependency>
55+
<dependency>
56+
<groupId>org.springframework.boot</groupId>
57+
<artifactId>spring-boot-autoconfigure</artifactId>
58+
</dependency>
59+
<dependency>
60+
<groupId>org.springframework.boot</groupId>
61+
<artifactId>spring-boot-starter-test</artifactId>
62+
<scope>test</scope>
63+
<exclusions>
64+
<exclusion>
65+
<groupId>junit</groupId>
66+
<artifactId>junit</artifactId>
67+
</exclusion>
68+
</exclusions>
69+
</dependency>
70+
<dependency>
71+
<groupId>org.junit.jupiter</groupId>
72+
<artifactId>junit-jupiter-api</artifactId>
73+
<version>${junit-jupiter.version}</version>
74+
<scope>test</scope>
75+
</dependency>
76+
<dependency>
77+
<groupId>org.junit.jupiter</groupId>
78+
<artifactId>junit-jupiter-engine</artifactId>
79+
<version>${junit-jupiter.version}</version>
80+
<scope>test</scope>
81+
</dependency>
82+
<dependency>
83+
<groupId>com.github.containersolutions</groupId>
84+
<artifactId>operator-framework</artifactId>
85+
<version>${project.version}</version>
86+
</dependency>
87+
<dependency>
88+
<groupId>org.slf4j</groupId>
89+
<artifactId>slf4j-api</artifactId>
90+
</dependency>
91+
<dependency>
92+
<groupId>org.mockito</groupId>
93+
<artifactId>mockito-core</artifactId>
94+
</dependency>
95+
</dependencies>
96+
</project>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,83 @@
1+
package com.github.containersolutions.operator.spingboot.starter;
2+
3+
import com.github.containersolutions.operator.Operator;
4+
import com.github.containersolutions.operator.api.ResourceController;
5+
import com.github.containersolutions.operator.processing.retry.GenericRetry;
6+
import com.github.containersolutions.operator.processing.retry.Retry;
7+
import io.fabric8.kubernetes.client.ConfigBuilder;
8+
import io.fabric8.kubernetes.client.DefaultKubernetesClient;
9+
import io.fabric8.kubernetes.client.KubernetesClient;
10+
import io.fabric8.openshift.client.DefaultOpenShiftClient;
11+
import org.apache.commons.lang3.StringUtils;
12+
import org.slf4j.Logger;
13+
import org.slf4j.LoggerFactory;
14+
import org.springframework.beans.factory.annotation.Autowired;
15+
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
16+
import org.springframework.boot.context.properties.EnableConfigurationProperties;
17+
import org.springframework.context.annotation.Bean;
18+
import org.springframework.context.annotation.Configuration;
19+
20+
import java.util.List;
21+
22+
@Configuration
23+
@EnableConfigurationProperties({OperatorProperties.class, RetryProperties.class})
24+
@ConditionalOnMissingBean(Operator.class)
25+
public class OperatorAutoConfiguration {
26+
private static final Logger log = LoggerFactory.getLogger(OperatorAutoConfiguration.class);
27+
28+
@Autowired
29+
private RetryProperties retryProperties;
30+
31+
@Autowired
32+
private OperatorProperties operatorProperties;
33+
34+
@Autowired
35+
private List<ResourceController> resourceControllers;
36+
37+
@Bean
38+
@ConditionalOnMissingBean
39+
public KubernetesClient kubernetesClient() {
40+
ConfigBuilder config = new ConfigBuilder();
41+
config.withTrustCerts(operatorProperties.isTrustSelfSignedCertificates());
42+
if (StringUtils.isNotBlank(operatorProperties.getUsername())) {
43+
config.withUsername(operatorProperties.getUsername());
44+
}
45+
if (StringUtils.isNotBlank(operatorProperties.getPassword())) {
46+
config.withUsername(operatorProperties.getPassword());
47+
}
48+
if (StringUtils.isNotBlank(operatorProperties.getMasterUrl())) {
49+
config.withMasterUrl(operatorProperties.getMasterUrl());
50+
}
51+
KubernetesClient k8sClient = operatorProperties.isOpenshift() ? new DefaultOpenShiftClient(config.build()) : new DefaultKubernetesClient(config.build());
52+
return k8sClient;
53+
}
54+
55+
@Bean
56+
public Operator operator(KubernetesClient kubernetesClient, Retry retry) {
57+
Operator operator = new Operator(kubernetesClient);
58+
resourceControllers.forEach(r -> operator.registerControllerForAllNamespaces(r, retry));
59+
return operator;
60+
}
61+
62+
@Bean
63+
@ConditionalOnMissingBean
64+
public Retry retry() {
65+
GenericRetry retry = new GenericRetry();
66+
if (retryProperties.getInitialInterval() != null) {
67+
retry.setInitialInterval(retryProperties.getInitialInterval());
68+
}
69+
if (retryProperties.getIntervalMultiplier() != null) {
70+
retry.setIntervalMultiplier(retryProperties.getIntervalMultiplier());
71+
}
72+
if (retryProperties.getMaxAttempts() != null) {
73+
retry.setMaxAttempts(retryProperties.getMaxAttempts());
74+
}
75+
if (retryProperties.getMaxElapsedTime() != null) {
76+
retry.setMaxElapsedTime(retryProperties.getMaxElapsedTime());
77+
}
78+
if (retryProperties.getMaxInterval() != null) {
79+
retry.setInitialInterval(retryProperties.getMaxInterval());
80+
}
81+
return retry;
82+
}
83+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
package com.github.containersolutions.operator.spingboot.starter;
2+
3+
import org.springframework.boot.context.properties.ConfigurationProperties;
4+
5+
@ConfigurationProperties(prefix = "operator.kubernetes.client")
6+
public class OperatorProperties {
7+
8+
private boolean openshift = false;
9+
private String username;
10+
private String password;
11+
private String masterUrl;
12+
private boolean trustSelfSignedCertificates = false;
13+
14+
public boolean isOpenshift() {
15+
return openshift;
16+
}
17+
18+
public OperatorProperties setOpenshift(boolean openshift) {
19+
this.openshift = openshift;
20+
return this;
21+
}
22+
23+
public String getUsername() {
24+
return username;
25+
}
26+
27+
public OperatorProperties setUsername(String username) {
28+
this.username = username;
29+
return this;
30+
}
31+
32+
public String getPassword() {
33+
return password;
34+
}
35+
36+
public OperatorProperties setPassword(String password) {
37+
this.password = password;
38+
return this;
39+
}
40+
41+
public String getMasterUrl() {
42+
return masterUrl;
43+
}
44+
45+
public OperatorProperties setMasterUrl(String masterUrl) {
46+
this.masterUrl = masterUrl;
47+
return this;
48+
}
49+
50+
public boolean isTrustSelfSignedCertificates() {
51+
return trustSelfSignedCertificates;
52+
}
53+
54+
public OperatorProperties setTrustSelfSignedCertificates(boolean trustSelfSignedCertificates) {
55+
this.trustSelfSignedCertificates = trustSelfSignedCertificates;
56+
return this;
57+
}
58+
}

0 commit comments

Comments
 (0)