Skip to content

Commit 37ea3a6

Browse files
authored
feat: improve Context / EventSource API
- Record type handled by EventSource so that we can retrieve an associated secondary resource from a primary one directly from the Context - Introduce `ResourceEventSource` concept - Update sample reconcilers to use the new Context functionality - Make `EventSourceInitializer` return list of `EventSource`s This makes the intent clearer: the `EventSourceInitializer` prepares `EventSource`s that the SDK then registers automatically, without the reconciler having to call the register method in `prepareEventSources`. This also allows for removing the `EventSourceRegistry` interface altogether. - Extract interfaces for mappers instead of using `Function` - Introduce `EventSourceInitializationContext` for future-proofing
1 parent 27865f5 commit 37ea3a6

File tree

51 files changed

+868
-399
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

51 files changed

+868
-399
lines changed

operator-framework-core/src/main/java/io/javaoperatorsdk/operator/ReconcilerUtils.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
import java.util.Locale;
44

5+
import io.javaoperatorsdk.operator.api.reconciler.Constants;
56
import io.javaoperatorsdk.operator.api.reconciler.ControllerConfiguration;
67
import io.javaoperatorsdk.operator.api.reconciler.Reconciler;
78

@@ -19,7 +20,7 @@ public static String getNameFor(Class<? extends Reconciler> reconcilerClass) {
1920
final var annotation = reconcilerClass.getAnnotation(ControllerConfiguration.class);
2021
if (annotation != null) {
2122
final var name = annotation.name();
22-
if (!ControllerConfiguration.EMPTY_STRING.equals(name)) {
23+
if (!Constants.EMPTY_STRING.equals(name)) {
2324
return name;
2425
}
2526
}

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

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
import io.fabric8.kubernetes.api.model.HasMetadata;
88
import io.fabric8.kubernetes.client.CustomResource;
99
import io.javaoperatorsdk.operator.ReconcilerUtils;
10+
import io.javaoperatorsdk.operator.api.reconciler.Constants;
1011
import io.javaoperatorsdk.operator.processing.event.source.controller.ResourceEventFilter;
1112
import io.javaoperatorsdk.operator.processing.event.source.controller.ResourceEventFilters;
1213

@@ -67,7 +68,7 @@ static boolean currentNamespaceWatched(Set<String> namespaces) {
6768
return namespaces != null
6869
&& namespaces.size() == 1
6970
&& namespaces.contains(
70-
io.javaoperatorsdk.operator.api.reconciler.ControllerConfiguration.WATCH_CURRENT_NAMESPACE);
71+
Constants.WATCH_CURRENT_NAMESPACE);
7172
}
7273

7374
/**
@@ -99,7 +100,7 @@ default RetryConfiguration getRetryConfiguration() {
99100
default void setConfigurationService(ConfigurationService service) {}
100101

101102
default boolean useFinalizer() {
102-
return !io.javaoperatorsdk.operator.api.reconciler.ControllerConfiguration.NO_FINALIZER
103+
return !Constants.NO_FINALIZER
103104
.equals(getFinalizer());
104105
}
105106

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
package io.javaoperatorsdk.operator.api.reconciler;
2+
3+
public final class Constants {
4+
5+
public static final String EMPTY_STRING = "";
6+
public static final String WATCH_CURRENT_NAMESPACE = "JOSDK_WATCH_CURRENT";
7+
public static final String NO_FINALIZER = "JOSDK_NO_FINALIZER";
8+
9+
private Constants() {}
10+
}

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

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,4 +6,5 @@ public interface Context {
66

77
Optional<RetryInfo> getRetryInfo();
88

9+
<T> T getSecondaryResource(Class<T> expectedType, String... qualifier);
910
}

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

Lines changed: 5 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -11,20 +11,16 @@
1111
@Target({ElementType.TYPE})
1212
public @interface ControllerConfiguration {
1313

14-
String EMPTY_STRING = "";
15-
String WATCH_CURRENT_NAMESPACE = "JOSDK_WATCH_CURRENT";
16-
String NO_FINALIZER = "JOSDK_NO_FINALIZER";
17-
18-
String name() default EMPTY_STRING;
14+
String name() default Constants.EMPTY_STRING;
1915

2016
/**
2117
* Optional finalizer name, if it is not provided, one will be automatically generated. If the
22-
* provided value is the value specified by {@link #NO_FINALIZER}, then no finalizer will be added
23-
* to custom resources.
18+
* provided value is the value specified by {@link Constants#NO_FINALIZER}, then no finalizer will
19+
* be added to custom resources.
2420
*
2521
* @return the finalizer name
2622
*/
27-
String finalizerName() default EMPTY_STRING;
23+
String finalizerName() default Constants.EMPTY_STRING;
2824

2925
/**
3026
* If true, will dispatch new event to the controller if generation increased since the last
@@ -50,7 +46,7 @@
5046
*
5147
* @return the label selector
5248
*/
53-
String labelSelector() default EMPTY_STRING;
49+
String labelSelector() default Constants.EMPTY_STRING;
5450

5551

5652
/**

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

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,16 +2,30 @@
22

33
import java.util.Optional;
44

5-
public class DefaultContext implements Context {
5+
import io.fabric8.kubernetes.api.model.HasMetadata;
6+
import io.javaoperatorsdk.operator.processing.Controller;
7+
8+
public class DefaultContext<P extends HasMetadata> implements Context {
69

710
private final RetryInfo retryInfo;
11+
private final Controller<P> controller;
12+
private final P primaryResource;
813

9-
public DefaultContext(RetryInfo retryInfo) {
14+
public DefaultContext(RetryInfo retryInfo, Controller<P> controller, P primaryResource) {
1015
this.retryInfo = retryInfo;
16+
this.controller = controller;
17+
this.primaryResource = primaryResource;
1118
}
1219

1320
@Override
1421
public Optional<RetryInfo> getRetryInfo() {
1522
return Optional.ofNullable(retryInfo);
1623
}
24+
25+
@Override
26+
public <T> T getSecondaryResource(Class<T> expectedType, String... qualifier) {
27+
final var eventSource =
28+
controller.getEventSourceManager().getResourceEventSourceFor(expectedType, qualifier);
29+
return eventSource.map(es -> es.getAssociated(primaryResource)).orElse(null);
30+
}
1731
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
package io.javaoperatorsdk.operator.api.reconciler;
2+
3+
import io.fabric8.kubernetes.api.model.HasMetadata;
4+
import io.javaoperatorsdk.operator.processing.event.source.ResourceCache;
5+
6+
public class EventSourceInitializationContext<P extends HasMetadata> {
7+
8+
private final ResourceCache<P> primaryCache;
9+
10+
public EventSourceInitializationContext(ResourceCache<P> primaryCache) {
11+
this.primaryCache = primaryCache;
12+
}
13+
14+
public ResourceCache<P> getPrimaryCache() {
15+
return primaryCache;
16+
}
17+
}
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,24 @@
11
package io.javaoperatorsdk.operator.api.reconciler;
22

3+
import java.util.List;
4+
35
import io.fabric8.kubernetes.api.model.HasMetadata;
4-
import io.javaoperatorsdk.operator.processing.event.source.EventSourceRegistry;
6+
import io.javaoperatorsdk.operator.processing.event.source.EventSource;
57

6-
public interface EventSourceInitializer<T extends HasMetadata> {
8+
/**
9+
* An interface that a {@link Reconciler} can implement to have the SDK register the provided
10+
* {@link EventSource}
11+
*
12+
* @param <P> the primary resource type handled by the associated {@link Reconciler}
13+
*/
14+
public interface EventSourceInitializer<P extends HasMetadata> {
715

816
/**
9-
* Reconciler can implement this interface typically to register event sources. But can access
10-
* CustomResourceEventSource, what might be useful for some edge cases.
17+
* Prepares a list of {@link EventSource} implementations to be registered by the SDK.
1118
*
12-
* @param eventSourceRegistry the {@link EventSourceRegistry} where event sources can be
13-
* registered.
19+
* @param primaryCache a cache providing direct access to primary resources so that event sources
20+
* can extract relevant information from primary resources as needed
1421
*/
15-
void prepareEventSources(EventSourceRegistry<T> eventSourceRegistry);
22+
List<EventSource> prepareEventSources(EventSourceInitializationContext<P> context);
1623

1724
}

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

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,5 +40,4 @@ public interface Reconciler<R extends HasMetadata> {
4040
default DeleteControl cleanup(R resource, Context context) {
4141
return DeleteControl.defaultDelete();
4242
}
43-
4443
}

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

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

3+
import java.util.List;
34
import java.util.Objects;
45

56
import io.fabric8.kubernetes.api.model.HasMetadata;
@@ -15,11 +16,12 @@
1516
import io.javaoperatorsdk.operator.api.monitoring.Metrics.ControllerExecution;
1617
import io.javaoperatorsdk.operator.api.reconciler.Context;
1718
import io.javaoperatorsdk.operator.api.reconciler.DeleteControl;
19+
import io.javaoperatorsdk.operator.api.reconciler.EventSourceInitializationContext;
1820
import io.javaoperatorsdk.operator.api.reconciler.EventSourceInitializer;
1921
import io.javaoperatorsdk.operator.api.reconciler.Reconciler;
2022
import io.javaoperatorsdk.operator.api.reconciler.UpdateControl;
2123
import io.javaoperatorsdk.operator.processing.event.EventSourceManager;
22-
import io.javaoperatorsdk.operator.processing.event.source.EventSourceRegistry;
24+
import io.javaoperatorsdk.operator.processing.event.source.EventSource;
2325

2426
public class Controller<R extends HasMetadata> implements Reconciler<R>,
2527
LifecycleAware, EventSourceInitializer<R> {
@@ -96,7 +98,7 @@ public UpdateControl<R> execute() {
9698
}
9799

98100
@Override
99-
public void prepareEventSources(EventSourceRegistry<R> eventSourceRegistry) {
101+
public List<EventSource> prepareEventSources(EventSourceInitializationContext<R> context) {
100102
throw new UnsupportedOperationException("This method should never be called directly");
101103
}
102104

@@ -169,7 +171,10 @@ public void start() throws OperatorException {
169171

170172
eventSourceManager = new EventSourceManager<>(this);
171173
if (reconciler instanceof EventSourceInitializer) {
172-
((EventSourceInitializer<R>) reconciler).prepareEventSources(eventSourceManager);
174+
((EventSourceInitializer<R>) reconciler)
175+
.prepareEventSources(new EventSourceInitializationContext<>(
176+
eventSourceManager.getControllerResourceEventSource().getResourceCache()))
177+
.forEach(eventSourceManager::registerEventSource);
173178
}
174179
if (failOnMissingCurrentNS()) {
175180
throw new OperatorException(

0 commit comments

Comments
 (0)