diff --git a/docs/content/en/docs/documentation/dependent-resource-and-workflows/dependent-resources.md b/docs/content/en/docs/documentation/dependent-resource-and-workflows/dependent-resources.md index 8a575f716f..1981729dc0 100644 --- a/docs/content/en/docs/documentation/dependent-resource-and-workflows/dependent-resources.md +++ b/docs/content/en/docs/documentation/dependent-resource-and-workflows/dependent-resources.md @@ -369,19 +369,22 @@ or we can use a matcher based SSA in most of the cases if the resource is manage ### Selecting the target resource Unfortunately this is not true for external resources. So to make sure we are selecting -the target resources from an event source, we provide a [mechanism](https://github.com/operator-framework/java-operator-sdk/blob/main/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/AbstractExternalDependentResource.java#L114-L138) that helps with that logic. -Your POJO representing an external resource can implement [`ExternalResourceIDProvider`](https://github.com/operator-framework/java-operator-sdk/blob/main/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/ExternalDependentIDProvider.java) : +the target resources from an event source, we provide a [mechanism](https://github.com/operator-framework/java-operator-sdk/blob/main/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/AbstractExternalDependentResource.java#L133-L147) that helps with that logic. +[`ResourceIDMapper`](https://github.com/operator-framework/java-operator-sdk/blob/main/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/ResourceIDMapper.java) +maps the resource to and ID and the ID of desired and actual resource is checked for equality. + +Your POJO representing an external resource can implement [`ResourceIDProvider`](https://github.com/operator-framework/java-operator-sdk/blob/main/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/ResourceIDProvider.java). +The default `ResourceIDMapper` implementation works on top of resource which implements the `ResourceIDProvider`: ```java -public interface ExternalDependentIDProvider { +public interface ResourceIDProvider { - T externalResourceId(); + T resourceId(); } ``` -That will provide an ID, what is used to check for equality for desired state and resources from event source caches. -Not that if some reason this mechanism does not suit for you, you can simply +Note that if those approaches does not work for your use case, you can simply override [`selectTargetSecondaryResource`](https://github.com/operator-framework/java-operator-sdk/blob/main/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/AbstractExternalDependentResource.java) method. diff --git a/docs/content/en/docs/migration/v5-2-migration.md b/docs/content/en/docs/migration/v5-2-migration.md new file mode 100644 index 0000000000..7bc28b6df7 --- /dev/null +++ b/docs/content/en/docs/migration/v5-2-migration.md @@ -0,0 +1,44 @@ +--- +title: Migrating from v5.1 to v5.2 +description: Migrating from v5.1 to v5.2 +--- + +Version 5.2 brings some breaking changes to certain components. This document provides +a migration guide for these changes. For all the new features, see the release notes. + +## Custom ID types across multiple components using ResourceIDMapper and ResourceIDProvider + +Working with the id of a resource is needed across various components in the framework. +Until this version, the components provided by the framework assumed that you could easily +convert the id of a resource into a String representation. For example, +[BulkDependentResources](https://github.com/operator-framework/java-operator-sdk/blob/main/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/BulkDependentResource.java#L46) +worked with a `Map` of resources, where the id was always of type String. + +Mainly because of the need to manage external dependent resources more elegantly, +we introduced a cross-cutting concept: [`ResourceIDMapper`](https://github.com/operator-framework/java-operator-sdk/blob/main/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/ResourceIDMapper.java), +which gets the ID of a resource. This is used across various components, see: + + - [`ExternalResourceCachingEventSource`](https://github.com/operator-framework/java-operator-sdk/blob/main/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/event/source/ExternalResourceCachingEventSource.java#L66) + - [`ExternalBulkDependentResource`](https://github.com/operator-framework/java-operator-sdk/blob/main/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/ExternalBulkDependentResource.java) + - [`AbstractExternalDependentResource`](https://github.com/operator-framework/java-operator-sdk/blob/main/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/AbstractExternalDependentResource.java#L39) + and its subclasses. + +We also added [`ResourceIDProvider`](https://github.com/operator-framework/java-operator-sdk/blob/main/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/ResourceIDProvider.java), +which you can implement in your Pojo representing a resource. + +The easiest way to migrate to this new approach is to implement this interface for your (external) resource +and set the ID type generics for the components above. The default implementation of the `ResourceIDMapper` +works with `ResourceIDProvider` (see [related implementation](https://github.com/operator-framework/java-operator-sdk/blob/main/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/ResourceIDMapper.java#L52)). + +If you cannot implement `ResourceIDProvider` because, for example, the class that represents the external resource is generated and final, +you can always set a custom `ResourceIDMapper` on the components above. + +See also: + - related issue: [link](https://github.com/operator-framework/java-operator-sdk/issues/2972) + - related pull requests: + - [2970](https://github.com/operator-framework/java-operator-sdk/pull/2970) + - [3020](https://github.com/operator-framework/java-operator-sdk/pull/3020) + + + + diff --git a/docs/content/fileList.txt b/docs/content/fileList.txt deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/ResourceIDMapper.java b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/ResourceIDMapper.java new file mode 100644 index 0000000000..9486953c93 --- /dev/null +++ b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/ResourceIDMapper.java @@ -0,0 +1,70 @@ +/* + * Copyright Java Operator SDK Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package io.javaoperatorsdk.operator.processing; + +import io.fabric8.kubernetes.api.model.HasMetadata; +import io.javaoperatorsdk.operator.processing.event.ResourceID; +import io.javaoperatorsdk.operator.processing.event.source.ExternalResourceCachingEventSource; + +/** + * Provides id for the target resource. This mapper is used across multiple components of the + * framework, like: + * + *
    + *
  • {@link io.javaoperatorsdk.operator.processing.dependent.AbstractExternalDependentResource} + *
  • {@link ExternalResourceCachingEventSource} + *
  • {@link io.javaoperatorsdk.operator.processing.dependent.KubernetesBulkDependentResource} + *
+ * + * @see ResourceIDProvider + */ +public interface ResourceIDMapper { + + /** + * @return id for the target resource. + */ + ID idFor(R resource); + + /** + * Can be used if a polling event source handles only single secondary resource and the id is + * String. See also docs for: {@link ExternalResourceCachingEventSource}; or in {@link + * io.javaoperatorsdk.operator.processing.dependent.AbstractExternalDependentResource} when there + * is always only one secondary resource for that dependent resource. By definition cannot be used + * for a BulkDependent resources. + * + * @return static id mapper, all resources are mapped for same id. + * @param secondary resource type + */ + static ResourceIDMapper singleResourceResourceIDMapper() { + return r -> "id"; + } + + @SuppressWarnings({"rawtypes", "unchecked"}) + static ResourceIDMapper resourceIdProviderMapper() { + return r -> { + if (r instanceof ResourceIDProvider resourceIDProvider) { + return (ID) resourceIDProvider.resourceId(); + } else { + throw new IllegalStateException( + "Resource does not implement ExternalDependentIDProvider: " + r.getClass()); + } + }; + } + + static ResourceIDMapper kubernetesResourceIdMapper() { + return ResourceID::fromResource; + } +} diff --git a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/ResourceIDProvider.java b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/ResourceIDProvider.java new file mode 100644 index 0000000000..b784f35744 --- /dev/null +++ b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/ResourceIDProvider.java @@ -0,0 +1,38 @@ +/* + * Copyright Java Operator SDK Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package io.javaoperatorsdk.operator.processing; + +/** + * Provides the identifier for an object that represents a resource. This ID is used: + * + *
    + *
  • to select the target external resource for a dependent resource from the resources returned + * by {@link io.javaoperatorsdk.operator.api.reconciler.Context#getSecondaryResources(Class)}, + *
  • used in {@link ResourceIDMapper} for event sources in external resources. But also for bulk + * dependent resource see {@link + * io.javaoperatorsdk.operator.processing.dependent.ExternalBulkDependentResource}, + *
  • and external event sources, see {@link + * io.javaoperatorsdk.operator.processing.event.source.ExternalResourceCachingEventSource} + *
+ * + * @see ResourceIDMapper + * @param type of the id + */ +public interface ResourceIDProvider { + + /** ID for the resource POJO that implement this interface. */ + ID resourceId(); +} diff --git a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/AbstractDependentResource.java b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/AbstractDependentResource.java index 9e827e16de..a7c5ce9e2d 100644 --- a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/AbstractDependentResource.java +++ b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/AbstractDependentResource.java @@ -63,7 +63,7 @@ protected AbstractDependentResource(String name) { dependentResourceReconciler = this instanceof BulkDependentResource - ? new BulkDependentResourceReconciler<>((BulkDependentResource) this) + ? new BulkDependentResourceReconciler<>((BulkDependentResource) this) : new SingleDependentResourceReconciler<>(this); this.name = name == null ? DependentResource.defaultNameFor(this.getClass()) : name; } diff --git a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/AbstractExternalDependentResource.java b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/AbstractExternalDependentResource.java index 2c5be82288..e601e937cf 100644 --- a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/AbstractExternalDependentResource.java +++ b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/AbstractExternalDependentResource.java @@ -22,19 +22,22 @@ import io.fabric8.kubernetes.api.model.HasMetadata; import io.javaoperatorsdk.operator.api.reconciler.Context; import io.javaoperatorsdk.operator.api.reconciler.dependent.RecentOperationCacheFiller; +import io.javaoperatorsdk.operator.processing.ResourceIDMapper; import io.javaoperatorsdk.operator.processing.event.EventSourceRetriever; import io.javaoperatorsdk.operator.processing.event.ResourceID; import io.javaoperatorsdk.operator.processing.event.source.EventSource; import io.javaoperatorsdk.operator.processing.event.source.informer.InformerEventSource; public abstract class AbstractExternalDependentResource< - R, P extends HasMetadata, T extends EventSource> + R, P extends HasMetadata, T extends EventSource, ID> extends AbstractEventSourceHolderDependentResource { private final boolean isDependentResourceWithExplicitState = this instanceof DependentResourceWithExplicitState; private final boolean isBulkDependentResource = this instanceof BulkDependentResource; + protected ResourceIDMapper resourceIDMapper = ResourceIDMapper.resourceIdProviderMapper(); + @SuppressWarnings("rawtypes") private DependentResourceWithExplicitState dependentResourceWithExplicitState; @@ -131,24 +134,23 @@ protected Optional selectTargetSecondaryResource( Set secondaryResources, P primary, Context

context) { R desired = desired(primary, context); List targetResources; - if (desired instanceof ExternalDependentIDProvider desiredWithId) { - targetResources = - secondaryResources.stream() - .filter( - r -> - ((ExternalDependentIDProvider) r) - .externalResourceId() - .equals(desiredWithId.externalResourceId())) - .toList(); - } else { - throw new IllegalStateException( - "Either implement ExternalDependentIDProvider or override this " - + " (selectTargetSecondaryResource) method."); - } + var desiredID = resourceIDMapper.idFor(desired); + targetResources = + secondaryResources.stream() + .filter(r -> resourceIDMapper.idFor(r).equals(desiredID)) + .toList(); if (targetResources.size() > 1) { throw new IllegalStateException( "More than one secondary resource related to primary: " + targetResources); } return targetResources.isEmpty() ? Optional.empty() : Optional.of(targetResources.get(0)); } + + public ResourceIDMapper resourceIDMapper() { + return resourceIDMapper; + } + + public void setResourceIDMapper(ResourceIDMapper resourceIDMapper) { + this.resourceIDMapper = resourceIDMapper; + } } diff --git a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/BulkDependentResource.java b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/BulkDependentResource.java index 89cd09d837..e13614df2e 100644 --- a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/BulkDependentResource.java +++ b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/BulkDependentResource.java @@ -27,10 +27,11 @@ * implementing this interface will typically also implement one or more additional interfaces such * as {@link Creator}, {@link Updater}, {@link Deleter}. * + * @param type of the id to distinguish resource * @param the dependent resource type * @param

the primary resource type */ -public interface BulkDependentResource { +public interface BulkDependentResource { /** * Retrieves a map of desired secondary resources associated with the specified primary resource, @@ -42,7 +43,7 @@ public interface BulkDependentResource { * @return a Map associating desired secondary resources with the specified primary via arbitrary * identifiers */ - default Map desiredResources(P primary, Context

context) { + default Map desiredResources(P primary, Context

context) { throw new IllegalStateException( "Implement desiredResources in case a non read-only bulk dependent resource"); } @@ -57,7 +58,7 @@ default Map desiredResources(P primary, Context

context) { * @return a Map associating actual secondary resources with the specified primary via arbitrary * identifiers */ - Map getSecondaryResources(P primary, Context

context); + Map getSecondaryResources(P primary, Context

context); /** * Deletes the actual resource identified by the specified key if it's not in the set of desired @@ -69,7 +70,7 @@ default Map desiredResources(P primary, Context

context) { * @param key key of the resource * @param context actual context */ - void deleteTargetResource(P primary, R resource, String key, Context

context); + void deleteTargetResource(P primary, R resource, ID key, Context

context); /** * Determines whether the specified secondary resource matches the desired state with target index diff --git a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/BulkDependentResourceReconciler.java b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/BulkDependentResourceReconciler.java index c808f75ea4..5b3617c26c 100644 --- a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/BulkDependentResourceReconciler.java +++ b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/BulkDependentResourceReconciler.java @@ -29,19 +29,19 @@ import io.javaoperatorsdk.operator.api.reconciler.dependent.ReconcileResult; import io.javaoperatorsdk.operator.processing.dependent.Matcher.Result; -class BulkDependentResourceReconciler +class BulkDependentResourceReconciler implements DependentResourceReconciler { - private final BulkDependentResource bulkDependentResource; + private final BulkDependentResource bulkDependentResource; - BulkDependentResourceReconciler(BulkDependentResource bulkDependentResource) { + BulkDependentResourceReconciler(BulkDependentResource bulkDependentResource) { this.bulkDependentResource = bulkDependentResource; } @Override public ReconcileResult reconcile(P primary, Context

context) { - Map actualResources = bulkDependentResource.getSecondaryResources(primary, context); + Map actualResources = bulkDependentResource.getSecondaryResources(primary, context); if (!(bulkDependentResource instanceof Creator) && !(bulkDependentResource instanceof Deleter) && !(bulkDependentResource instanceof Updater)) { @@ -73,7 +73,7 @@ public void delete(P primary, Context

context) { } private void deleteExtraResources( - Set expectedKeys, Map actualResources, P primary, Context

context) { + Set expectedKeys, Map actualResources, P primary, Context

context) { actualResources.forEach( (key, value) -> { if (!expectedKeys.contains(key)) { @@ -90,13 +90,13 @@ private void deleteExtraResources( * @param

*/ @Ignore - private static class BulkDependentResourceInstance + private static class BulkDependentResourceInstance extends AbstractDependentResource implements Creator, Deleter

, Updater { - private final BulkDependentResource bulkDependentResource; + private final BulkDependentResource bulkDependentResource; private final R desired; private BulkDependentResourceInstance( - BulkDependentResource bulkDependentResource, R desired) { + BulkDependentResource bulkDependentResource, R desired) { this.bulkDependentResource = bulkDependentResource; this.desired = desired; } diff --git a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/CRUDBulkDependentResource.java b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/CRUDBulkDependentResource.java index 565fcd65f6..59545f63d2 100644 --- a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/CRUDBulkDependentResource.java +++ b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/CRUDBulkDependentResource.java @@ -18,5 +18,5 @@ import io.fabric8.kubernetes.api.model.HasMetadata; import io.javaoperatorsdk.operator.api.reconciler.dependent.Deleter; -public interface CRUDBulkDependentResource - extends BulkDependentResource, Creator, BulkUpdater, Deleter

{} +public interface CRUDBulkDependentResource + extends BulkDependentResource, Creator, BulkUpdater, Deleter

{} diff --git a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/event/source/CacheKeyMapper.java b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/CRUDExternalBulkDependentResource.java similarity index 55% rename from operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/event/source/CacheKeyMapper.java rename to operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/CRUDExternalBulkDependentResource.java index 8038dd1555..f290bcbbbc 100644 --- a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/event/source/CacheKeyMapper.java +++ b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/CRUDExternalBulkDependentResource.java @@ -13,20 +13,12 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package io.javaoperatorsdk.operator.processing.event.source; +package io.javaoperatorsdk.operator.processing.dependent; -public interface CacheKeyMapper { +import io.fabric8.kubernetes.api.model.HasMetadata; +import io.javaoperatorsdk.operator.api.reconciler.dependent.Deleter; +import io.javaoperatorsdk.operator.processing.ResourceIDProvider; - String keyFor(R resource); - - /** - * Used if a polling event source handles only single secondary resource. See also docs for: - * {@link ExternalResourceCachingEventSource} - * - * @return static id mapper, all resources are mapped for same id. - * @param secondary resource type - */ - static CacheKeyMapper singleResourceCacheKeyMapper() { - return r -> "id"; - } -} +public interface CRUDExternalBulkDependentResource< + R extends ResourceIDProvider, P extends HasMetadata, ID> + extends ExternalBulkDependentResource, Creator, BulkUpdater, Deleter

{} diff --git a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/ExternalDependentIDProvider.java b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/CRUDKubernetesBulkDependentResource.java similarity index 63% rename from operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/ExternalDependentIDProvider.java rename to operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/CRUDKubernetesBulkDependentResource.java index b6c755178d..be15faf645 100644 --- a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/ExternalDependentIDProvider.java +++ b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/CRUDKubernetesBulkDependentResource.java @@ -15,14 +15,9 @@ */ package io.javaoperatorsdk.operator.processing.dependent; -/** - * Provides the identifier for an object that represents an external resource. This ID is used to - * select target resource for a dependent resource from the resources returned by `{@link - * io.javaoperatorsdk.operator.api.reconciler.Context#getSecondaryResources(Class)}`. - * - * @param - */ -public interface ExternalDependentIDProvider { +import io.fabric8.kubernetes.api.model.HasMetadata; +import io.javaoperatorsdk.operator.api.reconciler.dependent.Deleter; +import io.javaoperatorsdk.operator.processing.event.ResourceID; - T externalResourceId(); -} +public interface CRUDKubernetesBulkDependentResource + extends BulkDependentResource, Creator, BulkUpdater, Deleter

{} diff --git a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/ExternalBulkDependentResource.java b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/ExternalBulkDependentResource.java new file mode 100644 index 0000000000..4ac15980f7 --- /dev/null +++ b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/ExternalBulkDependentResource.java @@ -0,0 +1,33 @@ +/* + * Copyright Java Operator SDK Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package io.javaoperatorsdk.operator.processing.dependent; + +import io.fabric8.kubernetes.api.model.HasMetadata; +import io.javaoperatorsdk.operator.processing.ResourceIDMapper; +import io.javaoperatorsdk.operator.processing.ResourceIDProvider; + +/** + * Specialized interface for bulk dependent resources where resource implement {@link + * ResourceIDProvider}. + */ +public interface ExternalBulkDependentResource< + R extends ResourceIDProvider, P extends HasMetadata, ID> + extends ResourceIDMapperBulkDependentResource { + + default ResourceIDMapper resourceIDMapper() { + return ResourceIDMapper.resourceIdProviderMapper(); + } +} diff --git a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/KubernetesBulkDependentResource.java b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/KubernetesBulkDependentResource.java new file mode 100644 index 0000000000..025c4c65ff --- /dev/null +++ b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/KubernetesBulkDependentResource.java @@ -0,0 +1,35 @@ +/* + * Copyright Java Operator SDK Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package io.javaoperatorsdk.operator.processing.dependent; + +import io.fabric8.kubernetes.api.model.HasMetadata; +import io.javaoperatorsdk.operator.processing.ResourceIDMapper; +import io.javaoperatorsdk.operator.processing.event.ResourceID; + +/** + * A narrowed interface for bulk dependent resources for Kubernetes resources, that assumes that the + * ID is a {@link ResourceID}. Note that you are not limited to this when dealing with Kubernetes + * resources you can still choose a different ID type and directly implement {@link + * BulkDependentResource}. + */ +public interface KubernetesBulkDependentResource + extends ResourceIDMapperBulkDependentResource { + + @Override + default ResourceIDMapper resourceIDMapper() { + return ResourceIDMapper.kubernetesResourceIdMapper(); + } +} diff --git a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/ResourceIDMapperBulkDependentResource.java b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/ResourceIDMapperBulkDependentResource.java new file mode 100644 index 0000000000..7cdd861cf6 --- /dev/null +++ b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/ResourceIDMapperBulkDependentResource.java @@ -0,0 +1,52 @@ +/* + * Copyright Java Operator SDK Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package io.javaoperatorsdk.operator.processing.dependent; + +import java.util.Map; +import java.util.function.Function; +import java.util.function.Predicate; +import java.util.stream.Collectors; + +import io.fabric8.kubernetes.api.model.HasMetadata; +import io.javaoperatorsdk.operator.api.reconciler.Context; +import io.javaoperatorsdk.operator.api.reconciler.dependent.DependentResource; +import io.javaoperatorsdk.operator.processing.ResourceIDMapper; + +public interface ResourceIDMapperBulkDependentResource + extends BulkDependentResource, DependentResource { + + ResourceIDMapper resourceIDMapper(); + + @Override + default Map getSecondaryResources(P primary, Context

context) { + return context + .getSecondaryResourcesAsStream(resourceType()) + .filter(secondaryResourceFilter(primary, context)) + .collect(Collectors.toMap(cm -> resourceIDMapper().idFor(cm), Function.identity())); + } + + /** + * Override of not all the secondary resources of a certain type are related to the target + * secondary resource. + * + * @param primary resource + * @param context of reconciliation + * @return predicate to filter secondary resources which are related to the bulk dependent. + */ + default Predicate secondaryResourceFilter(P primary, Context

context) { + return r -> true; + } +} diff --git a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/external/AbstractPollingDependentResource.java b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/external/AbstractPollingDependentResource.java index 4b255a35d7..1776194e33 100644 --- a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/external/AbstractPollingDependentResource.java +++ b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/external/AbstractPollingDependentResource.java @@ -20,13 +20,12 @@ import io.fabric8.kubernetes.api.model.HasMetadata; import io.javaoperatorsdk.operator.api.reconciler.Ignore; import io.javaoperatorsdk.operator.processing.dependent.AbstractExternalDependentResource; -import io.javaoperatorsdk.operator.processing.event.source.CacheKeyMapper; import io.javaoperatorsdk.operator.processing.event.source.ExternalResourceCachingEventSource; @Ignore -public abstract class AbstractPollingDependentResource - extends AbstractExternalDependentResource> - implements CacheKeyMapper { +public abstract class AbstractPollingDependentResource + extends AbstractExternalDependentResource< + R, P, ExternalResourceCachingEventSource, ID> { public static final Duration DEFAULT_POLLING_PERIOD = Duration.ofMillis(5000); private Duration pollingPeriod; @@ -49,10 +48,4 @@ public void setPollingPeriod(Duration pollingPeriod) { public Duration getPollingPeriod() { return pollingPeriod; } - - // for now dependent resources support event sources only with one owned resource. - @Override - public String keyFor(R resource) { - return CacheKeyMapper.singleResourceCacheKeyMapper().keyFor(resource); - } } diff --git a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/external/PerResourcePollingDependentResource.java b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/external/PerResourcePollingDependentResource.java index 4df1dcf578..6b9aaf9c1e 100644 --- a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/external/PerResourcePollingDependentResource.java +++ b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/external/PerResourcePollingDependentResource.java @@ -20,34 +20,47 @@ import io.fabric8.kubernetes.api.model.HasMetadata; import io.javaoperatorsdk.operator.api.reconciler.EventSourceContext; import io.javaoperatorsdk.operator.api.reconciler.Ignore; +import io.javaoperatorsdk.operator.processing.ResourceIDMapper; import io.javaoperatorsdk.operator.processing.event.source.ExternalResourceCachingEventSource; import io.javaoperatorsdk.operator.processing.event.source.polling.PerResourcePollingConfigurationBuilder; import io.javaoperatorsdk.operator.processing.event.source.polling.PerResourcePollingEventSource; @Ignore -public abstract class PerResourcePollingDependentResource - extends AbstractPollingDependentResource +public abstract class PerResourcePollingDependentResource + extends AbstractPollingDependentResource implements PerResourcePollingEventSource.ResourceFetcher { - public PerResourcePollingDependentResource() {} + protected PerResourcePollingDependentResource() {} - public PerResourcePollingDependentResource(Class resourceType) { + protected PerResourcePollingDependentResource( + Class resourceType, ResourceIDMapper resourceIDMapper) { super(resourceType); + setResourceIDMapper(resourceIDMapper); } - public PerResourcePollingDependentResource(Class resourceType, Duration pollingPeriod) { + protected PerResourcePollingDependentResource(Class resourceType) { + super(resourceType); + } + + protected PerResourcePollingDependentResource(Class resourceType, Duration pollingPeriod) { + super(resourceType, pollingPeriod); + } + + protected PerResourcePollingDependentResource( + Class resourceType, Duration pollingPeriod, ResourceIDMapper resourceIDMapper) { super(resourceType, pollingPeriod); + setResourceIDMapper(resourceIDMapper); } @Override - protected ExternalResourceCachingEventSource createEventSource( + protected ExternalResourceCachingEventSource createEventSource( EventSourceContext

context) { return new PerResourcePollingEventSource<>( resourceType(), context, - new PerResourcePollingConfigurationBuilder<>(this, getPollingPeriod()) - .withCacheKeyMapper(this) + new PerResourcePollingConfigurationBuilder(this, getPollingPeriod()) + .withResourceIDMapper(resourceIDMapper()) .withName(name()) .build()); } diff --git a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/external/PollingDependentResource.java b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/external/PollingDependentResource.java index 6b80edc61a..894e359d57 100644 --- a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/external/PollingDependentResource.java +++ b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/external/PollingDependentResource.java @@ -20,34 +20,41 @@ import io.fabric8.kubernetes.api.model.HasMetadata; import io.javaoperatorsdk.operator.api.reconciler.EventSourceContext; import io.javaoperatorsdk.operator.api.reconciler.Ignore; -import io.javaoperatorsdk.operator.processing.event.source.CacheKeyMapper; +import io.javaoperatorsdk.operator.processing.ResourceIDMapper; import io.javaoperatorsdk.operator.processing.event.source.ExternalResourceCachingEventSource; import io.javaoperatorsdk.operator.processing.event.source.polling.PollingConfiguration; import io.javaoperatorsdk.operator.processing.event.source.polling.PollingEventSource; @Ignore -public abstract class PollingDependentResource - extends AbstractPollingDependentResource +public abstract class PollingDependentResource + extends AbstractPollingDependentResource implements PollingEventSource.GenericResourceFetcher { - private final CacheKeyMapper cacheKeyMapper; + protected PollingDependentResource(Class resourceType) { + super(resourceType); + } - public PollingDependentResource(Class resourceType, CacheKeyMapper cacheKeyMapper) { + protected PollingDependentResource( + Class resourceType, ResourceIDMapper resourceIDMapper) { super(resourceType); - this.cacheKeyMapper = cacheKeyMapper; + setResourceIDMapper(resourceIDMapper); + } + + protected PollingDependentResource(Class resourceType, Duration pollingPeriod) { + super(resourceType, pollingPeriod); } - public PollingDependentResource( - Class resourceType, Duration pollingPeriod, CacheKeyMapper cacheKeyMapper) { + protected PollingDependentResource( + Class resourceType, Duration pollingPeriod, ResourceIDMapper resourceIDMapper) { super(resourceType, pollingPeriod); - this.cacheKeyMapper = cacheKeyMapper; + setResourceIDMapper(resourceIDMapper); } @Override - protected ExternalResourceCachingEventSource createEventSource( + protected ExternalResourceCachingEventSource createEventSource( EventSourceContext

context) { return new PollingEventSource<>( resourceType(), - new PollingConfiguration<>(name(), this, getPollingPeriod(), cacheKeyMapper)); + new PollingConfiguration<>(name(), this, getPollingPeriod(), resourceIDMapper)); } } diff --git a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/kubernetes/KubernetesDependentResource.java b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/kubernetes/KubernetesDependentResource.java index efe25b9a43..05cddcade1 100644 --- a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/kubernetes/KubernetesDependentResource.java +++ b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/kubernetes/KubernetesDependentResource.java @@ -205,7 +205,7 @@ protected void handleDelete(P primary, R secondary, Context

context) { } @SuppressWarnings("unused") - public void deleteTargetResource(P primary, R resource, String key, Context

context) { + public void deleteTargetResource(P primary, R resource, ResourceID key, Context

context) { context.getClient().resource(resource).delete(); } diff --git a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/event/source/ExternalResourceCachingEventSource.java b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/event/source/ExternalResourceCachingEventSource.java index 1c4ce45cb9..de85b4aad4 100644 --- a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/event/source/ExternalResourceCachingEventSource.java +++ b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/event/source/ExternalResourceCachingEventSource.java @@ -32,6 +32,8 @@ import io.fabric8.kubernetes.api.model.HasMetadata; import io.javaoperatorsdk.operator.api.reconciler.dependent.RecentOperationCacheFiller; +import io.javaoperatorsdk.operator.processing.ResourceIDMapper; +import io.javaoperatorsdk.operator.processing.ResourceIDProvider; import io.javaoperatorsdk.operator.processing.event.Event; import io.javaoperatorsdk.operator.processing.event.ResourceID; @@ -42,7 +44,8 @@ *

There are two related concepts to understand: * *

    - *
  • CacheKeyMapper - maps/extracts a key used to reference the associated resource in the cache + *
  • ResourceIDMapper - maps/extracts a key used to reference the associated resource in the + * cache *
  • Object equals usage - compares if the two resources are the same or same version. *
* @@ -54,25 +57,30 @@ * @param type of polled external secondary resource * @param

primary resource */ -public abstract class ExternalResourceCachingEventSource +public abstract class ExternalResourceCachingEventSource extends AbstractEventSource implements RecentOperationCacheFiller { private static final Logger log = LoggerFactory.getLogger(ExternalResourceCachingEventSource.class); - protected final CacheKeyMapper cacheKeyMapper; + protected final ResourceIDMapper resourceIDMapper; - protected Map> cache = new ConcurrentHashMap<>(); + protected Map> cache = new ConcurrentHashMap<>(); protected ExternalResourceCachingEventSource( - Class resourceClass, CacheKeyMapper cacheKeyMapper) { - this(null, resourceClass, cacheKeyMapper); + Class resourceClass, ResourceIDMapper resourceIDMapper) { + this(null, resourceClass, resourceIDMapper); } protected ExternalResourceCachingEventSource( - String name, Class resourceClass, CacheKeyMapper cacheKeyMapper) { + String name, Class resourceClass, ResourceIDMapper resourceIDMapper) { super(resourceClass, name); - this.cacheKeyMapper = cacheKeyMapper; + if (resourceIDMapper == ResourceIDMapper.resourceIdProviderMapper() + && !ResourceIDProvider.class.isAssignableFrom(resourceClass)) { + throw new IllegalArgumentException( + "resource class is not a " + ResourceIDProvider.class.getSimpleName()); + } + this.resourceIDMapper = resourceIDMapper; } protected synchronized void handleDelete(ResourceID primaryID) { @@ -84,14 +92,14 @@ protected synchronized void handleDelete(ResourceID primaryID) { protected synchronized void handleDeletes(ResourceID primaryID, Set resource) { handleDelete( - primaryID, resource.stream().map(cacheKeyMapper::keyFor).collect(Collectors.toSet())); + primaryID, resource.stream().map(resourceIDMapper::idFor).collect(Collectors.toSet())); } protected synchronized void handleDelete(ResourceID primaryID, R resource) { - handleDelete(primaryID, Set.of(cacheKeyMapper.keyFor(resource))); + handleDelete(primaryID, Set.of(resourceIDMapper.idFor(resource))); } - protected synchronized void handleDelete(ResourceID primaryID, Set resourceIDs) { + protected synchronized void handleDelete(ResourceID primaryID, Set resourceIDs) { if (!isRunning()) { return; } @@ -137,7 +145,7 @@ protected synchronized void handleResources( cachedResources = Collections.emptyMap(); } var newResourcesMap = - newResources.stream().collect(Collectors.toMap(cacheKeyMapper::keyFor, r -> r)); + newResources.stream().collect(Collectors.toMap(resourceIDMapper::idFor, r -> r)); cache.put(primaryID, newResourcesMap); if (propagateEvent && !newResourcesMap.equals(cachedResources) @@ -146,8 +154,7 @@ && acceptedByFiler(cachedResources, newResourcesMap)) { } } - private boolean acceptedByFiler( - Map cachedResourceMap, Map newResourcesMap) { + private boolean acceptedByFiler(Map cachedResourceMap, Map newResourcesMap) { var addedResources = new HashMap<>(newResourcesMap); addedResources.keySet().removeAll(cachedResourceMap.keySet()); @@ -175,7 +182,7 @@ private boolean acceptedByFiler( return true; } - Map possibleUpdatedResources = new HashMap<>(cachedResourceMap); + Map possibleUpdatedResources = new HashMap<>(cachedResourceMap); possibleUpdatedResources.keySet().retainAll(newResourcesMap.keySet()); possibleUpdatedResources = possibleUpdatedResources.entrySet().stream() @@ -200,7 +207,7 @@ private boolean acceptedByGenericFiler(R resource) { @Override public synchronized void handleRecentResourceCreate(ResourceID primaryID, R resource) { var actualValues = cache.get(primaryID); - var resourceId = cacheKeyMapper.keyFor(resource); + var resourceId = resourceIDMapper.idFor(resource); if (actualValues == null) { actualValues = new HashMap<>(); cache.put(primaryID, actualValues); @@ -215,7 +222,7 @@ public synchronized void handleRecentResourceUpdate( ResourceID primaryID, R resource, R previousVersionOfResource) { var actualValues = cache.get(primaryID); if (actualValues != null) { - var resourceId = cacheKeyMapper.keyFor(resource); + var resourceId = resourceIDMapper.idFor(resource); R actualResource = actualValues.get(resourceId); if (actualResource.equals(previousVersionOfResource)) { actualValues.put(resourceId, resource); @@ -248,7 +255,7 @@ public Optional getSecondaryResource(ResourceID primaryID) { } } - public Map> getCache() { + public Map> getCache() { return Collections.unmodifiableMap(cache); } diff --git a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/event/source/inbound/CachingInboundEventSource.java b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/event/source/inbound/CachingInboundEventSource.java index 6c9e6ec660..44e0a684b6 100644 --- a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/event/source/inbound/CachingInboundEventSource.java +++ b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/event/source/inbound/CachingInboundEventSource.java @@ -21,13 +21,13 @@ import java.util.concurrent.ConcurrentHashMap; import io.fabric8.kubernetes.api.model.HasMetadata; +import io.javaoperatorsdk.operator.processing.ResourceIDMapper; import io.javaoperatorsdk.operator.processing.event.ResourceID; -import io.javaoperatorsdk.operator.processing.event.source.CacheKeyMapper; import io.javaoperatorsdk.operator.processing.event.source.ExternalResourceCachingEventSource; import io.javaoperatorsdk.operator.processing.event.source.ResourceEventAware; -public class CachingInboundEventSource - extends ExternalResourceCachingEventSource implements ResourceEventAware

{ +public class CachingInboundEventSource + extends ExternalResourceCachingEventSource implements ResourceEventAware

{ private final ResourceFetcher resourceFetcher; private final Set fetchedForPrimaries = ConcurrentHashMap.newKeySet(); @@ -35,8 +35,8 @@ public class CachingInboundEventSource public CachingInboundEventSource( ResourceFetcher resourceFetcher, Class resourceClass, - CacheKeyMapper cacheKeyMapper) { - super(resourceClass, cacheKeyMapper); + ResourceIDMapper resourceIDMapper) { + super(resourceClass, resourceIDMapper); this.resourceFetcher = resourceFetcher; } @@ -48,7 +48,7 @@ public void handleResourceEvent(ResourceID primaryID, R resource) { super.handleResources(primaryID, resource); } - public void handleResourceDeleteEvent(ResourceID primaryID, String resourceID) { + public void handleResourceDeleteEvent(ResourceID primaryID, ID resourceID) { super.handleDelete(primaryID, Set.of(resourceID)); } diff --git a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/event/source/polling/PerResourcePollingConfiguration.java b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/event/source/polling/PerResourcePollingConfiguration.java index a66b92cffd..599647ff29 100644 --- a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/event/source/polling/PerResourcePollingConfiguration.java +++ b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/event/source/polling/PerResourcePollingConfiguration.java @@ -22,12 +22,12 @@ import java.util.function.Predicate; import io.fabric8.kubernetes.api.model.HasMetadata; -import io.javaoperatorsdk.operator.processing.event.source.CacheKeyMapper; +import io.javaoperatorsdk.operator.processing.ResourceIDMapper; -public record PerResourcePollingConfiguration( +public record PerResourcePollingConfiguration( String name, ScheduledExecutorService executorService, - CacheKeyMapper cacheKeyMapper, + ResourceIDMapper resourceIDMapper, PerResourcePollingEventSource.ResourceFetcher resourceFetcher, Predicate

registerPredicate, Duration defaultPollingPeriod) { @@ -37,7 +37,7 @@ public record PerResourcePollingConfiguration( public PerResourcePollingConfiguration( String name, ScheduledExecutorService executorService, - CacheKeyMapper cacheKeyMapper, + ResourceIDMapper resourceIDMapper, PerResourcePollingEventSource.ResourceFetcher resourceFetcher, Predicate

registerPredicate, Duration defaultPollingPeriod) { @@ -46,8 +46,8 @@ public PerResourcePollingConfiguration( executorService == null ? new ScheduledThreadPoolExecutor(DEFAULT_EXECUTOR_THREAD_NUMBER) : executorService; - this.cacheKeyMapper = - cacheKeyMapper == null ? CacheKeyMapper.singleResourceCacheKeyMapper() : cacheKeyMapper; + this.resourceIDMapper = + resourceIDMapper == null ? ResourceIDMapper.resourceIdProviderMapper() : resourceIDMapper; this.resourceFetcher = Objects.requireNonNull(resourceFetcher); this.registerPredicate = registerPredicate; this.defaultPollingPeriod = defaultPollingPeriod; diff --git a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/event/source/polling/PerResourcePollingConfigurationBuilder.java b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/event/source/polling/PerResourcePollingConfigurationBuilder.java index 13a70bd9f2..6fcf5d2678 100644 --- a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/event/source/polling/PerResourcePollingConfigurationBuilder.java +++ b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/event/source/polling/PerResourcePollingConfigurationBuilder.java @@ -20,9 +20,9 @@ import java.util.function.Predicate; import io.fabric8.kubernetes.api.model.HasMetadata; -import io.javaoperatorsdk.operator.processing.event.source.CacheKeyMapper; +import io.javaoperatorsdk.operator.processing.ResourceIDMapper; -public final class PerResourcePollingConfigurationBuilder { +public final class PerResourcePollingConfigurationBuilder { private final Duration defaultPollingPeriod; private final PerResourcePollingEventSource.ResourceFetcher resourceFetcher; @@ -30,7 +30,7 @@ public final class PerResourcePollingConfigurationBuilder registerPredicate; private ScheduledExecutorService executorService; - private CacheKeyMapper cacheKeyMapper; + private ResourceIDMapper resourceIDMapper; public PerResourcePollingConfigurationBuilder( PerResourcePollingEventSource.ResourceFetcher resourceFetcher, @@ -40,34 +40,34 @@ public PerResourcePollingConfigurationBuilder( } @SuppressWarnings("unused") - public PerResourcePollingConfigurationBuilder withExecutorService( + public PerResourcePollingConfigurationBuilder withExecutorService( ScheduledExecutorService executorService) { this.executorService = executorService; return this; } - public PerResourcePollingConfigurationBuilder withRegisterPredicate( + public PerResourcePollingConfigurationBuilder withRegisterPredicate( Predicate

registerPredicate) { this.registerPredicate = registerPredicate; return this; } - public PerResourcePollingConfigurationBuilder withCacheKeyMapper( - CacheKeyMapper cacheKeyMapper) { - this.cacheKeyMapper = cacheKeyMapper; + public PerResourcePollingConfigurationBuilder withResourceIDMapper( + ResourceIDMapper resourceIDMapper) { + this.resourceIDMapper = resourceIDMapper; return this; } - public PerResourcePollingConfigurationBuilder withName(String name) { + public PerResourcePollingConfigurationBuilder withName(String name) { this.name = name; return this; } - public PerResourcePollingConfiguration build() { + public PerResourcePollingConfiguration build() { return new PerResourcePollingConfiguration<>( name, executorService, - cacheKeyMapper, + resourceIDMapper, resourceFetcher, registerPredicate, defaultPollingPeriod); diff --git a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/event/source/polling/PerResourcePollingEventSource.java b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/event/source/polling/PerResourcePollingEventSource.java index 2827c0bac0..0f0eb78a69 100644 --- a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/event/source/polling/PerResourcePollingEventSource.java +++ b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/event/source/polling/PerResourcePollingEventSource.java @@ -48,8 +48,8 @@ * @param the resource polled by the event source * @param

related custom resource */ -public class PerResourcePollingEventSource - extends ExternalResourceCachingEventSource implements ResourceEventAware

{ +public class PerResourcePollingEventSource + extends ExternalResourceCachingEventSource implements ResourceEventAware

{ private static final Logger log = LoggerFactory.getLogger(PerResourcePollingEventSource.class); @@ -65,8 +65,8 @@ public class PerResourcePollingEventSource public PerResourcePollingEventSource( Class resourceClass, EventSourceContext

context, - PerResourcePollingConfiguration config) { - super(config.name(), resourceClass, config.cacheKeyMapper()); + PerResourcePollingConfiguration config) { + super(config.name(), resourceClass, config.resourceIDMapper()); this.primaryResourceCache = context.getPrimaryCache(); this.resourceFetcher = config.resourceFetcher(); this.registerPredicate = config.registerPredicate(); diff --git a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/event/source/polling/PollingConfiguration.java b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/event/source/polling/PollingConfiguration.java index 56b6261a88..9ac1b8cc96 100644 --- a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/event/source/polling/PollingConfiguration.java +++ b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/event/source/polling/PollingConfiguration.java @@ -18,23 +18,23 @@ import java.time.Duration; import java.util.Objects; -import io.javaoperatorsdk.operator.processing.event.source.CacheKeyMapper; +import io.javaoperatorsdk.operator.processing.ResourceIDMapper; -public record PollingConfiguration( +public record PollingConfiguration( String name, PollingEventSource.GenericResourceFetcher genericResourceFetcher, Duration period, - CacheKeyMapper cacheKeyMapper) { + ResourceIDMapper resourceIDMapper) { public PollingConfiguration( String name, PollingEventSource.GenericResourceFetcher genericResourceFetcher, Duration period, - CacheKeyMapper cacheKeyMapper) { + ResourceIDMapper resourceIDMapper) { this.name = name; this.genericResourceFetcher = Objects.requireNonNull(genericResourceFetcher); this.period = period; - this.cacheKeyMapper = - cacheKeyMapper == null ? CacheKeyMapper.singleResourceCacheKeyMapper() : cacheKeyMapper; + this.resourceIDMapper = + resourceIDMapper == null ? ResourceIDMapper.resourceIdProviderMapper() : resourceIDMapper; } } diff --git a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/event/source/polling/PollingConfigurationBuilder.java b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/event/source/polling/PollingConfigurationBuilder.java index 8d922080eb..0e68876b60 100644 --- a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/event/source/polling/PollingConfigurationBuilder.java +++ b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/event/source/polling/PollingConfigurationBuilder.java @@ -17,12 +17,12 @@ import java.time.Duration; -import io.javaoperatorsdk.operator.processing.event.source.CacheKeyMapper; +import io.javaoperatorsdk.operator.processing.ResourceIDMapper; -public final class PollingConfigurationBuilder { +public final class PollingConfigurationBuilder { private final Duration period; private final PollingEventSource.GenericResourceFetcher genericResourceFetcher; - private CacheKeyMapper cacheKeyMapper; + private ResourceIDMapper resourceIDMapper; private String name; public PollingConfigurationBuilder( @@ -31,17 +31,18 @@ public PollingConfigurationBuilder( this.period = period; } - public PollingConfigurationBuilder withCacheKeyMapper(CacheKeyMapper cacheKeyMapper) { - this.cacheKeyMapper = cacheKeyMapper; + public PollingConfigurationBuilder withResourceIDMapper( + ResourceIDMapper resourceIDMapper) { + this.resourceIDMapper = resourceIDMapper; return this; } - public PollingConfigurationBuilder withName(String name) { + public PollingConfigurationBuilder withName(String name) { this.name = name; return this; } - public PollingConfiguration build() { - return new PollingConfiguration<>(name, genericResourceFetcher, period, cacheKeyMapper); + public PollingConfiguration build() { + return new PollingConfiguration<>(name, genericResourceFetcher, period, resourceIDMapper); } } diff --git a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/event/source/polling/PollingEventSource.java b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/event/source/polling/PollingEventSource.java index 04548e1a11..f5e5a79430 100644 --- a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/event/source/polling/PollingEventSource.java +++ b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/event/source/polling/PollingEventSource.java @@ -57,8 +57,8 @@ * @param type of the polled resource * @param

primary resource type */ -public class PollingEventSource - extends ExternalResourceCachingEventSource { +public class PollingEventSource + extends ExternalResourceCachingEventSource { private static final Logger log = LoggerFactory.getLogger(PollingEventSource.class); @@ -67,8 +67,8 @@ public class PollingEventSource private final Duration period; private final AtomicBoolean healthy = new AtomicBoolean(true); - public PollingEventSource(Class resourceClass, PollingConfiguration config) { - super(config.name(), resourceClass, config.cacheKeyMapper()); + public PollingEventSource(Class resourceClass, PollingConfiguration config) { + super(config.name(), resourceClass, config.resourceIDMapper()); this.genericResourceFetcher = config.genericResourceFetcher(); this.period = config.period(); } diff --git a/operator-framework-core/src/test/java/io/javaoperatorsdk/operator/processing/event/source/ExternalResourceCachingEventSourceTest.java b/operator-framework-core/src/test/java/io/javaoperatorsdk/operator/processing/event/source/ExternalResourceCachingEventSourceTest.java index 0fc5495545..889cc4da75 100644 --- a/operator-framework-core/src/test/java/io/javaoperatorsdk/operator/processing/event/source/ExternalResourceCachingEventSourceTest.java +++ b/operator-framework-core/src/test/java/io/javaoperatorsdk/operator/processing/event/source/ExternalResourceCachingEventSourceTest.java @@ -30,7 +30,8 @@ class ExternalResourceCachingEventSourceTest extends AbstractEventSourceTestBase< - ExternalResourceCachingEventSource, EventHandler> { + ExternalResourceCachingEventSource, + EventHandler> { @BeforeEach public void setup() { @@ -211,7 +212,7 @@ void genericFilteringEvents() { } public static class TestExternalCachingEventSource - extends ExternalResourceCachingEventSource { + extends ExternalResourceCachingEventSource { public TestExternalCachingEventSource() { super(SampleExternalResource.class, SampleExternalResource::getName); } diff --git a/operator-framework-core/src/test/java/io/javaoperatorsdk/operator/processing/event/source/SampleExternalResource.java b/operator-framework-core/src/test/java/io/javaoperatorsdk/operator/processing/event/source/SampleExternalResource.java index a6cebc0916..4abac62b2e 100644 --- a/operator-framework-core/src/test/java/io/javaoperatorsdk/operator/processing/event/source/SampleExternalResource.java +++ b/operator-framework-core/src/test/java/io/javaoperatorsdk/operator/processing/event/source/SampleExternalResource.java @@ -18,9 +18,10 @@ import java.io.Serializable; import java.util.Objects; +import io.javaoperatorsdk.operator.processing.ResourceIDProvider; import io.javaoperatorsdk.operator.processing.event.ResourceID; -public class SampleExternalResource implements Serializable { +public class SampleExternalResource implements Serializable, ResourceIDProvider { public static final String DEFAULT_VALUE_1 = "value1"; public static final String DEFAULT_VALUE_2 = "value2"; @@ -81,4 +82,9 @@ public boolean equals(Object o) { public int hashCode() { return Objects.hash(name, value); } + + @Override + public String resourceId() { + return name; + } } diff --git a/operator-framework-core/src/test/java/io/javaoperatorsdk/operator/processing/event/source/inbound/CachingInboundEventSourceTest.java b/operator-framework-core/src/test/java/io/javaoperatorsdk/operator/processing/event/source/inbound/CachingInboundEventSourceTest.java index e468e20561..9356de626b 100644 --- a/operator-framework-core/src/test/java/io/javaoperatorsdk/operator/processing/event/source/inbound/CachingInboundEventSourceTest.java +++ b/operator-framework-core/src/test/java/io/javaoperatorsdk/operator/processing/event/source/inbound/CachingInboundEventSourceTest.java @@ -21,10 +21,10 @@ import org.junit.jupiter.api.Test; import io.javaoperatorsdk.operator.TestUtils; +import io.javaoperatorsdk.operator.processing.ResourceIDMapper; import io.javaoperatorsdk.operator.processing.event.EventHandler; import io.javaoperatorsdk.operator.processing.event.ResourceID; import io.javaoperatorsdk.operator.processing.event.source.AbstractEventSourceTestBase; -import io.javaoperatorsdk.operator.processing.event.source.CacheKeyMapper; import io.javaoperatorsdk.operator.processing.event.source.SampleExternalResource; import io.javaoperatorsdk.operator.sample.simple.TestCustomResource; @@ -39,7 +39,8 @@ class CachingInboundEventSourceTest extends AbstractEventSourceTestBase< - CachingInboundEventSource, EventHandler> { + CachingInboundEventSource, + EventHandler> { @SuppressWarnings("unchecked") private final CachingInboundEventSource.ResourceFetcher< @@ -47,7 +48,7 @@ class CachingInboundEventSourceTest supplier = mock(CachingInboundEventSource.ResourceFetcher.class); private final TestCustomResource testCustomResource = TestUtils.testCustomResource(); - private final CacheKeyMapper cacheKeyMapper = + private final ResourceIDMapper resourceIDMapper = r -> r.getName() + "#" + r.getValue(); @BeforeEach @@ -55,7 +56,7 @@ public void setup() { when(supplier.fetchResources(any())).thenReturn(Set.of(SampleExternalResource.testResource1())); setUpSource( - new CachingInboundEventSource<>(supplier, SampleExternalResource.class, cacheKeyMapper)); + new CachingInboundEventSource<>(supplier, SampleExternalResource.class, resourceIDMapper)); } @Test @@ -89,10 +90,10 @@ void propagateEventOnDeletedResource() throws InterruptedException { ResourceID.fromResource(testCustomResource), SampleExternalResource.testResource1()); source.handleResourceDeleteEvent( ResourceID.fromResource(testCustomResource), - cacheKeyMapper.keyFor(SampleExternalResource.testResource1())); + resourceIDMapper.idFor(SampleExternalResource.testResource1())); source.handleResourceDeleteEvent( ResourceID.fromResource(testCustomResource), - cacheKeyMapper.keyFor(SampleExternalResource.testResource2())); + resourceIDMapper.idFor(SampleExternalResource.testResource2())); verify(eventHandler, times(2)).handleEvent(any()); } diff --git a/operator-framework-core/src/test/java/io/javaoperatorsdk/operator/processing/event/source/polling/PerResourcePollingEventSourceTest.java b/operator-framework-core/src/test/java/io/javaoperatorsdk/operator/processing/event/source/polling/PerResourcePollingEventSourceTest.java index cc5958cef4..907ed19fe5 100644 --- a/operator-framework-core/src/test/java/io/javaoperatorsdk/operator/processing/event/source/polling/PerResourcePollingEventSourceTest.java +++ b/operator-framework-core/src/test/java/io/javaoperatorsdk/operator/processing/event/source/polling/PerResourcePollingEventSourceTest.java @@ -25,9 +25,9 @@ import io.javaoperatorsdk.operator.TestUtils; import io.javaoperatorsdk.operator.api.reconciler.EventSourceContext; +import io.javaoperatorsdk.operator.processing.ResourceIDMapper; import io.javaoperatorsdk.operator.processing.event.EventHandler; import io.javaoperatorsdk.operator.processing.event.source.AbstractEventSourceTestBase; -import io.javaoperatorsdk.operator.processing.event.source.CacheKeyMapper; import io.javaoperatorsdk.operator.processing.event.source.IndexerResourceCache; import io.javaoperatorsdk.operator.processing.event.source.SampleExternalResource; import io.javaoperatorsdk.operator.sample.simple.TestCustomResource; @@ -40,7 +40,8 @@ class PerResourcePollingEventSourceTest extends AbstractEventSourceTestBase< - PerResourcePollingEventSource, EventHandler> { + PerResourcePollingEventSource, + EventHandler> { public static final int PERIOD = 150; @@ -66,8 +67,10 @@ public void setup() { new PerResourcePollingEventSource<>( SampleExternalResource.class, context, - new PerResourcePollingConfigurationBuilder<>(supplier, Duration.ofMillis(PERIOD)) - .withCacheKeyMapper(r -> r.getName() + "#" + r.getValue()) + new PerResourcePollingConfigurationBuilder< + SampleExternalResource, TestCustomResource, String>( + supplier, Duration.ofMillis(PERIOD)) + .withResourceIDMapper(r -> r.getName() + "#" + r.getValue()) .build())); } @@ -91,10 +94,12 @@ void registeringTaskOnAPredicate() { new PerResourcePollingEventSource<>( SampleExternalResource.class, context, - new PerResourcePollingConfigurationBuilder<>(supplier, Duration.ofMillis(PERIOD)) + new PerResourcePollingConfigurationBuilder< + SampleExternalResource, TestCustomResource, String>( + supplier, Duration.ofMillis(PERIOD)) .withRegisterPredicate( testCustomResource -> testCustomResource.getMetadata().getGeneration() > 1) - .withCacheKeyMapper(CacheKeyMapper.singleResourceCacheKeyMapper()) + .withResourceIDMapper(ResourceIDMapper.resourceIdProviderMapper()) .build())); source.onResourceCreated(testCustomResource); diff --git a/operator-framework-core/src/test/java/io/javaoperatorsdk/operator/processing/event/source/polling/PollingEventSourceTest.java b/operator-framework-core/src/test/java/io/javaoperatorsdk/operator/processing/event/source/polling/PollingEventSourceTest.java index 923a4915b9..fbf657ba0b 100644 --- a/operator-framework-core/src/test/java/io/javaoperatorsdk/operator/processing/event/source/polling/PollingEventSourceTest.java +++ b/operator-framework-core/src/test/java/io/javaoperatorsdk/operator/processing/event/source/polling/PollingEventSourceTest.java @@ -37,7 +37,7 @@ class PollingEventSourceTest extends AbstractEventSourceTestBase< - PollingEventSource, EventHandler> { + PollingEventSource, EventHandler> { public static final int DEFAULT_WAIT_PERIOD = 100; public static final Duration POLL_PERIOD = Duration.ofMillis(30L); @@ -46,7 +46,7 @@ class PollingEventSourceTest private final PollingEventSource.GenericResourceFetcher resourceFetcher = mock(PollingEventSource.GenericResourceFetcher.class); - private final PollingEventSource pollingEventSource = + private final PollingEventSource pollingEventSource = new PollingEventSource<>( SampleExternalResource.class, new PollingConfiguration<>( diff --git a/operator-framework/src/test/java/io/javaoperatorsdk/operator/baseapi/perresourceeventsource/PerResourcePollingEventSourceTestReconciler.java b/operator-framework/src/test/java/io/javaoperatorsdk/operator/baseapi/perresourceeventsource/PerResourcePollingEventSourceTestReconciler.java index c2233d931b..1e66ceacd5 100644 --- a/operator-framework/src/test/java/io/javaoperatorsdk/operator/baseapi/perresourceeventsource/PerResourcePollingEventSourceTestReconciler.java +++ b/operator-framework/src/test/java/io/javaoperatorsdk/operator/baseapi/perresourceeventsource/PerResourcePollingEventSourceTestReconciler.java @@ -27,6 +27,7 @@ import io.javaoperatorsdk.operator.api.reconciler.EventSourceContext; import io.javaoperatorsdk.operator.api.reconciler.Reconciler; import io.javaoperatorsdk.operator.api.reconciler.UpdateControl; +import io.javaoperatorsdk.operator.processing.ResourceIDMapper; import io.javaoperatorsdk.operator.processing.event.source.EventSource; import io.javaoperatorsdk.operator.processing.event.source.polling.PerResourcePollingConfigurationBuilder; import io.javaoperatorsdk.operator.processing.event.source.polling.PerResourcePollingEventSource; @@ -52,19 +53,22 @@ public UpdateControl reconcile( @Override public List> prepareEventSources( EventSourceContext context) { - PerResourcePollingEventSource eventSource = - new PerResourcePollingEventSource<>( - String.class, - context, - new PerResourcePollingConfigurationBuilder<>( - (PerResourceEventSourceCustomResource resource) -> { - numberOfFetchExecutions.putIfAbsent(resource.getMetadata().getName(), 0); - numberOfFetchExecutions.compute( - resource.getMetadata().getName(), (s, v) -> v + 1); - return Set.of(UUID.randomUUID().toString()); - }, - Duration.ofMillis(POLL_PERIOD)) - .build()); + PerResourcePollingEventSource + eventSource = + new PerResourcePollingEventSource<>( + String.class, + context, + new PerResourcePollingConfigurationBuilder< + String, PerResourceEventSourceCustomResource, String>( + (PerResourceEventSourceCustomResource resource) -> { + numberOfFetchExecutions.putIfAbsent(resource.getMetadata().getName(), 0); + numberOfFetchExecutions.compute( + resource.getMetadata().getName(), (s, v) -> v + 1); + return Set.of(UUID.randomUUID().toString()); + }, + Duration.ofMillis(POLL_PERIOD)) + .withResourceIDMapper(ResourceIDMapper.singleResourceResourceIDMapper()) + .build()); return List.of(eventSource); } diff --git a/operator-framework/src/test/java/io/javaoperatorsdk/operator/dependent/bulkdependent/ConfigMapDeleterBulkDependentResource.java b/operator-framework/src/test/java/io/javaoperatorsdk/operator/dependent/bulkdependent/ConfigMapDeleterBulkDependentResource.java index b234523a60..939039a8f5 100644 --- a/operator-framework/src/test/java/io/javaoperatorsdk/operator/dependent/bulkdependent/ConfigMapDeleterBulkDependentResource.java +++ b/operator-framework/src/test/java/io/javaoperatorsdk/operator/dependent/bulkdependent/ConfigMapDeleterBulkDependentResource.java @@ -23,13 +23,15 @@ import io.fabric8.kubernetes.api.model.ConfigMap; import io.fabric8.kubernetes.api.model.ObjectMetaBuilder; import io.javaoperatorsdk.operator.api.reconciler.Context; +import io.javaoperatorsdk.operator.processing.ResourceIDMapper; import io.javaoperatorsdk.operator.processing.dependent.*; import io.javaoperatorsdk.operator.processing.dependent.kubernetes.KubernetesDependentResource; +import io.javaoperatorsdk.operator.processing.event.ResourceID; /** Not using CRUDKubernetesDependentResource so the delete functionality can be tested. */ public class ConfigMapDeleterBulkDependentResource extends KubernetesDependentResource - implements CRUDBulkDependentResource { + implements CRUDKubernetesBulkDependentResource { public static final String LABEL_KEY = "bulk"; public static final String LABEL_VALUE = "true"; @@ -37,13 +39,14 @@ public class ConfigMapDeleterBulkDependentResource public static final String INDEX_DELIMITER = "-"; @Override - public Map desiredResources( + public Map desiredResources( BulkDependentTestCustomResource primary, Context context) { var number = primary.getSpec().getNumberOfResources(); - Map res = new HashMap<>(); + Map res = new HashMap<>(); for (int i = 0; i < number; i++) { var key = Integer.toString(i); - res.put(key, desired(primary, key)); + var desired = desired(primary, key); + res.put(ResourceIDMapper.kubernetesResourceIdMapper().idFor(desired), desired); } return res; } @@ -62,15 +65,12 @@ public ConfigMap desired(BulkDependentTestCustomResource primary, String key) { } @Override - public Map getSecondaryResources( + public Map getSecondaryResources( BulkDependentTestCustomResource primary, Context context) { return context .getSecondaryResourcesAsStream(ConfigMap.class) .filter(cm -> getName(cm).startsWith(primary.getMetadata().getName())) - .collect( - Collectors.toMap( - cm -> getName(cm).substring(getName(cm).lastIndexOf(INDEX_DELIMITER) + 1), - Function.identity())); + .collect(Collectors.toMap(ResourceID::fromResource, Function.identity())); } private static String getName(ConfigMap cm) { diff --git a/operator-framework/src/test/java/io/javaoperatorsdk/operator/dependent/bulkdependent/external/ExternalBulkResourceReconciler.java b/operator-framework/src/test/java/io/javaoperatorsdk/operator/dependent/bulkdependent/external/ExternalBulkResourceReconciler.java index 28d65ecd5a..6753ee51fd 100644 --- a/operator-framework/src/test/java/io/javaoperatorsdk/operator/dependent/bulkdependent/external/ExternalBulkResourceReconciler.java +++ b/operator-framework/src/test/java/io/javaoperatorsdk/operator/dependent/bulkdependent/external/ExternalBulkResourceReconciler.java @@ -19,7 +19,7 @@ import io.javaoperatorsdk.operator.api.reconciler.dependent.Dependent; import io.javaoperatorsdk.operator.dependent.bulkdependent.BulkDependentTestCustomResource; -@Workflow(dependents = @Dependent(type = ExternalBulkDependentResource.class)) +@Workflow(dependents = @Dependent(type = SampleExternalBulkDependentResource.class)) @ControllerConfiguration() public class ExternalBulkResourceReconciler implements Reconciler { diff --git a/operator-framework/src/test/java/io/javaoperatorsdk/operator/dependent/bulkdependent/external/ExternalResource.java b/operator-framework/src/test/java/io/javaoperatorsdk/operator/dependent/bulkdependent/external/ExternalResource.java index fff4f70656..a9fb27e56d 100644 --- a/operator-framework/src/test/java/io/javaoperatorsdk/operator/dependent/bulkdependent/external/ExternalResource.java +++ b/operator-framework/src/test/java/io/javaoperatorsdk/operator/dependent/bulkdependent/external/ExternalResource.java @@ -17,7 +17,9 @@ import java.util.Objects; -public class ExternalResource { +import io.javaoperatorsdk.operator.processing.ResourceIDProvider; + +public class ExternalResource implements ResourceIDProvider { private final String id; private final String data; @@ -47,4 +49,9 @@ public boolean equals(Object o) { public int hashCode() { return Objects.hash(id, data); } + + @Override + public String resourceId() { + return id; + } } diff --git a/operator-framework/src/test/java/io/javaoperatorsdk/operator/dependent/bulkdependent/external/ExternalBulkDependentResource.java b/operator-framework/src/test/java/io/javaoperatorsdk/operator/dependent/bulkdependent/external/SampleExternalBulkDependentResource.java similarity index 71% rename from operator-framework/src/test/java/io/javaoperatorsdk/operator/dependent/bulkdependent/external/ExternalBulkDependentResource.java rename to operator-framework/src/test/java/io/javaoperatorsdk/operator/dependent/bulkdependent/external/SampleExternalBulkDependentResource.java index d6f3893674..ba8a4a205a 100644 --- a/operator-framework/src/test/java/io/javaoperatorsdk/operator/dependent/bulkdependent/external/ExternalBulkDependentResource.java +++ b/operator-framework/src/test/java/io/javaoperatorsdk/operator/dependent/bulkdependent/external/SampleExternalBulkDependentResource.java @@ -19,29 +19,24 @@ import java.util.HashSet; import java.util.Map; import java.util.Set; -import java.util.stream.Collectors; +import java.util.function.Predicate; import io.javaoperatorsdk.operator.api.reconciler.Context; -import io.javaoperatorsdk.operator.api.reconciler.dependent.Deleter; import io.javaoperatorsdk.operator.dependent.bulkdependent.BulkDependentTestCustomResource; -import io.javaoperatorsdk.operator.processing.dependent.BulkDependentResource; -import io.javaoperatorsdk.operator.processing.dependent.BulkUpdater; -import io.javaoperatorsdk.operator.processing.dependent.Creator; +import io.javaoperatorsdk.operator.processing.dependent.CRUDExternalBulkDependentResource; import io.javaoperatorsdk.operator.processing.dependent.external.PollingDependentResource; import io.javaoperatorsdk.operator.processing.event.ResourceID; -public class ExternalBulkDependentResource - extends PollingDependentResource - implements BulkDependentResource, - Creator, - Deleter, - BulkUpdater { +public class SampleExternalBulkDependentResource + extends PollingDependentResource + implements CRUDExternalBulkDependentResource< + ExternalResource, BulkDependentTestCustomResource, String> { public static final String EXTERNAL_RESOURCE_NAME_DELIMITER = "#"; private final ExternalServiceMock externalServiceMock = ExternalServiceMock.getInstance(); - public ExternalBulkDependentResource() { + public SampleExternalBulkDependentResource() { super(ExternalResource.class, ExternalResource::getId); } @@ -95,33 +90,24 @@ public Map desiredResources( Map res = new HashMap<>(); for (int i = 0; i < number; i++) { var key = Integer.toString(i); - res.put( - key, + var resource = new ExternalResource( - toExternalResourceId(primary, key), primary.getSpec().getAdditionalData())); + toExternalResourceId(primary, key), primary.getSpec().getAdditionalData()); + res.put(resourceIDMapper().idFor(resource), resource); } return res; } @Override - public Map getSecondaryResources( + public Predicate secondaryResourceFilter( BulkDependentTestCustomResource primary, Context context) { - return context - .getSecondaryResourcesAsStream(resourceType()) - .filter( - r -> - r.getId() - .startsWith( - primary.getMetadata().getName() - + EXTERNAL_RESOURCE_NAME_DELIMITER - + primary.getMetadata().getNamespace() - + EXTERNAL_RESOURCE_NAME_DELIMITER)) - .collect( - Collectors.toMap( - r -> - r.getId() - .substring(r.getId().lastIndexOf(EXTERNAL_RESOURCE_NAME_DELIMITER) + 1), - r -> r)); + return r -> + r.getId() + .startsWith( + primary.getMetadata().getName() + + EXTERNAL_RESOURCE_NAME_DELIMITER + + primary.getMetadata().getNamespace() + + EXTERNAL_RESOURCE_NAME_DELIMITER); } @Override diff --git a/operator-framework/src/test/java/io/javaoperatorsdk/operator/dependent/bulkdependent/readonly/ReadOnlyBulkDependentResource.java b/operator-framework/src/test/java/io/javaoperatorsdk/operator/dependent/bulkdependent/readonly/ReadOnlyBulkDependentResource.java index 01f68f2c77..2d5b612ad8 100644 --- a/operator-framework/src/test/java/io/javaoperatorsdk/operator/dependent/bulkdependent/readonly/ReadOnlyBulkDependentResource.java +++ b/operator-framework/src/test/java/io/javaoperatorsdk/operator/dependent/bulkdependent/readonly/ReadOnlyBulkDependentResource.java @@ -15,15 +15,13 @@ */ package io.javaoperatorsdk.operator.dependent.bulkdependent.readonly; -import java.util.Map; import java.util.Set; -import java.util.function.Function; -import java.util.stream.Collectors; +import java.util.function.Predicate; import io.fabric8.kubernetes.api.model.ConfigMap; import io.javaoperatorsdk.operator.api.reconciler.Context; import io.javaoperatorsdk.operator.dependent.bulkdependent.BulkDependentTestCustomResource; -import io.javaoperatorsdk.operator.processing.dependent.BulkDependentResource; +import io.javaoperatorsdk.operator.processing.dependent.KubernetesBulkDependentResource; import io.javaoperatorsdk.operator.processing.dependent.kubernetes.KubernetesDependent; import io.javaoperatorsdk.operator.processing.dependent.kubernetes.KubernetesDependentResource; import io.javaoperatorsdk.operator.processing.event.ResourceID; @@ -33,21 +31,15 @@ @KubernetesDependent public class ReadOnlyBulkDependentResource extends KubernetesDependentResource - implements BulkDependentResource, + implements KubernetesBulkDependentResource, SecondaryToPrimaryMapper { public static final String INDEX_DELIMITER = "-"; @Override - public Map getSecondaryResources( + public Predicate secondaryResourceFilter( BulkDependentTestCustomResource primary, Context context) { - return context - .getSecondaryResourcesAsStream(ConfigMap.class) - .filter(cm -> getName(cm).startsWith(primary.getMetadata().getName())) - .collect( - Collectors.toMap( - cm -> getName(cm).substring(getName(cm).lastIndexOf(INDEX_DELIMITER) + 1), - Function.identity())); + return cm -> getName(cm).startsWith(primary.getMetadata().getName()); } private static String getName(ConfigMap cm) { diff --git a/operator-framework/src/test/java/io/javaoperatorsdk/operator/dependent/bulkdependent/readonly/ReadOnlyBulkReadyPostCondition.java b/operator-framework/src/test/java/io/javaoperatorsdk/operator/dependent/bulkdependent/readonly/ReadOnlyBulkReadyPostCondition.java index 110ec0d4f0..cc331e70f0 100644 --- a/operator-framework/src/test/java/io/javaoperatorsdk/operator/dependent/bulkdependent/readonly/ReadOnlyBulkReadyPostCondition.java +++ b/operator-framework/src/test/java/io/javaoperatorsdk/operator/dependent/bulkdependent/readonly/ReadOnlyBulkReadyPostCondition.java @@ -32,7 +32,7 @@ public boolean isMet( var minResourceNumber = primary.getSpec().getNumberOfResources(); @SuppressWarnings("unchecked") var secondaryResources = - ((BulkDependentResource) dependentResource) + ((BulkDependentResource) dependentResource) .getSecondaryResources(primary, context); return minResourceNumber <= secondaryResources.size(); } diff --git a/operator-framework/src/test/java/io/javaoperatorsdk/operator/dependent/externalstate/ExternalStateReconciler.java b/operator-framework/src/test/java/io/javaoperatorsdk/operator/dependent/externalstate/ExternalStateReconciler.java index d1a03b0c8e..de485cfc4e 100644 --- a/operator-framework/src/test/java/io/javaoperatorsdk/operator/dependent/externalstate/ExternalStateReconciler.java +++ b/operator-framework/src/test/java/io/javaoperatorsdk/operator/dependent/externalstate/ExternalStateReconciler.java @@ -56,7 +56,7 @@ public class ExternalStateReconciler private final ExternalIDGenServiceMock externalService = ExternalIDGenServiceMock.getInstance(); InformerEventSource configMapEventSource; - PerResourcePollingEventSource + PerResourcePollingEventSource externalResourceEventSource; @Override @@ -158,10 +158,13 @@ public List> prepareEventSources( return externalResource.map(Set::of).orElseGet(Collections::emptySet); }; externalResourceEventSource = - new PerResourcePollingEventSource<>( + new PerResourcePollingEventSource( ExternalResource.class, context, - new PerResourcePollingConfigurationBuilder<>(fetcher, Duration.ofMillis(300L)).build()); + new PerResourcePollingConfigurationBuilder< + ExternalResource, ExternalStateCustomResource, String>( + fetcher, Duration.ofMillis(300L)) + .build()); return Arrays.asList(configMapEventSource, externalResourceEventSource); } diff --git a/operator-framework/src/test/java/io/javaoperatorsdk/operator/dependent/externalstate/ExternalWithStateDependentResource.java b/operator-framework/src/test/java/io/javaoperatorsdk/operator/dependent/externalstate/ExternalWithStateDependentResource.java index c264ff52c7..e31578a843 100644 --- a/operator-framework/src/test/java/io/javaoperatorsdk/operator/dependent/externalstate/ExternalWithStateDependentResource.java +++ b/operator-framework/src/test/java/io/javaoperatorsdk/operator/dependent/externalstate/ExternalWithStateDependentResource.java @@ -33,7 +33,8 @@ import io.javaoperatorsdk.operator.support.ExternalResource; public class ExternalWithStateDependentResource - extends PerResourcePollingDependentResource + extends PerResourcePollingDependentResource< + ExternalResource, ExternalStateCustomResource, String> implements DependentResourceWithExplicitState< ExternalResource, ExternalStateCustomResource, ConfigMap>, Updater { diff --git a/operator-framework/src/test/java/io/javaoperatorsdk/operator/dependent/externalstate/externalstatebulkdependent/BulkDependentResourceExternalWithState.java b/operator-framework/src/test/java/io/javaoperatorsdk/operator/dependent/externalstate/externalstatebulkdependent/BulkDependentResourceExternalWithState.java index 696b02c01e..ba08f7fdfa 100644 --- a/operator-framework/src/test/java/io/javaoperatorsdk/operator/dependent/externalstate/externalstatebulkdependent/BulkDependentResourceExternalWithState.java +++ b/operator-framework/src/test/java/io/javaoperatorsdk/operator/dependent/externalstate/externalstatebulkdependent/BulkDependentResourceExternalWithState.java @@ -34,9 +34,11 @@ public class BulkDependentResourceExternalWithState extends PerResourcePollingDependentResource< - ExternalResource, ExternalStateBulkDependentCustomResource> - implements BulkDependentResource, - CRUDBulkDependentResource, + ExternalResource, ExternalStateBulkDependentCustomResource, String> + implements BulkDependentResource< + ExternalResource, ExternalStateBulkDependentCustomResource, String>, + CRUDBulkDependentResource< + ExternalResource, ExternalStateBulkDependentCustomResource, String>, DependentResourceWithExplicitState< ExternalResource, ExternalStateBulkDependentCustomResource, ConfigMap> { @@ -45,6 +47,7 @@ public class BulkDependentResourceExternalWithState public BulkDependentResourceExternalWithState() { super(ExternalResource.class, Duration.ofMillis(300)); + setResourceIDMapper(this::externalResourceIndex); } @Override @@ -159,9 +162,4 @@ private String configMapName( ExternalStateBulkDependentCustomResource primary, ExternalResource resource) { return primary.getMetadata().getName() + DELIMITER + externalResourceIndex(resource); } - - @Override - public String keyFor(ExternalResource resource) { - return externalResourceIndex(resource); - } } diff --git a/operator-framework/src/test/java/io/javaoperatorsdk/operator/dependent/multiplemanagedexternaldependenttype/AbstractExternalDependentResource.java b/operator-framework/src/test/java/io/javaoperatorsdk/operator/dependent/multiplemanagedexternaldependenttype/AbstractExternalDependentResource.java index 743e6b94f9..7c39a7db9a 100644 --- a/operator-framework/src/test/java/io/javaoperatorsdk/operator/dependent/multiplemanagedexternaldependenttype/AbstractExternalDependentResource.java +++ b/operator-framework/src/test/java/io/javaoperatorsdk/operator/dependent/multiplemanagedexternaldependenttype/AbstractExternalDependentResource.java @@ -30,7 +30,7 @@ public abstract class AbstractExternalDependentResource extends PollingDependentResource< - ExternalResource, MultipleManagedExternalDependentResourceCustomResource> + ExternalResource, MultipleManagedExternalDependentResourceCustomResource, String> implements Creator, Updater, Deleter { diff --git a/operator-framework/src/test/java/io/javaoperatorsdk/operator/dependent/multiplemanagedexternaldependenttype/MultipleManagedExternalDependentResourceReconciler.java b/operator-framework/src/test/java/io/javaoperatorsdk/operator/dependent/multiplemanagedexternaldependenttype/MultipleManagedExternalDependentResourceReconciler.java index 9380895105..dec9422486 100644 --- a/operator-framework/src/test/java/io/javaoperatorsdk/operator/dependent/multiplemanagedexternaldependenttype/MultipleManagedExternalDependentResourceReconciler.java +++ b/operator-framework/src/test/java/io/javaoperatorsdk/operator/dependent/multiplemanagedexternaldependenttype/MultipleManagedExternalDependentResourceReconciler.java @@ -91,13 +91,15 @@ public int getNumberOfExecutions() { return res; }; - PollingEventSource + PollingEventSource< + ExternalResource, MultipleManagedExternalDependentResourceCustomResource, String> pollingEventSource = new PollingEventSource<>( ExternalResource.class, - new PollingConfigurationBuilder<>(fetcher, Duration.ofMillis(1000L)) + new PollingConfigurationBuilder( + fetcher, Duration.ofMillis(1000L)) .withName(EVENT_SOURCE_NAME) - .withCacheKeyMapper(ExternalResource::getId) + .withResourceIDMapper(ExternalResource::getId) .build()); return List.of(pollingEventSource); diff --git a/operator-framework/src/test/java/io/javaoperatorsdk/operator/support/ExternalResource.java b/operator-framework/src/test/java/io/javaoperatorsdk/operator/support/ExternalResource.java index f281fe95db..d581f3c624 100644 --- a/operator-framework/src/test/java/io/javaoperatorsdk/operator/support/ExternalResource.java +++ b/operator-framework/src/test/java/io/javaoperatorsdk/operator/support/ExternalResource.java @@ -18,10 +18,10 @@ import java.util.Objects; import io.fabric8.kubernetes.api.model.HasMetadata; -import io.javaoperatorsdk.operator.processing.dependent.ExternalDependentIDProvider; +import io.javaoperatorsdk.operator.processing.ResourceIDProvider; import io.javaoperatorsdk.operator.processing.event.ResourceID; -public class ExternalResource implements ExternalDependentIDProvider { +public class ExternalResource implements ResourceIDProvider { public static final String EXTERNAL_RESOURCE_NAME_DELIMITER = "#"; @@ -83,7 +83,7 @@ public static String toExternalResourceId(HasMetadata primary) { } @Override - public String externalResourceId() { + public String resourceId() { return id; } } diff --git a/sample-operators/mysql-schema/src/main/java/io/javaoperatorsdk/operator/sample/dependent/SchemaDependentResource.java b/sample-operators/mysql-schema/src/main/java/io/javaoperatorsdk/operator/sample/dependent/SchemaDependentResource.java index 4c510edee5..6400d312c7 100644 --- a/sample-operators/mysql-schema/src/main/java/io/javaoperatorsdk/operator/sample/dependent/SchemaDependentResource.java +++ b/sample-operators/mysql-schema/src/main/java/io/javaoperatorsdk/operator/sample/dependent/SchemaDependentResource.java @@ -58,7 +58,7 @@ with = ResourcePollerConfig.class, converter = ResourcePollerConfigConverter.class) public class SchemaDependentResource - extends PerResourcePollingDependentResource + extends PerResourcePollingDependentResource implements ConfiguredDependentResource, Creator, Deleter { diff --git a/sample-operators/mysql-schema/src/main/java/io/javaoperatorsdk/operator/sample/schema/Schema.java b/sample-operators/mysql-schema/src/main/java/io/javaoperatorsdk/operator/sample/schema/Schema.java index baaa829534..a7c001ffe5 100644 --- a/sample-operators/mysql-schema/src/main/java/io/javaoperatorsdk/operator/sample/schema/Schema.java +++ b/sample-operators/mysql-schema/src/main/java/io/javaoperatorsdk/operator/sample/schema/Schema.java @@ -18,9 +18,9 @@ import java.io.Serializable; import java.util.Objects; -import io.javaoperatorsdk.operator.processing.dependent.ExternalDependentIDProvider; +import io.javaoperatorsdk.operator.processing.ResourceIDProvider; -public class Schema implements Serializable, ExternalDependentIDProvider { +public class Schema implements Serializable, ResourceIDProvider { private final String name; private final String characterSet; @@ -57,7 +57,7 @@ public String toString() { } @Override - public String externalResourceId() { + public String resourceId() { return name; } }