From 26628bf766b14d66f683a4608b97b7538ca582d6 Mon Sep 17 00:00:00 2001 From: "Singal, Kapil (ks220y)" Date: Mon, 8 May 2023 09:10:58 -0400 Subject: [PATCH] Enhancing BluePrintJinjaTemplateService * Using CustomJinjavaInterpreter to override getAsString API, and returning context.currentNode.master.image instead of empty string * Earlier rendered result was not keeping unresolved variable rather replacing with empty string, and above helps keeping those. * Upgrading jinja.version to 2.7.0 from 2.5.1 and adding related Junit Test Issue-ID: CCSDK-3895 Signed-off-by: Singal, Kapil (ks220y) Change-Id: I00da64811883957f44f819a44405e073ed7a7755 --- .../Tests/kotlin/default-variable-value-data.txt | 4 +- .../core/service/BluePrintJinjaTemplateService.kt | 49 ++++++++++++++++------ .../core/service/BluePrintTemplateServiceTest.kt | 24 ++++++++--- .../default-variable-jinja-template-resolved.jinja | 6 +++ .../default-variable-jinja-template.jinja | 6 +++ .../templates/default-variable-value-data.json | 3 +- ms/blueprintsprocessor/parent/pom.xml | 4 +- 7 files changed, 72 insertions(+), 24 deletions(-) create mode 100644 ms/blueprintsprocessor/modules/blueprints/blueprint-core/src/test/resources/templates/default-variable-jinja-template-resolved.jinja create mode 100644 ms/blueprintsprocessor/modules/blueprints/blueprint-core/src/test/resources/templates/default-variable-jinja-template.jinja diff --git a/components/model-catalog/blueprint-model/archetype-blueprint/src/main/resources/archetype-resources/Tests/kotlin/default-variable-value-data.txt b/components/model-catalog/blueprint-model/archetype-blueprint/src/main/resources/archetype-resources/Tests/kotlin/default-variable-value-data.txt index f2359e863..c16bedb0b 100644 --- a/components/model-catalog/blueprint-model/archetype-blueprint/src/main/resources/archetype-resources/Tests/kotlin/default-variable-value-data.txt +++ b/components/model-catalog/blueprint-model/archetype-blueprint/src/main/resources/archetype-resources/Tests/kotlin/default-variable-value-data.txt @@ -1,2 +1,2 @@ -sample-hostname -${node0_backup_router_address} \ No newline at end of file +sample-node0_hostname +${node0_backup_router_address} diff --git a/ms/blueprintsprocessor/modules/blueprints/blueprint-core/src/main/kotlin/org/onap/ccsdk/cds/controllerblueprints/core/service/BluePrintJinjaTemplateService.kt b/ms/blueprintsprocessor/modules/blueprints/blueprint-core/src/main/kotlin/org/onap/ccsdk/cds/controllerblueprints/core/service/BluePrintJinjaTemplateService.kt index fdc348bf7..d3a7f0fe0 100644 --- a/ms/blueprintsprocessor/modules/blueprints/blueprint-core/src/main/kotlin/org/onap/ccsdk/cds/controllerblueprints/core/service/BluePrintJinjaTemplateService.kt +++ b/ms/blueprintsprocessor/modules/blueprints/blueprint-core/src/main/kotlin/org/onap/ccsdk/cds/controllerblueprints/core/service/BluePrintJinjaTemplateService.kt @@ -21,9 +21,12 @@ import com.fasterxml.jackson.databind.JsonNode import com.fasterxml.jackson.databind.ObjectMapper import com.hubspot.jinjava.Jinjava import com.hubspot.jinjava.JinjavaConfig +import com.hubspot.jinjava.interpret.Context +import com.hubspot.jinjava.interpret.InterpreterFactory import com.hubspot.jinjava.interpret.JinjavaInterpreter import com.hubspot.jinjava.loader.ResourceLocator import com.hubspot.jinjava.loader.ResourceNotFoundException +import com.hubspot.jinjava.objects.serialization.PyishObjectMapper import org.onap.ccsdk.cds.controllerblueprints.core.BluePrintProcessorException import org.onap.ccsdk.cds.controllerblueprints.core.config.BluePrintLoadConfiguration import org.onap.ccsdk.cds.controllerblueprints.core.interfaces.BluePrintJsonNodeFactory @@ -33,6 +36,7 @@ import java.io.IOException import java.nio.charset.Charset import java.nio.file.Files.readAllBytes import java.nio.file.Paths +import java.util.Objects object BluePrintJinjaTemplateService { @@ -89,27 +93,46 @@ object BluePrintJinjaTemplateService { additionalContext: MutableMap, resourceLocator: ResourceLocator? = null ): String { - val jinJava = Jinjava(JinjavaConfig()) - if (resourceLocator != null) { - jinJava.resourceLocator = resourceLocator - } - - val mapper = ObjectMapper() - val nodeFactory = BluePrintJsonNodeFactory() - mapper.nodeFactory = nodeFactory - // Add the JSON Data to the context if (json.isNotEmpty()) { - val jsonNode = mapper.readValue(json, JsonNode::class.java) + val mapper = ObjectMapper().setNodeFactory(BluePrintJsonNodeFactory()) + val jsonNode = mapper.readValue(json, JsonNode::class.java) ?: throw BluePrintProcessorException("couldn't get json node from json") if (ignoreJsonNull) { jsonNode.removeNullNode() } + additionalContext.putAll(mapper.readValue(json, object : TypeReference>() {})) + } + + val jinjava = Jinjava( + JinjavaConfig(object : InterpreterFactory { + override fun newInstance(interpreter: JinjavaInterpreter): JinjavaInterpreter { + return CustomJinjavaInterpreter(interpreter) + } - val jsonMap: Map = mapper.readValue(json, object : TypeReference>() {}) - additionalContext.putAll(jsonMap) + override fun newInstance(jinjava: Jinjava, context: Context, config: JinjavaConfig): JinjavaInterpreter { + return CustomJinjavaInterpreter(jinjava, context, config) + } + }) + ) + + if (resourceLocator != null) { + jinjava.resourceLocator = resourceLocator } - return jinJava.render(template, additionalContext) + return jinjava.render(template, additionalContext) + } + + class CustomJinjavaInterpreter : JinjavaInterpreter { + constructor(interpreter: JinjavaInterpreter) : super(interpreter) + constructor(jinjava: Jinjava, context: Context, config: JinjavaConfig) : super(jinjava, context, config) + + // Overriding actual getAsString method to return `context.currentNode.master.image` instead of empty string + override fun getAsString(`object`: Any?): String { + return if (config.legacyOverrides.isUsePyishObjectMapper) + PyishObjectMapper.getAsUnquotedPyishString(`object`) + else + Objects.toString(`object`, context.currentNode.master.image) + } } } diff --git a/ms/blueprintsprocessor/modules/blueprints/blueprint-core/src/test/kotlin/org/onap/ccsdk/cds/controllerblueprints/core/service/BluePrintTemplateServiceTest.kt b/ms/blueprintsprocessor/modules/blueprints/blueprint-core/src/test/kotlin/org/onap/ccsdk/cds/controllerblueprints/core/service/BluePrintTemplateServiceTest.kt index 0e93ccf6b..87591e1c9 100644 --- a/ms/blueprintsprocessor/modules/blueprints/blueprint-core/src/test/kotlin/org/onap/ccsdk/cds/controllerblueprints/core/service/BluePrintTemplateServiceTest.kt +++ b/ms/blueprintsprocessor/modules/blueprints/blueprint-core/src/test/kotlin/org/onap/ccsdk/cds/controllerblueprints/core/service/BluePrintTemplateServiceTest.kt @@ -61,22 +61,36 @@ class BluePrintTemplateServiceTest { ) val content = BluePrintJinjaTemplateService.generateContent(template, json, false, element) - assertNotNull(content, "failed to generate content for velocity template") + assertNotNull(content, "failed to generate content for jinja template") } } @Test - fun `no value variable should evaluate to default value - standalone template mesh test`() { + fun `Unresolved variable should be kept as-is - standalone velocity template mesh test`() { runBlocking { val template = JacksonUtils.getClassPathFileContent("templates/default-variable-value-velocity-template.vtl") val json = JacksonUtils.getClassPathFileContent("templates/default-variable-value-data.json") val content = BluePrintVelocityTemplateService.generateContent(template, json) - // first line represents a variable whose value was successfully retrieved, second line contains a variable - // whose value could not be evaluated - val expected = "sample-hostname\n\${node0_backup_router_address}" + // first line represents a variable whose value was successfully retrieved, + // second line contains a variable whose value could not be evaluated + val expected = "sample-node0_hostname\n\${node0_backup_router_address}" assertEquals(expected, content, "No value variable should use default value") } } + + @Test + fun `Unresolved variable should be kept as-is - standalone jinja template mesh test`() { + runBlocking { + val context = JacksonUtils.getClassPathFileContent("templates/default-variable-value-data.json") + val jinjaTemplate = + JacksonUtils.getClassPathFileContent("templates/default-variable-jinja-template.jinja") + val renderedContent = + BluePrintJinjaTemplateService.generateContent(jinjaTemplate, context, false, mutableMapOf()) + val expectedContent = + JacksonUtils.getClassPathFileContent("templates/default-variable-jinja-template-resolved.jinja") + assertEquals(expectedContent, renderedContent, "No value variable should use default value") + } + } } diff --git a/ms/blueprintsprocessor/modules/blueprints/blueprint-core/src/test/resources/templates/default-variable-jinja-template-resolved.jinja b/ms/blueprintsprocessor/modules/blueprints/blueprint-core/src/test/resources/templates/default-variable-jinja-template-resolved.jinja new file mode 100644 index 000000000..b9617d677 --- /dev/null +++ b/ms/blueprintsprocessor/modules/blueprints/blueprint-core/src/test/resources/templates/default-variable-jinja-template-resolved.jinja @@ -0,0 +1,6 @@ +sample-node0_hostname +{{ node1_hostname }} +This will be kept as-is {{ node0_backup_router_address }} +sample-node0_hostname +Even this one {{ node1_backup_router_address }} as it doesn't matter if variable is surrounded by text +sample-node2_backup_router_address {{ node1_backup_router_address }} Even this One if multiple variable in same line diff --git a/ms/blueprintsprocessor/modules/blueprints/blueprint-core/src/test/resources/templates/default-variable-jinja-template.jinja b/ms/blueprintsprocessor/modules/blueprints/blueprint-core/src/test/resources/templates/default-variable-jinja-template.jinja new file mode 100644 index 000000000..5d483e383 --- /dev/null +++ b/ms/blueprintsprocessor/modules/blueprints/blueprint-core/src/test/resources/templates/default-variable-jinja-template.jinja @@ -0,0 +1,6 @@ +{{ node0_hostname }} +{{ node1_hostname }} +This will be kept as-is {{ node0_backup_router_address }} +{{ node0_hostname }} +Even this one {{ node1_backup_router_address }} as it doesn't matter if variable is surrounded by text +{{ node2_backup_router_address }} {{ node1_backup_router_address }} Even this One if multiple variable in same line diff --git a/ms/blueprintsprocessor/modules/blueprints/blueprint-core/src/test/resources/templates/default-variable-value-data.json b/ms/blueprintsprocessor/modules/blueprints/blueprint-core/src/test/resources/templates/default-variable-value-data.json index 940ca8d73..e3bc35525 100755 --- a/ms/blueprintsprocessor/modules/blueprints/blueprint-core/src/test/resources/templates/default-variable-value-data.json +++ b/ms/blueprintsprocessor/modules/blueprints/blueprint-core/src/test/resources/templates/default-variable-value-data.json @@ -1,3 +1,4 @@ { - "node0_hostname": "sample-hostname" + "node0_hostname": "sample-node0_hostname", + "node2_backup_router_address": "sample-node2_backup_router_address" } diff --git a/ms/blueprintsprocessor/parent/pom.xml b/ms/blueprintsprocessor/parent/pom.xml index 3de8e9be5..7db6003bd 100755 --- a/ms/blueprintsprocessor/parent/pom.xml +++ b/ms/blueprintsprocessor/parent/pom.xml @@ -44,13 +44,11 @@ 2.8.0 2.6.3 - - 2.2.0 0.1.55 0.1.8 2.7.2 - 2.5.1 + 2.7.0 27.0.1-jre 1.9 2.4.6 -- 2.16.6