Skip to content

Commit 1b99537

Browse files
committed
feat: decouple event source from cache + list discriminator (#1378)
1 parent f1ead67 commit 1b99537

File tree

46 files changed

+614
-214
lines changed

Some content is hidden

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

46 files changed

+614
-214
lines changed

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

+10-7
Original file line numberDiff line numberDiff line change
@@ -15,9 +15,8 @@
1515
import io.javaoperatorsdk.operator.OperatorException;
1616
import io.javaoperatorsdk.operator.ReconcilerUtils;
1717
import io.javaoperatorsdk.operator.api.config.dependent.DependentResourceSpec;
18-
import io.javaoperatorsdk.operator.api.reconciler.Constants;
18+
import io.javaoperatorsdk.operator.api.reconciler.*;
1919
import io.javaoperatorsdk.operator.api.reconciler.ControllerConfiguration;
20-
import io.javaoperatorsdk.operator.api.reconciler.Reconciler;
2120
import io.javaoperatorsdk.operator.api.reconciler.dependent.Dependent;
2221
import io.javaoperatorsdk.operator.api.reconciler.dependent.DependentResource;
2322
import io.javaoperatorsdk.operator.processing.dependent.kubernetes.KubernetesDependent;
@@ -48,9 +47,8 @@ public AnnotationControllerConfiguration(Reconciler<P> reconciler) {
4847
this.reconciler = reconciler;
4948
this.annotation = reconciler.getClass().getAnnotation(ControllerConfiguration.class);
5049
if (annotation == null) {
51-
throw new OperatorException(
52-
"Missing mandatory @" + ControllerConfiguration.class.getSimpleName() +
53-
" annotation for reconciler: " + reconciler);
50+
throw new OperatorException("Missing mandatory @" + CONTROLLER_CONFIG_ANNOTATION +
51+
" annotation for reconciler: " + reconciler);
5452
}
5553
}
5654

@@ -256,6 +254,7 @@ private Object createKubernetesResourceConfig(Class<? extends DependentResource>
256254
OnUpdateFilter<? extends HasMetadata> onUpdateFilter = null;
257255
OnDeleteFilter<? extends HasMetadata> onDeleteFilter = null;
258256
GenericFilter<? extends HasMetadata> genericFilter = null;
257+
ResourceDiscriminator<?, ? extends HasMetadata> resourceDiscriminator = null;
259258
if (kubeDependent != null) {
260259
if (!Arrays.equals(KubernetesDependent.DEFAULT_NAMESPACES,
261260
kubeDependent.namespaces())) {
@@ -266,7 +265,6 @@ private Object createKubernetesResourceConfig(Class<? extends DependentResource>
266265
final var fromAnnotation = kubeDependent.labelSelector();
267266
labelSelector = Constants.NO_VALUE_SET.equals(fromAnnotation) ? null : fromAnnotation;
268267

269-
270268
final var context =
271269
Utils.contextFor(this, dependentType, null);
272270
onAddFilter = Utils.instantiate(kubeDependent.onAddFilter(), OnAddFilter.class, context);
@@ -276,10 +274,15 @@ private Object createKubernetesResourceConfig(Class<? extends DependentResource>
276274
Utils.instantiate(kubeDependent.onDeleteFilter(), OnDeleteFilter.class, context);
277275
genericFilter =
278276
Utils.instantiate(kubeDependent.genericFilter(), GenericFilter.class, context);
277+
278+
resourceDiscriminator =
279+
Utils.instantiate(kubeDependent.resourceDiscriminator(),
280+
ResourceDiscriminator.class, context);
279281
}
280282

281283
config =
282-
new KubernetesDependentResourceConfig(namespaces, labelSelector, configuredNS, onAddFilter,
284+
new KubernetesDependentResourceConfig(namespaces, labelSelector, configuredNS,
285+
resourceDiscriminator, onAddFilter,
283286
onUpdateFilter, onDeleteFilter, genericFilter);
284287

285288
return config;

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

+11-4
Original file line numberDiff line numberDiff line change
@@ -6,20 +6,27 @@
66
import io.fabric8.kubernetes.api.model.HasMetadata;
77
import io.javaoperatorsdk.operator.api.config.ControllerConfiguration;
88
import io.javaoperatorsdk.operator.api.reconciler.dependent.managed.ManagedDependentResourceContext;
9+
import io.javaoperatorsdk.operator.processing.event.EventSourceRetriever;
910

1011
public interface Context<P extends HasMetadata> {
1112

1213
Optional<RetryInfo> getRetryInfo();
1314

14-
default <T> Optional<T> getSecondaryResource(Class<T> expectedType) {
15-
return getSecondaryResource(expectedType, null);
15+
default <R> Optional<R> getSecondaryResource(Class<R> expectedType) {
16+
return getSecondaryResource(expectedType, (String) null);
1617
}
1718

18-
<T> Set<T> getSecondaryResources(Class<T> expectedType);
19+
<R> Set<R> getSecondaryResources(Class<R> expectedType);
1920

20-
<T> Optional<T> getSecondaryResource(Class<T> expectedType, String eventSourceName);
21+
@Deprecated(forRemoval = true)
22+
<R> Optional<R> getSecondaryResource(Class<R> expectedType, String eventSourceName);
23+
24+
<R> Optional<R> getSecondaryResource(Class<R> expectedType,
25+
ResourceDiscriminator<R, P> discriminator);
2126

2227
ControllerConfiguration<P> getControllerConfiguration();
2328

2429
ManagedDependentResourceContext managedDependentResourceContext();
30+
31+
EventSourceRetriever<P> eventSourceRetriever();
2532
}

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

+12
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
import io.javaoperatorsdk.operator.api.reconciler.dependent.managed.DefaultManagedDependentResourceContext;
1010
import io.javaoperatorsdk.operator.api.reconciler.dependent.managed.ManagedDependentResourceContext;
1111
import io.javaoperatorsdk.operator.processing.Controller;
12+
import io.javaoperatorsdk.operator.processing.event.EventSourceRetriever;
1213

1314
public class DefaultContext<P extends HasMetadata> implements Context<P> {
1415

@@ -47,6 +48,12 @@ public <T> Optional<T> getSecondaryResource(Class<T> expectedType, String eventS
4748
.getSecondaryResource(primaryResource);
4849
}
4950

51+
@Override
52+
public <R> Optional<R> getSecondaryResource(Class<R> expectedType,
53+
ResourceDiscriminator<R, P> discriminator) {
54+
return discriminator.distinguish(expectedType, primaryResource, this);
55+
}
56+
5057
@Override
5158
public ControllerConfiguration<P> getControllerConfiguration() {
5259
return controllerConfiguration;
@@ -57,6 +64,11 @@ public ManagedDependentResourceContext managedDependentResourceContext() {
5764
return defaultManagedDependentResourceContext;
5865
}
5966

67+
@Override
68+
public EventSourceRetriever<P> eventSourceRetriever() {
69+
return controller.getEventSourceManager();
70+
}
71+
6072
public DefaultContext<P> setRetryInfo(RetryInfo retryInfo) {
6173
this.retryInfo = retryInfo;
6274
return this;
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
package io.javaoperatorsdk.operator.api.reconciler;
2+
3+
import java.util.Optional;
4+
5+
import io.fabric8.kubernetes.api.model.HasMetadata;
6+
7+
public interface ResourceDiscriminator<R, P extends HasMetadata> {
8+
9+
Optional<R> distinguish(Class<R> resource, P primary, Context<P> context);
10+
11+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
package io.javaoperatorsdk.operator.api.reconciler;
2+
3+
import java.util.Optional;
4+
import java.util.function.Function;
5+
6+
import io.fabric8.kubernetes.api.model.HasMetadata;
7+
import io.javaoperatorsdk.operator.processing.event.ResourceID;
8+
9+
public class ResourceIDMatcherDiscriminator<R extends HasMetadata, P extends HasMetadata>
10+
implements ResourceDiscriminator<R, P> {
11+
12+
private final Function<P, ResourceID> mapper;
13+
14+
public ResourceIDMatcherDiscriminator(Function<P, ResourceID> mapper) {
15+
this.mapper = mapper;
16+
}
17+
18+
@Override
19+
public Optional<R> distinguish(Class<R> resource, P primary, Context<P> context) {
20+
var resourceID = mapper.apply(primary);
21+
return context.getSecondaryResources(resource).stream()
22+
.filter(resourceID::isSameResource)
23+
.findFirst();
24+
}
25+
}

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

+14-2
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,17 @@
11
package io.javaoperatorsdk.operator.api.reconciler.dependent;
22

3+
import java.util.Optional;
4+
35
import io.fabric8.kubernetes.api.model.HasMetadata;
46
import io.javaoperatorsdk.operator.api.reconciler.Context;
5-
import io.javaoperatorsdk.operator.processing.ResourceOwner;
67

78
/**
89
* An interface to implement and provide dependent resource support.
910
*
1011
* @param <R> the dependent resource type
1112
* @param <P> the associated primary resource type
1213
*/
13-
public interface DependentResource<R, P extends HasMetadata> extends ResourceOwner<R, P> {
14+
public interface DependentResource<R, P extends HasMetadata> {
1415

1516
/**
1617
* Reconciles the dependent resource given the desired primary state
@@ -21,6 +22,17 @@ public interface DependentResource<R, P extends HasMetadata> extends ResourceOwn
2122
*/
2223
ReconcileResult<R> reconcile(P primary, Context<P> context);
2324

25+
/**
26+
* Retrieves the resource type associated with this DependentResource
27+
*
28+
* @return the resource type associated with this DependentResource
29+
*/
30+
Class<R> resourceType();
31+
32+
default Optional<R> getSecondaryResource(P primary, Context<P> context) {
33+
return Optional.empty();
34+
}
35+
2436
/**
2537
* Computes a default name for the specified DependentResource class
2638
*

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

-26
This file was deleted.

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

+20-1
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,14 @@
11
package io.javaoperatorsdk.operator.processing.dependent;
22

3+
import java.util.Optional;
4+
35
import org.slf4j.Logger;
46
import org.slf4j.LoggerFactory;
57

68
import io.fabric8.kubernetes.api.model.HasMetadata;
79
import io.javaoperatorsdk.operator.api.reconciler.Context;
810
import io.javaoperatorsdk.operator.api.reconciler.Ignore;
11+
import io.javaoperatorsdk.operator.api.reconciler.ResourceDiscriminator;
912
import io.javaoperatorsdk.operator.api.reconciler.dependent.DependentResource;
1013
import io.javaoperatorsdk.operator.api.reconciler.dependent.ReconcileResult;
1114
import io.javaoperatorsdk.operator.processing.event.ResourceID;
@@ -21,6 +24,8 @@ public abstract class AbstractDependentResource<R, P extends HasMetadata>
2124
protected Creator<R, P> creator;
2225
protected Updater<R, P> updater;
2326

27+
private ResourceDiscriminator<R, P> resourceDiscriminator;
28+
2429
@SuppressWarnings("unchecked")
2530
public AbstractDependentResource() {
2631
creator = creatable ? (Creator<R, P>) this : null;
@@ -29,7 +34,7 @@ public AbstractDependentResource() {
2934

3035
@Override
3136
public ReconcileResult<R> reconcile(P primary, Context<P> context) {
32-
var maybeActual = getSecondaryResource(primary);
37+
Optional<R> maybeActual = getSecondaryResource(primary, context);
3338
if (creatable || updatable) {
3439
if (maybeActual.isEmpty()) {
3540
if (creatable) {
@@ -62,6 +67,11 @@ public ReconcileResult<R> reconcile(P primary, Context<P> context) {
6267
return ReconcileResult.noOperation(maybeActual.orElse(null));
6368
}
6469

70+
public Optional<R> getSecondaryResource(P primary, Context<P> context) {
71+
return resourceDiscriminator == null ? context.getSecondaryResource(resourceType())
72+
: resourceDiscriminator.distinguish(resourceType(), primary, context);
73+
}
74+
6575
private void throwIfNull(R desired, P primary, String descriptor) {
6676
if (desired == null) {
6777
throw new DependentResourceException(
@@ -118,4 +128,13 @@ protected R desired(P primary, Context<P> context) {
118128
throw new IllegalStateException(
119129
"desired method must be implemented if this DependentResource can be created and/or updated");
120130
}
131+
132+
public void setResourceDiscriminator(
133+
ResourceDiscriminator<R, P> resourceDiscriminator) {
134+
this.resourceDiscriminator = resourceDiscriminator;
135+
}
136+
137+
public ResourceDiscriminator<R, P> getResourceDiscriminator() {
138+
return resourceDiscriminator;
139+
}
121140
}

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

+9
Original file line numberDiff line numberDiff line change
@@ -19,12 +19,16 @@ public abstract class AbstractEventSourceHolderDependentResource<R, P extends Ha
1919
implements EventSourceProvider<P> {
2020

2121
private T eventSource;
22+
private final Class<R> resourceType;
2223
private boolean isCacheFillerEventSource;
2324
protected OnAddFilter<R> onAddFilter;
2425
protected OnUpdateFilter<R> onUpdateFilter;
2526
protected OnDeleteFilter<R> onDeleteFilter;
2627
protected GenericFilter<R> genericFilter;
2728

29+
protected AbstractEventSourceHolderDependentResource(Class<R> resourceType) {
30+
this.resourceType = resourceType;
31+
}
2832

2933
public EventSource initEventSource(EventSourceContext<P> context) {
3034
// some sub-classes (e.g. KubernetesDependentResource) can have their event source created
@@ -42,6 +46,11 @@ public EventSource initEventSource(EventSourceContext<P> context) {
4246
return eventSource;
4347
}
4448

49+
@Override
50+
public Class<R> resourceType() {
51+
return resourceType;
52+
}
53+
4554
protected abstract T createEventSource(EventSourceContext<P> context);
4655

4756
protected void setEventSource(T eventSource) {

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

-29
This file was deleted.

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

+5-1
Original file line numberDiff line numberDiff line change
@@ -2,11 +2,15 @@
22

33
import io.fabric8.kubernetes.api.model.HasMetadata;
44
import io.javaoperatorsdk.operator.api.reconciler.Ignore;
5+
import io.javaoperatorsdk.operator.processing.dependent.AbstractEventSourceHolderDependentResource;
56
import io.javaoperatorsdk.operator.processing.event.source.CacheKeyMapper;
7+
import io.javaoperatorsdk.operator.processing.event.source.ExternalResourceCachingEventSource;
68

79
@Ignore
810
public abstract class AbstractPollingDependentResource<R, P extends HasMetadata>
9-
extends AbstractCachingDependentResource<R, P> implements CacheKeyMapper<R> {
11+
extends
12+
AbstractEventSourceHolderDependentResource<R, P, ExternalResourceCachingEventSource<R, P>>
13+
implements CacheKeyMapper<R> {
1014

1115
public static final int DEFAULT_POLLING_PERIOD = 5000;
1216
private long pollingPeriod;

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

+1-1
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ public AbstractSimpleDependentResource(UpdatableCache<R> cache) {
3333
}
3434

3535
@Override
36-
public Optional<R> getSecondaryResource(HasMetadata primaryResource) {
36+
public Optional<R> getSecondaryResource(P primaryResource, Context<P> context) {
3737
return cache.get(ResourceID.fromResource(primaryResource));
3838
}
3939

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

+4
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,8 @@
66
import java.lang.annotation.Target;
77

88
import io.javaoperatorsdk.operator.api.reconciler.Constants;
9+
import io.javaoperatorsdk.operator.api.reconciler.ResourceDiscriminator;
10+
import io.javaoperatorsdk.operator.processing.event.source.filter.*;
911
import io.javaoperatorsdk.operator.processing.event.source.filter.GenericFilter;
1012
import io.javaoperatorsdk.operator.processing.event.source.filter.OnAddFilter;
1113
import io.javaoperatorsdk.operator.processing.event.source.filter.OnDeleteFilter;
@@ -68,4 +70,6 @@
6870
* itself if no value is set
6971
*/
7072
Class<? extends GenericFilter> genericFilter() default GenericFilter.class;
73+
74+
Class<? extends ResourceDiscriminator> resourceDiscriminator() default ResourceDiscriminator.class;
7175
}

0 commit comments

Comments
 (0)