Skip to content

Commit 8d90a6b

Browse files
committed
feat: initial rewrite of Spring Boot auto-configuration for new format
Still lots of work needed for it to completely fit operator-framework#237
1 parent af844ba commit 8d90a6b

File tree

10 files changed

+337
-131
lines changed

10 files changed

+337
-131
lines changed
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
package io.javaoperatorsdk.operator.config;
2+
3+
import java.util.Optional;
4+
5+
public interface ClientConfiguration {
6+
ClientConfiguration DEFAULT = new ClientConfiguration() {
7+
};
8+
9+
default boolean isOpenshift() {
10+
return false;
11+
}
12+
13+
default Optional<String> getUsername() {
14+
return Optional.empty();
15+
}
16+
17+
default Optional<String> getPassword() {
18+
return Optional.empty();
19+
}
20+
21+
default Optional<String> getMasterUrl() {
22+
return Optional.empty();
23+
}
24+
25+
default boolean isTrustSelfSignedCertificates() {
26+
return false;
27+
}
28+
}

operator-framework/src/main/java/io/javaoperatorsdk/operator/config/ConfigurationService.java

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,4 +5,8 @@
55

66
public interface ConfigurationService {
77
<R extends CustomResource> ControllerConfiguration<R> getConfigurationFor(ResourceController<R> controller);
8+
9+
default ClientConfiguration getClientConfiguration() {
10+
return ClientConfiguration.DEFAULT;
11+
}
812
}

operator-framework/src/main/java/io/javaoperatorsdk/operator/config/RetryConfiguration.java

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,9 @@
11
package io.javaoperatorsdk.operator.config;
22

33
public interface RetryConfiguration {
4+
RetryConfiguration DEFAULT = new RetryConfiguration() {
5+
};
6+
47
int DEFAULT_MAX_ATTEMPTS = 5;
58
long DEFAULT_INITIAL_INTERVAL = 2000L;
69
long DEFAULT_MAX_ELAPSED_TIME = 30_000L;
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
package io.javaoperatorsdk.operator.springboot.starter;
2+
3+
import java.util.Map;
4+
5+
@org.springframework.boot.context.properties.ConfigurationProperties(prefix = "io.javaoperatorsdk")
6+
public class ConfigurationProperties {
7+
private OperatorProperties client;
8+
private Map<String, ControllerProperties> controllers;
9+
10+
// todo: figure out how to be able to use `.kubernetes.client` as prefix
11+
public OperatorProperties getClient() {
12+
return client;
13+
}
14+
15+
public void setClient(OperatorProperties client) {
16+
this.client = client;
17+
}
18+
19+
public Map<String, ControllerProperties> getControllers() {
20+
return controllers;
21+
}
22+
23+
public void setControllers(Map<String, ControllerProperties> controllers) {
24+
this.controllers = controllers;
25+
}
26+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
package io.javaoperatorsdk.operator.springboot.starter;
2+
3+
import java.util.Set;
4+
5+
public class ControllerProperties {
6+
private String name;
7+
private String crdName;
8+
private String finalizer;
9+
private boolean generationAware;
10+
private boolean clusterScoped;
11+
private Set<String> namespaces;
12+
private RetryProperties retry;
13+
14+
15+
public String getName() {
16+
return name;
17+
}
18+
19+
public String getCRDName() {
20+
return crdName;
21+
}
22+
23+
public String getFinalizer() {
24+
return finalizer;
25+
}
26+
27+
public boolean isGenerationAware() {
28+
return generationAware;
29+
}
30+
31+
32+
public boolean isClusterScoped() {
33+
return clusterScoped;
34+
}
35+
36+
public Set<String> getNamespaces() {
37+
return namespaces;
38+
}
39+
40+
public RetryProperties getRetry() {
41+
return retry;
42+
}
43+
44+
public void setRetry(RetryProperties retry) {
45+
this.retry = retry;
46+
}
47+
}
Lines changed: 103 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -1,71 +1,132 @@
11
package io.javaoperatorsdk.operator.springboot.starter;
22

3+
import java.util.List;
4+
import java.util.Map;
5+
import java.util.Optional;
6+
import java.util.Set;
7+
import java.util.concurrent.ConcurrentHashMap;
8+
39
import io.fabric8.kubernetes.client.ConfigBuilder;
10+
import io.fabric8.kubernetes.client.CustomResource;
411
import io.fabric8.kubernetes.client.DefaultKubernetesClient;
512
import io.fabric8.kubernetes.client.KubernetesClient;
613
import io.fabric8.openshift.client.DefaultOpenShiftClient;
714
import io.javaoperatorsdk.operator.Operator;
815
import io.javaoperatorsdk.operator.api.ResourceController;
16+
import io.javaoperatorsdk.operator.config.AnnotationConfiguration;
17+
import io.javaoperatorsdk.operator.config.ClientConfiguration;
18+
import io.javaoperatorsdk.operator.config.ConfigurationService;
19+
import io.javaoperatorsdk.operator.config.ControllerConfiguration;
20+
import io.javaoperatorsdk.operator.config.RetryConfiguration;
921
import io.javaoperatorsdk.operator.processing.retry.GenericRetry;
1022
import io.javaoperatorsdk.operator.processing.retry.Retry;
11-
import java.util.List;
1223
import org.apache.commons.lang3.StringUtils;
1324
import org.slf4j.Logger;
1425
import org.slf4j.LoggerFactory;
26+
import org.springframework.beans.factory.annotation.Autowired;
1527
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
1628
import org.springframework.boot.context.properties.EnableConfigurationProperties;
1729
import org.springframework.context.annotation.Bean;
1830
import org.springframework.context.annotation.Configuration;
1931

2032
@Configuration
21-
@EnableConfigurationProperties({OperatorProperties.class, RetryProperties.class})
22-
public class OperatorAutoConfiguration {
23-
private static final Logger log = LoggerFactory.getLogger(OperatorAutoConfiguration.class);
24-
25-
@Bean
26-
@ConditionalOnMissingBean
27-
public KubernetesClient kubernetesClient(OperatorProperties operatorProperties) {
33+
@EnableConfigurationProperties({ConfigurationProperties.class})
34+
public class OperatorAutoConfiguration implements ConfigurationService {
35+
private static final Logger log = LoggerFactory.getLogger(OperatorAutoConfiguration.class);
36+
@Autowired
37+
private ConfigurationProperties configuration;
38+
private final Map<String, ControllerConfiguration> controllers = new ConcurrentHashMap<>();
39+
40+
@Bean
41+
@ConditionalOnMissingBean
42+
public KubernetesClient kubernetesClient() {
43+
final var clientCfg = getClientConfiguration();
2844
ConfigBuilder config = new ConfigBuilder();
29-
config.withTrustCerts(operatorProperties.isTrustSelfSignedCertificates());
30-
if (StringUtils.isNotBlank(operatorProperties.getUsername())) {
31-
config.withUsername(operatorProperties.getUsername());
45+
config.withTrustCerts(clientCfg.isTrustSelfSignedCertificates());
46+
clientCfg.getMasterUrl().ifPresent(config::withMasterUrl);
47+
clientCfg.getUsername().ifPresent(config::withUsername);
48+
clientCfg.getPassword().ifPresent(config::withPassword);
49+
return clientCfg.isOpenshift() ? new DefaultOpenShiftClient(config.build()) : new DefaultKubernetesClient(config.build());
3250
}
33-
if (StringUtils.isNotBlank(operatorProperties.getPassword())) {
34-
config.withUsername(operatorProperties.getPassword());
51+
52+
@Bean
53+
@ConditionalOnMissingBean(Operator.class)
54+
public Operator operator(KubernetesClient kubernetesClient, ConfigurationProperties config, List<ResourceController> resourceControllers) {
55+
Operator operator = new Operator(kubernetesClient);
56+
// todo: create register method that takes the controller's configuration into account
57+
resourceControllers.forEach(r -> operator.registerController(processController(r)));
58+
return operator;
3559
}
36-
if (StringUtils.isNotBlank(operatorProperties.getMasterUrl())) {
37-
config.withMasterUrl(operatorProperties.getMasterUrl());
60+
61+
private ResourceController processController(ResourceController controller) {
62+
final var controllerPropertiesMap = configuration.getControllers();
63+
var controllerProps = controllerPropertiesMap.get(controller.getName());
64+
final var cfg = new ConfigurationWrapper(controller, controllerProps);
65+
this.controllers.put(controller.getName(), cfg);
66+
return controller;
3867
}
39-
return operatorProperties.isOpenshift()
40-
? new DefaultOpenShiftClient(config.build())
41-
: new DefaultKubernetesClient(config.build());
42-
}
43-
44-
@Bean
45-
@ConditionalOnMissingBean(Operator.class)
46-
public Operator operator(
47-
KubernetesClient kubernetesClient, List<ResourceController> resourceControllers) {
48-
Operator operator = new Operator(kubernetesClient);
49-
resourceControllers.forEach(r -> operator.registerControllerForAllNamespaces(r));
50-
return operator;
51-
}
52-
53-
@Bean
54-
@ConditionalOnMissingBean
55-
public Retry retry(RetryProperties retryProperties) {
56-
GenericRetry retry = new GenericRetry();
57-
if (retryProperties.getInitialInterval() != null) {
58-
retry.setInitialInterval(retryProperties.getInitialInterval());
68+
69+
@Override
70+
public <R extends CustomResource> ControllerConfiguration<R> getConfigurationFor(ResourceController<R> controller) {
71+
return controllers.get(controller.getName());
5972
}
60-
if (retryProperties.getIntervalMultiplier() != null) {
61-
retry.setIntervalMultiplier(retryProperties.getIntervalMultiplier());
73+
74+
@Override
75+
public ClientConfiguration getClientConfiguration() {
76+
return configuration.getClient();
6277
}
63-
if (retryProperties.getMaxAttempts() != null) {
64-
retry.setMaxAttempts(retryProperties.getMaxAttempts());
78+
79+
private static class ConfigurationWrapper<R extends CustomResource> extends AnnotationConfiguration<R> {
80+
private final Optional<ControllerProperties> properties;
81+
82+
private ConfigurationWrapper(ResourceController<R> controller, ControllerProperties properties) {
83+
super(controller);
84+
this.properties = Optional.ofNullable(properties);
85+
}
86+
87+
@Override
88+
public String getName() {
89+
return super.getName();
90+
}
91+
92+
@Override
93+
public String getCRDName() {
94+
return properties.map(ControllerProperties::getCRDName).orElse(super.getCRDName());
95+
}
96+
97+
@Override
98+
public String getFinalizer() {
99+
return properties.map(ControllerProperties::getFinalizer).orElse(super.getFinalizer());
100+
}
101+
102+
@Override
103+
public boolean isGenerationAware() {
104+
return properties.map(ControllerProperties::isGenerationAware).orElse(super.isGenerationAware());
105+
}
106+
107+
@Override
108+
public Class<R> getCustomResourceClass() {
109+
return super.getCustomResourceClass();
65110
}
66-
if (retryProperties.getMaxInterval() != null) {
67-
retry.setInitialInterval(retryProperties.getMaxInterval());
111+
112+
@Override
113+
public boolean isClusterScoped() {
114+
return properties.map(ControllerProperties::isClusterScoped).orElse(super.isClusterScoped());
68115
}
69-
return retry;
116+
117+
@Override
118+
public Set<String> getNamespaces() {
119+
return properties.map(ControllerProperties::getNamespaces).orElse(super.getNamespaces());
120+
}
121+
122+
@Override
123+
public boolean watchAllNamespaces() {
124+
return super.watchAllNamespaces();
125+
}
126+
127+
@Override
128+
public RetryConfiguration getRetryConfiguration() {
129+
return properties.map(ControllerProperties::getRetry).map(RetryProperties::asRetryConfiguration).orElse(RetryConfiguration.DEFAULT);
130+
}
70131
}
71132
}

0 commit comments

Comments
 (0)