diff --git a/README.md b/README.md index d850c4551d..a58a8dcd51 100644 --- a/README.md +++ b/README.md @@ -40,7 +40,6 @@ It makes it easy to implement best practices and patterns for an Operator. Featu * Handling dependent resources, related events, and caching. * Automatic Retries * Smart event scheduling -* Handling Observed Generations automatically * Easy to use Error Handling * ... and everything that a batteries included framework needs diff --git a/bootstrapper-maven-plugin/src/main/resources/templates/Status.java b/bootstrapper-maven-plugin/src/main/resources/templates/Status.java index 4c37b99947..52bd0fd4d2 100644 --- a/bootstrapper-maven-plugin/src/main/resources/templates/Status.java +++ b/bootstrapper-maven-plugin/src/main/resources/templates/Status.java @@ -1,7 +1,5 @@ package {{groupId}}; -import io.javaoperatorsdk.operator.api.ObservedGenerationAwareStatus; - -public class {{artifactClassId}}Status extends ObservedGenerationAwareStatus { +public class {{artifactClassId}}Status { } diff --git a/caffeine-bounded-cache-support/src/test/java/io/javaoperatorsdk/operator/processing/event/source/cache/sample/namespacescope/BoundedCacheTestStatus.java b/caffeine-bounded-cache-support/src/test/java/io/javaoperatorsdk/operator/processing/event/source/cache/sample/namespacescope/BoundedCacheTestStatus.java index 03a311529e..2bdd434d23 100644 --- a/caffeine-bounded-cache-support/src/test/java/io/javaoperatorsdk/operator/processing/event/source/cache/sample/namespacescope/BoundedCacheTestStatus.java +++ b/caffeine-bounded-cache-support/src/test/java/io/javaoperatorsdk/operator/processing/event/source/cache/sample/namespacescope/BoundedCacheTestStatus.java @@ -1,6 +1,4 @@ package io.javaoperatorsdk.operator.processing.event.source.cache.sample.namespacescope; -import io.javaoperatorsdk.operator.api.ObservedGenerationAwareStatus; - -public class BoundedCacheTestStatus extends ObservedGenerationAwareStatus { +public class BoundedCacheTestStatus { } diff --git a/docs/documentation/features.md b/docs/documentation/features.md index d2ead0710b..68e8422c7c 100644 --- a/docs/documentation/features.md +++ b/docs/documentation/features.md @@ -186,57 +186,6 @@ annotation. If you do not specify a finalizer name, one will be automatically ge From v5 by default finalizer is added using Served Side Apply. See also UpdateControl in docs. -## Automatic Observed Generation Handling - -Having an `.observedGeneration` value on your resources' status is a best practice to -indicate the last generation of the resource which was successfully reconciled by the controller. -This helps users / administrators diagnose potential issues. - -In order to have this feature working: - -- the **status class** (not the resource itself) must implement the - [`ObservedGenerationAware`](https://github.com/java-operator-sdk/java-operator-sdk/blob/main/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/ObservedGenerationAware.java) - interface. See also - the [`ObservedGenerationAwareStatus`](https://github.com/java-operator-sdk/java-operator-sdk/blob/main/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/ObservedGenerationAwareStatus.java) - convenience implementation that you can extend in your own status class implementations. -- The other condition is that the `CustomResource.getStatus()` method should not return `null`. - So the status should be instantiated when the object is returned using the `UpdateControl`. - -If these conditions are fulfilled and generation awareness is activated, the observed generation -is automatically set by the framework after the `reconcile` method is called. - -When using SSA based patches, the observed generation is only updated when `UpdateControl.patchStatus` or -`UpdateControl.patchResourceAndStatus` is returned. In case the of non-SSA based patches -the observed generation is also updated even when `UpdateControl.noUpdate()` is returned from the -reconciler. -See this feature at work in the [WebPage example](https://github.com/java-operator-sdk/java-operator-sdk/blob/main/sample-operators/webpage/src/main/java/io/javaoperatorsdk/operator/sample/WebPageStatus.java#L5). -See turning off an on the SSA based patching at [`ConfigurationServcice.useSSAToPatchPrimaryResource()`](https://github.com/operator-framework/java-operator-sdk/blob/main/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/config/ConfigurationService.java#L385-L385). - -```java -public class WebPageStatus extends ObservedGenerationAwareStatus { - // omitted code -} -``` - -Initializing status automatically on custom resource could be done by overriding the `initStatus` method -of `CustomResource`. However, this is NOT advised, since breaks the status patching if you use: -`UpdateControl.patchStatus`. See -also [javadocs](https://github.com/java-operator-sdk/java-operator-sdk/blob/3994f5ffc1fb000af81aa198abf72a5f75fd3e97/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/reconciler/UpdateControl.java#L41-L42) -. - -```java -@Group("sample.javaoperatorsdk") -@Version("v1") -public class WebPage extends CustomResource - implements Namespaced { - - @Override - protected WebPageStatus initStatus() { - return new WebPageStatus(); - } -} -``` - ## Generation Awareness and Event Filtering A best practice when an operator starts up is to reconcile all the associated resources because @@ -254,9 +203,7 @@ To turn off this feature, set `generationAwareEventProcessing` to `false` for th ## Support for Well Known (non-custom) Kubernetes Resources A Controller can be registered for a non-custom resource, so well known Kubernetes resources like ( -`Ingress`, `Deployment`,...). Note that automatic observed generation handling is not supported -for these resources, though, in this case, the handling of the observed generation is probably -handled by the primary controller. +`Ingress`, `Deployment`,...). See the [integration test](https://github.com/java-operator-sdk/java-operator-sdk/blob/main/operator-framework/src/test/java/io/javaoperatorsdk/operator/sample/deployment/DeploymentReconciler.java) diff --git a/docs/documentation/v5-0-migration.md b/docs/documentation/v5-0-migration.md index b051e2018f..f338d97381 100644 --- a/docs/documentation/v5-0-migration.md +++ b/docs/documentation/v5-0-migration.md @@ -44,11 +44,6 @@ permalink: /docs/v5-0-migration where it is demonstrated. Also, the related part of a [workaround](https://github.com/operator-framework/java-operator-sdk/blob/main/operator-framework/src/test/java/io/javaoperatorsdk/operator/StatusPatchSSAMigrationIT.java#L110-L116). - Related automatic observed generation handling changes: - Automated Observed Generation (see features in docs), is automatically handled for non-SSA, even if - the status sub-resource is not instructed to be updated. This is not true for SSA, observed generation is updated - only when patch status is instructed by `UpdateControl`. - 6. `ManagedDependentResourceContext` has been renamed to `ManagedWorkflowAndDependentResourceContext` and is accessed via the accordingly renamed `managedWorkflowAndDependentResourceContext` method. 7. `ResourceDiscriminator` was removed. In most of the cases you can just delete the discriminator, everything should @@ -57,3 +52,9 @@ permalink: /docs/v5-0-migration 8. `ConfigurationService.getTerminationTimeoutSeconds` and associated overriding mechanism have been removed, use `Operator.stop(Duration)` instead. 9. `Operator.installShutdownHook()` has been removed, use `Operator.installShutdownHook(Duration)` instead +10. Automated observed generation handling feature was removed (`ObservedGenerationAware` interface + and `ObservedGenerationAwareStatus` class were deleted). Manually handling observed generation is fairly easy to do + in your reconciler, however, it cannot be done automatically when using SSA. We therefore removed the feature since + it would have been confusing to have a different behavior for SSA and non-SSA cases. For an example of how to do + observed generation handling manually in your reconciler, see + [this sample](https://github.com/operator-framework/java-operator-sdk/blob/main/operator-framework/src/test/java/io/javaoperatorsdk/operator/sample/manualobservedgeneration/ManualObservedGenerationReconciler.java). \ No newline at end of file diff --git a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/ObservedGenerationAware.java b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/ObservedGenerationAware.java deleted file mode 100644 index eafe51e6f4..0000000000 --- a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/ObservedGenerationAware.java +++ /dev/null @@ -1,29 +0,0 @@ -package io.javaoperatorsdk.operator.api; - -import io.fabric8.kubernetes.api.model.HasMetadata; -import io.fabric8.kubernetes.client.CustomResource; -import io.javaoperatorsdk.operator.api.config.ConfigurationService; -import io.javaoperatorsdk.operator.api.reconciler.UpdateControl; - -/** - * If the custom resource's status implements this interface, the observed generation will be - * automatically handled. The last observed generation will be updated on status. - *

- * In order for this automatic handling to work the status object returned by - * {@link CustomResource#getStatus()} should not be null. - *

- * The observed generation is updated with SSA mode only if - * {@link UpdateControl#patchStatus(HasMetadata)} or - * {@link UpdateControl#patchResourceAndStatus(HasMetadata)} is called. In non-SSA mode (see - * {@link ConfigurationService#useSSAToPatchPrimaryResource()}) observed generation is update even - * if patch is not called. - * - * @see ObservedGenerationAwareStatus - */ -public interface ObservedGenerationAware { - - void setObservedGeneration(Long generation); - - Long getObservedGeneration(); - -} diff --git a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/ObservedGenerationAwareStatus.java b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/ObservedGenerationAwareStatus.java deleted file mode 100644 index d2048c9513..0000000000 --- a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/ObservedGenerationAwareStatus.java +++ /dev/null @@ -1,19 +0,0 @@ -package io.javaoperatorsdk.operator.api; - -/** - * A helper base class for status sub-resources classes to extend to support generate awareness. - */ -public class ObservedGenerationAwareStatus implements ObservedGenerationAware { - - private Long observedGeneration; - - @Override - public void setObservedGeneration(Long generation) { - this.observedGeneration = generation; - } - - @Override - public Long getObservedGeneration() { - return observedGeneration; - } -} diff --git a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/config/ConfigurationService.java b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/config/ConfigurationService.java index eb3c9a9b01..16d01c4ddd 100644 --- a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/config/ConfigurationService.java +++ b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/config/ConfigurationService.java @@ -395,7 +395,7 @@ default boolean parseResourceVersionsForEventFilteringAndCaching() { /** * {@link io.javaoperatorsdk.operator.api.reconciler.UpdateControl} patch resource or status can * either use simple patches or SSA. Setting this to {@code true}, controllers will use SSA for - * adding finalizers, managing observed generation, patching resources and status. + * adding finalizers, patching resources and status. * * @return {@code true} if Server-Side Apply (SSA) should be used when patching the primary * resources, {@code false} otherwise 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 531917adac..601a92ba60 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 @@ -10,14 +10,12 @@ import io.fabric8.kubernetes.api.model.KubernetesResourceList; import io.fabric8.kubernetes.api.model.Namespaced; import io.fabric8.kubernetes.api.model.ObjectMeta; -import io.fabric8.kubernetes.client.CustomResource; import io.fabric8.kubernetes.client.KubernetesClientException; import io.fabric8.kubernetes.client.dsl.MixedOperation; import io.fabric8.kubernetes.client.dsl.Resource; import io.fabric8.kubernetes.client.dsl.base.PatchContext; import io.fabric8.kubernetes.client.dsl.base.PatchType; import io.javaoperatorsdk.operator.OperatorException; -import io.javaoperatorsdk.operator.api.ObservedGenerationAware; import io.javaoperatorsdk.operator.api.config.Cloner; import io.javaoperatorsdk.operator.api.config.ControllerConfiguration; import io.javaoperatorsdk.operator.api.reconciler.BaseControl; @@ -170,13 +168,8 @@ private PostExecutionControl

reconcileExecution(ExecutionScope

executionSc } } - // check if status also needs to be updated - final var updateObservedGeneration = updateControl.isNoUpdate() - ? shouldUpdateObservedGenerationAutomatically(resourceForExecution) - : shouldUpdateObservedGenerationAutomatically(updatedCustomResource); - // if using SSA the observed generation is updated only if user instructs patching the status - if (updateControl.isPatchStatus() || (updateObservedGeneration && !useSSA)) { - updatedCustomResource = patchStatusGenerationAware(toUpdate, originalResource); + if (updateControl.isPatchStatus()) { + customResourceFacade.patchStatus(toUpdate, originalResource); } return createPostExecutionControl(updatedCustomResource, updateControl); } @@ -206,9 +199,8 @@ public boolean isLastAttempt() { P updatedResource = null; if (errorStatusUpdateControl.getResource().isPresent()) { - updatedResource = - patchStatusGenerationAware(errorStatusUpdateControl.getResource().orElseThrow(), - originalResource); + updatedResource = customResourceFacade + .patchStatus(errorStatusUpdateControl.getResource().orElseThrow(), originalResource); } if (errorStatusUpdateControl.isNoRetry()) { PostExecutionControl

postExecutionControl; @@ -234,38 +226,9 @@ private boolean isErrorStatusHandlerPresent() { } private P patchStatusGenerationAware(P resource, P originalResource) { - updateStatusObservedGenerationIfRequired(resource); return customResourceFacade.patchStatus(resource, originalResource); } - @SuppressWarnings("rawtypes") - private boolean shouldUpdateObservedGenerationAutomatically(P resource) { - if (configuration().isGenerationAware() && resource instanceof CustomResource) { - var customResource = (CustomResource) resource; - var status = customResource.getStatus(); - // Note that if status is null we won't update the observed generation. - if (status instanceof ObservedGenerationAware) { - var observedGen = ((ObservedGenerationAware) status).getObservedGeneration(); - var currentGen = resource.getMetadata().getGeneration(); - return !currentGen.equals(observedGen); - } - } - return false; - } - - @SuppressWarnings("rawtypes") - private void updateStatusObservedGenerationIfRequired(P resource) { - if (configuration().isGenerationAware() && resource instanceof CustomResource) { - var customResource = (CustomResource) resource; - var status = customResource.getStatus(); - // Note that if status is null we won't update the observed generation. - if (status instanceof ObservedGenerationAware) { - ((ObservedGenerationAware) status) - .setObservedGeneration(resource.getMetadata().getGeneration()); - } - } - } - private PostExecutionControl

createPostExecutionControl(P updatedCustomResource, UpdateControl

updateControl) { PostExecutionControl

postExecutionControl; 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 bf4e5a8f27..7e80f4aedc 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 @@ -435,29 +435,6 @@ void reScheduleOnDeleteWithoutFinalizerRemoval() { .isEqualTo(1000L); } - @Test - void setObservedGenerationForStatusIfNeeded() throws Exception { - var observedGenResource = createObservedGenCustomResource(); - - Reconciler reconciler = mock(Reconciler.class); - ControllerConfiguration config = - MockControllerConfiguration.forResource(ObservedGenCustomResource.class); - CustomResourceFacade facade = mock(CustomResourceFacade.class); - var dispatcher = init(observedGenResource, reconciler, config, facade, true); - - when(config.isGenerationAware()).thenReturn(true); - - when(reconciler.reconcile(any(), any())) - .thenReturn(UpdateControl.patchStatus(observedGenResource)); - when(facade.patchStatus(eq(observedGenResource), any())).thenReturn(observedGenResource); - - PostExecutionControl control = dispatcher.handleExecution( - executionScopeWithCREvent(observedGenResource)); - assertThat(control.getUpdatedCustomResource().orElseGet(() -> fail("Missing optional")) - .getStatus().getObservedGeneration()) - .isEqualTo(1L); - } - @Test void doesNotUpdatesObservedGenerationIfStatusIsNotPatchedWhenUsingSSA() throws Exception { var observedGenResource = createObservedGenCustomResource(); @@ -476,28 +453,6 @@ void doesNotUpdatesObservedGenerationIfStatusIsNotPatchedWhenUsingSSA() throws E assertThat(control.getUpdatedCustomResource()).isEmpty(); } - @Test - void patchObservedGenerationOnCustomResourcePatchIfNoSSA() throws Exception { - var observedGenResource = createObservedGenCustomResource(); - - Reconciler reconciler = mock(Reconciler.class); - final var config = MockControllerConfiguration.forResource(ObservedGenCustomResource.class); - CustomResourceFacade facade = mock(CustomResourceFacade.class); - when(config.isGenerationAware()).thenReturn(true); - when(reconciler.reconcile(any(), any())) - .thenReturn(UpdateControl.patchResource(observedGenResource)); - when(facade.patchResource(any(), any())).thenReturn(observedGenResource); - when(facade.patchStatus(eq(observedGenResource), any())).thenReturn(observedGenResource); - initConfigService(false); - var dispatcher = init(observedGenResource, reconciler, config, facade, true); - - PostExecutionControl control = dispatcher.handleExecution( - executionScopeWithCREvent(observedGenResource)); - assertThat(control.getUpdatedCustomResource().orElseGet(() -> fail("Missing optional")) - .getStatus().getObservedGeneration()) - .isEqualTo(1L); - } - @Test void doesNotPatchObservedGenerationOnCustomResourcePatch() throws Exception { var observedGenResource = createObservedGenCustomResource(); diff --git a/operator-framework-core/src/test/java/io/javaoperatorsdk/operator/sample/observedgeneration/ObservedGenStatus.java b/operator-framework-core/src/test/java/io/javaoperatorsdk/operator/sample/observedgeneration/ObservedGenStatus.java index d4ffee5416..81ce9a435d 100644 --- a/operator-framework-core/src/test/java/io/javaoperatorsdk/operator/sample/observedgeneration/ObservedGenStatus.java +++ b/operator-framework-core/src/test/java/io/javaoperatorsdk/operator/sample/observedgeneration/ObservedGenStatus.java @@ -1,7 +1,5 @@ package io.javaoperatorsdk.operator.sample.observedgeneration; -import io.javaoperatorsdk.operator.api.ObservedGenerationAwareStatus; - -public class ObservedGenStatus extends ObservedGenerationAwareStatus { +public class ObservedGenStatus { } diff --git a/operator-framework/src/test/java/io/javaoperatorsdk/operator/ManualObservedGenerationIT.java b/operator-framework/src/test/java/io/javaoperatorsdk/operator/ManualObservedGenerationIT.java new file mode 100644 index 0000000000..ddfb2370d6 --- /dev/null +++ b/operator-framework/src/test/java/io/javaoperatorsdk/operator/ManualObservedGenerationIT.java @@ -0,0 +1,54 @@ +package io.javaoperatorsdk.operator; + +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.RegisterExtension; + +import io.fabric8.kubernetes.api.model.ObjectMetaBuilder; +import io.javaoperatorsdk.operator.junit.LocallyRunOperatorExtension; +import io.javaoperatorsdk.operator.sample.manualobservedgeneration.ManualObservedGenerationCustomResource; +import io.javaoperatorsdk.operator.sample.manualobservedgeneration.ManualObservedGenerationReconciler; +import io.javaoperatorsdk.operator.sample.manualobservedgeneration.ManualObservedGenerationSpec; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.awaitility.Awaitility.await; + +public class ManualObservedGenerationIT { + + public static final String RESOURCE_NAME = "test1"; + @RegisterExtension + LocallyRunOperatorExtension extension = + LocallyRunOperatorExtension.builder().withReconciler(new ManualObservedGenerationReconciler()) + .build(); + + @Test + void observedGenerationUpdated() { + extension.create(testResource()); + + await().untilAsserted(() -> { + var r = extension.get(ManualObservedGenerationCustomResource.class, RESOURCE_NAME); + assertThat(r).isNotNull(); + assertThat(r.getStatus().getObservedGeneration()).isEqualTo(1); + assertThat(r.getStatus().getObservedGeneration()).isEqualTo(r.getMetadata().getGeneration()); + }); + + var changed = testResource(); + changed.getSpec().setValue("changed value"); + extension.replace(changed); + + await().untilAsserted(() -> { + var r = extension.get(ManualObservedGenerationCustomResource.class, RESOURCE_NAME); + assertThat(r.getStatus().getObservedGeneration()).isEqualTo(2); + assertThat(r.getStatus().getObservedGeneration()).isEqualTo(r.getMetadata().getGeneration()); + }); + } + + ManualObservedGenerationCustomResource testResource() { + var res = new ManualObservedGenerationCustomResource(); + res.setMetadata(new ObjectMetaBuilder() + .withName(RESOURCE_NAME) + .build()); + res.setSpec(new ManualObservedGenerationSpec()); + res.getSpec().setValue("Initial Value"); + return res; + } +} diff --git a/operator-framework/src/test/java/io/javaoperatorsdk/operator/ObservedGenerationHandlingIT.java b/operator-framework/src/test/java/io/javaoperatorsdk/operator/ObservedGenerationHandlingIT.java deleted file mode 100644 index 0e28ddec4c..0000000000 --- a/operator-framework/src/test/java/io/javaoperatorsdk/operator/ObservedGenerationHandlingIT.java +++ /dev/null @@ -1,37 +0,0 @@ -package io.javaoperatorsdk.operator; - -import java.util.concurrent.TimeUnit; - -import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.extension.RegisterExtension; - -import io.fabric8.kubernetes.api.model.ObjectMeta; -import io.javaoperatorsdk.operator.junit.LocallyRunOperatorExtension; -import io.javaoperatorsdk.operator.sample.observedgeneration.ObservedGenerationTestCustomResource; -import io.javaoperatorsdk.operator.sample.observedgeneration.ObservedGenerationTestReconciler; - -import static org.assertj.core.api.Assertions.assertThat; -import static org.awaitility.Awaitility.await; - -class ObservedGenerationHandlingIT { - @RegisterExtension - LocallyRunOperatorExtension operator = - LocallyRunOperatorExtension.builder().withReconciler(new ObservedGenerationTestReconciler()) - .build(); - - @Test - void testReconciliationOfNonCustomResourceAndStatusUpdate() { - var resource = new ObservedGenerationTestCustomResource(); - resource.setMetadata(new ObjectMeta()); - resource.getMetadata().setName("observed-gen1"); - - var createdResource = operator.create(resource); - - await().atMost(10, TimeUnit.SECONDS).untilAsserted(() -> { - var d = operator.get(ObservedGenerationTestCustomResource.class, - createdResource.getMetadata().getName()); - assertThat(d.getStatus().getObservedGeneration()).isNotNull(); - assertThat(d.getStatus().getObservedGeneration()).isEqualTo(1); - }); - } -} diff --git a/operator-framework/src/test/java/io/javaoperatorsdk/operator/sample/createupdateeventfilter/CreateUpdateEventFilterTestCustomResource.java b/operator-framework/src/test/java/io/javaoperatorsdk/operator/sample/createupdateeventfilter/CreateUpdateEventFilterTestCustomResource.java index 5797a44d9d..8a0ee77474 100644 --- a/operator-framework/src/test/java/io/javaoperatorsdk/operator/sample/createupdateeventfilter/CreateUpdateEventFilterTestCustomResource.java +++ b/operator-framework/src/test/java/io/javaoperatorsdk/operator/sample/createupdateeventfilter/CreateUpdateEventFilterTestCustomResource.java @@ -11,12 +11,7 @@ @ShortNames("cue") public class CreateUpdateEventFilterTestCustomResource extends - CustomResource + CustomResource implements Namespaced { - @Override - protected CreateUpdateEventFilterTestCustomResourceStatus initStatus() { - return new CreateUpdateEventFilterTestCustomResourceStatus(); - } - } diff --git a/operator-framework/src/test/java/io/javaoperatorsdk/operator/sample/createupdateeventfilter/CreateUpdateEventFilterTestCustomResourceStatus.java b/operator-framework/src/test/java/io/javaoperatorsdk/operator/sample/createupdateeventfilter/CreateUpdateEventFilterTestCustomResourceStatus.java index 6733e1a7cd..e8f8da78f4 100644 --- a/operator-framework/src/test/java/io/javaoperatorsdk/operator/sample/createupdateeventfilter/CreateUpdateEventFilterTestCustomResourceStatus.java +++ b/operator-framework/src/test/java/io/javaoperatorsdk/operator/sample/createupdateeventfilter/CreateUpdateEventFilterTestCustomResourceStatus.java @@ -1,7 +1,5 @@ package io.javaoperatorsdk.operator.sample.createupdateeventfilter; -import io.javaoperatorsdk.operator.api.ObservedGenerationAwareStatus; - -public class CreateUpdateEventFilterTestCustomResourceStatus extends ObservedGenerationAwareStatus { +public class CreateUpdateEventFilterTestCustomResourceStatus { } diff --git a/operator-framework/src/test/java/io/javaoperatorsdk/operator/sample/gracefulstop/GracefulStopTestCustomResourceStatus.java b/operator-framework/src/test/java/io/javaoperatorsdk/operator/sample/gracefulstop/GracefulStopTestCustomResourceStatus.java index f59f5b1163..fa80e79c19 100644 --- a/operator-framework/src/test/java/io/javaoperatorsdk/operator/sample/gracefulstop/GracefulStopTestCustomResourceStatus.java +++ b/operator-framework/src/test/java/io/javaoperatorsdk/operator/sample/gracefulstop/GracefulStopTestCustomResourceStatus.java @@ -1,7 +1,14 @@ package io.javaoperatorsdk.operator.sample.gracefulstop; -import io.javaoperatorsdk.operator.api.ObservedGenerationAwareStatus; +public class GracefulStopTestCustomResourceStatus { -public class GracefulStopTestCustomResourceStatus extends ObservedGenerationAwareStatus { + private long observedGeneration; + public long getObservedGeneration() { + return observedGeneration; + } + + public void setObservedGeneration(long observedGeneration) { + this.observedGeneration = observedGeneration; + } } diff --git a/operator-framework/src/test/java/io/javaoperatorsdk/operator/sample/gracefulstop/GracefulStopTestReconciler.java b/operator-framework/src/test/java/io/javaoperatorsdk/operator/sample/gracefulstop/GracefulStopTestReconciler.java index cf266c0b48..7ff0d9d246 100644 --- a/operator-framework/src/test/java/io/javaoperatorsdk/operator/sample/gracefulstop/GracefulStopTestReconciler.java +++ b/operator-framework/src/test/java/io/javaoperatorsdk/operator/sample/gracefulstop/GracefulStopTestReconciler.java @@ -22,6 +22,7 @@ public UpdateControl reconcile( numberOfExecutions.addAndGet(1); resource.setStatus(new GracefulStopTestCustomResourceStatus()); + resource.getStatus().setObservedGeneration(resource.getMetadata().getGeneration()); Thread.sleep(RECONCILER_SLEEP); return UpdateControl.patchStatus(resource); diff --git a/operator-framework/src/test/java/io/javaoperatorsdk/operator/sample/observedgeneration/ObservedGenerationTestCustomResource.java b/operator-framework/src/test/java/io/javaoperatorsdk/operator/sample/manualobservedgeneration/ManualObservedGenerationCustomResource.java similarity index 53% rename from operator-framework/src/test/java/io/javaoperatorsdk/operator/sample/observedgeneration/ObservedGenerationTestCustomResource.java rename to operator-framework/src/test/java/io/javaoperatorsdk/operator/sample/manualobservedgeneration/ManualObservedGenerationCustomResource.java index 8a0ede3a5d..10b54fe79d 100644 --- a/operator-framework/src/test/java/io/javaoperatorsdk/operator/sample/observedgeneration/ObservedGenerationTestCustomResource.java +++ b/operator-framework/src/test/java/io/javaoperatorsdk/operator/sample/manualobservedgeneration/ManualObservedGenerationCustomResource.java @@ -1,18 +1,15 @@ -package io.javaoperatorsdk.operator.sample.observedgeneration; +package io.javaoperatorsdk.operator.sample.manualobservedgeneration; import io.fabric8.kubernetes.api.model.Namespaced; import io.fabric8.kubernetes.client.CustomResource; import io.fabric8.kubernetes.model.annotation.Group; -import io.fabric8.kubernetes.model.annotation.Kind; import io.fabric8.kubernetes.model.annotation.ShortNames; import io.fabric8.kubernetes.model.annotation.Version; @Group("sample.javaoperatorsdk") @Version("v1") -@Kind("ObservedGenerationTestCustomResource") -@ShortNames("og") -public class ObservedGenerationTestCustomResource - extends CustomResource +@ShortNames("mog") +public class ManualObservedGenerationCustomResource + extends CustomResource implements Namespaced { - } diff --git a/operator-framework/src/test/java/io/javaoperatorsdk/operator/sample/manualobservedgeneration/ManualObservedGenerationReconciler.java b/operator-framework/src/test/java/io/javaoperatorsdk/operator/sample/manualobservedgeneration/ManualObservedGenerationReconciler.java new file mode 100644 index 0000000000..6e3aa15dce --- /dev/null +++ b/operator-framework/src/test/java/io/javaoperatorsdk/operator/sample/manualobservedgeneration/ManualObservedGenerationReconciler.java @@ -0,0 +1,48 @@ +package io.javaoperatorsdk.operator.sample.manualobservedgeneration; + +import java.util.Objects; +import java.util.concurrent.atomic.AtomicInteger; + +import io.fabric8.kubernetes.api.model.ObjectMetaBuilder; +import io.javaoperatorsdk.operator.api.reconciler.*; + +@ControllerConfiguration +public class ManualObservedGenerationReconciler + implements Reconciler { + + private final AtomicInteger numberOfExecutions = new AtomicInteger(0); + + @Override + public UpdateControl reconcile( + ManualObservedGenerationCustomResource resource, + Context context) { + numberOfExecutions.addAndGet(1); + var resourceForStatusPatch = resourceForStatusPatch(resource); + if (!Objects.equals(resource.getMetadata().getGeneration(), + resourceForStatusPatch.getStatus().getObservedGeneration())) { + resourceForStatusPatch.getStatus() + .setObservedGeneration(resource.getMetadata().getGeneration()); + return UpdateControl.patchStatus(resourceForStatusPatch); + } else { + return UpdateControl.noUpdate(); + } + } + + private ManualObservedGenerationCustomResource resourceForStatusPatch( + ManualObservedGenerationCustomResource original) { + var res = new ManualObservedGenerationCustomResource(); + res.setMetadata(new ObjectMetaBuilder() + .withName(original.getMetadata().getName()) + .withNamespace(original.getMetadata().getNamespace()) + .build()); + res.setStatus(original.getStatus()); + if (res.getStatus() == null) { + res.setStatus(new ManualObservedGenerationStatus()); + } + return res; + } + + public int getNumberOfExecutions() { + return numberOfExecutions.get(); + } +} diff --git a/operator-framework/src/test/java/io/javaoperatorsdk/operator/sample/manualobservedgeneration/ManualObservedGenerationSpec.java b/operator-framework/src/test/java/io/javaoperatorsdk/operator/sample/manualobservedgeneration/ManualObservedGenerationSpec.java new file mode 100644 index 0000000000..35b04685aa --- /dev/null +++ b/operator-framework/src/test/java/io/javaoperatorsdk/operator/sample/manualobservedgeneration/ManualObservedGenerationSpec.java @@ -0,0 +1,14 @@ +package io.javaoperatorsdk.operator.sample.manualobservedgeneration; + +public class ManualObservedGenerationSpec { + + private String value; + + public String getValue() { + return value; + } + + public void setValue(String value) { + this.value = value; + } +} diff --git a/operator-framework/src/test/java/io/javaoperatorsdk/operator/sample/manualobservedgeneration/ManualObservedGenerationStatus.java b/operator-framework/src/test/java/io/javaoperatorsdk/operator/sample/manualobservedgeneration/ManualObservedGenerationStatus.java new file mode 100644 index 0000000000..cdb6d56b2e --- /dev/null +++ b/operator-framework/src/test/java/io/javaoperatorsdk/operator/sample/manualobservedgeneration/ManualObservedGenerationStatus.java @@ -0,0 +1,14 @@ +package io.javaoperatorsdk.operator.sample.manualobservedgeneration; + +public class ManualObservedGenerationStatus { + + private long observedGeneration; + + public long getObservedGeneration() { + return observedGeneration; + } + + public void setObservedGeneration(long observedGeneration) { + this.observedGeneration = observedGeneration; + } +} diff --git a/operator-framework/src/test/java/io/javaoperatorsdk/operator/sample/observedgeneration/ObservedGenerationTestCustomResourceStatus.java b/operator-framework/src/test/java/io/javaoperatorsdk/operator/sample/observedgeneration/ObservedGenerationTestCustomResourceStatus.java deleted file mode 100644 index 14071775f3..0000000000 --- a/operator-framework/src/test/java/io/javaoperatorsdk/operator/sample/observedgeneration/ObservedGenerationTestCustomResourceStatus.java +++ /dev/null @@ -1,7 +0,0 @@ -package io.javaoperatorsdk.operator.sample.observedgeneration; - -import io.javaoperatorsdk.operator.api.ObservedGenerationAwareStatus; - -public class ObservedGenerationTestCustomResourceStatus extends ObservedGenerationAwareStatus { - -} diff --git a/operator-framework/src/test/java/io/javaoperatorsdk/operator/sample/observedgeneration/ObservedGenerationTestReconciler.java b/operator-framework/src/test/java/io/javaoperatorsdk/operator/sample/observedgeneration/ObservedGenerationTestReconciler.java deleted file mode 100644 index 7e2127ec7c..0000000000 --- a/operator-framework/src/test/java/io/javaoperatorsdk/operator/sample/observedgeneration/ObservedGenerationTestReconciler.java +++ /dev/null @@ -1,28 +0,0 @@ -package io.javaoperatorsdk.operator.sample.observedgeneration; - -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import io.javaoperatorsdk.operator.api.reconciler.Context; -import io.javaoperatorsdk.operator.api.reconciler.ControllerConfiguration; -import io.javaoperatorsdk.operator.api.reconciler.Reconciler; -import io.javaoperatorsdk.operator.api.reconciler.UpdateControl; - -@ControllerConfiguration -public class ObservedGenerationTestReconciler - implements Reconciler { - - private static final Logger log = LoggerFactory.getLogger(ObservedGenerationTestReconciler.class); - - @Override - public UpdateControl reconcile( - ObservedGenerationTestCustomResource resource, - Context context) { - log.info("Reconcile ObservedGenerationTestCustomResource: {}", - resource.getMetadata().getName()); - if (resource.getStatus() == null) { - resource.setStatus(new ObservedGenerationTestCustomResourceStatus()); - } - return UpdateControl.patchStatus(resource); - } -} diff --git a/operator-framework/src/test/java/io/javaoperatorsdk/operator/sample/ratelimit/RateLimitCustomResourceStatus.java b/operator-framework/src/test/java/io/javaoperatorsdk/operator/sample/ratelimit/RateLimitCustomResourceStatus.java index 087408fc16..975728c18c 100644 --- a/operator-framework/src/test/java/io/javaoperatorsdk/operator/sample/ratelimit/RateLimitCustomResourceStatus.java +++ b/operator-framework/src/test/java/io/javaoperatorsdk/operator/sample/ratelimit/RateLimitCustomResourceStatus.java @@ -1,7 +1,5 @@ package io.javaoperatorsdk.operator.sample.ratelimit; -import io.javaoperatorsdk.operator.api.ObservedGenerationAwareStatus; - -public class RateLimitCustomResourceStatus extends ObservedGenerationAwareStatus { +public class RateLimitCustomResourceStatus { } diff --git a/sample-operators/mysql-schema/src/main/java/io/javaoperatorsdk/operator/sample/SchemaStatus.java b/sample-operators/mysql-schema/src/main/java/io/javaoperatorsdk/operator/sample/SchemaStatus.java index 92ddb67a63..168cd8db15 100644 --- a/sample-operators/mysql-schema/src/main/java/io/javaoperatorsdk/operator/sample/SchemaStatus.java +++ b/sample-operators/mysql-schema/src/main/java/io/javaoperatorsdk/operator/sample/SchemaStatus.java @@ -1,8 +1,6 @@ package io.javaoperatorsdk.operator.sample; -import io.javaoperatorsdk.operator.api.ObservedGenerationAwareStatus; - -public class SchemaStatus extends ObservedGenerationAwareStatus { +public class SchemaStatus { private String url; diff --git a/sample-operators/webpage/src/main/java/io/javaoperatorsdk/operator/sample/customresource/WebPageStatus.java b/sample-operators/webpage/src/main/java/io/javaoperatorsdk/operator/sample/customresource/WebPageStatus.java index 7ab20c76be..36409ac7f9 100644 --- a/sample-operators/webpage/src/main/java/io/javaoperatorsdk/operator/sample/customresource/WebPageStatus.java +++ b/sample-operators/webpage/src/main/java/io/javaoperatorsdk/operator/sample/customresource/WebPageStatus.java @@ -1,8 +1,6 @@ package io.javaoperatorsdk.operator.sample.customresource; -import io.javaoperatorsdk.operator.api.ObservedGenerationAwareStatus; - -public class WebPageStatus extends ObservedGenerationAwareStatus { +public class WebPageStatus { private String htmlConfigMap;