Skip to content

Commit 928a88f

Browse files
metacosmcsviri
authored andcommitted
feat: decouple from ObjectMapper (#1953)
* refactor: use unmarshal instead of adding new method, works with 6.7.2 * feat: provide and use Kubernetes client directly
1 parent 3316e75 commit 928a88f

28 files changed

+253
-301
lines changed

Diff for: operator-framework-core/src/main/java/io/javaoperatorsdk/operator/LeaderElectionManager.java

+5-8
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,6 @@
99

1010
import io.fabric8.kubernetes.api.model.authorization.v1.SelfSubjectRulesReview;
1111
import io.fabric8.kubernetes.api.model.authorization.v1.SelfSubjectRulesReviewSpecBuilder;
12-
import io.fabric8.kubernetes.client.KubernetesClient;
1312
import io.fabric8.kubernetes.client.extended.leaderelection.LeaderCallbacks;
1413
import io.fabric8.kubernetes.client.extended.leaderelection.LeaderElectionConfig;
1514
import io.fabric8.kubernetes.client.extended.leaderelection.LeaderElector;
@@ -32,14 +31,11 @@ public class LeaderElectionManager {
3231
private final ControllerManager controllerManager;
3332
private String identity;
3433
private CompletableFuture<?> leaderElectionFuture;
35-
private KubernetesClient kubernetesClient;
3634
private final ConfigurationService configurationService;
3735
private String leaseNamespace;
3836

39-
public LeaderElectionManager(KubernetesClient kubernetesClient,
40-
ControllerManager controllerManager,
37+
LeaderElectionManager(ControllerManager controllerManager,
4138
ConfigurationService configurationService) {
42-
this.kubernetesClient = kubernetesClient;
4339
this.controllerManager = controllerManager;
4440
this.configurationService = configurationService;
4541
}
@@ -52,7 +48,7 @@ private void init(LeaderElectionConfiguration config) {
5248
this.identity = identity(config);
5349
leaseNamespace =
5450
config.getLeaseNamespace().orElseGet(
55-
() -> configurationService.getClientConfiguration().getNamespace());
51+
() -> configurationService.getKubernetesClient().getConfiguration().getNamespace());
5652
if (leaseNamespace == null) {
5753
final var message =
5854
"Lease namespace is not set and cannot be inferred. Leader election cannot continue.";
@@ -62,7 +58,8 @@ private void init(LeaderElectionConfiguration config) {
6258
final var lock = new LeaseLock(leaseNamespace, config.getLeaseName(), identity);
6359
// releaseOnCancel is not used in the underlying implementation
6460
leaderElector = new LeaderElectorBuilder(
65-
kubernetesClient, configurationService.getExecutorServiceManager().cachingExecutorService())
61+
configurationService.getKubernetesClient(),
62+
configurationService.getExecutorServiceManager().cachingExecutorService())
6663
.withConfig(
6764
new LeaderElectionConfig(
6865
lock,
@@ -122,7 +119,7 @@ private void checkLeaseAccess() {
122119
var verbs = Arrays.asList("create", "update", "get");
123120
SelfSubjectRulesReview review = new SelfSubjectRulesReview();
124121
review.setSpec(new SelfSubjectRulesReviewSpecBuilder().withNamespace(leaseNamespace).build());
125-
var reviewResult = kubernetesClient.resource(review).create();
122+
var reviewResult = configurationService.getKubernetesClient().resource(review).create();
126123
log.debug("SelfSubjectRulesReview result: {}", reviewResult);
127124
var foundRule = reviewResult.getStatus().getResourceRules().stream()
128125
.filter(rule -> rule.getApiGroups().contains(COORDINATION_GROUP)

Diff for: operator-framework-core/src/main/java/io/javaoperatorsdk/operator/Operator.java

+29-25
Original file line numberDiff line numberDiff line change
@@ -10,11 +10,8 @@
1010
import org.slf4j.LoggerFactory;
1111

1212
import io.fabric8.kubernetes.api.model.HasMetadata;
13-
import io.fabric8.kubernetes.client.ConfigBuilder;
1413
import io.fabric8.kubernetes.client.KubernetesClient;
15-
import io.fabric8.kubernetes.client.KubernetesClientBuilder;
1614
import io.fabric8.kubernetes.client.Version;
17-
import io.javaoperatorsdk.operator.api.config.BaseConfigurationService;
1815
import io.javaoperatorsdk.operator.api.config.ConfigurationService;
1916
import io.javaoperatorsdk.operator.api.config.ConfigurationServiceOverrider;
2017
import io.javaoperatorsdk.operator.api.config.ControllerConfiguration;
@@ -26,7 +23,7 @@
2623
@SuppressWarnings("rawtypes")
2724
public class Operator implements LifecycleAware {
2825
private static final Logger log = LoggerFactory.getLogger(Operator.class);
29-
private static final int DEFAULT_MAX_CONCURRENT_REQUEST = 512;
26+
3027
private final KubernetesClient kubernetesClient;
3128
private final ControllerManager controllerManager;
3229
private final LeaderElectionManager leaderElectionManager;
@@ -38,49 +35,56 @@ public Operator() {
3835
this((KubernetesClient) null);
3936
}
4037

41-
public Operator(KubernetesClient kubernetesClient) {
42-
this(kubernetesClient, new BaseConfigurationService());
38+
Operator(KubernetesClient kubernetesClient) {
39+
this(kubernetesClient, null);
4340
}
4441

4542
/**
4643
* @param configurationService implementation
4744
* @deprecated Use {@link #Operator(Consumer)} instead
4845
*/
4946
@Deprecated(forRemoval = true)
47+
@SuppressWarnings("unused")
5048
public Operator(ConfigurationService configurationService) {
51-
this(null, configurationService);
49+
this(null, null);
5250
}
5351

5452
public Operator(Consumer<ConfigurationServiceOverrider> overrider) {
5553
this(null, overrider);
5654
}
5755

58-
public Operator(KubernetesClient client, Consumer<ConfigurationServiceOverrider> overrider) {
59-
this(client, ConfigurationService
60-
.newOverriddenConfigurationService(new BaseConfigurationService(), overrider));
61-
}
62-
6356
/**
6457
* Note that Operator by default closes the client on stop, this can be changed using
6558
* {@link ConfigurationService}
6659
*
67-
* @param kubernetesClient client to use to all Kubernetes related operations
68-
* @param configurationService provides configuration
60+
* @param client client to use to all Kubernetes related operations
61+
* @param overrider a {@link ConfigurationServiceOverrider} consumer used to override the default
62+
* {@link ConfigurationService} values
63+
* @deprecated Use {@link Operator#Operator(Consumer)} instead, passing your custom client with
64+
* {@link ConfigurationServiceOverrider#withKubernetesClient(KubernetesClient)}
6965
*/
70-
public Operator(KubernetesClient kubernetesClient, ConfigurationService configurationService) {
71-
this.configurationService = configurationService;
66+
@Deprecated
67+
public Operator(KubernetesClient client, Consumer<ConfigurationServiceOverrider> overrider) {
68+
// initialize the client if the user didn't provide one
69+
if (client == null) {
70+
var configurationService = ConfigurationService.newOverriddenConfigurationService(overrider);
71+
client = configurationService.getKubernetesClient();
72+
}
73+
74+
this.kubernetesClient = client;
75+
76+
// override the configuration service to use the same client
77+
if (overrider != null) {
78+
overrider = overrider.andThen(o -> o.withKubernetesClient(this.kubernetesClient));
79+
} else {
80+
overrider = o -> o.withKubernetesClient(this.kubernetesClient);
81+
}
82+
this.configurationService = ConfigurationService.newOverriddenConfigurationService(overrider);
83+
7284
final var executorServiceManager = configurationService.getExecutorServiceManager();
7385
controllerManager = new ControllerManager(executorServiceManager);
74-
this.kubernetesClient =
75-
kubernetesClient != null ? kubernetesClient
76-
: new KubernetesClientBuilder()
77-
.withConfig(new ConfigBuilder()
78-
.withMaxConcurrentRequests(DEFAULT_MAX_CONCURRENT_REQUEST).build())
79-
.build();
80-
8186

82-
leaderElectionManager =
83-
new LeaderElectionManager(kubernetesClient, controllerManager, configurationService);
87+
leaderElectionManager = new LeaderElectionManager(controllerManager, configurationService);
8488
}
8589

8690
/**

Diff for: operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/config/AbstractConfigurationService.java

+9-20
Original file line numberDiff line numberDiff line change
@@ -9,44 +9,38 @@
99
import io.javaoperatorsdk.operator.ReconcilerUtils;
1010
import io.javaoperatorsdk.operator.api.reconciler.Reconciler;
1111

12-
import com.fasterxml.jackson.databind.ObjectMapper;
13-
1412
@SuppressWarnings("rawtypes")
1513
public class AbstractConfigurationService implements ConfigurationService {
1614
private final Map<String, ControllerConfiguration> configurations = new ConcurrentHashMap<>();
1715
private final Version version;
1816
private Cloner cloner;
19-
private ObjectMapper mapper;
2017
private ExecutorServiceManager executorServiceManager;
2118

2219
public AbstractConfigurationService(Version version) {
23-
this(version, null, null, null);
20+
this(version, null, null);
2421
}
2522

2623
public AbstractConfigurationService(Version version, Cloner cloner) {
27-
this(version, cloner, null, null);
24+
this(version, cloner, null);
2825
}
2926

30-
public AbstractConfigurationService(Version version, Cloner cloner, ObjectMapper mapper,
27+
public AbstractConfigurationService(Version version, Cloner cloner,
3128
ExecutorServiceManager executorServiceManager) {
3229
this.version = version;
33-
init(cloner, mapper, executorServiceManager);
30+
init(cloner, executorServiceManager);
3431
}
3532

3633
/**
37-
* Subclasses can call this method to more easily initialize the {@link Cloner}
38-
* {@link ObjectMapper} and {@link ExecutorServiceManager} associated with this
39-
* ConfigurationService implementation. This is useful in situations where the cloner depends on a
40-
* mapper that might require additional configuration steps before it's ready to be used.
34+
* Subclasses can call this method to more easily initialize the {@link Cloner} and
35+
* {@link ExecutorServiceManager} associated with this ConfigurationService implementation. This
36+
* is useful in situations where the cloner depends on a mapper that might require additional
37+
* configuration steps before it's ready to be used.
4138
*
4239
* @param cloner the {@link Cloner} instance to be used
43-
* @param mapper the {@link ObjectMapper} instance to be used
4440
* @param executorServiceManager the {@link ExecutorServiceManager} instance to be used
4541
*/
46-
protected void init(Cloner cloner, ObjectMapper mapper,
47-
ExecutorServiceManager executorServiceManager) {
42+
protected void init(Cloner cloner, ExecutorServiceManager executorServiceManager) {
4843
this.cloner = cloner != null ? cloner : ConfigurationService.super.getResourceCloner();
49-
this.mapper = mapper != null ? mapper : ConfigurationService.super.getObjectMapper();
5044
this.executorServiceManager = executorServiceManager;
5145
}
5246

@@ -133,11 +127,6 @@ public Cloner getResourceCloner() {
133127
return cloner;
134128
}
135129

136-
@Override
137-
public ObjectMapper getObjectMapper() {
138-
return mapper;
139-
}
140-
141130
@Override
142131
public ExecutorServiceManager getExecutorServiceManager() {
143132
// lazy init to avoid initializing thread pools for nothing in an overriding scenario

Diff for: operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/config/BaseConfigurationService.java

-6
Original file line numberDiff line numberDiff line change
@@ -31,8 +31,6 @@
3131
import io.javaoperatorsdk.operator.processing.event.source.filter.OnUpdateFilter;
3232
import io.javaoperatorsdk.operator.processing.retry.Retry;
3333

34-
import com.fasterxml.jackson.databind.ObjectMapper;
35-
3634
import static io.javaoperatorsdk.operator.api.config.ControllerConfiguration.CONTROLLER_NAME_AS_FIELD_MANAGER;
3735
import static io.javaoperatorsdk.operator.api.reconciler.Constants.DEFAULT_NAMESPACES_SET;
3836

@@ -45,10 +43,6 @@ public BaseConfigurationService(Version version) {
4543
super(version);
4644
}
4745

48-
public BaseConfigurationService(Version version, Cloner cloner, ObjectMapper mapper) {
49-
super(version, cloner, mapper, null);
50-
}
51-
5246
public BaseConfigurationService(Version version, Cloner cloner) {
5347
super(version, cloner);
5448
}

Diff for: operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/config/ConfigurationService.java

+32-35
Original file line numberDiff line numberDiff line change
@@ -11,23 +11,25 @@
1111

1212
import io.fabric8.kubernetes.api.model.HasMetadata;
1313
import io.fabric8.kubernetes.client.Config;
14+
import io.fabric8.kubernetes.client.ConfigBuilder;
1415
import io.fabric8.kubernetes.client.CustomResource;
15-
import io.fabric8.kubernetes.client.utils.Serialization;
16+
import io.fabric8.kubernetes.client.KubernetesClient;
17+
import io.fabric8.kubernetes.client.KubernetesClientBuilder;
18+
import io.fabric8.kubernetes.client.utils.KubernetesSerialization;
1619
import io.javaoperatorsdk.operator.api.monitoring.Metrics;
1720
import io.javaoperatorsdk.operator.api.reconciler.Reconciler;
1821
import io.javaoperatorsdk.operator.api.reconciler.dependent.DependentResourceFactory;
1922
import io.javaoperatorsdk.operator.processing.dependent.workflow.ManagedWorkflowFactory;
2023

21-
import com.fasterxml.jackson.core.JsonProcessingException;
22-
import com.fasterxml.jackson.databind.ObjectMapper;
23-
2424
import static io.javaoperatorsdk.operator.api.config.ExecutorServiceManager.newThreadPoolExecutor;
2525

2626
/** An interface from which to retrieve configuration information. */
2727
public interface ConfigurationService {
2828

2929
Logger log = LoggerFactory.getLogger(ConfigurationService.class);
3030

31+
int DEFAULT_MAX_CONCURRENT_REQUEST = 512;
32+
3133
/**
3234
* Retrieves the configuration associated with the specified reconciler
3335
*
@@ -38,14 +40,30 @@ public interface ConfigurationService {
3840
*/
3941
<R extends HasMetadata> ControllerConfiguration<R> getConfigurationFor(Reconciler<R> reconciler);
4042

43+
4144
/**
42-
* Retrieves the Kubernetes client configuration
45+
* Used to clone custom resources. It is strongly suggested that implementors override this method
46+
* since the default implementation creates a new {@link Cloner} instance each time this method is
47+
* called.
4348
*
44-
* @return the configuration of the Kubernetes client, defaulting to the provided
45-
* auto-configuration
49+
* @return the configured {@link Cloner}
4650
*/
47-
default Config getClientConfiguration() {
48-
return Config.autoConfigure(null);
51+
default Cloner getResourceCloner() {
52+
return new Cloner() {
53+
@Override
54+
public <R extends HasMetadata> R clone(R object) {
55+
return getKubernetesClient().getKubernetesSerialization().clone(object);
56+
}
57+
};
58+
}
59+
60+
default KubernetesClient getKubernetesClient() {
61+
return new KubernetesClientBuilder()
62+
.withConfig(new ConfigBuilder(Config.autoConfigure(null))
63+
.withMaxConcurrentRequests(DEFAULT_MAX_CONCURRENT_REQUEST)
64+
.build())
65+
.withKubernetesSerialization(new KubernetesSerialization())
66+
.build();
4967
}
5068

5169
/**
@@ -120,28 +138,6 @@ default int minConcurrentWorkflowExecutorThreads() {
120138
return MIN_DEFAULT_WORKFLOW_EXECUTOR_THREAD_NUMBER;
121139
}
122140

123-
/**
124-
* Used to clone custom resources. It is strongly suggested that implementors override this method
125-
* since the default implementation creates a new {@link Cloner} instance each time this method is
126-
* called.
127-
*
128-
* @return the configured {@link Cloner}
129-
*/
130-
default Cloner getResourceCloner() {
131-
return new Cloner() {
132-
@SuppressWarnings("unchecked")
133-
@Override
134-
public HasMetadata clone(HasMetadata object) {
135-
try {
136-
final var mapper = getObjectMapper();
137-
return mapper.readValue(mapper.writeValueAsString(object), object.getClass());
138-
} catch (JsonProcessingException e) {
139-
throw new IllegalStateException(e);
140-
}
141-
}
142-
};
143-
}
144-
145141
int DEFAULT_TERMINATION_TIMEOUT_SECONDS = 10;
146142

147143
/**
@@ -176,10 +172,6 @@ default boolean closeClientOnStop() {
176172
return true;
177173
}
178174

179-
default ObjectMapper getObjectMapper() {
180-
return Serialization.jsonMapper();
181-
}
182-
183175
@SuppressWarnings("rawtypes")
184176
default DependentResourceFactory dependentResourceFactory() {
185177
return DependentResourceFactory.DEFAULT;
@@ -261,6 +253,11 @@ static ConfigurationService newOverriddenConfigurationService(
261253
return baseConfiguration;
262254
}
263255

256+
static ConfigurationService newOverriddenConfigurationService(
257+
Consumer<ConfigurationServiceOverrider> overrider) {
258+
return newOverriddenConfigurationService(new BaseConfigurationService(), overrider);
259+
}
260+
264261
default ExecutorServiceManager getExecutorServiceManager() {
265262
return new ExecutorServiceManager(this);
266263
}

0 commit comments

Comments
 (0)