From 413197799295c0c8f30fa1320ff3055b6297147b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Attila=20M=C3=A9sz=C3=A1ros?= Date: Thu, 2 Jan 2025 19:25:40 +0100 Subject: [PATCH 1/4] feat: bulk dependent resource MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Attila Mészáros --- .../javaoperatorsdk/operator/glue/Utils.java | 10 ++-- .../glue/DependentResourceSpec.java | 14 ++++- .../GCGenericBulkDependentResource.java | 17 ++++++ .../GenericBulkDependentResource.java | 52 +++++++++++++++++++ .../dependent/GenericDependentResource.java | 13 +++-- .../reconciler/ValidationAndErrorHandler.java | 15 +++++- .../glue/reconciler/glue/GlueReconciler.java | 14 +++-- .../operator/GlueOperatorReconciler.java | 2 +- 8 files changed, 119 insertions(+), 18 deletions(-) create mode 100644 src/main/java/io/javaoperatorsdk/operator/glue/dependent/GCGenericBulkDependentResource.java create mode 100644 src/main/java/io/javaoperatorsdk/operator/glue/dependent/GenericBulkDependentResource.java diff --git a/src/main/java/io/javaoperatorsdk/operator/glue/Utils.java b/src/main/java/io/javaoperatorsdk/operator/glue/Utils.java index 7149143..d5af998 100644 --- a/src/main/java/io/javaoperatorsdk/operator/glue/Utils.java +++ b/src/main/java/io/javaoperatorsdk/operator/glue/Utils.java @@ -138,9 +138,7 @@ public static String getKindFromTemplate(String resourceTemplate) { public static Set leafResourceNames(Glue glue) { Set result = new HashSet<>(); glue.getSpec().getChildResources().forEach(r -> result.add(r.getName())); - glue.getSpec().getChildResources().forEach(r -> { - r.getDependsOn().forEach(result::remove); - }); + glue.getSpec().getChildResources().forEach(r -> r.getDependsOn().forEach(result::remove)); return result; } @@ -157,4 +155,10 @@ private static String getPropertyValueFromTemplate(String resourceTemplate, Stri "Template does not contain property. " + resourceTemplate)); } + public static GroupVersionKind getGVKFromTemplate(String resourceTemplate) { + String apiVersion = getApiVersionFromTemplate(resourceTemplate); + String kind = getKindFromTemplate(resourceTemplate); + return new GroupVersionKind(apiVersion, kind); + } + } diff --git a/src/main/java/io/javaoperatorsdk/operator/glue/customresource/glue/DependentResourceSpec.java b/src/main/java/io/javaoperatorsdk/operator/glue/customresource/glue/DependentResourceSpec.java index ba929f5..baa7b85 100644 --- a/src/main/java/io/javaoperatorsdk/operator/glue/customresource/glue/DependentResourceSpec.java +++ b/src/main/java/io/javaoperatorsdk/operator/glue/customresource/glue/DependentResourceSpec.java @@ -23,6 +23,8 @@ public class DependentResourceSpec { private Matcher matcher = Matcher.SSA; + private Boolean bulk = false; + private List dependsOn = new ArrayList<>(); @PreserveUnknownFields @@ -102,6 +104,14 @@ public void setMatcher(Matcher matcher) { this.matcher = matcher; } + public Boolean getBulk() { + return bulk; + } + + public void setBulk(Boolean bulk) { + this.bulk = bulk; + } + @Override public boolean equals(Object o) { if (this == o) @@ -112,14 +122,14 @@ public boolean equals(Object o) { return clusterScoped == that.clusterScoped && Objects.equals(name, that.name) && Objects.equals(resource, that.resource) && Objects.equals(resourceTemplate, that.resourceTemplate) && matcher == that.matcher - && Objects.equals(dependsOn, that.dependsOn) + && Objects.equals(bulk, that.bulk) && Objects.equals(dependsOn, that.dependsOn) && Objects.equals(readyPostCondition, that.readyPostCondition) && Objects.equals(condition, that.condition); } @Override public int hashCode() { - return Objects.hash(name, clusterScoped, resource, resourceTemplate, matcher, dependsOn, + return Objects.hash(name, clusterScoped, resource, resourceTemplate, matcher, bulk, dependsOn, readyPostCondition, condition); } } diff --git a/src/main/java/io/javaoperatorsdk/operator/glue/dependent/GCGenericBulkDependentResource.java b/src/main/java/io/javaoperatorsdk/operator/glue/dependent/GCGenericBulkDependentResource.java new file mode 100644 index 0000000..9a735c2 --- /dev/null +++ b/src/main/java/io/javaoperatorsdk/operator/glue/dependent/GCGenericBulkDependentResource.java @@ -0,0 +1,17 @@ +package io.javaoperatorsdk.operator.glue.dependent; + +import io.javaoperatorsdk.operator.api.reconciler.dependent.GarbageCollected; +import io.javaoperatorsdk.operator.glue.customresource.glue.Glue; +import io.javaoperatorsdk.operator.glue.customresource.glue.Matcher; +import io.javaoperatorsdk.operator.glue.templating.GenericTemplateHandler; + +public class GCGenericBulkDependentResource extends GenericBulkDependentResource + implements GarbageCollected { + + public GCGenericBulkDependentResource(GenericTemplateHandler genericTemplateHandler, + String desiredTemplate, String name, + boolean clusterScoped, Matcher matcher) { + super(genericTemplateHandler, desiredTemplate, name, clusterScoped, matcher); + } + +} diff --git a/src/main/java/io/javaoperatorsdk/operator/glue/dependent/GenericBulkDependentResource.java b/src/main/java/io/javaoperatorsdk/operator/glue/dependent/GenericBulkDependentResource.java new file mode 100644 index 0000000..b509eea --- /dev/null +++ b/src/main/java/io/javaoperatorsdk/operator/glue/dependent/GenericBulkDependentResource.java @@ -0,0 +1,52 @@ +package io.javaoperatorsdk.operator.glue.dependent; + +import java.util.Map; +import java.util.stream.Collectors; + +import io.fabric8.kubernetes.api.model.GenericKubernetesResource; +import io.fabric8.kubernetes.api.model.GenericKubernetesResourceList; +import io.fabric8.kubernetes.client.utils.Serialization; +import io.javaoperatorsdk.operator.api.reconciler.Context; +import io.javaoperatorsdk.operator.glue.customresource.glue.Glue; +import io.javaoperatorsdk.operator.glue.customresource.glue.Matcher; +import io.javaoperatorsdk.operator.glue.templating.GenericTemplateHandler; +import io.javaoperatorsdk.operator.processing.dependent.BulkDependentResource; + +import static io.javaoperatorsdk.operator.glue.reconciler.glue.GlueReconciler.DEPENDENT_NAME_ANNOTATION_KEY; + +public class GenericBulkDependentResource extends + GenericDependentResource implements + BulkDependentResource { + + public GenericBulkDependentResource(GenericTemplateHandler genericTemplateHandler, + String desiredTemplate, String name, + boolean clusterScoped, + Matcher matcher) { + super(genericTemplateHandler, desiredTemplate, name, clusterScoped, matcher); + } + + @Override + public Map desiredResources(Glue primary, + Context context) { + + var res = genericTemplateHandler.processTemplate(desiredTemplate, primary, context); + var desiredList = Serialization.unmarshal(res, GenericKubernetesResourceList.class).getItems(); + desiredList.forEach(r -> { + r.getMetadata().getAnnotations() + .put(DEPENDENT_NAME_ANNOTATION_KEY, name); + if (r.getMetadata().getNamespace() == null && !clusterScoped) { + r.getMetadata().setNamespace(primary.getMetadata().getNamespace()); + } + }); + return desiredList.stream().collect(Collectors.toMap(r -> r.getMetadata().getName(), r -> r)); + } + + @Override + public Map getSecondaryResources(Glue glue, + Context context) { + return context.getSecondaryResources(GenericKubernetesResource.class).stream() + .filter( + r -> name.equals(r.getMetadata().getAnnotations().get(DEPENDENT_NAME_ANNOTATION_KEY))) + .collect(Collectors.toMap(r -> r.getMetadata().getName(), r -> r)); + } +} diff --git a/src/main/java/io/javaoperatorsdk/operator/glue/dependent/GenericDependentResource.java b/src/main/java/io/javaoperatorsdk/operator/glue/dependent/GenericDependentResource.java index 679f52e..9a2b251 100644 --- a/src/main/java/io/javaoperatorsdk/operator/glue/dependent/GenericDependentResource.java +++ b/src/main/java/io/javaoperatorsdk/operator/glue/dependent/GenericDependentResource.java @@ -20,14 +20,13 @@ public class GenericDependentResource Updater, Creator { - private final GenericKubernetesResource desired; - private final String desiredTemplate; - private final String name; - private final boolean clusterScoped; - private final Matcher matcher; + protected final GenericKubernetesResource desired; + protected final String desiredTemplate; + protected final String name; + protected final boolean clusterScoped; + protected final Matcher matcher; - // optimize share between instances - private final GenericTemplateHandler genericTemplateHandler; + protected final GenericTemplateHandler genericTemplateHandler; public GenericDependentResource(GenericTemplateHandler genericTemplateHandler, GenericKubernetesResource desired, String name, diff --git a/src/main/java/io/javaoperatorsdk/operator/glue/reconciler/ValidationAndErrorHandler.java b/src/main/java/io/javaoperatorsdk/operator/glue/reconciler/ValidationAndErrorHandler.java index 87f6749..6210329 100644 --- a/src/main/java/io/javaoperatorsdk/operator/glue/reconciler/ValidationAndErrorHandler.java +++ b/src/main/java/io/javaoperatorsdk/operator/glue/reconciler/ValidationAndErrorHandler.java @@ -42,7 +42,20 @@ public class ValidationAndErrorHandler { } } - public void checkIfNamesAreUnique(GlueSpec glueSpec) { + public void checkIfValidGlueSpec(GlueSpec glueSpec) { + checkIfBulkProvidesResourceTemplate(glueSpec); + checkIfNamesAreUnique(glueSpec); + } + + private void checkIfBulkProvidesResourceTemplate(GlueSpec glueSpec) { + glueSpec.getChildResources().forEach(r -> { + if (Boolean.TRUE.equals(r.getBulk()) && r.getResourceTemplate() == null) { + throw new GlueException("Bulk resource requires a template to be set"); + } + }); + } + + void checkIfNamesAreUnique(GlueSpec glueSpec) { Set seen = new HashSet<>(); List duplicates = new ArrayList<>(); diff --git a/src/main/java/io/javaoperatorsdk/operator/glue/reconciler/glue/GlueReconciler.java b/src/main/java/io/javaoperatorsdk/operator/glue/reconciler/glue/GlueReconciler.java index 9a9571e..7113ca6 100644 --- a/src/main/java/io/javaoperatorsdk/operator/glue/reconciler/glue/GlueReconciler.java +++ b/src/main/java/io/javaoperatorsdk/operator/glue/reconciler/glue/GlueReconciler.java @@ -21,6 +21,7 @@ import io.javaoperatorsdk.operator.glue.customresource.glue.condition.ConditionSpec; import io.javaoperatorsdk.operator.glue.customresource.glue.condition.JavaScriptConditionSpec; import io.javaoperatorsdk.operator.glue.customresource.glue.condition.ReadyConditionSpec; +import io.javaoperatorsdk.operator.glue.dependent.GCGenericBulkDependentResource; import io.javaoperatorsdk.operator.glue.dependent.GCGenericDependentResource; import io.javaoperatorsdk.operator.glue.dependent.GenericDependentResource; import io.javaoperatorsdk.operator.glue.dependent.GenericResourceDiscriminator; @@ -78,7 +79,7 @@ public UpdateControl reconcile(Glue primary, log.debug("Reconciling glue. name: {} namespace: {}", primary.getMetadata().getName(), primary.getMetadata().getNamespace()); - validationAndErrorHandler.checkIfNamesAreUnique(primary.getSpec()); + validationAndErrorHandler.checkIfValidGlueSpec(primary.getSpec()); registerRelatedResourceInformers(context, primary); if (deletedGlueIfParentMarkedForDeletion(context, primary)) { @@ -209,9 +210,14 @@ private GenericDependentResource createDependentResource(DependentResourceSpec s if (leafDependent && resourceInSameNamespaceAsPrimary && !spec.isClusterScoped()) { return spec.getResourceTemplate() != null - ? new GCGenericDependentResource(genericTemplateHandler, spec.getResourceTemplate(), - spec.getName(), - spec.isClusterScoped(), spec.getMatcher()) + ? spec.getBulk() + ? new GCGenericBulkDependentResource(genericTemplateHandler, + spec.getResourceTemplate(), + spec.getName(), + spec.isClusterScoped(), spec.getMatcher()) + : new GCGenericDependentResource(genericTemplateHandler, spec.getResourceTemplate(), + spec.getName(), + spec.isClusterScoped(), spec.getMatcher()) : new GCGenericDependentResource(genericTemplateHandler, spec.getResource(), spec.getName(), spec.isClusterScoped(), spec.getMatcher()); diff --git a/src/main/java/io/javaoperatorsdk/operator/glue/reconciler/operator/GlueOperatorReconciler.java b/src/main/java/io/javaoperatorsdk/operator/glue/reconciler/operator/GlueOperatorReconciler.java index 6c18137..fb17073 100644 --- a/src/main/java/io/javaoperatorsdk/operator/glue/reconciler/operator/GlueOperatorReconciler.java +++ b/src/main/java/io/javaoperatorsdk/operator/glue/reconciler/operator/GlueOperatorReconciler.java @@ -75,7 +75,7 @@ public UpdateControl reconcile(GlueOperator glueOperator, log.info("Reconciling GlueOperator {} in namespace: {}", glueOperator.getMetadata().getName(), glueOperator.getMetadata().getNamespace()); - validationAndErrorHandler.checkIfNamesAreUnique(glueOperator.getSpec()); + validationAndErrorHandler.checkIfValidGlueSpec(glueOperator.getSpec()); var targetCREventSource = getOrRegisterCustomResourceEventSource(glueOperator, context); targetCREventSource.list().forEach(cr -> { From 4aba9009c5eee7bf23c4c19f3055f43462da111d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Attila=20M=C3=A9sz=C3=A1ros?= Date: Fri, 3 Jan 2025 19:11:11 +0100 Subject: [PATCH 2/4] bulks sample + fixes MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Attila Mészáros --- .../javaoperatorsdk/operator/glue/Utils.java | 8 +++- .../glue/reconciler/glue/GlueReconciler.java | 9 +++-- .../operator/glue/GlueTest.java | 25 ++++++++++++ .../operator/glue/TestBase.java | 5 +++ .../operator/glue/UtilsTest.java | 39 +++++++++++++++++++ src/test/resources/glue/SimpleBulk.yaml | 19 +++++++++ 6 files changed, 101 insertions(+), 4 deletions(-) create mode 100644 src/test/java/io/javaoperatorsdk/operator/glue/UtilsTest.java create mode 100644 src/test/resources/glue/SimpleBulk.yaml diff --git a/src/main/java/io/javaoperatorsdk/operator/glue/Utils.java b/src/main/java/io/javaoperatorsdk/operator/glue/Utils.java index d5af998..5311c49 100644 --- a/src/main/java/io/javaoperatorsdk/operator/glue/Utils.java +++ b/src/main/java/io/javaoperatorsdk/operator/glue/Utils.java @@ -146,7 +146,13 @@ private static Optional getOptionalPropertyValueFromTemplate(String reso String property) { var finalProp = property + ":"; var targetLine = resourceTemplate.lines().filter(l -> l.contains(finalProp)).findFirst(); - return targetLine.map(l -> l.replace(finalProp, "").trim()); + return targetLine.map(l -> { + int index = l.indexOf(finalProp); + if (index > 0) { + l = l.substring(index); + } + return l.replace(finalProp, "").trim(); + }); } private static String getPropertyValueFromTemplate(String resourceTemplate, String property) { diff --git a/src/main/java/io/javaoperatorsdk/operator/glue/reconciler/glue/GlueReconciler.java b/src/main/java/io/javaoperatorsdk/operator/glue/reconciler/glue/GlueReconciler.java index 7113ca6..34b72d8 100644 --- a/src/main/java/io/javaoperatorsdk/operator/glue/reconciler/glue/GlueReconciler.java +++ b/src/main/java/io/javaoperatorsdk/operator/glue/reconciler/glue/GlueReconciler.java @@ -28,6 +28,7 @@ import io.javaoperatorsdk.operator.glue.reconciler.ValidationAndErrorHandler; import io.javaoperatorsdk.operator.glue.reconciler.operator.GlueOperatorReconciler; import io.javaoperatorsdk.operator.glue.templating.GenericTemplateHandler; +import io.javaoperatorsdk.operator.processing.dependent.BulkDependentResource; import io.javaoperatorsdk.operator.processing.dependent.workflow.Condition; import io.javaoperatorsdk.operator.processing.dependent.workflow.KubernetesResourceDeletedCondition; import io.javaoperatorsdk.operator.processing.dependent.workflow.WorkflowBuilder; @@ -184,9 +185,11 @@ private void createAndAddDependentToWorkflow(Glue primary, Context context var dr = createDependentResource(spec, leafDependent, resourceInSameNamespaceAsPrimary); var gvk = dr.getGroupVersionKind(); - dr.setResourceDiscriminator(new GenericResourceDiscriminator(dr.getGroupVersionKind(), - genericTemplateHandler.processTemplate(Utils.getName(spec), primary, context), - targetNamespace.orElse(null))); + if (!(dr instanceof BulkDependentResource)) { + dr.setResourceDiscriminator(new GenericResourceDiscriminator(dr.getGroupVersionKind(), + genericTemplateHandler.processTemplate(Utils.getName(spec), primary, context), + targetNamespace.orElse(null))); + } var es = informerRegister.registerInformer(context, gvk, primary); dr.configureWith(es); diff --git a/src/test/java/io/javaoperatorsdk/operator/glue/GlueTest.java b/src/test/java/io/javaoperatorsdk/operator/glue/GlueTest.java index 4ca0f66..4d98055 100644 --- a/src/test/java/io/javaoperatorsdk/operator/glue/GlueTest.java +++ b/src/test/java/io/javaoperatorsdk/operator/glue/GlueTest.java @@ -368,6 +368,31 @@ void customizeMatcher() { }); } + @Test + void simpleBulk() { + var glue = createGlue("/glue/" + "SimpleBulk.yaml"); + + await().untilAsserted(() -> { + var configMaps = getRelatedConfigMaps(glue.getMetadata().getName()); + assertThat(configMaps).hasSize(3); + assertThat(configMaps) + .allMatch(cm -> cm.getMetadata().getName().startsWith("simple-glue-configmap-")); + }); + + delete(glue); + + await().untilAsserted( + () -> assertThat(getRelatedConfigMaps(glue.getMetadata().getName())).isEmpty()); + } + + List getRelatedConfigMaps(String ownerName) { + return list(ConfigMap.class).stream() + .filter(cm -> !cm.getMetadata().getOwnerReferences().isEmpty() + && cm.getMetadata().getOwnerReferences() + .get(0).getName().equals(ownerName)) + .toList(); + } + private List testWorkflowList(int num) { List res = new ArrayList<>(); IntStream.range(0, num).forEach(index -> { diff --git a/src/test/java/io/javaoperatorsdk/operator/glue/TestBase.java b/src/test/java/io/javaoperatorsdk/operator/glue/TestBase.java index 06b02de..c914687 100644 --- a/src/test/java/io/javaoperatorsdk/operator/glue/TestBase.java +++ b/src/test/java/io/javaoperatorsdk/operator/glue/TestBase.java @@ -1,6 +1,7 @@ package io.javaoperatorsdk.operator.glue; import java.time.Duration; +import java.util.List; import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.BeforeEach; @@ -70,6 +71,10 @@ protected T get(Class clazz, String name) { return client.resources(clazz).inNamespace(testNamespace).withName(name).get(); } + protected List list(Class clazz) { + return client.resources(clazz).inNamespace(testNamespace).list().getItems(); + } + protected T update(T resource) { resource.getMetadata().setResourceVersion(null); return client.resource(resource).inNamespace(testNamespace).update(); diff --git a/src/test/java/io/javaoperatorsdk/operator/glue/UtilsTest.java b/src/test/java/io/javaoperatorsdk/operator/glue/UtilsTest.java new file mode 100644 index 0000000..f789f3c --- /dev/null +++ b/src/test/java/io/javaoperatorsdk/operator/glue/UtilsTest.java @@ -0,0 +1,39 @@ +package io.javaoperatorsdk.operator.glue; + +import org.junit.jupiter.api.Test; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.junit.jupiter.api.Assertions.*; + +class UtilsTest { + + + @Test + void getAPIVersionFromListResource() { + String apiVersion = Utils.getApiVersionFromTemplate(""" + - apiVersion: v1 + kind: ConfigMap + metadata: + name: simple-glue-configmap-{i} + data: + key: "value1" + """); + + assertThat(apiVersion).isEqualTo("v1"); + } + + @Test + void getAPIVersionPFromResource() { + String apiVersion = Utils.getApiVersionFromTemplate(""" + apiVersion: v1 + kind: ConfigMap + metadata: + name: simple-glue-configmap-{i} + data: + key: "value1" + """); + + assertThat(apiVersion).isEqualTo("v1"); + } + +} diff --git a/src/test/resources/glue/SimpleBulk.yaml b/src/test/resources/glue/SimpleBulk.yaml new file mode 100644 index 0000000..d8eeb39 --- /dev/null +++ b/src/test/resources/glue/SimpleBulk.yaml @@ -0,0 +1,19 @@ +# Invalid GLUE, presents resources with non-unique name +apiVersion: io.javaoperatorsdk.operator.glue/v1beta1 +kind: Glue +metadata: + name: simple-glue +spec: + childResources: + - name: configMaps + bulk: true + resourceTemplate: | + items: + {#for i in 3} + - apiVersion: v1 + kind: ConfigMap + metadata: + name: simple-glue-configmap-{i} + data: + key: "value1" + {/for} From 566c503e5234340a5ef3c1afd6319390c1d40053 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Attila=20M=C3=A9sz=C3=A1ros?= Date: Fri, 3 Jan 2025 20:16:16 +0100 Subject: [PATCH 3/4] operator test MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Attila Mészáros --- .../operator/glue/GlueOperatorTest.java | 35 +++++++++++++++++++ .../operator/glue/GlueTest.java | 12 ++----- .../operator/glue/TestBase.java | 8 +++++ .../TestCustomResourceSpec.java | 11 ++++++ .../resources/glueoperator/BulkOperator.yaml | 21 +++++++++++ 5 files changed, 78 insertions(+), 9 deletions(-) create mode 100644 src/test/resources/glueoperator/BulkOperator.yaml diff --git a/src/test/java/io/javaoperatorsdk/operator/glue/GlueOperatorTest.java b/src/test/java/io/javaoperatorsdk/operator/glue/GlueOperatorTest.java index 9ae7409..7806b9c 100644 --- a/src/test/java/io/javaoperatorsdk/operator/glue/GlueOperatorTest.java +++ b/src/test/java/io/javaoperatorsdk/operator/glue/GlueOperatorTest.java @@ -4,6 +4,7 @@ import java.util.ArrayList; import java.util.stream.IntStream; +import io.javaoperatorsdk.operator.glue.reconciler.operator.GlueOperatorReconciler; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; @@ -229,6 +230,40 @@ void secretCopySample() { }); } + @Test + void operatorWithBulkResource() { + var go = create(TestUtils + .loadGlueOperator("/glueoperator/BulkOperator.yaml")); + + var cr = testCustomResource(); + cr.getSpec().setReplicas(2); + var createdCR = create(cr); + assertConfigMapsCreated(cr, 2); + + createdCR.getSpec().setReplicas(3); + createdCR = update(createdCR); + assertConfigMapsCreated(cr, 3); + + createdCR.getSpec().setReplicas(1); + createdCR = update(createdCR); + assertConfigMapsCreated(cr, 1); + + delete(createdCR); + assertConfigMapsCreated(cr, 0); + await().untilAsserted(()->{ + var actualCR = get(TestCustomResource.class,cr.getMetadata().getName()); + assertThat(actualCR).isNull(); + }); + + delete(go); + } + + private void assertConfigMapsCreated(TestCustomResource cr, int expected) { + await().untilAsserted(() -> { + var configMaps = getRelatedList(ConfigMap.class, GlueOperatorReconciler.glueName(cr.getMetadata().getName(),cr.getKind())); + assertThat(configMaps).hasSize(expected); + }); + } GlueOperator testWorkflowOperator() { var wo = new GlueOperator(); diff --git a/src/test/java/io/javaoperatorsdk/operator/glue/GlueTest.java b/src/test/java/io/javaoperatorsdk/operator/glue/GlueTest.java index 4d98055..cfe62b2 100644 --- a/src/test/java/io/javaoperatorsdk/operator/glue/GlueTest.java +++ b/src/test/java/io/javaoperatorsdk/operator/glue/GlueTest.java @@ -373,7 +373,7 @@ void simpleBulk() { var glue = createGlue("/glue/" + "SimpleBulk.yaml"); await().untilAsserted(() -> { - var configMaps = getRelatedConfigMaps(glue.getMetadata().getName()); + var configMaps = getRelatedList(ConfigMap.class, glue.getMetadata().getName()); assertThat(configMaps).hasSize(3); assertThat(configMaps) .allMatch(cm -> cm.getMetadata().getName().startsWith("simple-glue-configmap-")); @@ -382,16 +382,10 @@ void simpleBulk() { delete(glue); await().untilAsserted( - () -> assertThat(getRelatedConfigMaps(glue.getMetadata().getName())).isEmpty()); + () -> assertThat(getRelatedList(ConfigMap.class, glue.getMetadata().getName()).isEmpty())); } - List getRelatedConfigMaps(String ownerName) { - return list(ConfigMap.class).stream() - .filter(cm -> !cm.getMetadata().getOwnerReferences().isEmpty() - && cm.getMetadata().getOwnerReferences() - .get(0).getName().equals(ownerName)) - .toList(); - } + private List testWorkflowList(int num) { List res = new ArrayList<>(); diff --git a/src/test/java/io/javaoperatorsdk/operator/glue/TestBase.java b/src/test/java/io/javaoperatorsdk/operator/glue/TestBase.java index c914687..67228e8 100644 --- a/src/test/java/io/javaoperatorsdk/operator/glue/TestBase.java +++ b/src/test/java/io/javaoperatorsdk/operator/glue/TestBase.java @@ -75,6 +75,14 @@ protected List list(Class clazz) { return client.resources(clazz).inNamespace(testNamespace).list().getItems(); } + protected List getRelatedList(Class clazz, String ownerName) { + return list(clazz).stream() + .filter(cm -> !cm.getMetadata().getOwnerReferences().isEmpty() + && cm.getMetadata().getOwnerReferences() + .get(0).getName().equals(ownerName)) + .toList(); + } + protected T update(T resource) { resource.getMetadata().setResourceVersion(null); return client.resource(resource).inNamespace(testNamespace).update(); diff --git a/src/test/java/io/javaoperatorsdk/operator/glue/customresource/TestCustomResourceSpec.java b/src/test/java/io/javaoperatorsdk/operator/glue/customresource/TestCustomResourceSpec.java index 40c8768..c6de425 100644 --- a/src/test/java/io/javaoperatorsdk/operator/glue/customresource/TestCustomResourceSpec.java +++ b/src/test/java/io/javaoperatorsdk/operator/glue/customresource/TestCustomResourceSpec.java @@ -6,6 +6,8 @@ public class TestCustomResourceSpec { private String value; + private Integer replicas; + private List listValues; public String getValue() { @@ -25,4 +27,13 @@ public TestCustomResourceSpec setListValues(List listValues) { this.listValues = listValues; return this; } + + + public Integer getReplicas() { + return replicas; + } + + public void setReplicas(Integer replicas) { + this.replicas = replicas; + } } diff --git a/src/test/resources/glueoperator/BulkOperator.yaml b/src/test/resources/glueoperator/BulkOperator.yaml new file mode 100644 index 0000000..559f8e8 --- /dev/null +++ b/src/test/resources/glueoperator/BulkOperator.yaml @@ -0,0 +1,21 @@ +apiVersion: io.javaoperatorsdk.operator.glue/v1beta1 +kind: GlueOperator +metadata: + name: templating-sample +spec: + parent: + apiVersion: io.javaoperatorsdk.operator.glue/v1 + kind: TestCustomResource + childResources: + - name: configMap1 + bulk: true + resourceTemplate: | + items: + {#for i in parent.spec.replicas} + - apiVersion: v1 + kind: ConfigMap + metadata: + name: {parent.metadata.name}-{i} + data: + key: "value{i}" + {/for} \ No newline at end of file From cc733d83b397550795d455a7e0f75f1d8cb5048c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Attila=20M=C3=A9sz=C3=A1ros?= Date: Fri, 3 Jan 2025 20:27:01 +0100 Subject: [PATCH 4/4] format MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Attila Mészáros --- .../javaoperatorsdk/operator/glue/GlueOperatorTest.java | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/src/test/java/io/javaoperatorsdk/operator/glue/GlueOperatorTest.java b/src/test/java/io/javaoperatorsdk/operator/glue/GlueOperatorTest.java index 7806b9c..e1febf8 100644 --- a/src/test/java/io/javaoperatorsdk/operator/glue/GlueOperatorTest.java +++ b/src/test/java/io/javaoperatorsdk/operator/glue/GlueOperatorTest.java @@ -4,7 +4,6 @@ import java.util.ArrayList; import java.util.stream.IntStream; -import io.javaoperatorsdk.operator.glue.reconciler.operator.GlueOperatorReconciler; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; @@ -20,6 +19,7 @@ import io.javaoperatorsdk.operator.glue.customresource.operator.GlueOperatorSpec; import io.javaoperatorsdk.operator.glue.customresource.operator.Parent; import io.javaoperatorsdk.operator.glue.reconciler.ValidationAndErrorHandler; +import io.javaoperatorsdk.operator.glue.reconciler.operator.GlueOperatorReconciler; import io.quarkus.test.junit.QuarkusTest; import static io.javaoperatorsdk.operator.glue.TestData.*; @@ -250,8 +250,8 @@ void operatorWithBulkResource() { delete(createdCR); assertConfigMapsCreated(cr, 0); - await().untilAsserted(()->{ - var actualCR = get(TestCustomResource.class,cr.getMetadata().getName()); + await().untilAsserted(() -> { + var actualCR = get(TestCustomResource.class, cr.getMetadata().getName()); assertThat(actualCR).isNull(); }); @@ -260,7 +260,8 @@ void operatorWithBulkResource() { private void assertConfigMapsCreated(TestCustomResource cr, int expected) { await().untilAsserted(() -> { - var configMaps = getRelatedList(ConfigMap.class, GlueOperatorReconciler.glueName(cr.getMetadata().getName(),cr.getKind())); + var configMaps = getRelatedList(ConfigMap.class, + GlueOperatorReconciler.glueName(cr.getMetadata().getName(), cr.getKind())); assertThat(configMaps).hasSize(expected); }); }