From 47552198e3a812e666ac17ac08be930a514b1c8b Mon Sep 17 00:00:00 2001 From: GitHub Action <action@github.com> Date: Wed, 21 May 2025 10:28:32 +0000 Subject: [PATCH 1/5] Set new SNAPSHOT version into pom files. --- bootstrapper-maven-plugin/pom.xml | 2 +- caffeine-bounded-cache-support/pom.xml | 2 +- micrometer-support/pom.xml | 2 +- operator-framework-bom/pom.xml | 2 +- operator-framework-core/pom.xml | 2 +- operator-framework-junit5/pom.xml | 2 +- operator-framework/pom.xml | 2 +- pom.xml | 2 +- sample-operators/controller-namespace-deletion/pom.xml | 2 +- sample-operators/leader-election/pom.xml | 2 +- sample-operators/mysql-schema/pom.xml | 2 +- sample-operators/pom.xml | 2 +- sample-operators/tomcat-operator/pom.xml | 2 +- sample-operators/webpage/pom.xml | 2 +- 14 files changed, 14 insertions(+), 14 deletions(-) diff --git a/bootstrapper-maven-plugin/pom.xml b/bootstrapper-maven-plugin/pom.xml index 0e28960832..7487daa6fd 100644 --- a/bootstrapper-maven-plugin/pom.xml +++ b/bootstrapper-maven-plugin/pom.xml @@ -5,7 +5,7 @@ <parent> <groupId>io.javaoperatorsdk</groupId> <artifactId>java-operator-sdk</artifactId> - <version>5.1.0-SNAPSHOT</version> + <version>5.1.1-SNAPSHOT</version> </parent> <artifactId>bootstrapper</artifactId> diff --git a/caffeine-bounded-cache-support/pom.xml b/caffeine-bounded-cache-support/pom.xml index da33ff0a6c..a421b3cd9f 100644 --- a/caffeine-bounded-cache-support/pom.xml +++ b/caffeine-bounded-cache-support/pom.xml @@ -4,7 +4,7 @@ <parent> <groupId>io.javaoperatorsdk</groupId> <artifactId>java-operator-sdk</artifactId> - <version>5.1.0-SNAPSHOT</version> + <version>5.1.1-SNAPSHOT</version> </parent> <artifactId>caffeine-bounded-cache-support</artifactId> diff --git a/micrometer-support/pom.xml b/micrometer-support/pom.xml index a48312b3cd..9d9a47464f 100644 --- a/micrometer-support/pom.xml +++ b/micrometer-support/pom.xml @@ -4,7 +4,7 @@ <parent> <groupId>io.javaoperatorsdk</groupId> <artifactId>java-operator-sdk</artifactId> - <version>5.1.0-SNAPSHOT</version> + <version>5.1.1-SNAPSHOT</version> </parent> <artifactId>micrometer-support</artifactId> diff --git a/operator-framework-bom/pom.xml b/operator-framework-bom/pom.xml index d6b33034c4..123ae032c7 100644 --- a/operator-framework-bom/pom.xml +++ b/operator-framework-bom/pom.xml @@ -4,7 +4,7 @@ <groupId>io.javaoperatorsdk</groupId> <artifactId>operator-framework-bom</artifactId> - <version>5.1.0-SNAPSHOT</version> + <version>5.1.1-SNAPSHOT</version> <packaging>pom</packaging> <name>Operator SDK - Bill of Materials</name> <description>Java SDK for implementing Kubernetes operators</description> diff --git a/operator-framework-core/pom.xml b/operator-framework-core/pom.xml index 6f9bd02ec3..b4166a3761 100644 --- a/operator-framework-core/pom.xml +++ b/operator-framework-core/pom.xml @@ -4,7 +4,7 @@ <parent> <groupId>io.javaoperatorsdk</groupId> <artifactId>java-operator-sdk</artifactId> - <version>5.1.0-SNAPSHOT</version> + <version>5.1.1-SNAPSHOT</version> <relativePath>../pom.xml</relativePath> </parent> diff --git a/operator-framework-junit5/pom.xml b/operator-framework-junit5/pom.xml index 20b6550f42..111fdf3b1b 100644 --- a/operator-framework-junit5/pom.xml +++ b/operator-framework-junit5/pom.xml @@ -4,7 +4,7 @@ <parent> <groupId>io.javaoperatorsdk</groupId> <artifactId>java-operator-sdk</artifactId> - <version>5.1.0-SNAPSHOT</version> + <version>5.1.1-SNAPSHOT</version> </parent> <artifactId>operator-framework-junit-5</artifactId> diff --git a/operator-framework/pom.xml b/operator-framework/pom.xml index 24a6181134..0d60152818 100644 --- a/operator-framework/pom.xml +++ b/operator-framework/pom.xml @@ -4,7 +4,7 @@ <parent> <groupId>io.javaoperatorsdk</groupId> <artifactId>java-operator-sdk</artifactId> - <version>5.1.0-SNAPSHOT</version> + <version>5.1.1-SNAPSHOT</version> </parent> <artifactId>operator-framework</artifactId> diff --git a/pom.xml b/pom.xml index 4452238f32..fb32bb1aaa 100644 --- a/pom.xml +++ b/pom.xml @@ -4,7 +4,7 @@ <groupId>io.javaoperatorsdk</groupId> <artifactId>java-operator-sdk</artifactId> - <version>5.1.0-SNAPSHOT</version> + <version>5.1.1-SNAPSHOT</version> <packaging>pom</packaging> <name>Operator SDK for Java</name> <description>Java SDK for implementing Kubernetes operators</description> diff --git a/sample-operators/controller-namespace-deletion/pom.xml b/sample-operators/controller-namespace-deletion/pom.xml index 831af2e40b..75ef1ee5eb 100644 --- a/sample-operators/controller-namespace-deletion/pom.xml +++ b/sample-operators/controller-namespace-deletion/pom.xml @@ -5,7 +5,7 @@ <parent> <groupId>io.javaoperatorsdk</groupId> <artifactId>sample-operators</artifactId> - <version>5.1.0-SNAPSHOT</version> + <version>5.1.1-SNAPSHOT</version> </parent> <artifactId>sample-controller-namespace-deletion</artifactId> diff --git a/sample-operators/leader-election/pom.xml b/sample-operators/leader-election/pom.xml index 3b2c32008e..5611726540 100644 --- a/sample-operators/leader-election/pom.xml +++ b/sample-operators/leader-election/pom.xml @@ -5,7 +5,7 @@ <parent> <groupId>io.javaoperatorsdk</groupId> <artifactId>sample-operators</artifactId> - <version>5.1.0-SNAPSHOT</version> + <version>5.1.1-SNAPSHOT</version> </parent> <artifactId>sample-leader-election</artifactId> diff --git a/sample-operators/mysql-schema/pom.xml b/sample-operators/mysql-schema/pom.xml index 25e079e8e2..263a832d10 100644 --- a/sample-operators/mysql-schema/pom.xml +++ b/sample-operators/mysql-schema/pom.xml @@ -5,7 +5,7 @@ <parent> <groupId>io.javaoperatorsdk</groupId> <artifactId>sample-operators</artifactId> - <version>5.1.0-SNAPSHOT</version> + <version>5.1.1-SNAPSHOT</version> </parent> <artifactId>sample-mysql-schema-operator</artifactId> diff --git a/sample-operators/pom.xml b/sample-operators/pom.xml index 79f1d0d034..d89c0677d6 100644 --- a/sample-operators/pom.xml +++ b/sample-operators/pom.xml @@ -5,7 +5,7 @@ <parent> <groupId>io.javaoperatorsdk</groupId> <artifactId>java-operator-sdk</artifactId> - <version>5.1.0-SNAPSHOT</version> + <version>5.1.1-SNAPSHOT</version> </parent> <artifactId>sample-operators</artifactId> diff --git a/sample-operators/tomcat-operator/pom.xml b/sample-operators/tomcat-operator/pom.xml index 9ccc91e15b..0bc6f86eda 100644 --- a/sample-operators/tomcat-operator/pom.xml +++ b/sample-operators/tomcat-operator/pom.xml @@ -5,7 +5,7 @@ <parent> <groupId>io.javaoperatorsdk</groupId> <artifactId>sample-operators</artifactId> - <version>5.1.0-SNAPSHOT</version> + <version>5.1.1-SNAPSHOT</version> </parent> <artifactId>sample-tomcat-operator</artifactId> diff --git a/sample-operators/webpage/pom.xml b/sample-operators/webpage/pom.xml index 47e134770a..d2bfacc70e 100644 --- a/sample-operators/webpage/pom.xml +++ b/sample-operators/webpage/pom.xml @@ -5,7 +5,7 @@ <parent> <groupId>io.javaoperatorsdk</groupId> <artifactId>sample-operators</artifactId> - <version>5.1.0-SNAPSHOT</version> + <version>5.1.1-SNAPSHOT</version> </parent> <artifactId>sample-webpage-operator</artifactId> From d82d51d3b2965f35d464938192b7e590c437d1f7 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 23 May 2025 07:08:54 +0200 Subject: [PATCH 2/5] chore(deps): bump io.github.git-commit-id:git-commit-id-maven-plugin (#2816) --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index fb32bb1aaa..6bc27adeed 100644 --- a/pom.xml +++ b/pom.xml @@ -89,7 +89,7 @@ <nexus-staging-maven-plugin.version>1.7.0</nexus-staging-maven-plugin.version> <maven-deploy-plugin.version>3.0.0</maven-deploy-plugin.version> <maven-install-plugin.version>3.1.4</maven-install-plugin.version> - <git-commit-id-maven-plugin.version>9.0.1</git-commit-id-maven-plugin.version> + <git-commit-id-maven-plugin.version>9.0.2</git-commit-id-maven-plugin.version> <jib-maven-plugin.version>3.4.5</jib-maven-plugin.version> <spotless.version>2.44.4</spotless.version> </properties> From f51c65b7b8ac42fa35782d03df2f43f20147e21a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Attila=20M=C3=A9sz=C3=A1ros?= <a_meszaros@apple.com> Date: Fri, 23 May 2025 12:40:43 +0200 Subject: [PATCH 3/5] fix: primary cache utils mechanism (#2814) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Reading from API server was not correct, this works in all cases only if the informer cache has the up to date resources. If we don't have the up to date resource in the cache, and don't do the update based on that, we cannot say for sure if we can remove the resource for the next event or not from overlay cache. Signed-off-by: Attila Mészáros <a_meszaros@apple.com> Signed-off-by: Chris Laprun <claprun@redhat.com> Co-authored-by: Chris Laprun <claprun@redhat.com> --- .../PrimaryUpdateAndCacheUtils.java | 63 +++++++++++++++---- .../informer/TemporaryResourceCache.java | 4 +- .../PrimaryUpdateAndCacheUtilsTest.java | 57 ++++++++++++++++- ...va => StatusPatchCacheCustomResource.java} | 5 +- ...ithLockIT.java => StatusPatchCacheIT.java} | 12 ++-- ...r.java => StatusPatchCacheReconciler.java} | 20 +++--- ...ockSpec.java => StatusPatchCacheSpec.java} | 2 +- ...tatus.java => StatusPatchCacheStatus.java} | 4 +- 8 files changed, 126 insertions(+), 41 deletions(-) rename operator-framework/src/test/java/io/javaoperatorsdk/operator/baseapi/statuscache/{StatusPatchCacheWithLockCustomResource.java => StatusPatchCacheCustomResource.java} (69%) rename operator-framework/src/test/java/io/javaoperatorsdk/operator/baseapi/statuscache/{StatusPatchCacheWithLockIT.java => StatusPatchCacheIT.java} (79%) rename operator-framework/src/test/java/io/javaoperatorsdk/operator/baseapi/statuscache/{StatusPatchCacheWithLockReconciler.java => StatusPatchCacheReconciler.java} (73%) rename operator-framework/src/test/java/io/javaoperatorsdk/operator/baseapi/statuscache/{StatusPatchCacheWithLockSpec.java => StatusPatchCacheSpec.java} (82%) rename operator-framework/src/test/java/io/javaoperatorsdk/operator/baseapi/statuscache/{StatusPatchCacheWithLockStatus.java => StatusPatchCacheStatus.java} (62%) 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 ac0fe9675c..c61cc837c1 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 @@ -1,5 +1,7 @@ package io.javaoperatorsdk.operator.api.reconciler; +import java.time.LocalTime; +import java.time.temporal.ChronoUnit; import java.util.function.UnaryOperator; import org.slf4j.Logger; @@ -25,6 +27,8 @@ public class PrimaryUpdateAndCacheUtils { public static final int DEFAULT_MAX_RETRY = 10; + public static final int DEFAULT_RESOURCE_CACHE_TIMEOUT_MILLIS = 10000; + public static final int DEFAULT_RESOURCE_CACHE_POLL_PERIOD_MILLIS = 50; private PrimaryUpdateAndCacheUtils() {} @@ -90,8 +94,10 @@ public static <P extends HasMetadata> P ssaPatchStatusAndCacheResource( } /** - * Same as {@link #updateAndCacheResource(HasMetadata, Context, UnaryOperator, UnaryOperator, - * int)} using the default maximum retry number as defined by {@link #DEFAULT_MAX_RETRY}. + * Same as {@link #updateAndCacheResource(HasMetadata, Context, UnaryOperator, UnaryOperator, int, + * long,long)} using the default maximum retry number as defined by {@link #DEFAULT_MAX_RETRY} and + * default cache maximum polling time and period as defined, respectively by {@link + * #DEFAULT_RESOURCE_CACHE_TIMEOUT_MILLIS} and {@link #DEFAULT_RESOURCE_CACHE_POLL_PERIOD_MILLIS}. * * @param resourceToUpdate original resource to update * @param context of reconciliation @@ -106,7 +112,13 @@ public static <P extends HasMetadata> P updateAndCacheResource( UnaryOperator<P> modificationFunction, UnaryOperator<P> updateMethod) { return updateAndCacheResource( - resourceToUpdate, context, modificationFunction, updateMethod, DEFAULT_MAX_RETRY); + resourceToUpdate, + context, + modificationFunction, + updateMethod, + DEFAULT_MAX_RETRY, + DEFAULT_RESOURCE_CACHE_TIMEOUT_MILLIS, + DEFAULT_RESOURCE_CACHE_POLL_PERIOD_MILLIS); } /** @@ -124,16 +136,20 @@ public static <P extends HasMetadata> P updateAndCacheResource( * @param modificationFunction modifications to make on primary * @param updateMethod the update method implementation * @param maxRetry maximum number of retries before giving up + * @param cachePollTimeoutMillis maximum amount of milliseconds to wait for the updated resource + * to appear in cache + * @param cachePollPeriodMillis cache polling period, in milliseconds * @param <P> primary type * @return the updated resource */ - @SuppressWarnings("unchecked") public static <P extends HasMetadata> P updateAndCacheResource( P resourceToUpdate, Context<P> context, UnaryOperator<P> modificationFunction, UnaryOperator<P> updateMethod, - int maxRetry) { + int maxRetry, + long cachePollTimeoutMillis, + long cachePollPeriodMillis) { if (log.isDebugEnabled()) { log.debug("Conflict retrying update for: {}", ResourceID.fromResource(resourceToUpdate)); @@ -180,14 +196,37 @@ public static <P extends HasMetadata> P updateAndCacheResource( resourceToUpdate.getMetadata().getNamespace(), e.getCode()); resourceToUpdate = - (P) - context - .getClient() - .resources(resourceToUpdate.getClass()) - .inNamespace(resourceToUpdate.getMetadata().getNamespace()) - .withName(resourceToUpdate.getMetadata().getName()) - .get(); + pollLocalCache( + context, resourceToUpdate, cachePollTimeoutMillis, cachePollPeriodMillis); + } + } + } + + private static <P extends HasMetadata> P pollLocalCache( + Context<P> context, P staleResource, long timeoutMillis, long pollDelayMillis) { + try { + var resourceId = ResourceID.fromResource(staleResource); + var startTime = LocalTime.now(); + final var timeoutTime = startTime.plus(timeoutMillis, ChronoUnit.MILLIS); + while (timeoutTime.isAfter(LocalTime.now())) { + log.debug("Polling cache for resource: {}", resourceId); + var cachedResource = context.getPrimaryCache().get(resourceId).orElseThrow(); + if (!cachedResource + .getMetadata() + .getResourceVersion() + .equals(staleResource.getMetadata().getResourceVersion())) { + return context + .getControllerConfiguration() + .getConfigurationService() + .getResourceCloner() + .clone(cachedResource); + } + Thread.sleep(pollDelayMillis); } + throw new OperatorException("Timeout of resource polling from cache for resource"); + } catch (InterruptedException e) { + Thread.currentThread().interrupt(); + throw new OperatorException(e); } } } diff --git a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/event/source/informer/TemporaryResourceCache.java b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/event/source/informer/TemporaryResourceCache.java index 9ec5b3694c..af75a5abc4 100644 --- a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/event/source/informer/TemporaryResourceCache.java +++ b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/event/source/informer/TemporaryResourceCache.java @@ -126,9 +126,7 @@ public synchronized void putResource(T newResource, String previousResourceVersi knownResourceVersions.add(newResource.getMetadata().getResourceVersion()); } var resourceId = ResourceID.fromResource(newResource); - var cachedResource = - getResourceFromCache(resourceId) - .orElse(managedInformerEventSource.get(resourceId).orElse(null)); + var cachedResource = managedInformerEventSource.get(resourceId).orElse(null); boolean moveAhead = false; if (previousResourceVersion == null && cachedResource == null) { diff --git a/operator-framework-core/src/test/java/io/javaoperatorsdk/operator/api/reconciler/PrimaryUpdateAndCacheUtilsTest.java b/operator-framework-core/src/test/java/io/javaoperatorsdk/operator/api/reconciler/PrimaryUpdateAndCacheUtilsTest.java index 438941db9c..80a254b50f 100644 --- a/operator-framework-core/src/test/java/io/javaoperatorsdk/operator/api/reconciler/PrimaryUpdateAndCacheUtilsTest.java +++ b/operator-framework-core/src/test/java/io/javaoperatorsdk/operator/api/reconciler/PrimaryUpdateAndCacheUtilsTest.java @@ -1,16 +1,22 @@ package io.javaoperatorsdk.operator.api.reconciler; +import java.util.Optional; import java.util.function.UnaryOperator; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; +import io.fabric8.kubernetes.api.model.HasMetadata; import io.fabric8.kubernetes.client.KubernetesClient; 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.utils.KubernetesSerialization; import io.javaoperatorsdk.operator.OperatorException; import io.javaoperatorsdk.operator.TestUtils; +import io.javaoperatorsdk.operator.api.config.Cloner; +import io.javaoperatorsdk.operator.api.config.ConfigurationService; +import io.javaoperatorsdk.operator.api.config.ControllerConfiguration; import io.javaoperatorsdk.operator.processing.event.EventSourceRetriever; import io.javaoperatorsdk.operator.processing.event.source.controller.ControllerEventSource; import io.javaoperatorsdk.operator.sample.simple.TestCustomResource; @@ -29,6 +35,7 @@ class PrimaryUpdateAndCacheUtilsTest { Context<TestCustomResource> context = mock(Context.class); KubernetesClient client = mock(KubernetesClient.class); Resource resource = mock(Resource.class); + IndexedResourceCache<TestCustomResource> primaryCache = mock(IndexedResourceCache.class); @BeforeEach void setup() { @@ -41,6 +48,20 @@ void setup() { when(mixedOp.inNamespace(any())).thenReturn(mixedOp); when(mixedOp.withName(any())).thenReturn(resource); when(resource.get()).thenReturn(TestUtils.testCustomResource1()); + when(context.getPrimaryCache()).thenReturn(primaryCache); + + var controllerConfiguration = mock(ControllerConfiguration.class); + when(context.getControllerConfiguration()).thenReturn(controllerConfiguration); + var configService = mock(ConfigurationService.class); + when(controllerConfiguration.getConfigurationService()).thenReturn(configService); + when(configService.getResourceCloner()) + .thenReturn( + new Cloner() { + @Override + public <R extends HasMetadata> R clone(R object) { + return new KubernetesSerialization().clone(object); + } + }); } @Test @@ -76,6 +97,10 @@ void retriesConflicts() { when(updateOperation.apply(any())) .thenThrow(new KubernetesClientException("", 409, null)) .thenReturn(TestUtils.testCustomResource1()); + var freshResource = TestUtils.testCustomResource1(); + + freshResource.getMetadata().setResourceVersion("2"); + when(primaryCache.get(any())).thenReturn(Optional.of(freshResource)); var updated = PrimaryUpdateAndCacheUtils.updateAndCacheResource( @@ -89,7 +114,7 @@ void retriesConflicts() { updateOperation); assertThat(updated).isNotNull(); - verify(resource, times(1)).get(); + verify(primaryCache, times(1)).get(any()); } @Test @@ -97,7 +122,13 @@ void throwsIfRetryExhausted() { var updateOperation = mock(UnaryOperator.class); when(updateOperation.apply(any())).thenThrow(new KubernetesClientException("", 409, null)); + var stubbing = when(primaryCache.get(any())); + for (int i = 0; i < DEFAULT_MAX_RETRY; i++) { + var resource = TestUtils.testCustomResource1(); + resource.getMetadata().setResourceVersion("" + i); + stubbing = stubbing.thenReturn(Optional.of(resource)); + } assertThrows( OperatorException.class, () -> @@ -106,6 +137,28 @@ void throwsIfRetryExhausted() { context, UnaryOperator.identity(), updateOperation)); - verify(resource, times(DEFAULT_MAX_RETRY)).get(); + verify(primaryCache, times(DEFAULT_MAX_RETRY)).get(any()); + } + + @Test + void cachePollTimeouts() { + var updateOperation = mock(UnaryOperator.class); + + when(updateOperation.apply(any())).thenThrow(new KubernetesClientException("", 409, null)); + when(primaryCache.get(any())).thenReturn(Optional.of(TestUtils.testCustomResource1())); + + var ex = + assertThrows( + OperatorException.class, + () -> + PrimaryUpdateAndCacheUtils.updateAndCacheResource( + TestUtils.testCustomResource1(), + context, + UnaryOperator.identity(), + updateOperation, + 2, + 50L, + 10L)); + assertThat(ex.getMessage()).contains("Timeout"); } } diff --git a/operator-framework/src/test/java/io/javaoperatorsdk/operator/baseapi/statuscache/StatusPatchCacheWithLockCustomResource.java b/operator-framework/src/test/java/io/javaoperatorsdk/operator/baseapi/statuscache/StatusPatchCacheCustomResource.java similarity index 69% rename from operator-framework/src/test/java/io/javaoperatorsdk/operator/baseapi/statuscache/StatusPatchCacheWithLockCustomResource.java rename to operator-framework/src/test/java/io/javaoperatorsdk/operator/baseapi/statuscache/StatusPatchCacheCustomResource.java index 8ab742a975..e87d8e8714 100644 --- a/operator-framework/src/test/java/io/javaoperatorsdk/operator/baseapi/statuscache/StatusPatchCacheWithLockCustomResource.java +++ b/operator-framework/src/test/java/io/javaoperatorsdk/operator/baseapi/statuscache/StatusPatchCacheCustomResource.java @@ -9,6 +9,5 @@ @Group("sample.javaoperatorsdk") @Version("v1") @ShortNames("spwl") -public class StatusPatchCacheWithLockCustomResource - extends CustomResource<StatusPatchCacheWithLockSpec, StatusPatchCacheWithLockStatus> - implements Namespaced {} +public class StatusPatchCacheCustomResource + extends CustomResource<StatusPatchCacheSpec, StatusPatchCacheStatus> implements Namespaced {} diff --git a/operator-framework/src/test/java/io/javaoperatorsdk/operator/baseapi/statuscache/StatusPatchCacheWithLockIT.java b/operator-framework/src/test/java/io/javaoperatorsdk/operator/baseapi/statuscache/StatusPatchCacheIT.java similarity index 79% rename from operator-framework/src/test/java/io/javaoperatorsdk/operator/baseapi/statuscache/StatusPatchCacheWithLockIT.java rename to operator-framework/src/test/java/io/javaoperatorsdk/operator/baseapi/statuscache/StatusPatchCacheIT.java index c5752f4aae..9d0b923056 100644 --- a/operator-framework/src/test/java/io/javaoperatorsdk/operator/baseapi/statuscache/StatusPatchCacheWithLockIT.java +++ b/operator-framework/src/test/java/io/javaoperatorsdk/operator/baseapi/statuscache/StatusPatchCacheIT.java @@ -11,19 +11,19 @@ import static org.assertj.core.api.Assertions.assertThat; import static org.awaitility.Awaitility.await; -public class StatusPatchCacheWithLockIT { +public class StatusPatchCacheIT { public static final String TEST_1 = "test1"; @RegisterExtension LocallyRunOperatorExtension extension = LocallyRunOperatorExtension.builder() - .withReconciler(StatusPatchCacheWithLockReconciler.class) + .withReconciler(StatusPatchCacheReconciler.class) .build(); @Test void testStatusAlwaysUpToDate() { - var reconciler = extension.getReconcilerOfType(StatusPatchCacheWithLockReconciler.class); + var reconciler = extension.getReconcilerOfType(StatusPatchCacheReconciler.class); extension.create(testResource()); @@ -39,10 +39,10 @@ void testStatusAlwaysUpToDate() { }); } - StatusPatchCacheWithLockCustomResource testResource() { - var res = new StatusPatchCacheWithLockCustomResource(); + StatusPatchCacheCustomResource testResource() { + var res = new StatusPatchCacheCustomResource(); res.setMetadata(new ObjectMetaBuilder().withName(TEST_1).build()); - res.setSpec(new StatusPatchCacheWithLockSpec()); + res.setSpec(new StatusPatchCacheSpec()); return res; } } diff --git a/operator-framework/src/test/java/io/javaoperatorsdk/operator/baseapi/statuscache/StatusPatchCacheWithLockReconciler.java b/operator-framework/src/test/java/io/javaoperatorsdk/operator/baseapi/statuscache/StatusPatchCacheReconciler.java similarity index 73% rename from operator-framework/src/test/java/io/javaoperatorsdk/operator/baseapi/statuscache/StatusPatchCacheWithLockReconciler.java rename to operator-framework/src/test/java/io/javaoperatorsdk/operator/baseapi/statuscache/StatusPatchCacheReconciler.java index 364f8e9ff5..69215d6d01 100644 --- a/operator-framework/src/test/java/io/javaoperatorsdk/operator/baseapi/statuscache/StatusPatchCacheWithLockReconciler.java +++ b/operator-framework/src/test/java/io/javaoperatorsdk/operator/baseapi/statuscache/StatusPatchCacheReconciler.java @@ -12,16 +12,14 @@ import io.javaoperatorsdk.operator.processing.event.source.EventSource; @ControllerConfiguration -public class StatusPatchCacheWithLockReconciler - implements Reconciler<StatusPatchCacheWithLockCustomResource> { +public class StatusPatchCacheReconciler implements Reconciler<StatusPatchCacheCustomResource> { public volatile int latestValue = 0; public volatile boolean errorPresent = false; @Override - public UpdateControl<StatusPatchCacheWithLockCustomResource> reconcile( - StatusPatchCacheWithLockCustomResource resource, - Context<StatusPatchCacheWithLockCustomResource> context) { + public UpdateControl<StatusPatchCacheCustomResource> reconcile( + StatusPatchCacheCustomResource resource, Context<StatusPatchCacheCustomResource> context) { if (resource.getStatus() != null && resource.getStatus().getValue() != latestValue) { errorPresent = true; @@ -50,22 +48,20 @@ public UpdateControl<StatusPatchCacheWithLockCustomResource> reconcile( } @Override - public List<EventSource<?, StatusPatchCacheWithLockCustomResource>> prepareEventSources( - EventSourceContext<StatusPatchCacheWithLockCustomResource> context) { + public List<EventSource<?, StatusPatchCacheCustomResource>> prepareEventSources( + EventSourceContext<StatusPatchCacheCustomResource> context) { // periodic event triggering for testing purposes return List.of(new PeriodicTriggerEventSource<>(context.getPrimaryCache())); } - private StatusPatchCacheWithLockCustomResource createFreshCopy( - StatusPatchCacheWithLockCustomResource resource) { - var res = new StatusPatchCacheWithLockCustomResource(); + private StatusPatchCacheCustomResource createFreshCopy(StatusPatchCacheCustomResource resource) { + var res = new StatusPatchCacheCustomResource(); res.setMetadata( new ObjectMetaBuilder() .withName(resource.getMetadata().getName()) .withNamespace(resource.getMetadata().getNamespace()) .build()); - res.setStatus(new StatusPatchCacheWithLockStatus()); - + res.setStatus(new StatusPatchCacheStatus()); return res; } } diff --git a/operator-framework/src/test/java/io/javaoperatorsdk/operator/baseapi/statuscache/StatusPatchCacheWithLockSpec.java b/operator-framework/src/test/java/io/javaoperatorsdk/operator/baseapi/statuscache/StatusPatchCacheSpec.java similarity index 82% rename from operator-framework/src/test/java/io/javaoperatorsdk/operator/baseapi/statuscache/StatusPatchCacheWithLockSpec.java rename to operator-framework/src/test/java/io/javaoperatorsdk/operator/baseapi/statuscache/StatusPatchCacheSpec.java index ebbabd49a0..0885b6a858 100644 --- a/operator-framework/src/test/java/io/javaoperatorsdk/operator/baseapi/statuscache/StatusPatchCacheWithLockSpec.java +++ b/operator-framework/src/test/java/io/javaoperatorsdk/operator/baseapi/statuscache/StatusPatchCacheSpec.java @@ -1,6 +1,6 @@ package io.javaoperatorsdk.operator.baseapi.statuscache; -public class StatusPatchCacheWithLockSpec { +public class StatusPatchCacheSpec { private int counter = 0; diff --git a/operator-framework/src/test/java/io/javaoperatorsdk/operator/baseapi/statuscache/StatusPatchCacheWithLockStatus.java b/operator-framework/src/test/java/io/javaoperatorsdk/operator/baseapi/statuscache/StatusPatchCacheStatus.java similarity index 62% rename from operator-framework/src/test/java/io/javaoperatorsdk/operator/baseapi/statuscache/StatusPatchCacheWithLockStatus.java rename to operator-framework/src/test/java/io/javaoperatorsdk/operator/baseapi/statuscache/StatusPatchCacheStatus.java index 5f2d8f5a6f..5918b2e3b8 100644 --- a/operator-framework/src/test/java/io/javaoperatorsdk/operator/baseapi/statuscache/StatusPatchCacheWithLockStatus.java +++ b/operator-framework/src/test/java/io/javaoperatorsdk/operator/baseapi/statuscache/StatusPatchCacheStatus.java @@ -1,6 +1,6 @@ package io.javaoperatorsdk.operator.baseapi.statuscache; -public class StatusPatchCacheWithLockStatus { +public class StatusPatchCacheStatus { private Integer value = 0; @@ -8,7 +8,7 @@ public Integer getValue() { return value; } - public StatusPatchCacheWithLockStatus setValue(Integer value) { + public StatusPatchCacheStatus setValue(Integer value) { this.value = value; return this; } From 874f545d1a53b981f116e3515ee931751272860c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Attila=20M=C3=A9sz=C3=A1ros?= <a_meszaros@apple.com> Date: Mon, 26 May 2025 09:18:24 +0200 Subject: [PATCH 4/5] docs: improve PrimaryUpdateAndCacheUtils documentation (#2818) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Attila Mészáros <a_meszaros@apple.com> Signed-off-by: Chris Laprun <claprun@redhat.com> Co-authored-by: Chris Laprun <claprun@redhat.com> --- docs/content/en/docs/documentation/reconciler.md | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/docs/content/en/docs/documentation/reconciler.md b/docs/content/en/docs/documentation/reconciler.md index fa51399de7..6444e70c7c 100644 --- a/docs/content/en/docs/documentation/reconciler.md +++ b/docs/content/en/docs/documentation/reconciler.md @@ -202,7 +202,8 @@ public UpdateControl<StatusPatchCacheCustomResource> reconcile( freshCopy.getStatus().setValue(statusWithState()); var updatedResource = PrimaryUpdateAndCacheUtils.ssaPatchStatusAndCacheResource(resource, freshCopy, context); - + + // the resource was updated transparently via the utils, no further action is required via UpdateControl in this case return UpdateControl.noUpdate(); } ``` @@ -213,5 +214,9 @@ Note that it is not necessarily the same version returned as response from the u can do additional updates meanwhile. However, unless it has been explicitly modified, that resource will contain the up-to-date status. +Note that you can also perform additional updates after the `PrimaryUpdateAndCacheUtils.*PatchStatusAndCacheResource` is +called, either by calling any of the `PrimeUpdateAndCacheUtils` methods again or via `UpdateControl`. Using +`PrimaryUpdateAndCacheUtils` guarantees that the next reconciliation will see a resource state no older than the version +updated via `PrimaryUpdateAndCacheUtils`. See related integration test [here](https://github.com/operator-framework/java-operator-sdk/blob/main/operator-framework/src/test/java/io/javaoperatorsdk/operator/baseapi/statuscache). From e3e94583617162b53156899944d2a2646c78046f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Attila=20M=C3=A9sz=C3=A1ros?= <a_meszaros@apple.com> Date: Mon, 26 May 2025 09:24:30 +0200 Subject: [PATCH 5/5] improve: add InformerEventSourceConfiguration withNamespaces overloaded version (#2817) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Attila Mészáros <a_meszaros@apple.com> Signed-off-by: Chris Laprun <claprun@redhat.com> Co-authored-by: Chris Laprun <claprun@redhat.com> --- .../InformerEventSourceConfiguration.java | 8 ++++++++ .../ControllerConfigurationOverriderTest.java | 16 ++++++++++++++++ 2 files changed, 24 insertions(+) diff --git a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/config/informer/InformerEventSourceConfiguration.java b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/config/informer/InformerEventSourceConfiguration.java index 9fb5ad4c82..2369d5f523 100644 --- a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/config/informer/InformerEventSourceConfiguration.java +++ b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/config/informer/InformerEventSourceConfiguration.java @@ -194,6 +194,14 @@ public Builder<R> withNamespaces(Set<String> namespaces) { return this; } + /** + * @since 5.1.1 + */ + public Builder<R> withNamespaces(String... namespaces) { + config.withNamespaces(Set.of(namespaces)); + return this; + } + public Builder<R> withNamespacesInheritedFromController() { withNamespaces(SAME_AS_CONTROLLER_NAMESPACES_SET); return this; diff --git a/operator-framework-core/src/test/java/io/javaoperatorsdk/operator/api/config/ControllerConfigurationOverriderTest.java b/operator-framework-core/src/test/java/io/javaoperatorsdk/operator/api/config/ControllerConfigurationOverriderTest.java index 49d0b76017..837ad7463a 100644 --- a/operator-framework-core/src/test/java/io/javaoperatorsdk/operator/api/config/ControllerConfigurationOverriderTest.java +++ b/operator-framework-core/src/test/java/io/javaoperatorsdk/operator/api/config/ControllerConfigurationOverriderTest.java @@ -89,6 +89,22 @@ private io.javaoperatorsdk.operator.api.config.ControllerConfiguration<?> create return configurationService.configFor(reconciler); } + @Test + void overridingNamespacesShouldNotThrowNPE() { + var configuration = createConfiguration(new NullReconciler()); + configuration = + ControllerConfigurationOverrider.override(configuration).settingNamespaces().build(); + assertTrue(configuration.getInformerConfig().watchAllNamespaces()); + } + + private static class NullReconciler implements Reconciler<HasMetadata> { + @Override + public UpdateControl<HasMetadata> reconcile(HasMetadata resource, Context<HasMetadata> context) + throws Exception { + return null; + } + } + @Test void overridingNamespacesShouldWork() { var configuration = createConfiguration(new WatchCurrentReconciler());