From 1f9d3834cb62d37876e0ce207680cf15b3fcb0ea Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Attila=20M=C3=A9sz=C3=A1ros?= Date: Sun, 5 Jan 2025 20:15:42 +0100 Subject: [PATCH] improve: double brackets to handle non string values in object templates MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Attila Mészáros --- README.md | 4 +-- docs/reference.md | 27 +++++++++++++++++-- .../templating/GenericTemplateHandler.java | 2 +- .../GenericTemplateHandlerTest.java | 26 +++++++++++++++++- .../sample/webpage/webpage.operator.yaml | 4 +-- 5 files changed, 55 insertions(+), 8 deletions(-) diff --git a/README.md b/README.md index 8f4f770..9e83b9f 100644 --- a/README.md +++ b/README.md @@ -67,8 +67,8 @@ spec: parent: apiVersion: glueoperator.sample/v1 # watches all the custom resource of type WebPage kind: WebPage - statusTemplate: | # update the status of the custom resource at the end of reconciliation - observedGeneration: {parent.metadata.generation} + status: # update the status of the custom resource at the end of reconciliation + observedGeneration: "{{parent.metadata.generation}}" # since it's a non-string value needs double curly brackets childResources: - name: htmlconfigmap resource: diff --git a/docs/reference.md b/docs/reference.md index 0c9101b..19b7c80 100644 --- a/docs/reference.md +++ b/docs/reference.md @@ -8,8 +8,31 @@ Although it is limited only to Kubernetes resources it makes it very easy to use ## Generic Notes -- All templates (both object and string based) uses [Qute templating engine](https://quarkus.io/guides/qute-reference). While objects allow only - placeholders, you can use the full power of qute in string templates. + - All templates (both object and string-based) uses [Qute templating engine](https://quarkus.io/guides/qute-reference). While objects allow only + placeholders, you can use the full power of qute in string templates. + + ONLY for object-based templates (thus not string templates) the values can be set using the placeholder notation from Qute: + ```yaml + value: "{string.value.reference}" + ``` + With this standard notation, the result value will be always encoded in double quotes: + ```yaml + value: "1" + ``` + Since there is no simple way to check if the referenced value is a string or other value + (boolean, numeric, etc) for non-string values, user should use double brackets: + ```yaml + value: "{{nonstring.value.reference}}" + ``` + what would result in a value without enclosed double quotes in the produced yaml: + ```yaml + value: 1 + ``` + See sample [here](https://github.com/java-operator-sdk/kubernetes-glue-operator/blob/main/src/test/resources/sample/webpage/webpage.operator.yaml#L10). + Implementation wise, this is a preprocessor that strips the enclosed quotes and additional curly bracket + before it is passed to Qute. + In the future, we might remove such obligation by checking the type + of the target value in the related schema. ## [Glue resource](https://github.com/java-operator-sdk/kubernetes-glue-operator/releases/latest/download/glues.glue-v1.yml) diff --git a/src/main/java/io/javaoperatorsdk/operator/glue/templating/GenericTemplateHandler.java b/src/main/java/io/javaoperatorsdk/operator/glue/templating/GenericTemplateHandler.java index 765d435..babe5ed 100644 --- a/src/main/java/io/javaoperatorsdk/operator/glue/templating/GenericTemplateHandler.java +++ b/src/main/java/io/javaoperatorsdk/operator/glue/templating/GenericTemplateHandler.java @@ -34,7 +34,7 @@ public String processTemplate(Map> data, String template, private String handleDoubleCurlyBrackets(String template) { template = template.replace("\"{{", "{"); - return template.replace("}}\n", "}"); + return template.replace("}}\"", "}"); } public String processInputAndTemplate(Map data, diff --git a/src/test/java/io/javaoperatorsdk/operator/glue/templating/GenericTemplateHandlerTest.java b/src/test/java/io/javaoperatorsdk/operator/glue/templating/GenericTemplateHandlerTest.java index a3c1617..73422c3 100644 --- a/src/test/java/io/javaoperatorsdk/operator/glue/templating/GenericTemplateHandlerTest.java +++ b/src/test/java/io/javaoperatorsdk/operator/glue/templating/GenericTemplateHandlerTest.java @@ -1,14 +1,38 @@ package io.javaoperatorsdk.operator.glue.templating; +import java.util.HashMap; +import java.util.Map; + import org.junit.jupiter.api.Test; +import io.fabric8.kubernetes.client.utils.Serialization; + import static org.junit.jupiter.api.Assertions.*; class GenericTemplateHandlerTest { + GenericTemplateHandler templateHandler = new GenericTemplateHandler(); + @Test void testDoubleCurlyBrackets() { - fail(); + var template = """ + intValue: "{{spec.intvalue}}" + stringValue: "{spec.stringvalue}" + """; + + Map> data = new HashMap<>(); + + Map values = new HashMap(); + values.put("intvalue", 1); + values.put("stringvalue", "value1"); + data.put("spec", values); + + var result = templateHandler.processTemplate(data, template, true); + + Map mapResult = Serialization.unmarshal(result, Map.class); + + assertEquals(1, mapResult.get("intValue")); + assertEquals("value1", mapResult.get("stringValue")); } } diff --git a/src/test/resources/sample/webpage/webpage.operator.yaml b/src/test/resources/sample/webpage/webpage.operator.yaml index 53606fe..5ae8fe8 100644 --- a/src/test/resources/sample/webpage/webpage.operator.yaml +++ b/src/test/resources/sample/webpage/webpage.operator.yaml @@ -6,8 +6,8 @@ spec: parent: apiVersion: glueoperator.sample/v1 kind: WebPage - statusTemplate: | - observedGeneration: {parent.metadata.generation} + status: + observedGeneration: "{{parent.metadata.generation}}" childResources: - name: htmlconfigmap resource: