Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -370,13 +370,13 @@ or we can use a matcher based SSA in most of the cases if the resource is manage

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) :
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) :

```java

public interface ExternalDependentIDProvider<T> {
public interface ResourceIDProvider<T> {

T externalResourceId();
T resourceId();
}
```

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
/*
* 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.javaoperatorsdk.operator.processing.event.source.ExternalResourceCachingEventSource;

/** Provides id for the target resource. */
public interface ResourceIDMapper<R, ID> {

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}
*
* @return static id mapper, all resources are mapped for same id.
* @param <T> secondary resource type
*/
static <T> ResourceIDMapper<T, String> singleResourceCacheKeyMapper() {
return r -> "id";
}

static <T, ID> ResourceIDMapper<T, ID> resourceIdProviderMapper() {
return r -> {
if (r instanceof ResourceIDProvider resourceIDProvider) {
return (ID) resourceIDProvider.resourceId();
} else {
throw new IllegalStateException(
"Resource does not implement ExternalDependentIDProvider: " + r.getClass());
}
};
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -13,16 +13,17 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package io.javaoperatorsdk.operator.processing.dependent;
package io.javaoperatorsdk.operator.processing;

/**
* 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)}`.
* Provides the identifier for an object that represents resource. This ID is used to select target
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
* Provides the identifier for an object that represents resource. This ID is used to select target
* 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)}`. But also for
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
* io.javaoperatorsdk.operator.api.reconciler.Context#getSecondaryResources(Class)}`. But also for
* io.javaoperatorsdk.operator.api.reconciler.Context#getSecondaryResources(Class)}`. Is is also used as

* {@link ResourceIDMapper} for event sources in external resources
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
* {@link ResourceIDMapper} for event sources in external resources
* {@link ResourceIDMapper} for event sources in external resources.

*
* @param <T>
*/
public interface ExternalDependentIDProvider<T> {
public interface ResourceIDProvider<T> {

T externalResourceId();
T resourceId();
}
Original file line number Diff line number Diff line change
Expand Up @@ -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>>
R, P extends HasMetadata, T extends EventSource<R, P>, ID>
extends AbstractEventSourceHolderDependentResource<R, P, T> {

private final boolean isDependentResourceWithExplicitState =
this instanceof DependentResourceWithExplicitState;
private final boolean isBulkDependentResource = this instanceof BulkDependentResource;

protected ResourceIDMapper<R, ID> resourceIDMapper = ResourceIDMapper.resourceIdProviderMapper();

@SuppressWarnings("rawtypes")
private DependentResourceWithExplicitState dependentResourceWithExplicitState;

Expand Down Expand Up @@ -131,24 +134,23 @@ protected Optional<R> selectTargetSecondaryResource(
Set<R> secondaryResources, P primary, Context<P> context) {
R desired = desired(primary, context);
List<R> 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<R, ID> getResourceIDMapper() {
return resourceIDMapper;
}

public void setResourceIDMapper(ResourceIDMapper<R, ID> resourceIDMapper) {
this.resourceIDMapper = resourceIDMapper;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -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<R, P extends HasMetadata>
extends AbstractExternalDependentResource<R, P, ExternalResourceCachingEventSource<R, P>>
implements CacheKeyMapper<R> {
public abstract class AbstractPollingDependentResource<R, P extends HasMetadata, ID>
extends AbstractExternalDependentResource<
R, P, ExternalResourceCachingEventSource<R, P, ID>, ID> {

public static final Duration DEFAULT_POLLING_PERIOD = Duration.ofMillis(5000);
private Duration pollingPeriod;
Expand All @@ -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);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -25,8 +25,8 @@
import io.javaoperatorsdk.operator.processing.event.source.polling.PerResourcePollingEventSource;

@Ignore
public abstract class PerResourcePollingDependentResource<R, P extends HasMetadata>
extends AbstractPollingDependentResource<R, P>
public abstract class PerResourcePollingDependentResource<R, P extends HasMetadata, ID>
extends AbstractPollingDependentResource<R, P, ID>
implements PerResourcePollingEventSource.ResourceFetcher<R, P> {

public PerResourcePollingDependentResource() {}
Expand All @@ -40,14 +40,14 @@ public PerResourcePollingDependentResource(Class<R> resourceType, Duration polli
}

@Override
protected ExternalResourceCachingEventSource<R, P> createEventSource(
protected ExternalResourceCachingEventSource<R, P, ID> createEventSource(
EventSourceContext<P> context) {

return new PerResourcePollingEventSource<>(
resourceType(),
context,
new PerResourcePollingConfigurationBuilder<>(this, getPollingPeriod())
.withCacheKeyMapper(this)
new PerResourcePollingConfigurationBuilder<R, P, ID>(this, getPollingPeriod())
.withResourceIDMapper(getResourceIDMapper())
.withName(name())
.build());
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,34 +20,34 @@
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<R, P extends HasMetadata>
extends AbstractPollingDependentResource<R, P>
public abstract class PollingDependentResource<R, P extends HasMetadata, ID>
extends AbstractPollingDependentResource<R, P, ID>
implements PollingEventSource.GenericResourceFetcher<R> {

private final CacheKeyMapper<R> cacheKeyMapper;
private final ResourceIDMapper<R, ID> resourceIDMapper;

public PollingDependentResource(Class<R> resourceType, CacheKeyMapper<R> cacheKeyMapper) {
public PollingDependentResource(Class<R> resourceType, ResourceIDMapper<R, ID> resourceIDMapper) {
super(resourceType);
this.cacheKeyMapper = cacheKeyMapper;
this.resourceIDMapper = resourceIDMapper;
}

public PollingDependentResource(
Class<R> resourceType, Duration pollingPeriod, CacheKeyMapper<R> cacheKeyMapper) {
Class<R> resourceType, Duration pollingPeriod, ResourceIDMapper<R, ID> resourceIDMapper) {
super(resourceType, pollingPeriod);
this.cacheKeyMapper = cacheKeyMapper;
this.resourceIDMapper = resourceIDMapper;
}

@Override
protected ExternalResourceCachingEventSource<R, P> createEventSource(
protected ExternalResourceCachingEventSource<R, P, ID> createEventSource(
EventSourceContext<P> context) {
return new PollingEventSource<>(
resourceType(),
new PollingConfiguration<>(name(), this, getPollingPeriod(), cacheKeyMapper));
new PollingConfiguration<>(name(), this, getPollingPeriod(), resourceIDMapper));
}
}

This file was deleted.

Loading