Skip to content

feat: expectations #2840

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Draft
wants to merge 4 commits into
base: next
Choose a base branch
from
Draft
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 @@ -3,10 +3,17 @@
import java.time.Duration;
import java.util.Optional;
import java.util.concurrent.TimeUnit;
import java.util.function.BiPredicate;

public abstract class BaseControl<T extends BaseControl<T>> {
import io.fabric8.kubernetes.api.model.HasMetadata;
import io.javaoperatorsdk.operator.api.reconciler.expectation.Expectation;
import io.javaoperatorsdk.operator.api.reconciler.expectation.ExpectationAdapter;
import io.javaoperatorsdk.operator.api.reconciler.expectation.ExpectationContext;

public abstract class BaseControl<T extends BaseControl<T, P>, P extends HasMetadata> {

private Long scheduleDelay = null;
private Expectation<P> expectation;

public T rescheduleAfter(long delay) {
rescheduleAfter(Duration.ofMillis(delay));
Expand All @@ -25,4 +32,16 @@ public T rescheduleAfter(long delay, TimeUnit timeUnit) {
public Optional<Long> getScheduleDelay() {
return Optional.ofNullable(scheduleDelay);
}

public void expect(Expectation<P> expectation) {
this.expectation = expectation;
}

public void expect(BiPredicate<P, ExpectationContext<P>> expectation, Duration timeout) {
this.expectation = new ExpectationAdapter<>(expectation, timeout);
}

public Expectation<P> getExpectation() {
return expectation;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
package io.javaoperatorsdk.operator.api.reconciler;

import java.util.Optional;
import java.util.Set;
import java.util.stream.Stream;

import io.fabric8.kubernetes.api.model.HasMetadata;
import io.javaoperatorsdk.operator.api.config.ControllerConfiguration;
import io.javaoperatorsdk.operator.processing.event.EventSourceRetriever;
import io.javaoperatorsdk.operator.processing.event.source.IndexerResourceCache;

public interface CacheAware<P extends HasMetadata> {
default <R> Optional<R> getSecondaryResource(Class<R> expectedType) {
return getSecondaryResource(expectedType, null);
}

<R> Set<R> getSecondaryResources(Class<R> expectedType);

default <R> Stream<R> getSecondaryResourcesAsStream(Class<R> expectedType) {
return getSecondaryResources(expectedType).stream();
}

<R> Optional<R> getSecondaryResource(Class<R> expectedType, String eventSourceName);

ControllerConfiguration<P> getControllerConfiguration();

/**
* Retrieves the primary resource.
*
* @return the primary resource associated with the current reconciliation
*/
P getPrimaryResource();

/**
* Retrieves the primary resource cache.
*
* @return the {@link IndexerResourceCache} associated with the associated {@link Reconciler} for
* this context
*/
@SuppressWarnings("unused")
IndexedResourceCache<P> getPrimaryCache();

EventSourceRetriever<P> eventSourceRetriever();
}
Original file line number Diff line number Diff line change
@@ -1,35 +1,18 @@
package io.javaoperatorsdk.operator.api.reconciler;

import java.util.Optional;
import java.util.Set;
import java.util.concurrent.ExecutorService;
import java.util.stream.Stream;

import io.fabric8.kubernetes.api.model.HasMetadata;
import io.fabric8.kubernetes.client.KubernetesClient;
import io.javaoperatorsdk.operator.api.config.ControllerConfiguration;
import io.javaoperatorsdk.operator.api.reconciler.dependent.managed.ManagedWorkflowAndDependentResourceContext;
import io.javaoperatorsdk.operator.processing.event.EventSourceRetriever;
import io.javaoperatorsdk.operator.api.reconciler.expectation.ExpectationResult;
import io.javaoperatorsdk.operator.processing.event.source.IndexerResourceCache;

public interface Context<P extends HasMetadata> {
public interface Context<P extends HasMetadata> extends CacheAware<P> {

Optional<RetryInfo> getRetryInfo();

default <R> Optional<R> getSecondaryResource(Class<R> expectedType) {
return getSecondaryResource(expectedType, null);
}

<R> Set<R> getSecondaryResources(Class<R> expectedType);

default <R> Stream<R> getSecondaryResourcesAsStream(Class<R> expectedType) {
return getSecondaryResources(expectedType).stream();
}

<R> Optional<R> getSecondaryResource(Class<R> expectedType, String eventSourceName);

ControllerConfiguration<P> getControllerConfiguration();

/**
* Retrieve the {@link ManagedWorkflowAndDependentResourceContext} used to interact with {@link
* io.javaoperatorsdk.operator.api.reconciler.dependent.DependentResource}s and associated {@link
Expand All @@ -39,8 +22,6 @@ default <R> Stream<R> getSecondaryResourcesAsStream(Class<R> expectedType) {
*/
ManagedWorkflowAndDependentResourceContext managedWorkflowAndDependentResourceContext();

EventSourceRetriever<P> eventSourceRetriever();

KubernetesClient getClient();

/** ExecutorService initialized by framework for workflows. Used for workflow standalone mode. */
Expand Down Expand Up @@ -72,4 +53,6 @@ default <R> Stream<R> getSecondaryResourcesAsStream(Class<R> expectedType) {
* @return {@code true} is another reconciliation is already scheduled, {@code false} otherwise
*/
boolean isNextReconciliationImminent();

Optional<ExpectationResult<P>> expectationResult();
}
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
import io.javaoperatorsdk.operator.api.config.ControllerConfiguration;
import io.javaoperatorsdk.operator.api.reconciler.dependent.managed.DefaultManagedWorkflowAndDependentResourceContext;
import io.javaoperatorsdk.operator.api.reconciler.dependent.managed.ManagedWorkflowAndDependentResourceContext;
import io.javaoperatorsdk.operator.api.reconciler.expectation.ExpectationResult;
import io.javaoperatorsdk.operator.processing.Controller;
import io.javaoperatorsdk.operator.processing.event.EventSourceRetriever;
import io.javaoperatorsdk.operator.processing.event.NoEventSourceForClassException;
Expand Down Expand Up @@ -119,6 +120,11 @@ public boolean isNextReconciliationImminent() {
.isNextReconciliationImminent(ResourceID.fromResource(primaryResource));
}

@Override
public Optional<ExpectationResult<P>> expectationResult() {
return Optional.empty();
}

public DefaultContext<P> setRetryInfo(RetryInfo retryInfo) {
this.retryInfo = retryInfo;
return this;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
package io.javaoperatorsdk.operator.api.reconciler;

public class DeleteControl extends BaseControl<DeleteControl> {
import io.fabric8.kubernetes.api.model.HasMetadata;

public class DeleteControl<P extends HasMetadata> extends BaseControl<DeleteControl<P>, P> {

private final boolean removeFinalizer;

Expand All @@ -27,7 +29,7 @@ public static DeleteControl defaultDelete() {
*
* @return delete control that will not remove finalizer.
*/
public static DeleteControl noFinalizerRemoval() {
public static <T extends HasMetadata> DeleteControl<T> noFinalizerRemoval() {
return new DeleteControl(false);
}

Expand All @@ -36,7 +38,7 @@ public boolean isRemoveFinalizer() {
}

@Override
public DeleteControl rescheduleAfter(long delay) {
public DeleteControl<P> rescheduleAfter(long delay) {
if (removeFinalizer) {
throw new IllegalStateException("Cannot reschedule cleanup if removing finalizer");
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
import io.fabric8.kubernetes.api.model.HasMetadata;

public class ErrorStatusUpdateControl<P extends HasMetadata>
extends BaseControl<ErrorStatusUpdateControl<P>> {
extends BaseControl<ErrorStatusUpdateControl<P>, P> {

private final P resource;
private boolean noRetry = false;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
import io.fabric8.kubernetes.api.model.HasMetadata;
import io.fabric8.kubernetes.client.CustomResource;

public class UpdateControl<P extends HasMetadata> extends BaseControl<UpdateControl<P>> {
public class UpdateControl<P extends HasMetadata> extends BaseControl<UpdateControl<P>, P> {

private final P resource;
private final boolean patchResource;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
package io.javaoperatorsdk.operator.api.reconciler.expectation;

import java.time.Duration;

import io.fabric8.kubernetes.api.model.HasMetadata;

public abstract class AbstractExpectation<P extends HasMetadata> implements Expectation<P> {

protected final Duration timeout;

protected AbstractExpectation(Duration timeout) {
this.timeout = timeout;
}

@Override
public abstract boolean isFulfilled(P primary, ExpectationContext<P> context);

@Override
public Duration timeout() {
return timeout;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
package io.javaoperatorsdk.operator.api.reconciler.expectation;

import java.time.Duration;

import io.fabric8.kubernetes.api.model.HasMetadata;

public interface Expectation<P extends HasMetadata> {

boolean isFulfilled(P primary, ExpectationContext<P> context);

Duration timeout();
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
package io.javaoperatorsdk.operator.api.reconciler.expectation;

import java.time.Duration;
import java.util.function.BiPredicate;

import io.fabric8.kubernetes.api.model.HasMetadata;

public class ExpectationAdapter<P extends HasMetadata> extends AbstractExpectation<P> {

private final BiPredicate<P, ExpectationContext<P>> expectation;

public ExpectationAdapter(BiPredicate<P, ExpectationContext<P>> expectation, Duration timeout) {
super(timeout);
this.expectation = expectation;
}

@Override
public boolean isFulfilled(P primary, ExpectationContext<P> context) {
return expectation.test(primary, context);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
package io.javaoperatorsdk.operator.api.reconciler.expectation;

import io.fabric8.kubernetes.api.model.HasMetadata;
import io.javaoperatorsdk.operator.api.reconciler.CacheAware;

public interface ExpectationContext<P extends HasMetadata> extends CacheAware<P> {}
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
package io.javaoperatorsdk.operator.api.reconciler.expectation;

import io.fabric8.kubernetes.api.model.HasMetadata;

public class ExpectationResult<P extends HasMetadata> {

private ExpectationStatus status;

private Expectation<P> expectation;

public ExpectationResult(ExpectationStatus status) {
this.status = status;
}

public ExpectationStatus getStatus() {
return status;
}

public Expectation<P> getExpectation() {
return expectation;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
package io.javaoperatorsdk.operator.api.reconciler.expectation;

public enum ExpectationStatus {
TIMEOUT,
FULFILLED;
}
Original file line number Diff line number Diff line change
Expand Up @@ -250,7 +250,7 @@ private PostExecutionControl<P> createPostExecutionControl(
}

private void updatePostExecutionControlWithReschedule(
PostExecutionControl<P> postExecutionControl, BaseControl<?> baseControl) {
PostExecutionControl<P> postExecutionControl, BaseControl<?, ?> baseControl) {
baseControl.getScheduleDelay().ifPresent(postExecutionControl::withReSchedule);
}

Expand Down