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/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..e4075fe1b8 --- /dev/null +++ b/operator-framework/src/test/java/io/javaoperatorsdk/operator/sample/ssastatefulsetmatcherissue/StatefulSetDependentResource.java @@ -0,0 +1,28 @@ +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/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 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