From 5f600051b31b8a26f3534b1944c251624294105e Mon Sep 17 00:00:00 2001 From: csviri Date: Tue, 29 Aug 2023 14:16:52 +0200 Subject: [PATCH 01/15] reproduce ssa issue MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Attila Mészáros --- .../SSAStatefulSetMatcherIssueIT.java | 45 +++++++++++++++++++ ...StatefulSetMatcherIssueCustomResource.java | 14 ++++++ .../SSAStatefulSetMatcherIssueReconciler.java | 20 +++++++++ .../StatefulSetDependentResource.java | 27 +++++++++++ .../statefulset.yaml | 38 ++++++++++++++++ 5 files changed, 144 insertions(+) create mode 100644 operator-framework/src/test/java/io/javaoperatorsdk/operator/SSAStatefulSetMatcherIssueIT.java create mode 100644 operator-framework/src/test/java/io/javaoperatorsdk/operator/sample/ssastatefulsetmatcherissue/SSAStatefulSetMatcherIssueCustomResource.java create mode 100644 operator-framework/src/test/java/io/javaoperatorsdk/operator/sample/ssastatefulsetmatcherissue/SSAStatefulSetMatcherIssueReconciler.java create mode 100644 operator-framework/src/test/java/io/javaoperatorsdk/operator/sample/ssastatefulsetmatcherissue/StatefulSetDependentResource.java create mode 100644 operator-framework/src/test/resources/io/javaoperatorsdk/operator/sample/ssastatefulsetmatcherissue/statefulset.yaml diff --git a/operator-framework/src/test/java/io/javaoperatorsdk/operator/SSAStatefulSetMatcherIssueIT.java b/operator-framework/src/test/java/io/javaoperatorsdk/operator/SSAStatefulSetMatcherIssueIT.java new file mode 100644 index 0000000000..08a8c897f3 --- /dev/null +++ b/operator-framework/src/test/java/io/javaoperatorsdk/operator/SSAStatefulSetMatcherIssueIT.java @@ -0,0 +1,45 @@ +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.fabric8.kubernetes.api.model.apps.StatefulSet; +import io.javaoperatorsdk.operator.junit.LocallyRunOperatorExtension; +import io.javaoperatorsdk.operator.sample.ssastatefulsetmatcherissue.SSAStatefulSetMatcherIssueCustomResource; +import io.javaoperatorsdk.operator.sample.ssastatefulsetmatcherissue.SSAStatefulSetMatcherIssueReconciler; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.awaitility.Awaitility.await; + +public class SSAStatefulSetMatcherIssueIT { + + public static final String TEST_1 = "test1"; + @RegisterExtension + LocallyRunOperatorExtension extension = + LocallyRunOperatorExtension.builder() + .withReconciler(new SSAStatefulSetMatcherIssueReconciler()) + .build(); + + @Test + void testSSAMatcher() { + extension.create(testResource()); + + + await().untilAsserted(() -> { + var statefulSet = extension.get(StatefulSet.class, TEST_1); + assertThat(statefulSet).isNotNull(); + }); + + System.out.println("ok"); + } + + SSAStatefulSetMatcherIssueCustomResource testResource() { + var res = new SSAStatefulSetMatcherIssueCustomResource(); + res.setMetadata(new ObjectMetaBuilder() + .withName(TEST_1) + .build()); + return res; + } + +} diff --git a/operator-framework/src/test/java/io/javaoperatorsdk/operator/sample/ssastatefulsetmatcherissue/SSAStatefulSetMatcherIssueCustomResource.java b/operator-framework/src/test/java/io/javaoperatorsdk/operator/sample/ssastatefulsetmatcherissue/SSAStatefulSetMatcherIssueCustomResource.java new file mode 100644 index 0000000000..00f3602d8d --- /dev/null +++ b/operator-framework/src/test/java/io/javaoperatorsdk/operator/sample/ssastatefulsetmatcherissue/SSAStatefulSetMatcherIssueCustomResource.java @@ -0,0 +1,14 @@ +package io.javaoperatorsdk.operator.sample.ssastatefulsetmatcherissue; + +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.Version; + +@Group("sample.javaoperatorsdk") +@Version("v1") +public class SSAStatefulSetMatcherIssueCustomResource + extends CustomResource + implements Namespaced { + +} diff --git a/operator-framework/src/test/java/io/javaoperatorsdk/operator/sample/ssastatefulsetmatcherissue/SSAStatefulSetMatcherIssueReconciler.java b/operator-framework/src/test/java/io/javaoperatorsdk/operator/sample/ssastatefulsetmatcherissue/SSAStatefulSetMatcherIssueReconciler.java new file mode 100644 index 0000000000..dbcb31fc6d --- /dev/null +++ b/operator-framework/src/test/java/io/javaoperatorsdk/operator/sample/ssastatefulsetmatcherissue/SSAStatefulSetMatcherIssueReconciler.java @@ -0,0 +1,20 @@ +package io.javaoperatorsdk.operator.sample.ssastatefulsetmatcherissue; + +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; +import io.javaoperatorsdk.operator.api.reconciler.dependent.Dependent; + +@ControllerConfiguration(dependents = {@Dependent(type = StatefulSetDependentResource.class)}) +public class SSAStatefulSetMatcherIssueReconciler + implements Reconciler { + + @Override + public UpdateControl reconcile( + SSAStatefulSetMatcherIssueCustomResource resource, + Context context) throws Exception { + return UpdateControl.noUpdate(); + } + +} diff --git a/operator-framework/src/test/java/io/javaoperatorsdk/operator/sample/ssastatefulsetmatcherissue/StatefulSetDependentResource.java b/operator-framework/src/test/java/io/javaoperatorsdk/operator/sample/ssastatefulsetmatcherissue/StatefulSetDependentResource.java new file mode 100644 index 0000000000..70ab1c4595 --- /dev/null +++ b/operator-framework/src/test/java/io/javaoperatorsdk/operator/sample/ssastatefulsetmatcherissue/StatefulSetDependentResource.java @@ -0,0 +1,27 @@ +package io.javaoperatorsdk.operator.sample.ssastatefulsetmatcherissue; + +import io.fabric8.kubernetes.api.model.ObjectMetaBuilder; +import io.fabric8.kubernetes.api.model.apps.StatefulSet; +import io.javaoperatorsdk.operator.ReconcilerUtils; +import io.javaoperatorsdk.operator.api.reconciler.Context; +import io.javaoperatorsdk.operator.processing.dependent.kubernetes.CRUDKubernetesDependentResource; + +public class StatefulSetDependentResource + extends CRUDKubernetesDependentResource { + + public StatefulSetDependentResource() { + + super(StatefulSet.class); + } + + @Override + protected StatefulSet desired(SSAStatefulSetMatcherIssueCustomResource primary, + Context context) { + var template = ReconcilerUtils.loadYaml(StatefulSet.class, getClass(), "statefulset.yaml"); + template.setMetadata(new ObjectMetaBuilder() + .withName(primary.getMetadata().getName()) + .withNamespace(primary.getMetadata().getNamespace()) + .build()); + return template; + } +} diff --git a/operator-framework/src/test/resources/io/javaoperatorsdk/operator/sample/ssastatefulsetmatcherissue/statefulset.yaml b/operator-framework/src/test/resources/io/javaoperatorsdk/operator/sample/ssastatefulsetmatcherissue/statefulset.yaml new file mode 100644 index 0000000000..67594e8365 --- /dev/null +++ b/operator-framework/src/test/resources/io/javaoperatorsdk/operator/sample/ssastatefulsetmatcherissue/statefulset.yaml @@ -0,0 +1,38 @@ +apiVersion: apps/v1 +kind: StatefulSet +metadata: + name: web +spec: + persistentVolumeClaimRetentionPolicy: + whenDeleted: "Retain" + whenScaled: "Delete" + selector: + matchLabels: + app: nginx # has to match .spec.template.metadata.labels + serviceName: "nginx" + replicas: 1 + minReadySeconds: 10 # by default is 0 + template: + metadata: + labels: + app: nginx # has to match .spec.selector.matchLabels + spec: + terminationGracePeriodSeconds: 10 + containers: + - name: nginx + image: registry.k8s.io/nginx-slim:0.8 + ports: + - containerPort: 80 + name: web + volumeMounts: + - name: www + mountPath: /usr/share/nginx/html + volumeClaimTemplates: + - metadata: + name: www + spec: + accessModes: [ "ReadWriteOnce" ] + storageClassName: "my-storage-class" + resources: + requests: + storage: 1Gi \ No newline at end of file From c880974613746435d678d47395d906624b736b34 Mon Sep 17 00:00:00 2001 From: csviri Date: Tue, 29 Aug 2023 15:41:47 +0200 Subject: [PATCH 02/15] fixes MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Attila Mészáros --- ...BasedGenericKubernetesResourceMatcher.java | 2 +- .../StatefulSetDependentResource.java | 3 +- .../statefulset_fixed_full.yaml | 38 +++++++++++++++++++ 3 files changed, 41 insertions(+), 2 deletions(-) create mode 100644 operator-framework/src/test/resources/io/javaoperatorsdk/operator/sample/ssastatefulsetmatcherissue/statefulset_fixed_full.yaml diff --git a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/kubernetes/SSABasedGenericKubernetesResourceMatcher.java b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/kubernetes/SSABasedGenericKubernetesResourceMatcher.java index f4718b45c3..d81f93a969 100644 --- a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/kubernetes/SSABasedGenericKubernetesResourceMatcher.java +++ b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/kubernetes/SSABasedGenericKubernetesResourceMatcher.java @@ -159,7 +159,7 @@ private static void fillResultsAndTraverseFurther(Map result, Object managedFieldValue) { var emptyMapValue = new HashMap(); result.put(keyInActual, emptyMapValue); - var actualMapValue = actualMap.get(keyInActual); + var actualMapValue = actualMap.getOrDefault(keyInActual, Map.of()); log.debug("key: {} actual map value: {} managedFieldValue: {}", keyInActual, actualMapValue, managedFieldValue); diff --git a/operator-framework/src/test/java/io/javaoperatorsdk/operator/sample/ssastatefulsetmatcherissue/StatefulSetDependentResource.java b/operator-framework/src/test/java/io/javaoperatorsdk/operator/sample/ssastatefulsetmatcherissue/StatefulSetDependentResource.java index 70ab1c4595..e4075fe1b8 100644 --- a/operator-framework/src/test/java/io/javaoperatorsdk/operator/sample/ssastatefulsetmatcherissue/StatefulSetDependentResource.java +++ b/operator-framework/src/test/java/io/javaoperatorsdk/operator/sample/ssastatefulsetmatcherissue/StatefulSetDependentResource.java @@ -17,7 +17,8 @@ public StatefulSetDependentResource() { @Override protected StatefulSet desired(SSAStatefulSetMatcherIssueCustomResource primary, Context context) { - var template = ReconcilerUtils.loadYaml(StatefulSet.class, getClass(), "statefulset.yaml"); + var template = + ReconcilerUtils.loadYaml(StatefulSet.class, getClass(), "statefulset_fixed_full.yaml"); template.setMetadata(new ObjectMetaBuilder() .withName(primary.getMetadata().getName()) .withNamespace(primary.getMetadata().getNamespace()) diff --git a/operator-framework/src/test/resources/io/javaoperatorsdk/operator/sample/ssastatefulsetmatcherissue/statefulset_fixed_full.yaml b/operator-framework/src/test/resources/io/javaoperatorsdk/operator/sample/ssastatefulsetmatcherissue/statefulset_fixed_full.yaml new file mode 100644 index 0000000000..e2a86d638e --- /dev/null +++ b/operator-framework/src/test/resources/io/javaoperatorsdk/operator/sample/ssastatefulsetmatcherissue/statefulset_fixed_full.yaml @@ -0,0 +1,38 @@ +apiVersion: apps/v1 +kind: StatefulSet +metadata: + name: web +spec: + selector: + matchLabels: + app: nginx # has to match .spec.template.metadata.labels + serviceName: "nginx" + replicas: 1 + minReadySeconds: 10 # by default is 0 + template: + metadata: + labels: + app: nginx # has to match .spec.selector.matchLabels + spec: + terminationGracePeriodSeconds: 10 + containers: + - name: nginx + image: registry.k8s.io/nginx-slim:0.8 + ports: + - containerPort: 80 + name: web + volumeMounts: + - name: www + mountPath: /usr/share/nginx/html + volumeClaimTemplates: + - metadata: + name: www + spec: + accessModes: [ "ReadWriteOnce" ] + storageClassName: "my-storage-class" + volumeMode: Filesystem + resources: + requests: + storage: 1Gi + status: + phase: pending \ No newline at end of file From ddf02dc4455a6a1ea7eed4b0cc37a404f2feb2cf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Attila=20M=C3=A9sz=C3=A1ros?= Date: Mon, 4 Sep 2023 12:15:04 +0200 Subject: [PATCH 03/15] test MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Attila Mészáros --- .../javaoperatorsdk/operator/SSAStatefulSetMatcherIssueIT.java | 2 -- 1 file changed, 2 deletions(-) diff --git a/operator-framework/src/test/java/io/javaoperatorsdk/operator/SSAStatefulSetMatcherIssueIT.java b/operator-framework/src/test/java/io/javaoperatorsdk/operator/SSAStatefulSetMatcherIssueIT.java index 08a8c897f3..8584ef1e5a 100644 --- a/operator-framework/src/test/java/io/javaoperatorsdk/operator/SSAStatefulSetMatcherIssueIT.java +++ b/operator-framework/src/test/java/io/javaoperatorsdk/operator/SSAStatefulSetMatcherIssueIT.java @@ -30,8 +30,6 @@ void testSSAMatcher() { var statefulSet = extension.get(StatefulSet.class, TEST_1); assertThat(statefulSet).isNotNull(); }); - - System.out.println("ok"); } SSAStatefulSetMatcherIssueCustomResource testResource() { From 33062811a5397c6b2804fc9180cfad9bbf1ad652 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Attila=20M=C3=A9sz=C3=A1ros?= Date: Mon, 4 Sep 2023 14:00:59 +0200 Subject: [PATCH 04/15] feat: sanitization of resources for matching MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Attila Mészáros --- .../kubernetes/DesiredResourceSanitizer.java | 50 ++++++++++++++++ .../KubernetesDependentResource.java | 23 +++++--- .../SSAStatefulSetMatcherIssueIT.java | 43 -------------- .../StatefulSetDesiredSanitizerIT.java | 57 +++++++++++++++++++ .../dependentssa/SSAConfigMapDependent.java | 4 +- .../ServiceDependentResource.java | 4 +- .../ServiceDependentResource.java | 8 +-- .../SSAStatefulSetMatcherIssueReconciler.java | 20 ------- .../StatefulSetDependentResource.java | 28 --------- ...fulSetDesiredSanitizerCustomResource.java} | 6 +- ...lSetDesiredSanitizerDependentResource.java | 43 ++++++++++++++ ...StatefulSetDesiredSanitizerReconciler.java | 20 +++++++ .../StatefulSetDesiredSanitizerSpec.java | 15 +++++ .../statefulset_fixed_full.yaml | 38 ------------- .../statefulset.yaml | 5 +- .../ConfigMapDependentResource.java | 4 +- 16 files changed, 214 insertions(+), 154 deletions(-) create mode 100644 operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/kubernetes/DesiredResourceSanitizer.java delete mode 100644 operator-framework/src/test/java/io/javaoperatorsdk/operator/SSAStatefulSetMatcherIssueIT.java create mode 100644 operator-framework/src/test/java/io/javaoperatorsdk/operator/StatefulSetDesiredSanitizerIT.java delete mode 100644 operator-framework/src/test/java/io/javaoperatorsdk/operator/sample/ssastatefulsetmatcherissue/SSAStatefulSetMatcherIssueReconciler.java delete mode 100644 operator-framework/src/test/java/io/javaoperatorsdk/operator/sample/ssastatefulsetmatcherissue/StatefulSetDependentResource.java rename operator-framework/src/test/java/io/javaoperatorsdk/operator/sample/{ssastatefulsetmatcherissue/SSAStatefulSetMatcherIssueCustomResource.java => statefulsetdesiredsanitizer/StatefulSetDesiredSanitizerCustomResource.java} (60%) create mode 100644 operator-framework/src/test/java/io/javaoperatorsdk/operator/sample/statefulsetdesiredsanitizer/StatefulSetDesiredSanitizerDependentResource.java create mode 100644 operator-framework/src/test/java/io/javaoperatorsdk/operator/sample/statefulsetdesiredsanitizer/StatefulSetDesiredSanitizerReconciler.java create mode 100644 operator-framework/src/test/java/io/javaoperatorsdk/operator/sample/statefulsetdesiredsanitizer/StatefulSetDesiredSanitizerSpec.java delete mode 100644 operator-framework/src/test/resources/io/javaoperatorsdk/operator/sample/ssastatefulsetmatcherissue/statefulset_fixed_full.yaml rename operator-framework/src/test/resources/io/javaoperatorsdk/operator/sample/{ssastatefulsetmatcherissue => statefulsetdesiredsanitizer}/statefulset.yaml (89%) diff --git a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/kubernetes/DesiredResourceSanitizer.java b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/kubernetes/DesiredResourceSanitizer.java new file mode 100644 index 0000000000..4e5962d1d2 --- /dev/null +++ b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/kubernetes/DesiredResourceSanitizer.java @@ -0,0 +1,50 @@ +package io.javaoperatorsdk.operator.processing.dependent.kubernetes; + +import io.fabric8.kubernetes.api.model.HasMetadata; +import io.fabric8.kubernetes.api.model.PersistentVolumeClaimStatus; +import io.fabric8.kubernetes.api.model.Secret; +import io.fabric8.kubernetes.api.model.apps.StatefulSet; +import io.javaoperatorsdk.operator.api.reconciler.Context; + +import static io.javaoperatorsdk.operator.processing.dependent.kubernetes.KubernetesDependentResource.useSSA; + +public class DesiredResourceSanitizer { + + private DesiredResourceSanitizer() {} + + public static void sanitizeDesired(R desired, R actual, P primary, + Context

context) { + if (useSSA(context)) { + if (desired instanceof StatefulSet) { + fillDefaultsOnVolumeClaimTemplate((StatefulSet) desired); + } + if (desired instanceof Secret) { + checkIfStringDataUsed((Secret) desired); + } + } + } + + private static void checkIfStringDataUsed(Secret secret) { + if (secret.getStringData() != null && !secret.getStringData().isEmpty()) { + throw new IllegalStateException( + "There is a known issue using StringData with SSA. Use data instead."); + } + } + + private static void fillDefaultsOnVolumeClaimTemplate(StatefulSet statefulSet) { + if (!statefulSet.getSpec().getVolumeClaimTemplates().isEmpty()) { + statefulSet.getSpec().getVolumeClaimTemplates().forEach(t -> { + if (t.getSpec().getVolumeMode() == null) { + t.getSpec().setVolumeMode("Filesystem"); + } + if (t.getStatus() == null) { + t.setStatus(new PersistentVolumeClaimStatus()); + } + if (t.getStatus().getPhase() == null) { + t.setStatus(new PersistentVolumeClaimStatus()); + t.getStatus().setPhase("pending"); + } + }); + } + } +} diff --git a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/kubernetes/KubernetesDependentResource.java b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/kubernetes/KubernetesDependentResource.java index 7fadcc6940..7dbdee91da 100644 --- a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/kubernetes/KubernetesDependentResource.java +++ b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/kubernetes/KubernetesDependentResource.java @@ -103,18 +103,19 @@ public void configureWith(InformerEventSource informerEventSource) { } @SuppressWarnings("unused") - public R create(R target, P primary, Context

context) { + public R create(R desired, P primary, Context

context) { if (useSSA(context)) { // setting resource version for SSA so only created if it doesn't exist already var createIfNotExisting = kubernetesDependentResourceConfig == null ? KubernetesDependentResourceConfig.DEFAULT_CREATE_RESOURCE_ONLY_IF_NOT_EXISTING_WITH_SSA : kubernetesDependentResourceConfig.createResourceOnlyIfNotExistingWithSSA(); if (createIfNotExisting) { - target.getMetadata().setResourceVersion("1"); + desired.getMetadata().setResourceVersion("1"); } } - addMetadata(false, null, target, primary); - final var resource = prepare(target, primary, "Creating"); + addMetadata(false, null, desired, primary); + sanitizeDesired(desired, null, primary, context); + final var resource = prepare(desired, primary, "Creating"); return useSSA(context) ? resource .fieldManager(context.getControllerConfiguration().fieldManager()) @@ -123,19 +124,20 @@ public R create(R target, P primary, Context

context) { : resource.create(); } - public R update(R actual, R target, P primary, Context

context) { + public R update(R actual, R desired, P primary, Context

context) { if (log.isDebugEnabled()) { log.debug("Updating actual resource: {} version: {}", ResourceID.fromResource(actual), actual.getMetadata().getResourceVersion()); } R updatedResource; - addMetadata(false, actual, target, primary); + addMetadata(false, actual, desired, primary); + sanitizeDesired(desired, actual, primary, context); if (useSSA(context)) { - updatedResource = prepare(target, primary, "Updating") + updatedResource = prepare(desired, primary, "Updating") .fieldManager(context.getControllerConfiguration().fieldManager()) .forceConflicts().serverSideApply(); } else { - var updatedActual = updaterMatcher.updateResource(actual, target, context); + var updatedActual = updaterMatcher.updateResource(actual, desired, context); updatedResource = prepare(updatedActual, primary, "Updating").update(); } log.debug("Resource version after update: {}", @@ -146,6 +148,7 @@ public R update(R actual, R target, P primary, Context

context) { @Override public Result match(R actualResource, P primary, Context

context) { final var desired = desired(primary, context); + sanitizeDesired(desired, actualResource, primary, context); return match(actualResource, desired, primary, updaterMatcher, context); } @@ -189,6 +192,10 @@ protected void addMetadata(boolean forMatch, R actualResource, final R target, P addReferenceHandlingMetadata(target, primary); } + protected void sanitizeDesired(R desired, R actual, P primary, Context

context) { + DesiredResourceSanitizer.sanitizeDesired(desired, actual, primary, context); + } + private boolean useSSA(Context

context) { Optional useSSAConfig = configuration().flatMap(KubernetesDependentResourceConfig::useSSA); diff --git a/operator-framework/src/test/java/io/javaoperatorsdk/operator/SSAStatefulSetMatcherIssueIT.java b/operator-framework/src/test/java/io/javaoperatorsdk/operator/SSAStatefulSetMatcherIssueIT.java deleted file mode 100644 index 8584ef1e5a..0000000000 --- a/operator-framework/src/test/java/io/javaoperatorsdk/operator/SSAStatefulSetMatcherIssueIT.java +++ /dev/null @@ -1,43 +0,0 @@ -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.fabric8.kubernetes.api.model.apps.StatefulSet; -import io.javaoperatorsdk.operator.junit.LocallyRunOperatorExtension; -import io.javaoperatorsdk.operator.sample.ssastatefulsetmatcherissue.SSAStatefulSetMatcherIssueCustomResource; -import io.javaoperatorsdk.operator.sample.ssastatefulsetmatcherissue.SSAStatefulSetMatcherIssueReconciler; - -import static org.assertj.core.api.Assertions.assertThat; -import static org.awaitility.Awaitility.await; - -public class SSAStatefulSetMatcherIssueIT { - - public static final String TEST_1 = "test1"; - @RegisterExtension - LocallyRunOperatorExtension extension = - LocallyRunOperatorExtension.builder() - .withReconciler(new SSAStatefulSetMatcherIssueReconciler()) - .build(); - - @Test - void testSSAMatcher() { - extension.create(testResource()); - - - await().untilAsserted(() -> { - var statefulSet = extension.get(StatefulSet.class, TEST_1); - assertThat(statefulSet).isNotNull(); - }); - } - - SSAStatefulSetMatcherIssueCustomResource testResource() { - var res = new SSAStatefulSetMatcherIssueCustomResource(); - res.setMetadata(new ObjectMetaBuilder() - .withName(TEST_1) - .build()); - return res; - } - -} diff --git a/operator-framework/src/test/java/io/javaoperatorsdk/operator/StatefulSetDesiredSanitizerIT.java b/operator-framework/src/test/java/io/javaoperatorsdk/operator/StatefulSetDesiredSanitizerIT.java new file mode 100644 index 0000000000..5313fb7dfb --- /dev/null +++ b/operator-framework/src/test/java/io/javaoperatorsdk/operator/StatefulSetDesiredSanitizerIT.java @@ -0,0 +1,57 @@ +package io.javaoperatorsdk.operator; + +import java.time.Duration; + +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.RegisterExtension; + +import io.fabric8.kubernetes.api.model.ObjectMetaBuilder; +import io.fabric8.kubernetes.api.model.apps.StatefulSet; +import io.javaoperatorsdk.operator.junit.LocallyRunOperatorExtension; +import io.javaoperatorsdk.operator.sample.statefulsetdesiredsanitizer.StatefulSetDesiredSanitizerCustomResource; +import io.javaoperatorsdk.operator.sample.statefulsetdesiredsanitizer.StatefulSetDesiredSanitizerDependentResource; +import io.javaoperatorsdk.operator.sample.statefulsetdesiredsanitizer.StatefulSetDesiredSanitizerReconciler; +import io.javaoperatorsdk.operator.sample.statefulsetdesiredsanitizer.StatefulSetDesiredSanitizerSpec; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.awaitility.Awaitility.await; + +public class StatefulSetDesiredSanitizerIT { + + public static final String TEST_1 = "test1"; + + @RegisterExtension + LocallyRunOperatorExtension extension = + LocallyRunOperatorExtension.builder() + .withReconciler(new StatefulSetDesiredSanitizerReconciler()) + .build(); + + @Test + void testSSAMatcher() { + var resource = extension.create(testResource()); + + await().pollDelay(Duration.ofMillis(200)).untilAsserted(() -> { + var statefulSet = extension.get(StatefulSet.class, TEST_1); + assertThat(statefulSet).isNotNull(); + }); + // make sure reconciliation happens at least once more + resource.getSpec().setValue("changed value"); + extension.replace(resource); + + await().untilAsserted( + () -> assertThat(StatefulSetDesiredSanitizerDependentResource.nonMatchedAtLeastOnce) + .isFalse()); + } + + StatefulSetDesiredSanitizerCustomResource testResource() { + var res = new StatefulSetDesiredSanitizerCustomResource(); + res.setMetadata(new ObjectMetaBuilder() + .withName(TEST_1) + .build()); + res.setSpec(new StatefulSetDesiredSanitizerSpec()); + res.getSpec().setValue("initial value"); + + return res; + } + +} diff --git a/operator-framework/src/test/java/io/javaoperatorsdk/operator/sample/dependentssa/SSAConfigMapDependent.java b/operator-framework/src/test/java/io/javaoperatorsdk/operator/sample/dependentssa/SSAConfigMapDependent.java index 70f0ddcf15..806eccd717 100644 --- a/operator-framework/src/test/java/io/javaoperatorsdk/operator/sample/dependentssa/SSAConfigMapDependent.java +++ b/operator-framework/src/test/java/io/javaoperatorsdk/operator/sample/dependentssa/SSAConfigMapDependent.java @@ -33,10 +33,10 @@ protected ConfigMap desired(DependnetSSACustomResource primary, } @Override - public ConfigMap update(ConfigMap actual, ConfigMap target, + public ConfigMap update(ConfigMap actual, ConfigMap desired, DependnetSSACustomResource primary, Context context) { NUMBER_OF_UPDATES.incrementAndGet(); - return super.update(actual, target, primary, context); + return super.update(actual, desired, primary, context); } } diff --git a/operator-framework/src/test/java/io/javaoperatorsdk/operator/sample/servicestrictmatcher/ServiceDependentResource.java b/operator-framework/src/test/java/io/javaoperatorsdk/operator/sample/servicestrictmatcher/ServiceDependentResource.java index 1079642b33..deddf20263 100644 --- a/operator-framework/src/test/java/io/javaoperatorsdk/operator/sample/servicestrictmatcher/ServiceDependentResource.java +++ b/operator-framework/src/test/java/io/javaoperatorsdk/operator/sample/servicestrictmatcher/ServiceDependentResource.java @@ -53,10 +53,10 @@ public Matcher.Result match(Service actualResource, } @Override - public Service update(Service actual, Service target, + public Service update(Service actual, Service desired, ServiceStrictMatcherTestCustomResource primary, Context context) { updated.addAndGet(1); - return super.update(actual, target, primary, context); + return super.update(actual, desired, primary, context); } } diff --git a/operator-framework/src/test/java/io/javaoperatorsdk/operator/sample/ssalegacymatcher/ServiceDependentResource.java b/operator-framework/src/test/java/io/javaoperatorsdk/operator/sample/ssalegacymatcher/ServiceDependentResource.java index 5230404ceb..a1f5f6faf0 100644 --- a/operator-framework/src/test/java/io/javaoperatorsdk/operator/sample/ssalegacymatcher/ServiceDependentResource.java +++ b/operator-framework/src/test/java/io/javaoperatorsdk/operator/sample/ssalegacymatcher/ServiceDependentResource.java @@ -45,17 +45,17 @@ public Result match(Service actualResource, SSALegacyMatcherCustomResou // override just to check the exec count @Override - public Service update(Service actual, Service target, SSALegacyMatcherCustomResource primary, + public Service update(Service actual, Service desired, SSALegacyMatcherCustomResource primary, Context context) { createUpdateCount.addAndGet(1); - return super.update(actual, target, primary, context); + return super.update(actual, desired, primary, context); } // override just to check the exec count @Override - public Service create(Service target, SSALegacyMatcherCustomResource primary, + public Service create(Service desired, SSALegacyMatcherCustomResource primary, Context context) { createUpdateCount.addAndGet(1); - return super.create(target, primary, context); + return super.create(desired, primary, context); } } diff --git a/operator-framework/src/test/java/io/javaoperatorsdk/operator/sample/ssastatefulsetmatcherissue/SSAStatefulSetMatcherIssueReconciler.java b/operator-framework/src/test/java/io/javaoperatorsdk/operator/sample/ssastatefulsetmatcherissue/SSAStatefulSetMatcherIssueReconciler.java deleted file mode 100644 index dbcb31fc6d..0000000000 --- a/operator-framework/src/test/java/io/javaoperatorsdk/operator/sample/ssastatefulsetmatcherissue/SSAStatefulSetMatcherIssueReconciler.java +++ /dev/null @@ -1,20 +0,0 @@ -package io.javaoperatorsdk.operator.sample.ssastatefulsetmatcherissue; - -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; -import io.javaoperatorsdk.operator.api.reconciler.dependent.Dependent; - -@ControllerConfiguration(dependents = {@Dependent(type = StatefulSetDependentResource.class)}) -public class SSAStatefulSetMatcherIssueReconciler - implements Reconciler { - - @Override - public UpdateControl reconcile( - SSAStatefulSetMatcherIssueCustomResource resource, - Context context) throws Exception { - return UpdateControl.noUpdate(); - } - -} diff --git a/operator-framework/src/test/java/io/javaoperatorsdk/operator/sample/ssastatefulsetmatcherissue/StatefulSetDependentResource.java b/operator-framework/src/test/java/io/javaoperatorsdk/operator/sample/ssastatefulsetmatcherissue/StatefulSetDependentResource.java deleted file mode 100644 index e4075fe1b8..0000000000 --- a/operator-framework/src/test/java/io/javaoperatorsdk/operator/sample/ssastatefulsetmatcherissue/StatefulSetDependentResource.java +++ /dev/null @@ -1,28 +0,0 @@ -package io.javaoperatorsdk.operator.sample.ssastatefulsetmatcherissue; - -import io.fabric8.kubernetes.api.model.ObjectMetaBuilder; -import io.fabric8.kubernetes.api.model.apps.StatefulSet; -import io.javaoperatorsdk.operator.ReconcilerUtils; -import io.javaoperatorsdk.operator.api.reconciler.Context; -import io.javaoperatorsdk.operator.processing.dependent.kubernetes.CRUDKubernetesDependentResource; - -public class StatefulSetDependentResource - extends CRUDKubernetesDependentResource { - - public StatefulSetDependentResource() { - - super(StatefulSet.class); - } - - @Override - protected StatefulSet desired(SSAStatefulSetMatcherIssueCustomResource primary, - Context context) { - var template = - ReconcilerUtils.loadYaml(StatefulSet.class, getClass(), "statefulset_fixed_full.yaml"); - template.setMetadata(new ObjectMetaBuilder() - .withName(primary.getMetadata().getName()) - .withNamespace(primary.getMetadata().getNamespace()) - .build()); - return template; - } -} diff --git a/operator-framework/src/test/java/io/javaoperatorsdk/operator/sample/ssastatefulsetmatcherissue/SSAStatefulSetMatcherIssueCustomResource.java b/operator-framework/src/test/java/io/javaoperatorsdk/operator/sample/statefulsetdesiredsanitizer/StatefulSetDesiredSanitizerCustomResource.java similarity index 60% rename from operator-framework/src/test/java/io/javaoperatorsdk/operator/sample/ssastatefulsetmatcherissue/SSAStatefulSetMatcherIssueCustomResource.java rename to operator-framework/src/test/java/io/javaoperatorsdk/operator/sample/statefulsetdesiredsanitizer/StatefulSetDesiredSanitizerCustomResource.java index 00f3602d8d..bf35304da0 100644 --- a/operator-framework/src/test/java/io/javaoperatorsdk/operator/sample/ssastatefulsetmatcherissue/SSAStatefulSetMatcherIssueCustomResource.java +++ b/operator-framework/src/test/java/io/javaoperatorsdk/operator/sample/statefulsetdesiredsanitizer/StatefulSetDesiredSanitizerCustomResource.java @@ -1,4 +1,4 @@ -package io.javaoperatorsdk.operator.sample.ssastatefulsetmatcherissue; +package io.javaoperatorsdk.operator.sample.statefulsetdesiredsanitizer; import io.fabric8.kubernetes.api.model.Namespaced; import io.fabric8.kubernetes.client.CustomResource; @@ -7,8 +7,8 @@ @Group("sample.javaoperatorsdk") @Version("v1") -public class SSAStatefulSetMatcherIssueCustomResource - extends CustomResource +public class StatefulSetDesiredSanitizerCustomResource + extends CustomResource implements Namespaced { } diff --git a/operator-framework/src/test/java/io/javaoperatorsdk/operator/sample/statefulsetdesiredsanitizer/StatefulSetDesiredSanitizerDependentResource.java b/operator-framework/src/test/java/io/javaoperatorsdk/operator/sample/statefulsetdesiredsanitizer/StatefulSetDesiredSanitizerDependentResource.java new file mode 100644 index 0000000000..12525c4c8d --- /dev/null +++ b/operator-framework/src/test/java/io/javaoperatorsdk/operator/sample/statefulsetdesiredsanitizer/StatefulSetDesiredSanitizerDependentResource.java @@ -0,0 +1,43 @@ +package io.javaoperatorsdk.operator.sample.statefulsetdesiredsanitizer; + +import io.fabric8.kubernetes.api.model.ObjectMetaBuilder; +import io.fabric8.kubernetes.api.model.apps.StatefulSet; +import io.javaoperatorsdk.operator.ReconcilerUtils; +import io.javaoperatorsdk.operator.api.reconciler.Context; +import io.javaoperatorsdk.operator.processing.dependent.kubernetes.CRUDKubernetesDependentResource; + +public class StatefulSetDesiredSanitizerDependentResource + extends + CRUDKubernetesDependentResource { + + public static volatile Boolean nonMatchedAtLeastOnce; + + public StatefulSetDesiredSanitizerDependentResource() { + super(StatefulSet.class); + } + + @Override + protected StatefulSet desired(StatefulSetDesiredSanitizerCustomResource primary, + Context context) { + var template = + ReconcilerUtils.loadYaml(StatefulSet.class, getClass(), "statefulset.yaml"); + template.setMetadata(new ObjectMetaBuilder() + .withName(primary.getMetadata().getName()) + .withNamespace(primary.getMetadata().getNamespace()) + .build()); + return template; + } + + @Override + public Result match(StatefulSet actualResource, + StatefulSetDesiredSanitizerCustomResource primary, + Context context) { + var res = super.match(actualResource, primary, context); + if (!res.matched()) { + nonMatchedAtLeastOnce = true; + } else if (nonMatchedAtLeastOnce == null) { + nonMatchedAtLeastOnce = false; + } + return res; + } +} diff --git a/operator-framework/src/test/java/io/javaoperatorsdk/operator/sample/statefulsetdesiredsanitizer/StatefulSetDesiredSanitizerReconciler.java b/operator-framework/src/test/java/io/javaoperatorsdk/operator/sample/statefulsetdesiredsanitizer/StatefulSetDesiredSanitizerReconciler.java new file mode 100644 index 0000000000..c884619227 --- /dev/null +++ b/operator-framework/src/test/java/io/javaoperatorsdk/operator/sample/statefulsetdesiredsanitizer/StatefulSetDesiredSanitizerReconciler.java @@ -0,0 +1,20 @@ +package io.javaoperatorsdk.operator.sample.statefulsetdesiredsanitizer; + +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; +import io.javaoperatorsdk.operator.api.reconciler.dependent.Dependent; + +@ControllerConfiguration( + dependents = {@Dependent(type = StatefulSetDesiredSanitizerDependentResource.class)}) +public class StatefulSetDesiredSanitizerReconciler + implements Reconciler { + + @Override + public UpdateControl reconcile( + StatefulSetDesiredSanitizerCustomResource resource, + Context context) throws Exception { + return UpdateControl.noUpdate(); + } +} diff --git a/operator-framework/src/test/java/io/javaoperatorsdk/operator/sample/statefulsetdesiredsanitizer/StatefulSetDesiredSanitizerSpec.java b/operator-framework/src/test/java/io/javaoperatorsdk/operator/sample/statefulsetdesiredsanitizer/StatefulSetDesiredSanitizerSpec.java new file mode 100644 index 0000000000..3cca134108 --- /dev/null +++ b/operator-framework/src/test/java/io/javaoperatorsdk/operator/sample/statefulsetdesiredsanitizer/StatefulSetDesiredSanitizerSpec.java @@ -0,0 +1,15 @@ +package io.javaoperatorsdk.operator.sample.statefulsetdesiredsanitizer; + +public class StatefulSetDesiredSanitizerSpec { + + private String value; + + public String getValue() { + return value; + } + + public StatefulSetDesiredSanitizerSpec setValue(String value) { + this.value = value; + return this; + } +} diff --git a/operator-framework/src/test/resources/io/javaoperatorsdk/operator/sample/ssastatefulsetmatcherissue/statefulset_fixed_full.yaml b/operator-framework/src/test/resources/io/javaoperatorsdk/operator/sample/ssastatefulsetmatcherissue/statefulset_fixed_full.yaml deleted file mode 100644 index e2a86d638e..0000000000 --- a/operator-framework/src/test/resources/io/javaoperatorsdk/operator/sample/ssastatefulsetmatcherissue/statefulset_fixed_full.yaml +++ /dev/null @@ -1,38 +0,0 @@ -apiVersion: apps/v1 -kind: StatefulSet -metadata: - name: web -spec: - selector: - matchLabels: - app: nginx # has to match .spec.template.metadata.labels - serviceName: "nginx" - replicas: 1 - minReadySeconds: 10 # by default is 0 - template: - metadata: - labels: - app: nginx # has to match .spec.selector.matchLabels - spec: - terminationGracePeriodSeconds: 10 - containers: - - name: nginx - image: registry.k8s.io/nginx-slim:0.8 - ports: - - containerPort: 80 - name: web - volumeMounts: - - name: www - mountPath: /usr/share/nginx/html - volumeClaimTemplates: - - metadata: - name: www - spec: - accessModes: [ "ReadWriteOnce" ] - storageClassName: "my-storage-class" - volumeMode: Filesystem - resources: - requests: - storage: 1Gi - status: - phase: pending \ No newline at end of file diff --git a/operator-framework/src/test/resources/io/javaoperatorsdk/operator/sample/ssastatefulsetmatcherissue/statefulset.yaml b/operator-framework/src/test/resources/io/javaoperatorsdk/operator/sample/statefulsetdesiredsanitizer/statefulset.yaml similarity index 89% rename from operator-framework/src/test/resources/io/javaoperatorsdk/operator/sample/ssastatefulsetmatcherissue/statefulset.yaml rename to operator-framework/src/test/resources/io/javaoperatorsdk/operator/sample/statefulsetdesiredsanitizer/statefulset.yaml index 67594e8365..f40fbeb607 100644 --- a/operator-framework/src/test/resources/io/javaoperatorsdk/operator/sample/ssastatefulsetmatcherissue/statefulset.yaml +++ b/operator-framework/src/test/resources/io/javaoperatorsdk/operator/sample/statefulsetdesiredsanitizer/statefulset.yaml @@ -1,11 +1,8 @@ apiVersion: apps/v1 kind: StatefulSet metadata: - name: web + name: "" spec: - persistentVolumeClaimRetentionPolicy: - whenDeleted: "Retain" - whenScaled: "Delete" selector: matchLabels: app: nginx # has to match .spec.template.metadata.labels diff --git a/sample-operators/webpage/src/main/java/io/javaoperatorsdk/operator/sample/dependentresource/ConfigMapDependentResource.java b/sample-operators/webpage/src/main/java/io/javaoperatorsdk/operator/sample/dependentresource/ConfigMapDependentResource.java index cc7b15146b..ea1731041f 100644 --- a/sample-operators/webpage/src/main/java/io/javaoperatorsdk/operator/sample/dependentresource/ConfigMapDependentResource.java +++ b/sample-operators/webpage/src/main/java/io/javaoperatorsdk/operator/sample/dependentresource/ConfigMapDependentResource.java @@ -47,9 +47,9 @@ protected ConfigMap desired(WebPage webPage, Context context) { } @Override - public ConfigMap update(ConfigMap actual, ConfigMap target, WebPage primary, + public ConfigMap update(ConfigMap actual, ConfigMap desired, WebPage primary, Context context) { - var res = super.update(actual, target, primary, context); + var res = super.update(actual, desired, primary, context); var ns = actual.getMetadata().getNamespace(); log.info("Restarting pods because HTML has changed in {}", ns); From ee1970e614da43190c18e49b6a0808dfa35b06c0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Attila=20M=C3=A9sz=C3=A1ros?= Date: Mon, 11 Sep 2023 14:14:25 +0200 Subject: [PATCH 05/15] add default resources MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Attila Mészáros --- .../kubernetes/DesiredResourceSanitizer.java | 6 ++---- .../KubernetesDependentResource.java | 20 +++++++++++++++---- 2 files changed, 18 insertions(+), 8 deletions(-) diff --git a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/kubernetes/DesiredResourceSanitizer.java b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/kubernetes/DesiredResourceSanitizer.java index 4e5962d1d2..0521a35173 100644 --- a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/kubernetes/DesiredResourceSanitizer.java +++ b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/kubernetes/DesiredResourceSanitizer.java @@ -6,15 +6,13 @@ import io.fabric8.kubernetes.api.model.apps.StatefulSet; import io.javaoperatorsdk.operator.api.reconciler.Context; -import static io.javaoperatorsdk.operator.processing.dependent.kubernetes.KubernetesDependentResource.useSSA; - public class DesiredResourceSanitizer { private DesiredResourceSanitizer() {} public static void sanitizeDesired(R desired, R actual, P primary, - Context

context) { - if (useSSA(context)) { + Context

context, boolean useSSA) { + if (useSSA) { if (desired instanceof StatefulSet) { fillDefaultsOnVolumeClaimTemplate((StatefulSet) desired); } diff --git a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/kubernetes/KubernetesDependentResource.java b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/kubernetes/KubernetesDependentResource.java index 7dbdee91da..9afabec7f1 100644 --- a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/kubernetes/KubernetesDependentResource.java +++ b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/kubernetes/KubernetesDependentResource.java @@ -7,7 +7,9 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import io.fabric8.kubernetes.api.model.ConfigMap; import io.fabric8.kubernetes.api.model.HasMetadata; +import io.fabric8.kubernetes.api.model.Secret; import io.fabric8.kubernetes.client.KubernetesClient; import io.fabric8.kubernetes.client.dsl.Resource; import io.javaoperatorsdk.operator.OperatorException; @@ -38,6 +40,10 @@ public abstract class KubernetesDependentResource> DEFAULT_NON_SSA_RESOURCES = + Set.of(ConfigMap.class, + Secret.class); + protected KubernetesClient client; private final ResourceUpdaterMatcher updaterMatcher; private final boolean garbageCollected = this instanceof GarbageCollected; @@ -134,6 +140,7 @@ public R update(R actual, R desired, P primary, Context

context) { sanitizeDesired(desired, actual, primary, context); if (useSSA(context)) { updatedResource = prepare(desired, primary, "Updating") + .fieldManager(context.getControllerConfiguration().fieldManager()) .fieldManager(context.getControllerConfiguration().fieldManager()) .forceConflicts().serverSideApply(); } else { @@ -192,13 +199,18 @@ protected void addMetadata(boolean forMatch, R actualResource, final R target, P addReferenceHandlingMetadata(target, primary); } - protected void sanitizeDesired(R desired, R actual, P primary, Context

context) { - DesiredResourceSanitizer.sanitizeDesired(desired, actual, primary, context); - } + protected void sanitizeDesired(R desired, R actual, P primary, Context

context) { + DesiredResourceSanitizer.sanitizeDesired(desired, actual, primary, context, useSSA(context)); + } - private boolean useSSA(Context

context) { + protected boolean useSSA(Context

context) { Optional useSSAConfig = configuration().flatMap(KubernetesDependentResourceConfig::useSSA); + + // don't use SSA for certain resources by default, only if explicitly overriden + if (useSSAConfig.isEmpty() && DEFAULT_NON_SSA_RESOURCES.contains(resourceType())) { + return false; + } return useSSAConfig.orElse(context.getControllerConfiguration().getConfigurationService() .ssaBasedCreateUpdateMatchForDependentResources()); } From 5faf9d7953fb6de05a55fffd4781abc20e34f2a9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Attila=20M=C3=A9sz=C3=A1ros?= Date: Mon, 11 Sep 2023 14:17:43 +0200 Subject: [PATCH 06/15] format MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Attila Mészáros --- .../dependent/kubernetes/KubernetesDependentResource.java | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/kubernetes/KubernetesDependentResource.java b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/kubernetes/KubernetesDependentResource.java index 9afabec7f1..7c6ae29205 100644 --- a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/kubernetes/KubernetesDependentResource.java +++ b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/kubernetes/KubernetesDependentResource.java @@ -41,8 +41,7 @@ public abstract class KubernetesDependentResource> DEFAULT_NON_SSA_RESOURCES = - Set.of(ConfigMap.class, - Secret.class); + Set.of(ConfigMap.class, Secret.class); protected KubernetesClient client; private final ResourceUpdaterMatcher updaterMatcher; From 4266e6c49904f37b0fc7beb104437a1a6c7da965 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Attila=20M=C3=A9sz=C3=A1ros?= Date: Mon, 11 Sep 2023 14:31:47 +0200 Subject: [PATCH 07/15] generic configs for default non SSA resources MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Attila Mészáros --- .../operator/api/config/ConfigurationService.java | 6 ++++++ .../api/config/ConfigurationServiceOverrider.java | 14 ++++++++++++++ .../kubernetes/KubernetesDependentResource.java | 7 ++----- 3 files changed, 22 insertions(+), 5 deletions(-) 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 2422f6ef74..860a3033de 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 @@ -9,7 +9,9 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import io.fabric8.kubernetes.api.model.ConfigMap; import io.fabric8.kubernetes.api.model.HasMetadata; +import io.fabric8.kubernetes.api.model.Secret; import io.fabric8.kubernetes.client.Config; import io.fabric8.kubernetes.client.ConfigBuilder; import io.fabric8.kubernetes.client.CustomResource; @@ -345,4 +347,8 @@ default boolean ssaBasedCreateUpdateMatchForDependentResources() { return true; } + default Set> defaultNonSSAResource() { + return Set.of(ConfigMap.class, Secret.class); + } + } diff --git a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/config/ConfigurationServiceOverrider.java b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/config/ConfigurationServiceOverrider.java index ebac41f640..15418aed5e 100644 --- a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/config/ConfigurationServiceOverrider.java +++ b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/config/ConfigurationServiceOverrider.java @@ -9,6 +9,7 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import io.fabric8.kubernetes.api.model.HasMetadata; import io.fabric8.kubernetes.client.KubernetesClient; import io.javaoperatorsdk.operator.api.monitoring.Metrics; @@ -35,6 +36,7 @@ public class ConfigurationServiceOverrider { private Duration cacheSyncTimeout; private ResourceClassResolver resourceClassResolver; private Boolean ssaBasedCreateUpdateMatchForDependentResources; + private Set> defaultNonSSAResource; ConfigurationServiceOverrider(ConfigurationService original) { this.original = original; @@ -150,6 +152,12 @@ public ConfigurationServiceOverrider withSSABasedCreateUpdateMatchForDependentRe return this; } + public ConfigurationServiceOverrider withDefaultNonSSAResource( + Set> defaultNonSSAResource) { + this.defaultNonSSAResource = defaultNonSSAResource; + return this; + } + public ConfigurationService build() { return new BaseConfigurationService(original.getVersion(), cloner, client) { @Override @@ -256,6 +264,12 @@ public boolean ssaBasedCreateUpdateMatchForDependentResources() { ? ssaBasedCreateUpdateMatchForDependentResources : super.ssaBasedCreateUpdateMatchForDependentResources(); } + + @Override + public Set> defaultNonSSAResource() { + return defaultNonSSAResource != null ? defaultNonSSAResource + : super.defaultNonSSAResource(); + } }; } diff --git a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/kubernetes/KubernetesDependentResource.java b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/kubernetes/KubernetesDependentResource.java index 7c6ae29205..22c1ea7f91 100644 --- a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/kubernetes/KubernetesDependentResource.java +++ b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/kubernetes/KubernetesDependentResource.java @@ -40,9 +40,6 @@ public abstract class KubernetesDependentResource> DEFAULT_NON_SSA_RESOURCES = - Set.of(ConfigMap.class, Secret.class); - protected KubernetesClient client; private final ResourceUpdaterMatcher updaterMatcher; private final boolean garbageCollected = this instanceof GarbageCollected; @@ -205,9 +202,9 @@ protected void sanitizeDesired(R desired, R actual, P primary, Context

contex protected boolean useSSA(Context

context) { Optional useSSAConfig = configuration().flatMap(KubernetesDependentResourceConfig::useSSA); - + var configService = context.getControllerConfiguration().getConfigurationService(); // don't use SSA for certain resources by default, only if explicitly overriden - if (useSSAConfig.isEmpty() && DEFAULT_NON_SSA_RESOURCES.contains(resourceType())) { + if (useSSAConfig.isEmpty() && configService.defaultNonSSAResource().contains(resourceType())) { return false; } return useSSAConfig.orElse(context.getControllerConfiguration().getConfigurationService() From 128328aa395ea40d7259c7505135d6eb78309723 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Attila=20M=C3=A9sz=C3=A1ros?= Date: Mon, 11 Sep 2023 14:34:16 +0200 Subject: [PATCH 08/15] format MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Attila Mészáros --- .../dependent/kubernetes/KubernetesDependentResource.java | 2 -- 1 file changed, 2 deletions(-) diff --git a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/kubernetes/KubernetesDependentResource.java b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/kubernetes/KubernetesDependentResource.java index 22c1ea7f91..27a259c4d4 100644 --- a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/kubernetes/KubernetesDependentResource.java +++ b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/kubernetes/KubernetesDependentResource.java @@ -7,9 +7,7 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import io.fabric8.kubernetes.api.model.ConfigMap; import io.fabric8.kubernetes.api.model.HasMetadata; -import io.fabric8.kubernetes.api.model.Secret; import io.fabric8.kubernetes.client.KubernetesClient; import io.fabric8.kubernetes.client.dsl.Resource; import io.javaoperatorsdk.operator.OperatorException; From 62f6b917d3bfbcc138fc28152ee44795cf508f9a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Attila=20M=C3=A9sz=C3=A1ros?= Date: Mon, 11 Sep 2023 14:46:13 +0200 Subject: [PATCH 09/15] docs MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Attila Mészáros --- .../operator/api/config/ConfigurationService.java | 8 ++++++++ 1 file changed, 8 insertions(+) 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 860a3033de..4f7de34bc3 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 @@ -21,6 +21,7 @@ import io.javaoperatorsdk.operator.api.monitoring.Metrics; import io.javaoperatorsdk.operator.api.reconciler.Reconciler; import io.javaoperatorsdk.operator.api.reconciler.dependent.DependentResourceFactory; +import io.javaoperatorsdk.operator.processing.dependent.kubernetes.KubernetesDependent; import io.javaoperatorsdk.operator.processing.dependent.workflow.ManagedWorkflowFactory; import static io.javaoperatorsdk.operator.api.config.ExecutorServiceManager.newThreadPoolExecutor; @@ -347,6 +348,13 @@ default boolean ssaBasedCreateUpdateMatchForDependentResources() { return true; } + /** + * There are certain resources where the intention is not use SSA in Kubernetes. Typical are + * ConfigMaps or Secrets. For these resources, if {@link KubernetesDependent#useSSA()} is not + * explicitly overriden for a dependent resource instance SSA will not be used, event if in + * general SSA is used for Dependent Resources, see + * {@link #ssaBasedCreateUpdateMatchForDependentResources()}. + */ default Set> defaultNonSSAResource() { return Set.of(ConfigMap.class, Secret.class); } From 81f98305758bbe33d28638a9380943126e2f8c5c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Attila=20M=C3=A9sz=C3=A1ros?= Date: Tue, 12 Sep 2023 08:41:16 +0200 Subject: [PATCH 10/15] remove unnecessary line MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Attila Mészáros --- .../dependent/kubernetes/DesiredResourceSanitizer.java | 1 - 1 file changed, 1 deletion(-) diff --git a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/kubernetes/DesiredResourceSanitizer.java b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/kubernetes/DesiredResourceSanitizer.java index 0521a35173..45b781af7a 100644 --- a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/kubernetes/DesiredResourceSanitizer.java +++ b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/kubernetes/DesiredResourceSanitizer.java @@ -39,7 +39,6 @@ private static void fillDefaultsOnVolumeClaimTemplate(StatefulSet statefulSet) { t.setStatus(new PersistentVolumeClaimStatus()); } if (t.getStatus().getPhase() == null) { - t.setStatus(new PersistentVolumeClaimStatus()); t.getStatus().setPhase("pending"); } }); From 34874e07a6bc1199b827bb5db6886e35ec43d94d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Attila=20M=C3=A9sz=C3=A1ros?= Date: Tue, 12 Sep 2023 09:56:38 +0200 Subject: [PATCH 11/15] fix it MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Attila Mészáros --- .../operator/sample/dependentssa/SSAConfigMapDependent.java | 3 +++ 1 file changed, 3 insertions(+) diff --git a/operator-framework/src/test/java/io/javaoperatorsdk/operator/sample/dependentssa/SSAConfigMapDependent.java b/operator-framework/src/test/java/io/javaoperatorsdk/operator/sample/dependentssa/SSAConfigMapDependent.java index 806eccd717..a7e8422494 100644 --- a/operator-framework/src/test/java/io/javaoperatorsdk/operator/sample/dependentssa/SSAConfigMapDependent.java +++ b/operator-framework/src/test/java/io/javaoperatorsdk/operator/sample/dependentssa/SSAConfigMapDependent.java @@ -7,8 +7,11 @@ import io.fabric8.kubernetes.api.model.ConfigMapBuilder; import io.fabric8.kubernetes.api.model.ObjectMetaBuilder; import io.javaoperatorsdk.operator.api.reconciler.Context; +import io.javaoperatorsdk.operator.processing.dependent.kubernetes.BooleanWithUndefined; import io.javaoperatorsdk.operator.processing.dependent.kubernetes.CRUDKubernetesDependentResource; +import io.javaoperatorsdk.operator.processing.dependent.kubernetes.KubernetesDependent; +@KubernetesDependent(useSSA = BooleanWithUndefined.TRUE) public class SSAConfigMapDependent extends CRUDKubernetesDependentResource { From c2fbacf284c5f028faf16bc46653352769a22152 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Attila=20M=C3=A9sz=C3=A1ros?= Date: Tue, 12 Sep 2023 14:17:09 +0200 Subject: [PATCH 12/15] fix IT MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Attila Mészáros --- ...ernetesDependentResourceConfigBuilder.java | 6 ++- .../operator/DependentSSAMigrationIT.java | 8 ++-- .../dependentssa/DependentSSAReconciler.java | 45 +++++++++++++++++-- .../dependentssa/SSAConfigMapDependent.java | 3 -- 4 files changed, 50 insertions(+), 12 deletions(-) diff --git a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/kubernetes/KubernetesDependentResourceConfigBuilder.java b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/kubernetes/KubernetesDependentResourceConfigBuilder.java index 8bdb8a47a5..a18d8b8a41 100644 --- a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/kubernetes/KubernetesDependentResourceConfigBuilder.java +++ b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/kubernetes/KubernetesDependentResourceConfigBuilder.java @@ -2,6 +2,7 @@ import java.util.Set; +import io.javaoperatorsdk.operator.api.reconciler.Constants; import io.javaoperatorsdk.operator.api.reconciler.ResourceDiscriminator; import io.javaoperatorsdk.operator.processing.event.source.filter.GenericFilter; import io.javaoperatorsdk.operator.processing.event.source.filter.OnAddFilter; @@ -10,7 +11,7 @@ public final class KubernetesDependentResourceConfigBuilder { - private Set namespaces; + private Set namespaces = Constants.SAME_AS_CONTROLLER_NAMESPACES_SET; private String labelSelector; private boolean createResourceOnlyIfNotExistingWithSSA; private ResourceDiscriminator resourceDiscriminator; @@ -77,7 +78,8 @@ public KubernetesDependentResourceConfigBuilder withGenericFilter( } public KubernetesDependentResourceConfig build() { - return new KubernetesDependentResourceConfig<>(namespaces, labelSelector, false, + return new KubernetesDependentResourceConfig<>(namespaces, labelSelector, + namespaces != Constants.SAME_AS_CONTROLLER_NAMESPACES_SET, createResourceOnlyIfNotExistingWithSSA, resourceDiscriminator, useSSA, onAddFilter, onUpdateFilter, onDeleteFilter, genericFilter); } diff --git a/operator-framework/src/test/java/io/javaoperatorsdk/operator/DependentSSAMigrationIT.java b/operator-framework/src/test/java/io/javaoperatorsdk/operator/DependentSSAMigrationIT.java index 7e226eca38..0eabc07c97 100644 --- a/operator-framework/src/test/java/io/javaoperatorsdk/operator/DependentSSAMigrationIT.java +++ b/operator-framework/src/test/java/io/javaoperatorsdk/operator/DependentSSAMigrationIT.java @@ -144,9 +144,10 @@ private DependnetSSACustomResource reconcileWithLegacyOperator(Operator legacyOp private Operator createOperator(KubernetesClient client, boolean legacyDependentHandling, String fieldManager) { Operator operator = new Operator(client, - o -> o.withSSABasedCreateUpdateMatchForDependentResources(!legacyDependentHandling) - .withCloseClientOnStop(false)); - operator.register(new DependentSSAReconciler(), o -> { + o -> o.withCloseClientOnStop(false)); + var reconciler = new DependentSSAReconciler(!legacyDependentHandling); + reconciler.setKubernetesClient(client); + operator.register(reconciler, o -> { o.settingNamespace(namespace); if (fieldManager != null) { o.withFieldManager(fieldManager); @@ -155,7 +156,6 @@ private Operator createOperator(KubernetesClient client, boolean legacyDependent return operator; } - public DependnetSSACustomResource testResource() { DependnetSSACustomResource resource = new DependnetSSACustomResource(); resource.setMetadata(new ObjectMetaBuilder() diff --git a/operator-framework/src/test/java/io/javaoperatorsdk/operator/sample/dependentssa/DependentSSAReconciler.java b/operator-framework/src/test/java/io/javaoperatorsdk/operator/sample/dependentssa/DependentSSAReconciler.java index d5c48256f7..f84dfe4597 100644 --- a/operator-framework/src/test/java/io/javaoperatorsdk/operator/sample/dependentssa/DependentSSAReconciler.java +++ b/operator-framework/src/test/java/io/javaoperatorsdk/operator/sample/dependentssa/DependentSSAReconciler.java @@ -1,21 +1,43 @@ package io.javaoperatorsdk.operator.sample.dependentssa; +import java.util.Map; import java.util.concurrent.atomic.AtomicInteger; +import io.fabric8.kubernetes.api.model.ConfigMap; +import io.fabric8.kubernetes.client.KubernetesClient; import io.javaoperatorsdk.operator.api.reconciler.*; -import io.javaoperatorsdk.operator.api.reconciler.dependent.Dependent; +import io.javaoperatorsdk.operator.junit.KubernetesClientAware; +import io.javaoperatorsdk.operator.processing.dependent.kubernetes.KubernetesDependentResourceConfigBuilder; +import io.javaoperatorsdk.operator.processing.event.source.EventSource; import io.javaoperatorsdk.operator.support.TestExecutionInfoProvider; -@ControllerConfiguration(dependents = {@Dependent(type = SSAConfigMapDependent.class)}) +@ControllerConfiguration public class DependentSSAReconciler - implements Reconciler, TestExecutionInfoProvider { + implements Reconciler, TestExecutionInfoProvider, + KubernetesClientAware, + EventSourceInitializer { private final AtomicInteger numberOfExecutions = new AtomicInteger(0); + private SSAConfigMapDependent ssaConfigMapDependent = new SSAConfigMapDependent(); + private KubernetesClient kubernetesClient; + + public DependentSSAReconciler() { + this(true); + } + + public DependentSSAReconciler(boolean useSSA) { + ssaConfigMapDependent.configureWith(new KubernetesDependentResourceConfigBuilder() + .withUseSSA(useSSA) + .build()); + } + @Override public UpdateControl reconcile( DependnetSSACustomResource resource, Context context) { + + ssaConfigMapDependent.reconcile(resource, context); numberOfExecutions.addAndGet(1); return UpdateControl.noUpdate(); } @@ -24,4 +46,21 @@ public int getNumberOfExecutions() { return numberOfExecutions.get(); } + @Override + public KubernetesClient getKubernetesClient() { + return kubernetesClient; + } + + @Override + public void setKubernetesClient(KubernetesClient kubernetesClient) { + this.kubernetesClient = kubernetesClient; + ssaConfigMapDependent.setKubernetesClient(kubernetesClient); + } + + @Override + public Map prepareEventSources( + EventSourceContext context) { + return EventSourceInitializer.nameEventSourcesFromDependentResource(context, + ssaConfigMapDependent); + } } diff --git a/operator-framework/src/test/java/io/javaoperatorsdk/operator/sample/dependentssa/SSAConfigMapDependent.java b/operator-framework/src/test/java/io/javaoperatorsdk/operator/sample/dependentssa/SSAConfigMapDependent.java index a7e8422494..806eccd717 100644 --- a/operator-framework/src/test/java/io/javaoperatorsdk/operator/sample/dependentssa/SSAConfigMapDependent.java +++ b/operator-framework/src/test/java/io/javaoperatorsdk/operator/sample/dependentssa/SSAConfigMapDependent.java @@ -7,11 +7,8 @@ import io.fabric8.kubernetes.api.model.ConfigMapBuilder; import io.fabric8.kubernetes.api.model.ObjectMetaBuilder; import io.javaoperatorsdk.operator.api.reconciler.Context; -import io.javaoperatorsdk.operator.processing.dependent.kubernetes.BooleanWithUndefined; import io.javaoperatorsdk.operator.processing.dependent.kubernetes.CRUDKubernetesDependentResource; -import io.javaoperatorsdk.operator.processing.dependent.kubernetes.KubernetesDependent; -@KubernetesDependent(useSSA = BooleanWithUndefined.TRUE) public class SSAConfigMapDependent extends CRUDKubernetesDependentResource { From ec9c35526151cdbd2d91f305db212c55f7a8d86f Mon Sep 17 00:00:00 2001 From: Chris Laprun Date: Tue, 12 Sep 2023 15:26:33 +0200 Subject: [PATCH 13/15] refactor: make intent more explicit Signed-off-by: Chris Laprun --- .../SSABasedGenericKubernetesResourceMatcher.java | 11 ++--------- 1 file changed, 2 insertions(+), 9 deletions(-) diff --git a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/kubernetes/SSABasedGenericKubernetesResourceMatcher.java b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/kubernetes/SSABasedGenericKubernetesResourceMatcher.java index d81f93a969..442119a822 100644 --- a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/kubernetes/SSABasedGenericKubernetesResourceMatcher.java +++ b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/kubernetes/SSABasedGenericKubernetesResourceMatcher.java @@ -1,14 +1,7 @@ package io.javaoperatorsdk.operator.processing.dependent.kubernetes; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.Map; +import java.util.*; import java.util.Map.Entry; -import java.util.Optional; -import java.util.Set; -import java.util.SortedMap; -import java.util.TreeMap; import java.util.stream.Collectors; import org.slf4j.Logger; @@ -159,7 +152,7 @@ private static void fillResultsAndTraverseFurther(Map result, Object managedFieldValue) { var emptyMapValue = new HashMap(); result.put(keyInActual, emptyMapValue); - var actualMapValue = actualMap.getOrDefault(keyInActual, Map.of()); + var actualMapValue = actualMap.getOrDefault(keyInActual, Collections.emptyMap()); log.debug("key: {} actual map value: {} managedFieldValue: {}", keyInActual, actualMapValue, managedFieldValue); From 43056e0fae0f412f1835a8c2eb83c26d0c516b9f Mon Sep 17 00:00:00 2001 From: Chris Laprun Date: Tue, 12 Sep 2023 15:28:19 +0200 Subject: [PATCH 14/15] fix: remove duplicated line Signed-off-by: Chris Laprun --- .../dependent/kubernetes/KubernetesDependentResource.java | 1 - 1 file changed, 1 deletion(-) diff --git a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/kubernetes/KubernetesDependentResource.java b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/kubernetes/KubernetesDependentResource.java index 27a259c4d4..22ec5a48f9 100644 --- a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/kubernetes/KubernetesDependentResource.java +++ b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/kubernetes/KubernetesDependentResource.java @@ -134,7 +134,6 @@ public R update(R actual, R desired, P primary, Context

context) { sanitizeDesired(desired, actual, primary, context); if (useSSA(context)) { updatedResource = prepare(desired, primary, "Updating") - .fieldManager(context.getControllerConfiguration().fieldManager()) .fieldManager(context.getControllerConfiguration().fieldManager()) .forceConflicts().serverSideApply(); } else { From 0c4db58c757c2b37be5dc1f97c6de50149891d8f Mon Sep 17 00:00:00 2001 From: Chris Laprun Date: Tue, 12 Sep 2023 15:34:28 +0200 Subject: [PATCH 15/15] docs: improve javadoc Signed-off-by: Chris Laprun --- .../api/config/ConfigurationService.java | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) 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 4f7de34bc3..86efb457c5 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 @@ -338,7 +338,7 @@ default ExecutorServiceManager getExecutorServiceManager() { * resources are created/updated and match was change to use * Server-Side * Apply (SSA) by default. - * + *

* SSA based create/update can be still used with the legacy matching, just overriding the match * method of Kubernetes Dependent Resource. * @@ -349,11 +349,16 @@ default boolean ssaBasedCreateUpdateMatchForDependentResources() { } /** - * There are certain resources where the intention is not use SSA in Kubernetes. Typical are - * ConfigMaps or Secrets. For these resources, if {@link KubernetesDependent#useSSA()} is not - * explicitly overriden for a dependent resource instance SSA will not be used, event if in - * general SSA is used for Dependent Resources, see - * {@link #ssaBasedCreateUpdateMatchForDependentResources()}. + * Returns the set of default resources for which Server-Side Apply (SSA) will not be used, even + * if it is the default behavior for dependent resources as specified by + * {@link #ssaBasedCreateUpdateMatchForDependentResources()}. The exception to this is in the case + * where the use of SSA is explicitly enabled on the dependent resource directly using + * {@link KubernetesDependent#useSSA()}. + *

+ * By default, SSA is disabled for {@link ConfigMap} and {@link Secret} resources. + * + * @return The set of resource types for which SSA will not be used + * @since 4.4.0 */ default Set> defaultNonSSAResource() { return Set.of(ConfigMap.class, Secret.class);