Skip to content

Commit f408a14

Browse files
authored
feat: improvements for Quarkus extension (#1043)
* feat: extract DependentResource instantiation to DependentResourceFactory * feat: add AbstractPollingDependentResource * feat: add ResourceTypeAware interface * refactor: create DependentResources in Controller and remove DependentResourceManager
1 parent 4b3178f commit f408a14

File tree

21 files changed

+235
-194
lines changed

21 files changed

+235
-194
lines changed

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

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
import io.fabric8.kubernetes.client.CustomResource;
1010
import io.javaoperatorsdk.operator.api.monitoring.Metrics;
1111
import io.javaoperatorsdk.operator.api.reconciler.Reconciler;
12+
import io.javaoperatorsdk.operator.api.reconciler.dependent.DependentResourceFactory;
1213

1314
import com.fasterxml.jackson.core.JsonProcessingException;
1415
import com.fasterxml.jackson.databind.ObjectMapper;
@@ -19,6 +20,7 @@ public interface ConfigurationService {
1920
ObjectMapper OBJECT_MAPPER = new ObjectMapper();
2021

2122
Cloner DEFAULT_CLONER = new Cloner() {
23+
@SuppressWarnings("unchecked")
2224
@Override
2325
public HasMetadata clone(HasMetadata object) {
2426
try {
@@ -126,4 +128,8 @@ default boolean closeClientOnStop() {
126128
default ObjectMapper getObjectMapper() {
127129
return OBJECT_MAPPER;
128130
}
131+
132+
default DependentResourceFactory dependentResourceFactory() {
133+
return new DependentResourceFactory() {};
134+
}
129135
}

operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/reconciler/dependent/AbstractDependentResource.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -125,6 +125,7 @@ private RecentOperationCacheFiller<R> eventSourceAsRecentOperationCacheFiller()
125125
return (RecentOperationCacheFiller<R>) ((EventSourceProvider<P>) this).getEventSource();
126126
}
127127

128+
@SuppressWarnings("unchecked")
128129
// this cannot be done in constructor since event source might be initialized later
129130
protected boolean isFilteringEventSource() {
130131
if (this instanceof EventSourceProvider) {
@@ -135,6 +136,7 @@ protected boolean isFilteringEventSource() {
135136
}
136137
}
137138

139+
@SuppressWarnings("unchecked")
138140
// this cannot be done in constructor since event source might be initialized later
139141
protected boolean isRecentOperationCacheFiller() {
140142
if (this instanceof EventSourceProvider) {
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
package io.javaoperatorsdk.operator.api.reconciler.dependent;
2+
3+
import java.lang.reflect.InvocationTargetException;
4+
5+
import io.javaoperatorsdk.operator.api.config.dependent.DependentResourceSpec;
6+
7+
public interface DependentResourceFactory {
8+
9+
default <T extends DependentResource<?, ?>> T createFrom(DependentResourceSpec<T, ?> spec) {
10+
try {
11+
return spec.getDependentResourceClass().getConstructor().newInstance();
12+
} catch (InstantiationException | NoSuchMethodException | IllegalAccessException
13+
| InvocationTargetException e) {
14+
throw new IllegalArgumentException("Cannot instantiate DependentResource "
15+
+ spec.getDependentResourceClass().getCanonicalName(), e);
16+
}
17+
}
18+
19+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
package io.javaoperatorsdk.operator.api.reconciler.dependent;
2+
3+
public interface ResourceTypeAware<R> {
4+
5+
Class<R> resourceType();
6+
}

operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/Controller.java

Lines changed: 48 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
import java.util.LinkedList;
44
import java.util.List;
5+
import java.util.stream.Collectors;
56

67
import org.slf4j.Logger;
78
import org.slf4j.LoggerFactory;
@@ -18,21 +19,25 @@
1819
import io.javaoperatorsdk.operator.OperatorException;
1920
import io.javaoperatorsdk.operator.api.config.ConfigurationServiceProvider;
2021
import io.javaoperatorsdk.operator.api.config.ControllerConfiguration;
22+
import io.javaoperatorsdk.operator.api.config.dependent.DependentResourceSpec;
2123
import io.javaoperatorsdk.operator.api.monitoring.Metrics;
2224
import io.javaoperatorsdk.operator.api.monitoring.Metrics.ControllerExecution;
2325
import io.javaoperatorsdk.operator.api.reconciler.Context;
26+
import io.javaoperatorsdk.operator.api.reconciler.ContextInitializer;
2427
import io.javaoperatorsdk.operator.api.reconciler.DeleteControl;
2528
import io.javaoperatorsdk.operator.api.reconciler.EventSourceContext;
2629
import io.javaoperatorsdk.operator.api.reconciler.EventSourceInitializer;
2730
import io.javaoperatorsdk.operator.api.reconciler.Ignore;
2831
import io.javaoperatorsdk.operator.api.reconciler.Reconciler;
2932
import io.javaoperatorsdk.operator.api.reconciler.UpdateControl;
3033
import io.javaoperatorsdk.operator.api.reconciler.dependent.DependentResource;
31-
import io.javaoperatorsdk.operator.processing.dependent.DependentResourceManager;
34+
import io.javaoperatorsdk.operator.api.reconciler.dependent.DependentResourceConfigurator;
35+
import io.javaoperatorsdk.operator.api.reconciler.dependent.EventSourceProvider;
36+
import io.javaoperatorsdk.operator.api.reconciler.dependent.KubernetesClientAware;
3237
import io.javaoperatorsdk.operator.processing.event.EventSourceManager;
3338
import io.javaoperatorsdk.operator.processing.event.source.EventSource;
3439

35-
@SuppressWarnings({"unchecked"})
40+
@SuppressWarnings({"unchecked", "rawtypes"})
3641
@Ignore
3742
public class Controller<P extends HasMetadata> implements Reconciler<P>,
3843
LifecycleAware, EventSourceInitializer<P> {
@@ -43,22 +48,51 @@ public class Controller<P extends HasMetadata> implements Reconciler<P>,
4348
private final ControllerConfiguration<P> configuration;
4449
private final KubernetesClient kubernetesClient;
4550
private final EventSourceManager<P> eventSourceManager;
46-
private final DependentResourceManager<P> dependents;
51+
private final List<DependentResource> dependents;
52+
private final boolean contextInitializer;
4753

4854
public Controller(Reconciler<P> reconciler,
4955
ControllerConfiguration<P> configuration,
5056
KubernetesClient kubernetesClient) {
5157
this.reconciler = reconciler;
5258
this.configuration = configuration;
5359
this.kubernetesClient = kubernetesClient;
60+
contextInitializer = reconciler instanceof ContextInitializer;
5461

5562
eventSourceManager = new EventSourceManager<>(this);
56-
dependents = new DependentResourceManager<>(this);
63+
64+
dependents = configuration.getDependentResources().stream()
65+
.map(drs -> createAndConfigureFrom(drs, kubernetesClient))
66+
.collect(Collectors.toList());
67+
}
68+
69+
@SuppressWarnings("rawtypes")
70+
private DependentResource createAndConfigureFrom(DependentResourceSpec spec,
71+
KubernetesClient client) {
72+
final var dependentResource =
73+
ConfigurationServiceProvider.instance().dependentResourceFactory().createFrom(spec);
74+
75+
if (dependentResource instanceof KubernetesClientAware) {
76+
((KubernetesClientAware) dependentResource).setKubernetesClient(client);
77+
}
78+
79+
if (dependentResource instanceof DependentResourceConfigurator) {
80+
final var configurator = (DependentResourceConfigurator) dependentResource;
81+
spec.getDependentResourceConfiguration().ifPresent(configurator::configureWith);
82+
}
83+
return dependentResource;
84+
}
85+
86+
private void initContextIfNeeded(P resource, Context<P> context) {
87+
if (contextInitializer) {
88+
((ContextInitializer<P>) reconciler).initContext(resource, context);
89+
}
5790
}
5891

5992
@Override
6093
public DeleteControl cleanup(P resource, Context<P> context) {
61-
dependents.cleanup(resource, context);
94+
initContextIfNeeded(resource, context);
95+
dependents.forEach(dependent -> dependent.cleanup(resource, context));
6296

6397
try {
6498
return metrics().timeControllerExecution(
@@ -90,7 +124,8 @@ public DeleteControl execute() {
90124

91125
@Override
92126
public UpdateControl<P> reconcile(P resource, Context<P> context) throws Exception {
93-
dependents.reconcile(resource, context);
127+
initContextIfNeeded(resource, context);
128+
dependents.forEach(dependent -> dependent.reconcile(resource, context));
94129

95130
return metrics().timeControllerExecution(
96131
new ControllerExecution<>() {
@@ -131,8 +166,12 @@ private Metrics metrics() {
131166

132167
@Override
133168
public List<EventSource> prepareEventSources(EventSourceContext<P> context) {
134-
final var dependentSources = dependents.prepareEventSources(context);
135-
List<EventSource> sources = new LinkedList<>(dependentSources);
169+
List<EventSource> sources = new LinkedList<>();
170+
dependents.stream()
171+
.filter(dependentResource -> dependentResource instanceof EventSourceProvider)
172+
.map(EventSourceProvider.class::cast)
173+
.map(provider -> provider.initEventSource(context))
174+
.forEach(sources::add);
136175

137176
// add manually defined event sources
138177
if (reconciler instanceof EventSourceInitializer) {
@@ -267,6 +306,6 @@ public void stop() {
267306

268307
@SuppressWarnings("rawtypes")
269308
public List<DependentResource> getDependents() {
270-
return dependents.getDependents();
309+
return dependents;
271310
}
272311
}

operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/DependentResourceManager.java

Lines changed: 0 additions & 112 deletions
This file was deleted.

operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/external/AbstractCachingDependentResource.java

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,16 +3,22 @@
33
import java.util.Optional;
44

55
import io.fabric8.kubernetes.api.model.HasMetadata;
6-
import io.javaoperatorsdk.operator.api.config.Utils;
76
import io.javaoperatorsdk.operator.api.reconciler.dependent.AbstractDependentResource;
87
import io.javaoperatorsdk.operator.api.reconciler.dependent.EventSourceProvider;
8+
import io.javaoperatorsdk.operator.api.reconciler.dependent.ResourceTypeAware;
99
import io.javaoperatorsdk.operator.processing.event.ExternalResourceCachingEventSource;
1010
import io.javaoperatorsdk.operator.processing.event.source.EventSource;
1111

1212
public abstract class AbstractCachingDependentResource<R, P extends HasMetadata>
13-
extends AbstractDependentResource<R, P> implements EventSourceProvider<P> {
13+
extends AbstractDependentResource<R, P>
14+
implements EventSourceProvider<P>, ResourceTypeAware<R> {
1415

1516
protected ExternalResourceCachingEventSource<R, P> eventSource;
17+
private final Class<R> resourceType;
18+
19+
protected AbstractCachingDependentResource(Class<R> resourceType) {
20+
this.resourceType = resourceType;
21+
}
1622

1723
public Optional<R> fetchResource(P primaryResource) {
1824
return eventSource.getAssociated(primaryResource);
@@ -23,8 +29,9 @@ public EventSource getEventSource() {
2329
return eventSource;
2430
}
2531

26-
protected Class<R> resourceType() {
27-
return (Class<R>) Utils.getFirstTypeArgumentFromExtendedClass(getClass());
32+
@Override
33+
public Class<R> resourceType() {
34+
return resourceType;
2835
}
2936

3037
@Override
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
package io.javaoperatorsdk.operator.processing.dependent.external;
2+
3+
import io.fabric8.kubernetes.api.model.HasMetadata;
4+
5+
public abstract class AbstractPollingDependentResource<R, P extends HasMetadata>
6+
extends AbstractCachingDependentResource<R, P> {
7+
8+
public static final int DEFAULT_POLLING_PERIOD = 5000;
9+
private long pollingPeriod;
10+
11+
protected AbstractPollingDependentResource(Class<R> resourceType) {
12+
this(resourceType, DEFAULT_POLLING_PERIOD);
13+
}
14+
15+
public AbstractPollingDependentResource(Class<R> resourceType, long pollingPeriod) {
16+
super(resourceType);
17+
this.pollingPeriod = pollingPeriod;
18+
}
19+
20+
public void setPollingPeriod(long pollingPeriod) {
21+
this.pollingPeriod = pollingPeriod;
22+
}
23+
24+
public long getPollingPeriod() {
25+
return pollingPeriod;
26+
}
27+
}

0 commit comments

Comments
 (0)