Skip to content

Commit 79b292a

Browse files
csvirimetacosm
andcommitted
improve: named event sources and related changes (#2340)
Signed-off-by: Attila Mészáros <[email protected]> Signed-off-by: Chris Laprun <[email protected]> Co-authored-by: Chris Laprun <[email protected]>
1 parent 34705ff commit 79b292a

File tree

82 files changed

+678
-786
lines changed

Some content is hidden

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

82 files changed

+678
-786
lines changed

caffeine-bounded-cache-support/src/test/java/io/javaoperatorsdk/operator/processing/event/source/cache/sample/AbstractTestReconciler.java

+3-2
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
package io.javaoperatorsdk.operator.processing.event.source.cache.sample;
22

33
import java.time.Duration;
4+
import java.util.List;
45
import java.util.Map;
56

67
import org.slf4j.Logger;
@@ -69,7 +70,7 @@ protected void createConfigMap(P resource, Context<P> context) {
6970
}
7071

7172
@Override
72-
public Map<String, EventSource> prepareEventSources(
73+
public List<EventSource> prepareEventSources(
7374
EventSourceContext<P> context) {
7475

7576
var boundedItemStore =
@@ -82,7 +83,7 @@ public Map<String, EventSource> prepareEventSources(
8283
Mappers.fromOwnerReference(this instanceof BoundedCacheClusterScopeTestReconciler))
8384
.build(), context);
8485

85-
return EventSourceUtils.nameEventSources(es);
86+
return List.of(es);
8687
}
8788

8889
private void ensureStatus(P resource) {

docs/documentation/features.md

+1-1
Original file line numberDiff line numberDiff line change
@@ -533,7 +533,7 @@ public class TomcatReconciler implements Reconciler<Tomcat> {
533533
.withSecondaryToPrimaryMapper(
534534
Mappers.fromAnnotation(ANNOTATION_NAME, ANNOTATION_NAMESPACE)
535535
.build(), context));
536-
return EventSourceUtils.nameEventSources(configMapEventSource);
536+
return List.of(configMapEventSource);
537537
}
538538

539539
}

docs/documentation/v5-0-migration.md

+24-9
Original file line numberDiff line numberDiff line change
@@ -17,8 +17,22 @@ permalink: /docs/v5-0-migration
1717
[`EventSourceUtils`](https://github.com/operator-framework/java-operator-sdk/blob/main/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/reconciler/EventSourceUtils.java#L11-L11)
1818
now contains all the utility methods used for event sources naming that were previously defined in
1919
the `EventSourceInitializer` interface.
20-
3. Updates through `UpdateControl` now use [Server Side Apply (SSA)](https://kubernetes.io/docs/reference/using-api/server-side-apply/) by default to add the finalizer and for all
21-
the patch operations in `UpdateControl`. The update operations were removed. If you do not wish to use SSA, you can deactivate the feature using `ConfigurationService.useSSAToPatchPrimaryResource` and related `ConfigurationServiceOverrider.withUseSSAToPatchPrimaryResource`.
20+
3. Event sources are now explicitly named (via the `name` method of the `EventSource` interface). Built-in event sources
21+
implementation have been updated to allow you to specify a name when instantiating them. If you don't provide a name
22+
for your `EventSource` implementation (for example, by using its default, no-arg constructor), one will be
23+
automatically generated. This simplifies the API to define event source to
24+
`List<EventSource> prepareEventSources(EventSourceContext<P> context)`.
25+
!!! IMPORTANT !!!
26+
If you use dynamic registration of event sources, be sure to name your event sources explicitly as letting JOSDK name
27+
them automatically might result in duplicated event sources being registered as JOSDK relies on the name to identify
28+
event sources and concurrent, dynamic registration might lead to identical event sources having different generated
29+
names, thus leading JOSDK to consider them as different and hence, register them multiple times.
30+
4. Updates through `UpdateControl` now
31+
use [Server Side Apply (SSA)](https://kubernetes.io/docs/reference/using-api/server-side-apply/) by default to add
32+
the finalizer and for all
33+
the patch operations in `UpdateControl`. The update operations were removed. If you do not wish to use SSA, you can
34+
deactivate the feature using `ConfigurationService.useSSAToPatchPrimaryResource` and
35+
related `ConfigurationServiceOverrider.withUseSSAToPatchPrimaryResource`.
2236

2337
!!! IMPORTANT !!!
2438

@@ -27,15 +41,16 @@ permalink: /docs/v5-0-migration
2741
where it is demonstrated. Also, the related part of
2842
a [workaround](https://github.com/operator-framework/java-operator-sdk/blob/main/operator-framework/src/test/java/io/javaoperatorsdk/operator/StatusPatchSSAMigrationIT.java#L110-L116).
2943

30-
Related automatic observed generation handling changes:
44+
Related automatic observed generation handling changes:
3145
Automated Observed Generation (see features in docs), is automatically handled for non-SSA, even if
32-
the status sub-resource is not instructed to be updated. This is not true for SSA, observed generation is updated
46+
the status sub-resource is not instructed to be updated. This is not true for SSA, observed generation is updated
3347
only when patch status is instructed by `UpdateControl`.
3448

35-
4. `ManagedDependentResourceContext` has been renamed to `ManagedWorkflowAndDependentResourceContext` and is accessed
49+
5. `ManagedDependentResourceContext` has been renamed to `ManagedWorkflowAndDependentResourceContext` and is accessed
3650
via the accordingly renamed `managedWorkflowAndDependentResourceContext` method.
37-
5. `ResourceDiscriminator` was removed. In most of the cases you can just delete the discriminator, everything should
38-
work without it by default. To optimize and handle special cases see the relevant section in [Dependent Resource documentation](/docs/dependent-resources#multiple-dependent-resources-of-same-type).
39-
6. `ConfigurationService.getTerminationTimeoutSeconds` and associated overriding mechanism have been removed,
51+
6. `ResourceDiscriminator` was removed. In most of the cases you can just delete the discriminator, everything should
52+
work without it by default. To optimize and handle special cases see the relevant section
53+
in [Dependent Resource documentation](/docs/dependent-resources#multiple-dependent-resources-of-same-type).
54+
7. `ConfigurationService.getTerminationTimeoutSeconds` and associated overriding mechanism have been removed,
4055
use `Operator.stop(Duration)` instead.
41-
7. `Operator.installShutdownHook()` has been removed, use `Operator.installShutdownHook(Duration)` instead
56+
8. `Operator.installShutdownHook()` has been removed, use `Operator.installShutdownHook(Duration)` instead

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

+1
Original file line numberDiff line numberDiff line change
@@ -88,4 +88,5 @@ public Optional<ItemStore<R>> getItemStore() {
8888
public Optional<Long> getInformerListLimit() {
8989
return Optional.ofNullable(informerListLimit);
9090
}
91+
9192
}

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

-1
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,6 @@ default <R> Stream<R> getSecondaryResourcesAsStream(Class<R> expectedType) {
2626
return getSecondaryResources(expectedType).stream();
2727
}
2828

29-
@Deprecated(forRemoval = true)
3029
<R> Optional<R> getSecondaryResource(Class<R> expectedType, String eventSourceName);
3130

3231
ControllerConfiguration<P> getControllerConfiguration();

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

+9-54
Original file line numberDiff line numberDiff line change
@@ -6,66 +6,21 @@
66
import io.javaoperatorsdk.operator.api.reconciler.dependent.DependentResource;
77
import io.javaoperatorsdk.operator.processing.dependent.workflow.Workflow;
88
import io.javaoperatorsdk.operator.processing.event.source.EventSource;
9-
import io.javaoperatorsdk.operator.processing.event.source.ResourceEventSource;
109

1110
public class EventSourceUtils {
12-
/**
13-
* Utility method to easily create map with generated name for event sources. This is for the use
14-
* case when the event sources are not access explicitly by name in the reconciler.
15-
*
16-
* @param eventSources to name
17-
* @return even source with default names
18-
*/
19-
public static Map<String, EventSource> nameEventSources(EventSource... eventSources) {
20-
Map<String, EventSource> eventSourceMap = new HashMap<>(eventSources.length);
21-
for (EventSource eventSource : eventSources) {
22-
eventSourceMap.put(generateNameFor(eventSource), eventSource);
23-
}
24-
return eventSourceMap;
11+
12+
@SuppressWarnings("unchecked")
13+
public static <R extends HasMetadata> List<EventSource> dependentEventSources(
14+
EventSourceContext<R> eventSourceContext, DependentResource... dependentResources) {
15+
return Arrays.stream(dependentResources)
16+
.flatMap(dr -> dr.eventSource(eventSourceContext).stream()).toList();
2517
}
2618

2719
@SuppressWarnings("unchecked")
28-
public static <K extends HasMetadata> Map<String, EventSource> eventSourcesFromWorkflow(
20+
public static <K extends HasMetadata> List<EventSource> eventSourcesFromWorkflow(
2921
EventSourceContext<K> context,
3022
Workflow<K> workflow) {
31-
Map<String, EventSource> result = new HashMap<>();
32-
for (var e : workflow.getDependentResourcesByNameWithoutActivationCondition().entrySet()) {
33-
var eventSource = e.getValue().eventSource(context);
34-
eventSource.ifPresent(es -> result.put(e.getKey(), (EventSource) es));
35-
}
36-
return result;
37-
}
38-
39-
@SuppressWarnings("rawtypes")
40-
public static <K extends HasMetadata> Map<String, EventSource> nameEventSourcesFromDependentResource(
41-
EventSourceContext<K> context, DependentResource... dependentResources) {
42-
return nameEventSourcesFromDependentResource(context, Arrays.asList(dependentResources));
43-
}
44-
45-
@SuppressWarnings("unchecked,rawtypes")
46-
public static <K extends HasMetadata> Map<String, EventSource> nameEventSourcesFromDependentResource(
47-
EventSourceContext<K> context, Collection<DependentResource> dependentResources) {
48-
49-
if (dependentResources != null) {
50-
Map<String, EventSource> eventSourceMap = new HashMap<>(dependentResources.size());
51-
for (DependentResource dependentResource : dependentResources) {
52-
Optional<ResourceEventSource> es = dependentResource.eventSource(context);
53-
es.ifPresent(e -> eventSourceMap.put(generateNameFor(e), e));
54-
}
55-
return eventSourceMap;
56-
} else {
57-
return Collections.emptyMap();
58-
}
59-
}
60-
61-
/**
62-
* Used when event sources are not explicitly named when created/registered.
63-
*
64-
* @param eventSource EventSource
65-
* @return generated name
66-
*/
67-
public static String generateNameFor(EventSource eventSource) {
68-
// we can have multiple event sources for the same class
69-
return eventSource.getClass().getName() + "#" + eventSource.hashCode();
23+
return workflow.getDependentResourcesWithoutActivationCondition().stream()
24+
.flatMap(dr -> dr.eventSource(context).stream()).toList();
7025
}
7126
}

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

+3-4
Original file line numberDiff line numberDiff line change
@@ -19,17 +19,16 @@ public interface Reconciler<P extends HasMetadata> {
1919
*/
2020
UpdateControl<P> reconcile(P resource, Context<P> context) throws Exception;
2121

22-
2322
/**
2423
* Prepares a map of {@link EventSource} implementations keyed by the name with which they need to
2524
* be registered by the SDK.
2625
*
2726
* @param context a {@link EventSourceContext} providing access to information useful to event
2827
* sources
29-
* @return a map of event sources to register
28+
* @return a list of event sources
3029
*/
31-
default Map<String, EventSource> prepareEventSources(EventSourceContext<P> context) {
32-
return Map.of();
30+
default List<EventSource> prepareEventSources(EventSourceContext<P> context) {
31+
return Collections.emptyList();
3332
}
3433

3534
}

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

-18
This file was deleted.

operator-framework-core/src/main/java/io/javaoperatorsdk/operator/health/ControllerHealthInfo.java

+15-14
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
import java.util.stream.Collectors;
55

66
import io.javaoperatorsdk.operator.processing.event.EventSourceManager;
7+
import io.javaoperatorsdk.operator.processing.event.source.EventSource;
78

89
@SuppressWarnings("rawtypes")
910
public class ControllerHealthInfo {
@@ -15,21 +16,21 @@ public ControllerHealthInfo(EventSourceManager eventSourceManager) {
1516
}
1617

1718
public Map<String, EventSourceHealthIndicator> eventSourceHealthIndicators() {
18-
return eventSourceManager.allEventSources().entrySet().stream()
19-
.collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue));
19+
return eventSourceManager.allEventSources().stream()
20+
.collect(Collectors.toMap(EventSource::name, e -> e));
2021
}
2122

2223
public Map<String, EventSourceHealthIndicator> unhealthyEventSources() {
23-
return eventSourceManager.allEventSources().entrySet().stream()
24-
.filter(e -> e.getValue().getStatus() == Status.UNHEALTHY)
25-
.collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue));
24+
return eventSourceManager.allEventSources().stream()
25+
.filter(e -> e.getStatus() == Status.UNHEALTHY)
26+
.collect(Collectors.toMap(EventSource::name, e -> e));
2627
}
2728

2829
public Map<String, InformerWrappingEventSourceHealthIndicator> informerEventSourceHealthIndicators() {
29-
return eventSourceManager.allEventSources().entrySet().stream()
30-
.filter(e -> e.getValue() instanceof InformerWrappingEventSourceHealthIndicator)
31-
.collect(Collectors.toMap(Map.Entry::getKey,
32-
e -> (InformerWrappingEventSourceHealthIndicator) e.getValue()));
30+
return eventSourceManager.allEventSources().stream()
31+
.filter(e -> e instanceof InformerWrappingEventSourceHealthIndicator)
32+
.collect(Collectors.toMap(EventSource::name,
33+
e -> (InformerWrappingEventSourceHealthIndicator) e));
3334

3435
}
3536

@@ -40,11 +41,11 @@ public Map<String, InformerWrappingEventSourceHealthIndicator> informerEventSour
4041
* {@link io.javaoperatorsdk.operator.processing.event.source.informer.InformerEventSource}.
4142
*/
4243
public Map<String, InformerWrappingEventSourceHealthIndicator> unhealthyInformerEventSourceHealthIndicators() {
43-
return eventSourceManager.allEventSources().entrySet().stream()
44-
.filter(e -> e.getValue().getStatus() == Status.UNHEALTHY)
45-
.filter(e -> e.getValue() instanceof InformerWrappingEventSourceHealthIndicator)
46-
.collect(Collectors.toMap(Map.Entry::getKey,
47-
e -> (InformerWrappingEventSourceHealthIndicator) e.getValue()));
44+
return eventSourceManager.allEventSources().stream()
45+
.filter(e -> e.getStatus() == Status.UNHEALTHY)
46+
.filter(e -> e instanceof InformerWrappingEventSourceHealthIndicator)
47+
.collect(Collectors.toMap(EventSource::name,
48+
e -> (InformerWrappingEventSourceHealthIndicator) e));
4849
}
4950

5051
}

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

+5-11
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,6 @@
3636
import io.javaoperatorsdk.operator.api.reconciler.Reconciler;
3737
import io.javaoperatorsdk.operator.api.reconciler.UpdateControl;
3838
import io.javaoperatorsdk.operator.api.reconciler.dependent.EventSourceNotFoundException;
39-
import io.javaoperatorsdk.operator.api.reconciler.dependent.EventSourceProvider;
4039
import io.javaoperatorsdk.operator.api.reconciler.dependent.EventSourceReferencer;
4140
import io.javaoperatorsdk.operator.api.reconciler.dependent.managed.DefaultManagedWorkflowAndDependentResourceContext;
4241
import io.javaoperatorsdk.operator.health.ControllerHealthInfo;
@@ -235,22 +234,17 @@ public void initAndRegisterEventSources(EventSourceContext<P> context) {
235234

236235
// register created event sources
237236
final var dependentResourcesByName =
238-
managedWorkflow.getDependentResourcesByNameWithoutActivationCondition();
237+
managedWorkflow.getDependentResourcesWithoutActivationCondition();
239238
final var size = dependentResourcesByName.size();
240239
if (size > 0) {
241-
dependentResourcesByName.forEach((key, dependentResource) -> {
242-
if (dependentResource instanceof EventSourceProvider provider) {
243-
final var source = provider.initEventSource(context);
244-
eventSourceManager.registerEventSource(key, source);
245-
} else {
246-
Optional<ResourceEventSource> eventSource = dependentResource.eventSource(context);
247-
eventSource.ifPresent(es -> eventSourceManager.registerEventSource(key, es));
248-
}
240+
dependentResourcesByName.forEach(dependentResource -> {
241+
Optional<ResourceEventSource> eventSource = dependentResource.eventSource(context);
242+
eventSource.ifPresent(eventSourceManager::registerEventSource);
249243
});
250244

251245
// resolve event sources referenced by name for dependents that reuse an existing event source
252246
final Map<String, List<EventSourceReferencer>> unresolvable = new HashMap<>(size);
253-
dependentResourcesByName.values().stream()
247+
dependentResourcesByName.stream()
254248
.filter(EventSourceReferencer.class::isInstance)
255249
.map(EventSourceReferencer.class::cast)
256250
.forEach(dr -> {

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

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

3+
import java.time.Duration;
4+
35
import io.fabric8.kubernetes.api.model.HasMetadata;
46
import io.javaoperatorsdk.operator.api.reconciler.Ignore;
57
import io.javaoperatorsdk.operator.processing.dependent.AbstractExternalDependentResource;
@@ -11,23 +13,23 @@ public abstract class AbstractPollingDependentResource<R, P extends HasMetadata>
1113
extends AbstractExternalDependentResource<R, P, ExternalResourceCachingEventSource<R, P>>
1214
implements CacheKeyMapper<R> {
1315

14-
public static final int DEFAULT_POLLING_PERIOD = 5000;
15-
private long pollingPeriod;
16+
public static final Duration DEFAULT_POLLING_PERIOD = Duration.ofMillis(5000);
17+
private Duration pollingPeriod;
1618

1719
protected AbstractPollingDependentResource(Class<R> resourceType) {
1820
this(resourceType, DEFAULT_POLLING_PERIOD);
1921
}
2022

21-
public AbstractPollingDependentResource(Class<R> resourceType, long pollingPeriod) {
23+
public AbstractPollingDependentResource(Class<R> resourceType, Duration pollingPeriod) {
2224
super(resourceType);
2325
this.pollingPeriod = pollingPeriod;
2426
}
2527

26-
public void setPollingPeriod(long pollingPeriod) {
28+
public void setPollingPeriod(Duration pollingPeriod) {
2729
this.pollingPeriod = pollingPeriod;
2830
}
2931

30-
public long getPollingPeriod() {
32+
public Duration getPollingPeriod() {
3133
return pollingPeriod;
3234
}
3335

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

+8-4
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
import io.javaoperatorsdk.operator.api.reconciler.EventSourceContext;
77
import io.javaoperatorsdk.operator.api.reconciler.Ignore;
88
import io.javaoperatorsdk.operator.processing.event.source.ExternalResourceCachingEventSource;
9+
import io.javaoperatorsdk.operator.processing.event.source.polling.PerResourcePollingConfigurationBuilder;
910
import io.javaoperatorsdk.operator.processing.event.source.polling.PerResourcePollingEventSource;
1011

1112
@Ignore
@@ -18,15 +19,18 @@ public PerResourcePollingDependentResource(Class<R> resourceType) {
1819
super(resourceType);
1920
}
2021

21-
public PerResourcePollingDependentResource(Class<R> resourceType, long pollingPeriod) {
22+
public PerResourcePollingDependentResource(Class<R> resourceType, Duration pollingPeriod) {
2223
super(resourceType, pollingPeriod);
2324
}
2425

2526
@Override
2627
protected ExternalResourceCachingEventSource<R, P> createEventSource(
2728
EventSourceContext<P> context) {
28-
return new PerResourcePollingEventSource<>(this, context,
29-
Duration.ofMillis(getPollingPeriod()), resourceType(), this);
30-
}
3129

30+
return new PerResourcePollingEventSource<>(name(), resourceType(), context,
31+
new PerResourcePollingConfigurationBuilder<>(
32+
this, getPollingPeriod())
33+
.withCacheKeyMapper(this)
34+
.build());
35+
}
3236
}

0 commit comments

Comments
 (0)