diff --git a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/reconciler/Context.java b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/reconciler/Context.java index cc7c865dc5..d390a5ad67 100644 --- a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/reconciler/Context.java +++ b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/reconciler/Context.java @@ -58,6 +58,8 @@ default Stream getSecondaryResourcesAsStream(Class expectedType) { KubernetesClient getClient(); + ResourceOperations

resourceOperations(); + /** ExecutorService initialized by framework for workflows. Used for workflow standalone mode. */ ExecutorService getWorkflowExecutorService(); diff --git a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/reconciler/DefaultContext.java b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/reconciler/DefaultContext.java index f1aeadd52a..3c7d6319a6 100644 --- a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/reconciler/DefaultContext.java +++ b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/reconciler/DefaultContext.java @@ -46,6 +46,7 @@ public class DefaultContext

implements Context

{ private final boolean primaryResourceDeleted; private final boolean primaryResourceFinalStateUnknown; private final Map, Object> desiredStates = new ConcurrentHashMap<>(); + private final ResourceOperations

resourceOperations; public DefaultContext( RetryInfo retryInfo, @@ -61,6 +62,7 @@ public DefaultContext( this.primaryResourceFinalStateUnknown = primaryResourceFinalStateUnknown; this.defaultManagedDependentResourceContext = new DefaultManagedWorkflowAndDependentResourceContext<>(controller, primaryResource, this); + this.resourceOperations = new ResourceOperations<>(this); } @Override @@ -124,6 +126,11 @@ public KubernetesClient getClient() { return controller.getClient(); } + @Override + public ResourceOperations

resourceOperations() { + return resourceOperations; + } + @Override public ExecutorService getWorkflowExecutorService() { // note that this should be always received from executor service manager, so we are able to do diff --git a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/reconciler/PrimaryUpdateAndCacheUtils.java b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/reconciler/PrimaryUpdateAndCacheUtils.java index 31c825e673..f74cd49ee7 100644 --- a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/reconciler/PrimaryUpdateAndCacheUtils.java +++ b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/reconciler/PrimaryUpdateAndCacheUtils.java @@ -46,8 +46,8 @@ * If the update fails, it reads the primary resource from the cluster, applies the modifications * again and retries the update. * - * @deprecated Use {@link ReconcileUtils} that contains the more efficient up-to-date versions of - * the target utils. + * @deprecated Use {@link Context#resourceOperations()} that contains the more efficient up-to-date + * versions of methods. */ @Deprecated(forRemoval = true) public class PrimaryUpdateAndCacheUtils { diff --git a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/reconciler/ReconcileUtils.java b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/reconciler/ResourceOperations.java similarity index 51% rename from operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/reconciler/ReconcileUtils.java rename to operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/reconciler/ResourceOperations.java index ed02c56a01..3fe3864403 100644 --- a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/reconciler/ReconcileUtils.java +++ b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/reconciler/ResourceOperations.java @@ -23,8 +23,6 @@ import org.slf4j.LoggerFactory; import io.fabric8.kubernetes.api.model.HasMetadata; -import io.fabric8.kubernetes.api.model.ObjectMeta; -import io.fabric8.kubernetes.client.KubernetesClient; import io.fabric8.kubernetes.client.KubernetesClientException; import io.fabric8.kubernetes.client.dsl.base.PatchContext; import io.fabric8.kubernetes.client.dsl.base.PatchType; @@ -35,33 +33,40 @@ import static io.javaoperatorsdk.operator.processing.KubernetesResourceUtils.getUID; import static io.javaoperatorsdk.operator.processing.KubernetesResourceUtils.getVersion; -public class ReconcileUtils { - - private static final Logger log = LoggerFactory.getLogger(ReconcileUtils.class); +/** + * Provides useful operations to manipulate resources (server-side apply, patch, etc.) in an + * idiomatic way, in particular to make sure that the latest version of the resource is present in + * the caches for the next reconciliation. + * + * @param

the resource type on which this object operates + */ +public class ResourceOperations

{ public static final int DEFAULT_MAX_RETRY = 10; - private ReconcileUtils() {} + private static final Logger log = LoggerFactory.getLogger(ResourceOperations.class); + + private final Context

context; + + public ResourceOperations(Context

context) { + this.context = context; + } /** * Updates the resource and caches the response if needed, thus making sure that next - * reconciliation will contain to updated resource. Or more recent one if someone did an update - * after our update. - * - *

Optionally also can filter out the event, what is the result of this update. + * reconciliation will see to updated resource - or more recent one if additional update happened + * after this update; In addition to that it filters out the event from the update, so + * reconciliation is not triggered by own update. * *

You are free to control the optimistic locking by setting the resource version in resource * metadata. In case of SSA we advise not to do updates with optimistic locking. * - * @param context of reconciler * @param resource fresh resource for server side apply * @return updated resource * @param resource type */ - public static R serverSideApply( - Context context, R resource) { + public R serverSideApply(R resource) { return resourcePatch( - context, resource, r -> context @@ -76,18 +81,22 @@ public static R serverSideApply( } /** - * Server-Side Apply the resource status subresource. Updates the resource status and caches the - * response if needed, ensuring the next reconciliation will contain the updated resource. + * Server-Side Apply the resource status subresource. + * + *

Updates the resource and caches the response if needed, thus making sure that next + * reconciliation will see to updated resource - or more recent one if additional update happened + * after this update; In addition to that it filters out the event from this update, so + * reconciliation is not triggered by own update. + * + *

You are free to control the optimistic locking by setting the resource version in resource + * metadata. In case of SSA we advise not to do updates with optimistic locking. * - * @param context of reconciler * @param resource fresh resource for server side apply * @return updated resource * @param resource type */ - public static R serverSideApplyStatus( - Context context, R resource) { + public R serverSideApplyStatus(R resource) { return resourcePatch( - context, resource, r -> context @@ -103,16 +112,20 @@ public static R serverSideApplyStatus( } /** - * Server-Side Apply the primary resource. Updates the primary resource and caches the response - * using the controller's event source, ensuring the next reconciliation will contain the updated - * resource. + * Server-Side Apply the primary resource. + * + *

Updates the resource and caches the response if needed, thus making sure that next + * reconciliation will see to updated resource - or more recent one if additional update happened + * after this update; In addition to that it filters out the event from this update, so + * reconciliation is not triggered by own update. + * + *

You are free to control the optimistic locking by setting the resource version in resource + * metadata. In case of SSA we advise not to do updates with optimistic locking. * - * @param context of reconciler * @param resource primary resource for server side apply * @return updated resource - * @param

primary resource type */ - public static

P serverSideApplyPrimary(Context

context, P resource) { + public P serverSideApplyPrimary(P resource) { return resourcePatch( resource, r -> @@ -129,16 +142,20 @@ public static

P serverSideApplyPrimary(Context

contex } /** - * Server-Side Apply the primary resource status subresource. Updates the primary resource status - * and caches the response using the controller's event source. + * Server-Side Apply the primary resource status subresource. + * + *

Updates the resource and caches the response if needed, thus making sure that next + * reconciliation will see to updated resource - or more recent one if additional update happened + * after this update; In addition to that it filters out the event from this update, so + * reconciliation is not triggered by own update. + * + *

You are free to control the optimistic locking by setting the resource version in resource + * metadata. In case of SSA we advise not to do updates with optimistic locking. * - * @param context of reconciler * @param resource primary resource for server side apply * @return updated resource - * @param

primary resource type */ - public static

P serverSideApplyPrimaryStatus( - Context

context, P resource) { + public P serverSideApplyPrimaryStatus(P resource) { return resourcePatch( resource, r -> @@ -156,43 +173,56 @@ public static

P serverSideApplyPrimaryStatus( } /** - * Updates the resource with optimistic locking based on the resource version. Caches the response - * if needed, ensuring the next reconciliation will contain the updated resource. + * Updates the resource and caches the response if needed, thus making sure that next + * reconciliation will see to updated resource - or more recent one if additional update happened + * after this update; In addition to that it filters out the event from this update, so + * reconciliation is not triggered by own update. + * + *

You are free to control the optimistic locking by setting the resource version in resource + * metadata. * - * @param context of reconciler * @param resource resource to update * @return updated resource * @param resource type */ - public static R update( - Context context, R resource) { - return resourcePatch(context, resource, r -> context.getClient().resource(r).update()); + public R update(R resource) { + return resourcePatch(resource, r -> context.getClient().resource(r).update()); } /** - * Updates the resource status subresource with optimistic locking. Caches the response if needed. + * Updates the resource status subresource. + * + *

Updates the resource and caches the response if needed, thus making sure that next + * reconciliation will see to updated resource - or more recent one if additional update happened + * after this update; In addition to that it filters out the event from this update, so + * reconciliation is not triggered by own update. + * + *

You are free to control the optimistic locking by setting the resource version in resource + * metadata. * - * @param context of reconciler * @param resource resource to update * @return updated resource * @param resource type */ - public static R updateStatus( - Context context, R resource) { - return resourcePatch(context, resource, r -> context.getClient().resource(r).updateStatus()); + public R updateStatus(R resource) { + return resourcePatch(resource, r -> context.getClient().resource(r).updateStatus()); } /** - * Updates the primary resource with optimistic locking. Caches the response using the - * controller's event source. + * Updates the primary resource. + * + *

Updates the resource and caches the response if needed, thus making sure that next + * reconciliation will see to updated resource - or more recent one if additional update happened + * after this update; In addition to that it filters out the event from this update, so + * reconciliation is not triggered by own update. + * + *

You are free to control the optimistic locking by setting the resource version in resource + * metadata. * - * @param context of reconciler * @param resource primary resource to update * @return updated resource - * @param resource type */ - public static R updatePrimary( - Context context, R resource) { + public P updatePrimary(P resource) { return resourcePatch( resource, r -> context.getClient().resource(r).update(), @@ -200,16 +230,20 @@ public static R updatePrimary( } /** - * Updates the primary resource status subresource with optimistic locking. Caches the response - * using the controller's event source. + * Updates the primary resource status subresource. + * + *

Updates the resource and caches the response if needed, thus making sure that next + * reconciliation will see to updated resource - or more recent one if additional update happened + * after this update; In addition to that it filters out the event from this update, so + * reconciliation is not triggered by own update. + * + *

You are free to control the optimistic locking by setting the resource version in resource + * metadata. * - * @param context of reconciler * @param resource primary resource to update * @return updated resource - * @param resource type */ - public static R updatePrimaryStatus( - Context context, R resource) { + public P updatePrimaryStatus(P resource) { return resourcePatch( resource, r -> context.getClient().resource(r).updateStatus(), @@ -220,46 +254,60 @@ public static R updatePrimaryStatus( * Applies a JSON Patch to the resource. The unaryOperator function is used to modify the * resource, and the differences are sent as a JSON Patch to the Kubernetes API server. * - * @param context of reconciler + *

Updates the resource and caches the response if needed, thus making sure that next + * reconciliation will see to updated resource - or more recent one if additional update happened + * after this update; In addition to that it filters out the event from this update, so + * reconciliation is not triggered by own update. + * + *

You are free to control the optimistic locking by setting the resource version in resource + * metadata. + * * @param resource resource to patch * @param unaryOperator function to modify the resource * @return updated resource * @param resource type */ - public static R jsonPatch( - Context context, R resource, UnaryOperator unaryOperator) { - return resourcePatch( - context, resource, r -> context.getClient().resource(r).edit(unaryOperator)); + public R jsonPatch(R resource, UnaryOperator unaryOperator) { + return resourcePatch(resource, r -> context.getClient().resource(r).edit(unaryOperator)); } /** * Applies a JSON Patch to the resource status subresource. The unaryOperator function is used to * modify the resource status, and the differences are sent as a JSON Patch. * - * @param context of reconciler + *

Updates the resource and caches the response if needed, thus making sure that next + * reconciliation will see to updated resource - or more recent one if additional update happened + * after this update; In addition to that it filters out the event from this update, so + * reconciliation is not triggered by own update. + * + *

You are free to control the optimistic locking by setting the resource version in resource + * metadata. + * * @param resource resource to patch * @param unaryOperator function to modify the resource * @return updated resource * @param resource type */ - public static R jsonPatchStatus( - Context context, R resource, UnaryOperator unaryOperator) { - return resourcePatch( - context, resource, r -> context.getClient().resource(r).editStatus(unaryOperator)); + public R jsonPatchStatus(R resource, UnaryOperator unaryOperator) { + return resourcePatch(resource, r -> context.getClient().resource(r).editStatus(unaryOperator)); } /** - * Applies a JSON Patch to the primary resource. Caches the response using the controller's event - * source. + * Applies a JSON Patch to the primary resource. + * + *

Updates the resource and caches the response if needed, thus making sure that next + * reconciliation will see to updated resource - or more recent one if additional update happened + * after this update; In addition to that it filters out the event from this update, so + * reconciliation is not triggered by own update. + * + *

You are free to control the optimistic locking by setting the resource version in resource + * metadata. * - * @param context of reconciler * @param resource primary resource to patch * @param unaryOperator function to modify the resource * @return updated resource - * @param resource type */ - public static R jsonPatchPrimary( - Context context, R resource, UnaryOperator unaryOperator) { + public P jsonPatchPrimary(P resource, UnaryOperator

unaryOperator) { return resourcePatch( resource, r -> context.getClient().resource(r).edit(unaryOperator), @@ -267,17 +315,21 @@ public static R jsonPatchPrimary( } /** - * Applies a JSON Patch to the primary resource status subresource. Caches the response using the - * controller's event source. + * Applies a JSON Patch to the primary resource status subresource. + * + *

Updates the resource and caches the response if needed, thus making sure that next + * reconciliation will see to updated resource - or more recent one if additional update happened + * after this update; In addition to that it filters out the event from this update, so + * reconciliation is not triggered by own update. + * + *

You are free to control the optimistic locking by setting the resource version in resource + * metadata. * - * @param context of reconciler * @param resource primary resource to patch * @param unaryOperator function to modify the resource * @return updated resource - * @param resource type */ - public static R jsonPatchPrimaryStatus( - Context context, R resource, UnaryOperator unaryOperator) { + public P jsonPatchPrimaryStatus(P resource, UnaryOperator

unaryOperator) { return resourcePatch( resource, r -> context.getClient().resource(r).editStatus(unaryOperator), @@ -288,41 +340,57 @@ public static R jsonPatchPrimaryStatus( * Applies a JSON Merge Patch to the resource. JSON Merge Patch (RFC 7386) is a simpler patching * strategy that merges the provided resource with the existing resource on the server. * - * @param context of reconciler + *

Updates the resource and caches the response if needed, thus making sure that next + * reconciliation will see to updated resource - or more recent one if additional update happened + * after this update; In addition to that it filters out the event from this update, so + * reconciliation is not triggered by own update. + * + *

You are free to control the optimistic locking by setting the resource version in resource + * metadata. + * * @param resource resource to patch * @return updated resource * @param resource type */ - public static R jsonMergePatch( - Context context, R resource) { - return resourcePatch(context, resource, r -> context.getClient().resource(r).patch()); + public R jsonMergePatch(R resource) { + return resourcePatch(resource, r -> context.getClient().resource(r).patch()); } /** - * Applies a JSON Merge Patch to the resource status subresource. Merges the provided resource - * status with the existing resource status on the server. + * Applies a JSON Merge Patch to the resource status subresource. + * + *

Updates the resource and caches the response if needed, thus making sure that next + * reconciliation will see to updated resource - or more recent one if additional update happened + * after this update; In addition to that it filters out the event from this update, so + * reconciliation is not triggered by own update. + * + *

You are free to control the optimistic locking by setting the resource version in resource + * metadata. * - * @param context of reconciler * @param resource resource to patch * @return updated resource * @param resource type */ - public static R jsonMergePatchStatus( - Context context, R resource) { - return resourcePatch(context, resource, r -> context.getClient().resource(r).patchStatus()); + public R jsonMergePatchStatus(R resource) { + return resourcePatch(resource, r -> context.getClient().resource(r).patchStatus()); } /** * Applies a JSON Merge Patch to the primary resource. Caches the response using the controller's * event source. * - * @param context of reconciler + *

Updates the resource and caches the response if needed, thus making sure that next + * reconciliation will see to updated resource - or more recent one if additional update happened + * after this update; In addition to that it filters out the event from this update, so + * reconciliation is not triggered by own update. + * + *

You are free to control the optimistic locking by setting the resource version in resource + * metadata. + * * @param resource primary resource to patch reconciliation * @return updated resource - * @param resource type */ - public static R jsonMergePatchPrimary( - Context context, R resource) { + public P jsonMergePatchPrimary(P resource) { return resourcePatch( resource, r -> context.getClient().resource(r).patch(), @@ -330,35 +398,40 @@ public static R jsonMergePatchPrimary( } /** - * Applies a JSON Merge Patch to the primary resource status subresource and filters out the - * resulting event. This is a convenience method that calls {@link - * #jsonMergePatchPrimaryStatus(Context, HasMetadata)} with filterEvent set to true. + * Applies a JSON Merge Patch to the primary resource. + * + *

Updates the resource and caches the response if needed, thus making sure that next + * reconciliation will see to updated resource - or more recent one if additional update happened + * after this update; In addition to that it filters out the event from this update, so + * reconciliation is not triggered by own update. + * + *

You are free to control the optimistic locking by setting the resource version in resource + * metadata. * - * @param context of reconciler * @param resource primary resource to patch * @return updated resource - * @param resource type - * @see #jsonMergePatchPrimaryStatus(Context, HasMetadata) + * @see #jsonMergePatchPrimaryStatus(HasMetadata) */ - public static R jsonMergePatchPrimaryStatus( - Context context, R resource) { - return jsonMergePatchPrimaryStatus(context, resource); + public P jsonMergePatchPrimaryStatus(P resource) { + return resourcePatch( + resource, + r -> context.getClient().resource(r).patchStatus(), + context.eventSourceRetriever().getControllerEventSource()); } /** - * Internal utility method to patch a resource and cache the result. Automatically discovers the - * event source for the resource type and delegates to {@link #resourcePatch(HasMetadata, - * UnaryOperator, ManagedInformerEventSource)}. + * Utility method to patch a resource and cache the result. Automatically discovers the event + * source for the resource type and delegates to {@link #resourcePatch(HasMetadata, UnaryOperator, + * ManagedInformerEventSource)}. * - * @param context of reconciler * @param resource resource to patch * @param updateOperation operation to perform (update, patch, edit, etc.) * @return updated resource * @param resource type * @throws IllegalStateException if no event source or multiple event sources are found */ - public static R resourcePatch( - Context context, R resource, UnaryOperator updateOperation) { + @SuppressWarnings({"rawtypes", "unchecked"}) + public R resourcePatch(R resource, UnaryOperator updateOperation) { var esList = context.eventSourceRetriever().getEventSourcesFor(resource.getClass()); if (esList.isEmpty()) { @@ -372,7 +445,7 @@ public static R resourcePatch( } var es = esList.get(0); if (es instanceof ManagedInformerEventSource mes) { - return resourcePatch(resource, updateOperation, mes); + return resourcePatch(resource, updateOperation, (ManagedInformerEventSource) mes); } else { throw new IllegalStateException( "Target event source must be a subclass off " @@ -381,9 +454,9 @@ public static R resourcePatch( } /** - * Internal utility method to patch a resource and cache the result using the specified event - * source. This method either filters out the resulting event or allows it to trigger - * reconciliation based on the filterEvent parameter. + * Utility method to patch a resource and cache the result using the specified event source. This + * method either filters out the resulting event or allows it to trigger reconciliation based on + * the filterEvent parameter. * * @param resource resource to patch * @param updateOperation operation to perform (update, patch, edit, etc.) @@ -391,41 +464,38 @@ public static R resourcePatch( * @return updated resource * @param resource type */ - @SuppressWarnings("unchecked") - public static R resourcePatch( - R resource, UnaryOperator updateOperation, ManagedInformerEventSource ies) { - return (R) ies.eventFilteringUpdateAndCacheResource(resource, updateOperation); + public R resourcePatch( + R resource, UnaryOperator updateOperation, ManagedInformerEventSource ies) { + return ies.eventFilteringUpdateAndCacheResource(resource, updateOperation); } /** * Adds the default finalizer (from controller configuration) to the primary resource. This is a - * convenience method that calls {@link #addFinalizer(Context, String)} with the configured - * finalizer name. + * convenience method that calls {@link #addFinalizer(String)} with the configured finalizer name. + * Note that explicitly adding/removing finalizer is required only if "Trigger reconciliation on + * all event" mode is on. * - * @param context of reconciler * @return updated resource from the server response - * @param

primary resource type - * @see #addFinalizer(Context, String) + * @see #addFinalizer(String) */ - public static

P addFinalizer(Context

context) { - return addFinalizer(context, context.getControllerConfiguration().getFinalizerName()); + public P addFinalizer() { + return addFinalizer(context.getControllerConfiguration().getFinalizerName()); } /** * Adds finalizer to the resource using JSON Patch. Retries conflicts and unprocessable content - * (HTTP 422), see {@link PrimaryUpdateAndCacheUtils#conflictRetryingPatch(KubernetesClient, - * HasMetadata, UnaryOperator, Predicate)} for details on retry. It does not try to add finalizer - * if there is already a finalizer or resource is marked for deletion. + * (HTTP 422). It does not try to add finalizer if there is already a finalizer or resource is + * marked for deletion. Note that explicitly adding/removing finalizer is required only if + * "Trigger reconciliation on all event" mode is on. * * @return updated resource from the server response */ - public static

P addFinalizer(Context

context, String finalizerName) { + public P addFinalizer(String finalizerName) { var resource = context.getPrimaryResource(); if (resource.isMarkedForDeletion() || resource.hasFinalizer(finalizerName)) { return resource; } - return conflictRetryingPatch( - context, + return conflictRetryingPatchPrimary( r -> { r.addFinalizer(finalizerName); return r; @@ -435,34 +505,31 @@ public static

P addFinalizer(Context

context, String /** * Removes the default finalizer (from controller configuration) from the primary resource. This - * is a convenience method that calls {@link #removeFinalizer(Context, String)} with the - * configured finalizer name. + * is a convenience method that calls {@link #removeFinalizer(String)} with the configured + * finalizer name. Note that explicitly adding/removing finalizer is required only if "Trigger + * reconciliation on all event" mode is on. * - * @param context of reconciler * @return updated resource from the server response - * @param

primary resource type - * @see #removeFinalizer(Context, String) + * @see #removeFinalizer(String) */ - public static

P removeFinalizer(Context

context) { - return removeFinalizer(context, context.getControllerConfiguration().getFinalizerName()); + public P removeFinalizer() { + return removeFinalizer(context.getControllerConfiguration().getFinalizerName()); } /** - * Removes the target finalizer from target resource. Uses JSON Patch and handles retries, see - * {@link PrimaryUpdateAndCacheUtils#conflictRetryingPatch(KubernetesClient, HasMetadata, - * UnaryOperator, Predicate)} for details. It does not try to remove finalizer if finalizer is not - * present on the resource. + * Removes the target finalizer from the primary resource. Uses JSON Patch and handles retries. It + * does not try to remove finalizer if finalizer is not present on the resource. Note that + * explicitly adding/removing finalizer is required only if "Trigger reconciliation on all event" + * mode is on. * * @return updated resource from the server response */ - public static

P removeFinalizer( - Context

context, String finalizerName) { + public P removeFinalizer(String finalizerName) { var resource = context.getPrimaryResource(); if (!resource.hasFinalizer(finalizerName)) { return resource; } - return conflictRetryingPatch( - context, + return conflictRetryingPatchPrimary( r -> { r.removeFinalizer(finalizerName); return r; @@ -479,18 +546,16 @@ public static

P removeFinalizer( /** * Patches the resource using JSON Patch. In case the server responds with conflict (HTTP 409) or * unprocessable content (HTTP 422) it retries the operation up to the maximum number defined in - * {@link ReconcileUtils#DEFAULT_MAX_RETRY}. + * {@link ResourceOperations#DEFAULT_MAX_RETRY}. * - * @param context reconciliation context * @param resourceChangesOperator changes to be done on the resource before update * @param preCondition condition to check if the patch operation still needs to be performed or * not. * @return updated resource from the server or unchanged if the precondition does not hold. - * @param

resource type */ @SuppressWarnings("unchecked") - public static

P conflictRetryingPatch( - Context

context, UnaryOperator

resourceChangesOperator, Predicate

preCondition) { + public P conflictRetryingPatchPrimary( + UnaryOperator

resourceChangesOperator, Predicate

preCondition) { var resource = context.getPrimaryResource(); var client = context.getClient(); if (log.isDebugEnabled()) { @@ -502,7 +567,7 @@ public static

P conflictRetryingPatch( if (!preCondition.test(resource)) { return resource; } - return jsonPatchPrimary(context, resource, resourceChangesOperator); + return jsonPatchPrimary(resource, resourceChangesOperator); } catch (KubernetesClientException e) { log.trace("Exception during patch for resource: {}", resource); retryIndex++; @@ -544,30 +609,27 @@ public static

P conflictRetryingPatch( /** * Adds the default finalizer (from controller configuration) to the primary resource using - * Server-Side Apply. This is a convenience method that calls {@link #addFinalizerWithSSA(Context, - * String)} with the configured finalizer name. + * Server-Side Apply. This is a convenience method that calls {@link #addFinalizerWithSSA( + * String)} with the configured finalizer name. Note that explicitly adding finalizer is required + * only if "Trigger reconciliation on all event" mode is on. * - * @param context of reconciler * @return the patched resource from the server response - * @param

primary resource type - * @see #addFinalizerWithSSA(Context, String) + * @see #addFinalizerWithSSA(String) */ - public static

P addFinalizerWithSSA(Context

context) { - return addFinalizerWithSSA(context, context.getControllerConfiguration().getFinalizerName()); + public P addFinalizerWithSSA() { + return addFinalizerWithSSA(context.getControllerConfiguration().getFinalizerName()); } /** * Adds finalizer using Server-Side Apply. In the background this method creates a fresh copy of * the target resource, setting only name, namespace and finalizer. Does not use optimistic - * locking for the patch. + * locking for the patch. Note that explicitly adding finalizer is required only if "Trigger + * reconciliation on all event" mode is on. * - * @param context of reconciler * @param finalizerName name of the finalizer to add * @return the patched resource from the server response - * @param

primary resource type */ - public static

P addFinalizerWithSSA( - Context

context, String finalizerName) { + public P addFinalizerWithSSA(String finalizerName) { var originalResource = context.getPrimaryResource(); if (log.isDebugEnabled()) { log.debug( @@ -576,14 +638,12 @@ public static

P addFinalizerWithSSA( getVersion(originalResource)); } try { + @SuppressWarnings("unchecked") P resource = (P) originalResource.getClass().getConstructor().newInstance(); - ObjectMeta objectMeta = new ObjectMeta(); - objectMeta.setName(originalResource.getMetadata().getName()); - objectMeta.setNamespace(originalResource.getMetadata().getNamespace()); - resource.setMetadata(objectMeta); + resource.initNameAndNamespaceFrom(originalResource); resource.addFinalizer(finalizerName); - return serverSideApplyPrimary(context, resource); + return serverSideApplyPrimary(resource); } catch (InstantiationException | IllegalAccessException | InvocationTargetException diff --git a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/event/ReconciliationDispatcher.java b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/event/ReconciliationDispatcher.java index 82d9a3ed21..010b161979 100644 --- a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/event/ReconciliationDispatcher.java +++ b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/event/ReconciliationDispatcher.java @@ -31,7 +31,6 @@ import io.javaoperatorsdk.operator.api.reconciler.Context; import io.javaoperatorsdk.operator.api.reconciler.DefaultContext; import io.javaoperatorsdk.operator.api.reconciler.DeleteControl; -import io.javaoperatorsdk.operator.api.reconciler.ReconcileUtils; import io.javaoperatorsdk.operator.api.reconciler.RetryInfo; import io.javaoperatorsdk.operator.api.reconciler.UpdateControl; import io.javaoperatorsdk.operator.processing.Controller; @@ -73,13 +72,14 @@ public ReconciliationDispatcher(Controller

controller) { public PostExecutionControl

handleExecution(ExecutionScope

executionScope) { validateExecutionScope(executionScope); try { - return handleDispatch(executionScope); + return handleDispatch(executionScope, null); } catch (Exception e) { return PostExecutionControl.exceptionDuringExecution(e); } } - private PostExecutionControl

handleDispatch(ExecutionScope

executionScope) + // visible for testing + PostExecutionControl

handleDispatch(ExecutionScope

executionScope, Context

context) throws Exception { P originalResource = executionScope.getResource(); var resourceForExecution = cloneResource(originalResource); @@ -98,13 +98,16 @@ && shouldNotDispatchToCleanupWhenMarkedForDeletion(originalResource)) { originalResource.getMetadata().getFinalizers()); return PostExecutionControl.defaultDispatch(); } - Context

context = - new DefaultContext<>( - executionScope.getRetryInfo(), - controller, - resourceForExecution, - executionScope.isDeleteEvent(), - executionScope.isDeleteFinalStateUnknown()); + // context can be provided only for testing purposes + context = + context == null + ? new DefaultContext<>( + executionScope.getRetryInfo(), + controller, + resourceForExecution, + executionScope.isDeleteEvent(), + executionScope.isDeleteFinalStateUnknown()) + : context; // checking the cleaner for all-event-mode if (!triggerOnAllEvents() && markedForDeletion) { @@ -137,9 +140,9 @@ private PostExecutionControl

handleReconcile( */ P updatedResource; if (useSSA) { - updatedResource = ReconcileUtils.addFinalizerWithSSA(context); + updatedResource = context.resourceOperations().addFinalizerWithSSA(); } else { - updatedResource = ReconcileUtils.addFinalizer(context); + updatedResource = context.resourceOperations().addFinalizer(); } return PostExecutionControl.onlyFinalizerAdded(updatedResource) .withReSchedule(BaseControl.INSTANT_RESCHEDULE); @@ -321,7 +324,7 @@ private PostExecutionControl

handleCleanup( // cleanup is finished, nothing left to be done final var finalizerName = configuration().getFinalizerName(); if (deleteControl.isRemoveFinalizer() && resourceForExecution.hasFinalizer(finalizerName)) { - P customResource = ReconcileUtils.removeFinalizer(context); + P customResource = context.resourceOperations().removeFinalizer(); return PostExecutionControl.customResourceFinalizerRemoved(customResource); } } @@ -387,9 +390,9 @@ public R patchResource(Context context, R resource, R originalResource) { resource.getMetadata().getResourceVersion()); } if (useSSA) { - return ReconcileUtils.serverSideApplyPrimary(context, resource); + return context.resourceOperations().serverSideApplyPrimary(resource); } else { - return ReconcileUtils.jsonPatchPrimary(context, originalResource, r -> resource); + return context.resourceOperations().jsonPatchPrimary(originalResource, r -> resource); } } @@ -399,7 +402,7 @@ public R patchStatus(Context context, R resource, R originalResource) { var managedFields = resource.getMetadata().getManagedFields(); try { resource.getMetadata().setManagedFields(null); - return ReconcileUtils.serverSideApplyPrimaryStatus(context, resource); + return context.resourceOperations().serverSideApplyPrimaryStatus(resource); } finally { resource.getMetadata().setManagedFields(managedFields); } @@ -416,13 +419,14 @@ private R editStatus(Context context, R resource, R originalResource) { try { clonedOriginal.getMetadata().setResourceVersion(null); resource.getMetadata().setResourceVersion(null); - return ReconcileUtils.jsonPatchPrimaryStatus( - context, - clonedOriginal, - r -> { - ReconcilerUtilsInternal.setStatus(r, ReconcilerUtilsInternal.getStatus(resource)); - return r; - }); + return context + .resourceOperations() + .jsonPatchPrimaryStatus( + clonedOriginal, + r -> { + ReconcilerUtilsInternal.setStatus(r, ReconcilerUtilsInternal.getStatus(resource)); + return r; + }); } finally { // restore initial resource version clonedOriginal.getMetadata().setResourceVersion(resourceVersion); diff --git a/operator-framework-core/src/test/java/io/javaoperatorsdk/operator/api/reconciler/ReconcileUtilsTest.java b/operator-framework-core/src/test/java/io/javaoperatorsdk/operator/api/reconciler/ResourceOperationsTest.java similarity index 93% rename from operator-framework-core/src/test/java/io/javaoperatorsdk/operator/api/reconciler/ReconcileUtilsTest.java rename to operator-framework-core/src/test/java/io/javaoperatorsdk/operator/api/reconciler/ResourceOperationsTest.java index f76ec61e16..82ecf8996c 100644 --- a/operator-framework-core/src/test/java/io/javaoperatorsdk/operator/api/reconciler/ReconcileUtilsTest.java +++ b/operator-framework-core/src/test/java/io/javaoperatorsdk/operator/api/reconciler/ResourceOperationsTest.java @@ -36,10 +36,9 @@ import static org.assertj.core.api.Assertions.assertThat; import static org.junit.jupiter.api.Assertions.*; -import static org.mockito.ArgumentMatchers.any; import static org.mockito.Mockito.*; -class ReconcileUtilsTest { +class ResourceOperationsTest { private static final String FINALIZER_NAME = "test.javaoperatorsdk.io/finalizer"; @@ -49,6 +48,7 @@ class ReconcileUtilsTest { private Resource resourceOp; private ControllerEventSource controllerEventSource; private ControllerConfiguration controllerConfiguration; + private ResourceOperations resourceOperations; @BeforeEach @SuppressWarnings("unchecked") @@ -71,6 +71,8 @@ void setupMocks() { when(client.resources(TestCustomResource.class)).thenReturn(mixedOperation); when(mixedOperation.inNamespace(any())).thenReturn(mixedOperation); when(mixedOperation.withName(any())).thenReturn(resourceOp); + + resourceOperations = new ResourceOperations<>(context); } @Test @@ -91,7 +93,7 @@ void addsFinalizer() { return res; }); - var result = ReconcileUtils.addFinalizer(context, FINALIZER_NAME); + var result = resourceOperations.addFinalizer(FINALIZER_NAME); assertThat(result).isNotNull(); assertThat(result.hasFinalizer(FINALIZER_NAME)).isTrue(); @@ -118,7 +120,7 @@ void addsFinalizerWithSSA() { return res; }); - var result = ReconcileUtils.addFinalizerWithSSA(context, FINALIZER_NAME); + var result = resourceOperations.addFinalizerWithSSA(FINALIZER_NAME); assertThat(result).isNotNull(); assertThat(result.hasFinalizer(FINALIZER_NAME)).isTrue(); @@ -146,7 +148,7 @@ void removesFinalizer() { return res; }); - var result = ReconcileUtils.removeFinalizer(context, FINALIZER_NAME); + var result = resourceOperations.removeFinalizer(FINALIZER_NAME); assertThat(result).isNotNull(); assertThat(result.hasFinalizer(FINALIZER_NAME)).isFalse(); @@ -177,7 +179,7 @@ void retriesAddingFinalizerWithoutSSA() { // Return fresh resource on retry when(resourceOp.get()).thenReturn(resource); - var result = ReconcileUtils.addFinalizer(context, FINALIZER_NAME); + var result = resourceOperations.addFinalizer(FINALIZER_NAME); assertThat(result).isNotNull(); assertThat(result.hasFinalizer(FINALIZER_NAME)).isTrue(); @@ -202,7 +204,7 @@ void nullResourceIsGracefullyHandledOnFinalizerRemovalRetry() { // Return null on retry (resource was deleted) when(resourceOp.get()).thenReturn(null); - ReconcileUtils.removeFinalizer(context, FINALIZER_NAME); + resourceOperations.removeFinalizer(FINALIZER_NAME); verify(controllerEventSource, times(1)) .eventFilteringUpdateAndCacheResource(any(), any(UnaryOperator.class)); @@ -235,7 +237,7 @@ void retriesFinalizerRemovalWithFreshResource() { freshResource.addFinalizer(FINALIZER_NAME); when(resourceOp.get()).thenReturn(freshResource); - var result = ReconcileUtils.removeFinalizer(context, FINALIZER_NAME); + var result = resourceOperations.removeFinalizer(FINALIZER_NAME); assertThat(result).isNotNull(); assertThat(result.getMetadata().getResourceVersion()).isEqualTo("3"); @@ -262,7 +264,7 @@ void resourcePatchWithSingleEventSource() { when(managedEventSource.eventFilteringUpdateAndCacheResource(any(), any(UnaryOperator.class))) .thenReturn(updatedResource); - var result = ReconcileUtils.resourcePatch(context, resource, UnaryOperator.identity()); + var result = resourceOperations.resourcePatch(resource, UnaryOperator.identity()); assertThat(result).isNotNull(); assertThat(result.getMetadata().getResourceVersion()).isEqualTo("2"); @@ -282,7 +284,7 @@ void resourcePatchThrowsWhenNoEventSourceFound() { var exception = assertThrows( IllegalStateException.class, - () -> ReconcileUtils.resourcePatch(context, resource, UnaryOperator.identity())); + () -> resourceOperations.resourcePatch(resource, UnaryOperator.identity())); assertThat(exception.getMessage()).contains("No event source found for type"); } @@ -301,7 +303,7 @@ void resourcePatchThrowsWhenMultipleEventSourcesFound() { var exception = assertThrows( IllegalStateException.class, - () -> ReconcileUtils.resourcePatch(context, resource, UnaryOperator.identity())); + () -> resourceOperations.resourcePatch(resource, UnaryOperator.identity())); assertThat(exception.getMessage()).contains("Multiple event sources found for"); assertThat(exception.getMessage()).contains("please provide the target event source"); @@ -320,7 +322,7 @@ void resourcePatchThrowsWhenEventSourceIsNotManagedInformer() { var exception = assertThrows( IllegalStateException.class, - () -> ReconcileUtils.resourcePatch(context, resource, UnaryOperator.identity())); + () -> resourceOperations.resourcePatch(resource, UnaryOperator.identity())); assertThat(exception.getMessage()).contains("Target event source must be a subclass off"); assertThat(exception.getMessage()).contains("ManagedInformerEventSource"); diff --git a/operator-framework-core/src/test/java/io/javaoperatorsdk/operator/processing/event/ReconciliationDispatcherTest.java b/operator-framework-core/src/test/java/io/javaoperatorsdk/operator/processing/event/ReconciliationDispatcherTest.java index 13673a72d5..c7d9458695 100644 --- a/operator-framework-core/src/test/java/io/javaoperatorsdk/operator/processing/event/ReconciliationDispatcherTest.java +++ b/operator-framework-core/src/test/java/io/javaoperatorsdk/operator/processing/event/ReconciliationDispatcherTest.java @@ -26,7 +26,6 @@ import org.junit.jupiter.api.Test; import org.mockito.ArgumentCaptor; import org.mockito.ArgumentMatchers; -import org.mockito.MockedStatic; import io.fabric8.kubernetes.api.model.HasMetadata; import io.fabric8.kubernetes.api.model.ObjectMeta; @@ -45,8 +44,8 @@ import io.javaoperatorsdk.operator.api.reconciler.DefaultContext; import io.javaoperatorsdk.operator.api.reconciler.DeleteControl; import io.javaoperatorsdk.operator.api.reconciler.ErrorStatusUpdateControl; -import io.javaoperatorsdk.operator.api.reconciler.ReconcileUtils; import io.javaoperatorsdk.operator.api.reconciler.Reconciler; +import io.javaoperatorsdk.operator.api.reconciler.ResourceOperations; import io.javaoperatorsdk.operator.api.reconciler.RetryInfo; import io.javaoperatorsdk.operator.api.reconciler.UpdateControl; import io.javaoperatorsdk.operator.processing.Controller; @@ -72,6 +71,7 @@ class ReconciliationDispatcherTest { private final CustomResourceFacade customResourceFacade = mock(ReconciliationDispatcher.CustomResourceFacade.class); private static ConfigurationService configurationService; + private ResourceOperations mockResourceOperations; @BeforeEach void setup() { @@ -151,27 +151,25 @@ public boolean useFinalizer() { } @Test - void addFinalizerOnNewResource() { - try (MockedStatic mockedReconcileUtils = mockStatic(ReconcileUtils.class)) { - assertFalse(testCustomResource.hasFinalizer(DEFAULT_FINALIZER)); - reconciliationDispatcher.handleExecution(executionScopeWithCREvent(testCustomResource)); - verify(reconciler, never()).reconcile(ArgumentMatchers.eq(testCustomResource), any()); - mockedReconcileUtils.verify(() -> ReconcileUtils.addFinalizerWithSSA(any()), times(1)); - } + void addFinalizerOnNewResource() throws Exception { + assertFalse(testCustomResource.hasFinalizer(DEFAULT_FINALIZER)); + reconciliationDispatcher.handleDispatch( + executionScopeWithCREvent(testCustomResource), createTestContext()); + verify(reconciler, never()).reconcile(ArgumentMatchers.eq(testCustomResource), any()); + verify(mockResourceOperations, times(1)).addFinalizerWithSSA(); } @Test - void addFinalizerOnNewResourceWithoutSSA() { - try (MockedStatic mockedReconcileUtils = mockStatic(ReconcileUtils.class)) { - initConfigService(false, false); - final ReconciliationDispatcher dispatcher = - init(testCustomResource, reconciler, null, customResourceFacade, true); + void addFinalizerOnNewResourceWithoutSSA() throws Exception { + initConfigService(false, false); + final ReconciliationDispatcher dispatcher = + init(testCustomResource, reconciler, null, customResourceFacade, true); + assertFalse(testCustomResource.hasFinalizer(DEFAULT_FINALIZER)); - assertFalse(testCustomResource.hasFinalizer(DEFAULT_FINALIZER)); - dispatcher.handleExecution(executionScopeWithCREvent(testCustomResource)); - verify(reconciler, never()).reconcile(ArgumentMatchers.eq(testCustomResource), any()); - mockedReconcileUtils.verify(() -> ReconcileUtils.addFinalizer(any()), times(1)); - } + dispatcher.handleDispatch(executionScopeWithCREvent(testCustomResource), createTestContext()); + + verify(reconciler, never()).reconcile(ArgumentMatchers.eq(testCustomResource), any()); + verify(mockResourceOperations, times(1)).addFinalizer(); } @Test @@ -227,17 +225,16 @@ void callsDeleteIfObjectHasFinalizerAndMarkedForDelete() { } @Test - void removesDefaultFinalizerOnDeleteIfSet() { - try (MockedStatic mockedReconcileUtils = mockStatic(ReconcileUtils.class)) { - testCustomResource.addFinalizer(DEFAULT_FINALIZER); - markForDeletion(testCustomResource); + void removesDefaultFinalizerOnDeleteIfSet() throws Exception { + testCustomResource.addFinalizer(DEFAULT_FINALIZER); + markForDeletion(testCustomResource); - var postExecControl = - reconciliationDispatcher.handleExecution(executionScopeWithCREvent(testCustomResource)); + var postExecControl = + reconciliationDispatcher.handleDispatch( + executionScopeWithCREvent(testCustomResource), createTestContext()); - assertThat(postExecControl.isFinalizerRemoved()).isTrue(); - mockedReconcileUtils.verify(() -> ReconcileUtils.removeFinalizer(any()), times(1)); - } + assertThat(postExecControl.isFinalizerRemoved()).isTrue(); + verify(mockResourceOperations, times(1)).removeFinalizer(); } @Test @@ -295,20 +292,21 @@ void doesNotUpdateTheResourceIfNoUpdateUpdateControlIfFinalizerSet() { } @Test - void addsFinalizerIfNotMarkedForDeletionAndEmptyCustomResourceReturned() { - try (MockedStatic mockedReconcileUtils = mockStatic(ReconcileUtils.class)) { - removeFinalizers(testCustomResource); - reconciler.reconcile = (r, c) -> UpdateControl.noUpdate(); - mockedReconcileUtils - .when(() -> ReconcileUtils.addFinalizerWithSSA(any())) - .thenReturn(testCustomResource); - var postExecControl = - reconciliationDispatcher.handleExecution(executionScopeWithCREvent(testCustomResource)); + void addsFinalizerIfNotMarkedForDeletionAndEmptyCustomResourceReturned() throws Exception { - mockedReconcileUtils.verify(() -> ReconcileUtils.addFinalizerWithSSA(any()), times(1)); - assertThat(postExecControl.updateIsStatusPatch()).isFalse(); - assertThat(postExecControl.getUpdatedCustomResource()).isPresent(); - } + removeFinalizers(testCustomResource); + reconciler.reconcile = (r, c) -> UpdateControl.noUpdate(); + var context = createTestContext(); + when(mockResourceOperations.addFinalizerWithSSA()).thenReturn(testCustomResource); + + var postExecControl = + reconciliationDispatcher.handleDispatch( + executionScopeWithCREvent(testCustomResource), context); + + verify(mockResourceOperations, times(1)).addFinalizerWithSSA(); + + assertThat(postExecControl.updateIsStatusPatch()).isFalse(); + assertThat(postExecControl.getUpdatedCustomResource()).isPresent(); } @Test @@ -646,6 +644,13 @@ void reconcilerContextUsesTheSameInstanceOfResourceAsParam() { .isNotSameAs(testCustomResource); } + private Context createTestContext() { + var mockContext = mock(Context.class); + mockResourceOperations = mock(ResourceOperations.class); + when(mockContext.resourceOperations()).thenReturn(mockResourceOperations); + return mockContext; + } + private ObservedGenCustomResource createObservedGenCustomResource() { ObservedGenCustomResource observedGenCustomResource = new ObservedGenCustomResource(); observedGenCustomResource.setMetadata(new ObjectMeta()); diff --git a/operator-framework/src/test/java/io/javaoperatorsdk/operator/baseapi/changenamespace/ChangeNamespaceTestReconciler.java b/operator-framework/src/test/java/io/javaoperatorsdk/operator/baseapi/changenamespace/ChangeNamespaceTestReconciler.java index 96bd43c9e2..d05364fc44 100644 --- a/operator-framework/src/test/java/io/javaoperatorsdk/operator/baseapi/changenamespace/ChangeNamespaceTestReconciler.java +++ b/operator-framework/src/test/java/io/javaoperatorsdk/operator/baseapi/changenamespace/ChangeNamespaceTestReconciler.java @@ -53,7 +53,7 @@ public UpdateControl reconcile( ChangeNamespaceTestCustomResource primary, Context context) { - ReconcileUtils.serverSideApply(context, configMap(primary)); + context.resourceOperations().serverSideApply(configMap(primary)); if (primary.getStatus() == null) { primary.setStatus(new ChangeNamespaceTestCustomResourceStatus()); diff --git a/operator-framework/src/test/java/io/javaoperatorsdk/operator/baseapi/generickubernetesresourcehandling/GenericKubernetesResourceHandlingReconciler.java b/operator-framework/src/test/java/io/javaoperatorsdk/operator/baseapi/generickubernetesresourcehandling/GenericKubernetesResourceHandlingReconciler.java index f76443c103..7efa8a0ad6 100644 --- a/operator-framework/src/test/java/io/javaoperatorsdk/operator/baseapi/generickubernetesresourcehandling/GenericKubernetesResourceHandlingReconciler.java +++ b/operator-framework/src/test/java/io/javaoperatorsdk/operator/baseapi/generickubernetesresourcehandling/GenericKubernetesResourceHandlingReconciler.java @@ -40,7 +40,7 @@ public UpdateControl reconcile( GenericKubernetesResourceHandlingCustomResource primary, Context context) { - ReconcileUtils.serverSideApply(context, desiredConfigMap(primary, context)); + context.resourceOperations().serverSideApply(desiredConfigMap(primary, context)); return UpdateControl.noUpdate(); } diff --git a/operator-framework/src/test/java/io/javaoperatorsdk/operator/baseapi/multiplesecondaryeventsource/MultipleSecondaryEventSourceReconciler.java b/operator-framework/src/test/java/io/javaoperatorsdk/operator/baseapi/multiplesecondaryeventsource/MultipleSecondaryEventSourceReconciler.java index aea2dfe0c2..2a11be1faf 100644 --- a/operator-framework/src/test/java/io/javaoperatorsdk/operator/baseapi/multiplesecondaryeventsource/MultipleSecondaryEventSourceReconciler.java +++ b/operator-framework/src/test/java/io/javaoperatorsdk/operator/baseapi/multiplesecondaryeventsource/MultipleSecondaryEventSourceReconciler.java @@ -26,7 +26,6 @@ import io.javaoperatorsdk.operator.api.reconciler.Context; import io.javaoperatorsdk.operator.api.reconciler.ControllerConfiguration; import io.javaoperatorsdk.operator.api.reconciler.EventSourceContext; -import io.javaoperatorsdk.operator.api.reconciler.ReconcileUtils; import io.javaoperatorsdk.operator.api.reconciler.Reconciler; import io.javaoperatorsdk.operator.api.reconciler.UpdateControl; import io.javaoperatorsdk.operator.processing.event.ResourceID; @@ -54,8 +53,8 @@ public UpdateControl reconcile( Context context) { numberOfExecutions.addAndGet(1); - ReconcileUtils.serverSideApply(context, configMap(getName1(resource), resource)); - ReconcileUtils.serverSideApply(context, configMap(getName2(resource), resource)); + context.resourceOperations().serverSideApply(configMap(getName1(resource), resource)); + context.resourceOperations().serverSideApply(configMap(getName2(resource), resource)); if (numberOfExecutions.get() >= 3) { if (context.getSecondaryResources(ConfigMap.class).size() != 2) { diff --git a/operator-framework/src/test/java/io/javaoperatorsdk/operator/baseapi/simple/TestReconciler.java b/operator-framework/src/test/java/io/javaoperatorsdk/operator/baseapi/simple/TestReconciler.java index 49dbe80554..974427ba43 100644 --- a/operator-framework/src/test/java/io/javaoperatorsdk/operator/baseapi/simple/TestReconciler.java +++ b/operator-framework/src/test/java/io/javaoperatorsdk/operator/baseapi/simple/TestReconciler.java @@ -69,7 +69,7 @@ public UpdateControl reconcile( if (existingConfigMap != null) { existingConfigMap.setData(configMapData(resource)); log.info("Updating config map"); - ReconcileUtils.serverSideApply(context, existingConfigMap); + context.resourceOperations().serverSideApply(existingConfigMap); } else { Map labels = new HashMap<>(); labels.put("managedBy", TestReconciler.class.getSimpleName()); @@ -84,7 +84,7 @@ public UpdateControl reconcile( .withData(configMapData(resource)) .build(); log.info("Creating config map"); - ReconcileUtils.serverSideApply(context, newConfigMap); + context.resourceOperations().serverSideApply(newConfigMap); } if (updateStatus) { var statusUpdateResource = new TestCustomResource(); diff --git a/operator-framework/src/test/java/io/javaoperatorsdk/operator/baseapi/triggerallevent/eventing/TriggerReconcilerOnAllEventReconciler.java b/operator-framework/src/test/java/io/javaoperatorsdk/operator/baseapi/triggerallevent/eventing/TriggerReconcilerOnAllEventReconciler.java index 2217662402..f8804bd25d 100644 --- a/operator-framework/src/test/java/io/javaoperatorsdk/operator/baseapi/triggerallevent/eventing/TriggerReconcilerOnAllEventReconciler.java +++ b/operator-framework/src/test/java/io/javaoperatorsdk/operator/baseapi/triggerallevent/eventing/TriggerReconcilerOnAllEventReconciler.java @@ -22,7 +22,6 @@ import io.javaoperatorsdk.operator.api.reconciler.Context; import io.javaoperatorsdk.operator.api.reconciler.ControllerConfiguration; -import io.javaoperatorsdk.operator.api.reconciler.ReconcileUtils; import io.javaoperatorsdk.operator.api.reconciler.Reconciler; import io.javaoperatorsdk.operator.api.reconciler.UpdateControl; @@ -75,7 +74,7 @@ public UpdateControl reconcile( if (!primary.isMarkedForDeletion() && getUseFinalizer() && !primary.hasFinalizer(FINALIZER)) { log.info("Adding finalizer"); - ReconcileUtils.addFinalizer(context, FINALIZER); + context.resourceOperations().addFinalizer(FINALIZER); return UpdateControl.noUpdate(); } @@ -98,7 +97,7 @@ public UpdateControl reconcile( setEventOnMarkedForDeletion(true); if (getUseFinalizer() && primary.hasFinalizer(FINALIZER)) { log.info("Removing finalizer"); - ReconcileUtils.removeFinalizer(context, FINALIZER); + context.resourceOperations().removeFinalizer(FINALIZER); } } diff --git a/operator-framework/src/test/java/io/javaoperatorsdk/operator/baseapi/triggerallevent/finalizerhandling/SelectiveFinalizerHandlingReconciler.java b/operator-framework/src/test/java/io/javaoperatorsdk/operator/baseapi/triggerallevent/finalizerhandling/SelectiveFinalizerHandlingReconciler.java index f9198d0eae..a7bf76a6e7 100644 --- a/operator-framework/src/test/java/io/javaoperatorsdk/operator/baseapi/triggerallevent/finalizerhandling/SelectiveFinalizerHandlingReconciler.java +++ b/operator-framework/src/test/java/io/javaoperatorsdk/operator/baseapi/triggerallevent/finalizerhandling/SelectiveFinalizerHandlingReconciler.java @@ -17,7 +17,6 @@ import io.javaoperatorsdk.operator.api.reconciler.Context; import io.javaoperatorsdk.operator.api.reconciler.ControllerConfiguration; -import io.javaoperatorsdk.operator.api.reconciler.ReconcileUtils; import io.javaoperatorsdk.operator.api.reconciler.Reconciler; import io.javaoperatorsdk.operator.api.reconciler.UpdateControl; @@ -37,11 +36,11 @@ public UpdateControl reconci } if (resource.getSpec().getUseFinalizer()) { - ReconcileUtils.addFinalizer(context, FINALIZER); + context.resourceOperations().addFinalizer(FINALIZER); } if (resource.isMarkedForDeletion()) { - ReconcileUtils.removeFinalizer(context, FINALIZER); + context.resourceOperations().removeFinalizer(FINALIZER); } return UpdateControl.noUpdate(); 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 b97d8ef679..4f4cab80d7 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 @@ -32,7 +32,6 @@ import io.javaoperatorsdk.operator.api.reconciler.ControllerConfiguration; import io.javaoperatorsdk.operator.api.reconciler.DeleteControl; import io.javaoperatorsdk.operator.api.reconciler.EventSourceContext; -import io.javaoperatorsdk.operator.api.reconciler.ReconcileUtils; import io.javaoperatorsdk.operator.api.reconciler.Reconciler; import io.javaoperatorsdk.operator.api.reconciler.UpdateControl; import io.javaoperatorsdk.operator.processing.event.ResourceID; @@ -111,7 +110,7 @@ private void createExternalResource( // This is critical in this case, since on next reconciliation if it would not be in the cache // it would be created again. configMapEventSource.eventFilteringUpdateAndCacheResource( - configMap, toCreate -> ReconcileUtils.serverSideApply(context, toCreate)); + configMap, toCreate -> context.resourceOperations().serverSideApply(toCreate)); externalResourceEventSource.handleRecentResourceCreate(primaryID, createdResource); } diff --git a/sample-operators/webpage/src/main/java/io/javaoperatorsdk/operator/sample/WebPageReconciler.java b/sample-operators/webpage/src/main/java/io/javaoperatorsdk/operator/sample/WebPageReconciler.java index 13fede9fcc..f46ccb193e 100644 --- a/sample-operators/webpage/src/main/java/io/javaoperatorsdk/operator/sample/WebPageReconciler.java +++ b/sample-operators/webpage/src/main/java/io/javaoperatorsdk/operator/sample/WebPageReconciler.java @@ -105,7 +105,7 @@ public UpdateControl reconcile(WebPage webPage, Context contex "Creating or updating ConfigMap {} in {}", desiredHtmlConfigMap.getMetadata().getName(), ns); - ReconcileUtils.serverSideApply(context, desiredHtmlConfigMap); + context.resourceOperations().serverSideApply(desiredHtmlConfigMap); } var existingDeployment = context.getSecondaryResource(Deployment.class).orElse(null); @@ -114,23 +114,21 @@ public UpdateControl reconcile(WebPage webPage, Context contex "Creating or updating Deployment {} in {}", desiredDeployment.getMetadata().getName(), ns); - ReconcileUtils.serverSideApply(context, desiredDeployment); + context.resourceOperations().serverSideApply(desiredDeployment); } var existingService = context.getSecondaryResource(Service.class).orElse(null); if (!match(desiredService, existingService)) { log.info( - "Creating or updating Deployment {} in {}", - desiredDeployment.getMetadata().getName(), - ns); - ReconcileUtils.serverSideApply(context, desiredService); + "Creating or updating Service {} in {}", desiredDeployment.getMetadata().getName(), ns); + context.resourceOperations().serverSideApply(desiredService); } var existingIngress = context.getSecondaryResource(Ingress.class); if (Boolean.TRUE.equals(webPage.getSpec().getExposed())) { var desiredIngress = makeDesiredIngress(webPage); if (existingIngress.isEmpty() || !match(desiredIngress, existingIngress.get())) { - ReconcileUtils.serverSideApply(context, desiredIngress); + context.resourceOperations().serverSideApply(desiredDeployment); } } else existingIngress.ifPresent(ingress -> context.getClient().resource(ingress).delete());