Add Jinja2 custom ResourceLocator 32/90132/8
authorAlexis de Talhouët <adetalhouet89@gmail.com>
Tue, 18 Jun 2019 23:43:50 +0000 (19:43 -0400)
committerAlexis de Talhouët <adetalhouet89@gmail.com>
Fri, 21 Jun 2019 01:10:53 +0000 (01:10 +0000)
This will allow to include template within template to create
template hierarchy

Change-Id: I21c5deaf51d391e1a51b9863a905c26b1891db16
Issue-ID: CCSDK-1417
Signed-off-by: Alexis de Talhouët <adetalhouet89@gmail.com>
12 files changed:
ms/blueprintsprocessor/functions/cli-executor/src/main/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/functions/cli/executor/CliComponentFunction.kt
ms/blueprintsprocessor/functions/cli-executor/src/main/kotlin/scripts/InternalSimpleCli.cba.kts
ms/blueprintsprocessor/functions/resource-resolution/src/main/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/functions/resource/resolution/ResourceResolutionService.kt
ms/controllerblueprints/modules/blueprint-core/src/main/kotlin/org/onap/ccsdk/cds/controllerblueprints/core/interfaces/BlueprintTemplateService.kt
ms/controllerblueprints/modules/blueprint-core/src/main/kotlin/org/onap/ccsdk/cds/controllerblueprints/core/service/BluePrintJinjaTemplateService.kt
ms/controllerblueprints/modules/blueprint-core/src/main/kotlin/org/onap/ccsdk/cds/controllerblueprints/core/service/BlueprintTemplateService.kt
ms/controllerblueprints/modules/blueprint-core/src/test/kotlin/org/onap/ccsdk/cds/controllerblueprints/core/service/BluePrintTemplateServiceTest.kt
ms/controllerblueprints/modules/blueprint-core/src/test/resources/templates/base-config-data-jinja.json
ms/controllerblueprints/modules/blueprint-core/src/test/resources/templates/base-config-jinja-template.jinja [deleted file]
ms/controllerblueprints/modules/blueprint-core/src/test/resources/templates/interface.jinja [new file with mode: 0755]
ms/controllerblueprints/modules/blueprint-core/src/test/resources/templates/isis.jinja [new file with mode: 0644]
ms/controllerblueprints/modules/blueprint-core/src/test/resources/templates/master.jinja [new file with mode: 0644]

index c7f35f7..1b84964 100644 (file)
@@ -41,12 +41,6 @@ abstract class CliComponentFunction : AbstractScriptComponentFunction() {
         return file.readNBLines()
     }
 
-    suspend fun generateMessage(artifactName: String, json: String): String {
-        val templateService = BluePrintTemplateService()
-        return templateService.generateContent(bluePrintRuntimeService, nodeTemplateName, artifactName, json, true)
-    }
-
-
     fun generateMessage(artifactName: String): String {
         return bluePrintRuntimeService.resolveNodeTemplateArtifact(nodeTemplateName, artifactName)
     }
index 18d4a47..0955ace 100644 (file)
@@ -20,6 +20,7 @@ import org.onap.ccsdk.cds.blueprintsprocessor.core.api.data.ExecutionServiceInpu
 import org.onap.ccsdk.cds.blueprintsprocessor.functions.cli.executor.CliComponentFunction
 import org.onap.ccsdk.cds.blueprintsprocessor.functions.cli.executor.ComponentCliExecutor
 import org.onap.ccsdk.cds.controllerblueprints.core.asJsonPrimitive
+import org.onap.ccsdk.cds.controllerblueprints.core.service.BluePrintTemplateService
 import org.slf4j.LoggerFactory
 
 open class TestCliScriptFunction : CliComponentFunction() {
index ebff478..fe59062 100644 (file)
@@ -59,7 +59,8 @@ interface ResourceResolutionService {
 
 @Service(ResourceResolutionConstants.SERVICE_RESOURCE_RESOLUTION)
 open class ResourceResolutionServiceImpl(private var applicationContext: ApplicationContext,
-                                         private var resolutionResultService: ResourceResolutionResultService) :
+                                         private var resolutionResultService: ResourceResolutionResultService,
+                                         private var blueprintTemplateService: BluePrintTemplateService) :
         ResourceResolutionService {
 
     private val log = LoggerFactory.getLogger(ResourceResolutionService::class.java)
@@ -137,7 +138,6 @@ open class ResourceResolutionServiceImpl(private var applicationContext: Applica
 
         // Check Template is there
         if (artifactTemplate != null) {
-            val blueprintTemplateService = BluePrintTemplateService()
             resolvedContent = blueprintTemplateService.generateContent(bluePrintRuntimeService, nodeTemplateName,
                     artifactTemplate, resolvedParamJsonContent)
 
@@ -189,6 +189,7 @@ open class ResourceResolutionServiceImpl(private var applicationContext: Applica
                                     // Set errors from RA
                                     blueprintRuntimeService.setBluePrintError(resourceAssignmentRuntimeService.getBluePrintError())
                                 } catch (e: RuntimeException) {
+                                    log.error("Fail in processing ${resourceAssignment.name}", e)
                                     throw BluePrintProcessorException(e)
                                 }
                             }
index 86bf3ff..98abf89 100644 (file)
@@ -40,21 +40,6 @@ interface BlueprintTemplateService {
                                 jsonData: String = "",
                                 ignoreJsonNull: Boolean = false,
                                 additionalContext: MutableMap<String, Any> = mutableMapOf()): String
-
-
-    /**
-     * Generate dynamique content using Velocity Template or Jinja template
-     *
-     * @param template template string content
-     * @param templateType template type
-     * @param jsonData json string data content to mash
-     * @param ignoreJsonNull Ignore Null value in the JSON content
-     * @param additionalContext (Key, value) mutable map for additional variables
-     * @return Content result
-     *
-     **/
-    suspend fun generateContent(template: String, templateType: String, jsonData: String = "", ignoreJsonNull: Boolean = false,
-                                additionalContext: MutableMap<String, Any> = mutableMapOf()): String
 }
 
 /**
index 1dbbd99..baddd6a 100644 (file)
@@ -19,18 +19,73 @@ package org.onap.ccsdk.cds.controllerblueprints.core.service
 import com.fasterxml.jackson.core.type.TypeReference
 import com.fasterxml.jackson.databind.JsonNode
 import com.fasterxml.jackson.databind.ObjectMapper
+import com.google.common.io.Resources
 import com.hubspot.jinjava.Jinjava
+import com.hubspot.jinjava.interpret.Context
+import com.hubspot.jinjava.interpret.JinjavaInterpreter
+import com.hubspot.jinjava.loader.ClasspathResourceLocator
+import com.hubspot.jinjava.loader.ResourceLocator
+import com.hubspot.jinjava.loader.ResourceNotFoundException
 import org.onap.ccsdk.cds.controllerblueprints.core.BluePrintProcessorException
+import org.onap.ccsdk.cds.controllerblueprints.core.config.BluePrintLoadConfiguration
+import org.onap.ccsdk.cds.controllerblueprints.core.config.BluePrintPathConfiguration
 import org.onap.ccsdk.cds.controllerblueprints.core.interfaces.BluePrintJsonNodeFactory
+import org.onap.ccsdk.cds.controllerblueprints.core.normalizedFile
+import org.onap.ccsdk.cds.controllerblueprints.core.normalizedPathName
 import org.onap.ccsdk.cds.controllerblueprints.core.removeNullNode
+import org.springframework.context.annotation.Scope
+import org.springframework.stereotype.Service
+import java.io.IOException
+import java.nio.charset.Charset
+import java.nio.file.Files.readAllBytes
+import java.nio.file.Paths
 
 object BluePrintJinjaTemplateService {
 
+    /**
+     * To enable inheritance within CBA, we need Jinja runtime to know where to load the templates.
+     */
+    class BlueprintRelatedTemplateLocator(private val bluePrintPathConfiguration: BluePrintPathConfiguration,
+                                          private val artifactName: String,
+                                          private val artifactVersion: String) : ResourceLocator {
+
+        @Throws(IOException::class)
+        override fun getString(fullName: String, encoding: Charset, interpreter: JinjavaInterpreter): String {
+            try {
+                val deployFile =
+                    normalizedPathName(bluePrintPathConfiguration.blueprintDeployPath,
+                        artifactName,
+                        artifactVersion,
+                        fullName)
+
+                return String(readAllBytes(Paths.get(deployFile)))
+            } catch (var5: IllegalArgumentException) {
+                throw ResourceNotFoundException("Couldn't find resource: $fullName")
+            }
+
+        }
+    }
+
     fun generateContent(template: String, json: String, ignoreJsonNull: Boolean,
-                        additionalContext: MutableMap<String, Any>): String {
+                        additionalContext: MutableMap<String, Any>,
+                        bluePrintPathConfiguration: BluePrintPathConfiguration, artifactName: String,
+                        artifactVersion: String): String {
 
-        // Load template
+
+        return generateContent(template,
+            json,
+            ignoreJsonNull,
+            additionalContext,
+            BlueprintRelatedTemplateLocator(bluePrintPathConfiguration, artifactName, artifactVersion))
+    }
+
+    fun generateContent(template: String, json: String, ignoreJsonNull: Boolean,
+                        additionalContext: MutableMap<String, Any>, resourceLocator: ResourceLocator? = null): String {
         val jinJava = Jinjava()
+        if (resourceLocator != null) {
+            jinJava.resourceLocator = resourceLocator
+        }
+
         val mapper = ObjectMapper()
         val nodeFactory = BluePrintJsonNodeFactory()
         mapper.nodeFactory = nodeFactory
index 45e2678..af97d66 100644 (file)
@@ -17,26 +17,33 @@ package org.onap.ccsdk.cds.controllerblueprints.core.service
 
 import org.onap.ccsdk.cds.controllerblueprints.core.BluePrintConstants
 import org.onap.ccsdk.cds.controllerblueprints.core.BluePrintProcessorException
+import org.onap.ccsdk.cds.controllerblueprints.core.config.BluePrintPathConfiguration
 import org.onap.ccsdk.cds.controllerblueprints.core.interfaces.BlueprintTemplateService
 import org.onap.ccsdk.cds.controllerblueprints.core.utils.JacksonUtils
+import org.springframework.stereotype.Service
 
-class BluePrintTemplateService : BlueprintTemplateService {
+@Service
+class BluePrintTemplateService(private val bluePrintPathConfiguration: BluePrintPathConfiguration) :
+    BlueprintTemplateService {
 
     override suspend fun generateContent(bluePrintRuntimeService: BluePrintRuntimeService<*>,
                                          nodeTemplateName: String, artifactName: String, jsonData: String,
                                          ignoreJsonNull: Boolean, additionalContext: MutableMap<String, Any>): String {
 
-        val artifactDefinition = bluePrintRuntimeService.resolveNodeTemplateArtifactDefinition(nodeTemplateName, artifactName)
+        val artifactDefinition =
+            bluePrintRuntimeService.resolveNodeTemplateArtifactDefinition(nodeTemplateName, artifactName)
         val templateType = artifactDefinition.type
         val template = bluePrintRuntimeService.resolveNodeTemplateArtifact(nodeTemplateName, artifactName)
-        return generateContent(template, templateType, jsonData, ignoreJsonNull, additionalContext)
-    }
 
-    override suspend fun generateContent(template: String, templateType: String, jsonData: String, ignoreJsonNull: Boolean,
-                                         additionalContext: MutableMap<String, Any>): String {
         return when (templateType) {
             BluePrintConstants.ARTIFACT_JINJA_TYPE_NAME -> {
-                BluePrintJinjaTemplateService.generateContent(template, jsonData, ignoreJsonNull, additionalContext)
+                BluePrintJinjaTemplateService.generateContent(template,
+                    jsonData,
+                    ignoreJsonNull,
+                    additionalContext,
+                    bluePrintPathConfiguration,
+                    bluePrintRuntimeService.bluePrintContext().name(),
+                    bluePrintRuntimeService.bluePrintContext().version())
             }
             BluePrintConstants.ARTIFACT_VELOCITY_TYPE_NAME -> {
                 BluePrintVelocityTemplateService.generateContent(template, jsonData, ignoreJsonNull, additionalContext)
@@ -47,12 +54,4 @@ class BluePrintTemplateService : BlueprintTemplateService {
             }
         }
     }
-
-    suspend fun generateContentFromFiles(templatePath: String, templateType: String, jsonPath: String,
-                                         ignoreJsonNull: Boolean,
-                                         additionalContext: MutableMap<String, Any>): String {
-        val json = JacksonUtils.getClassPathFileContent(jsonPath)
-        val template = JacksonUtils.getClassPathFileContent(templatePath)
-        return generateContent(template, templateType, json, ignoreJsonNull, additionalContext)
-    }
 }
\ No newline at end of file
index 6f961c8..63c8ad7 100644 (file)
@@ -36,7 +36,8 @@ class BluePrintTemplateServiceTest {
 
     @BeforeTest
     fun setup() {
-        val blueprintBasePath: String = ("./../../../../components/model-catalog/blueprint-model/test-blueprint/baseconfiguration")
+        val blueprintBasePath: String =
+            ("./../../../../components/model-catalog/blueprint-model/test-blueprint/baseconfiguration")
         blueprintRuntime = BluePrintMetadataUtils.getBluePrintRuntime("1234", blueprintBasePath)
     }
 
@@ -55,11 +56,12 @@ class BluePrintTemplateServiceTest {
     @Test
     fun testJinjaGeneratedContent() {
         runBlocking {
-            val template = JacksonUtils.getClassPathFileContent("templates/base-config-jinja-template.jinja")
+            val template = JacksonUtils.getClassPathFileContent("templates/master.jinja")
             val json = JacksonUtils.getClassPathFileContent("templates/base-config-data-jinja.json")
 
             var element: MutableMap<String, Any> = mutableMapOf()
-            element["additional_array"] = arrayListOf(hashMapOf("name" to "Element1", "location" to "Region0"), hashMapOf("name" to "Element2", "location" to "Region1"))
+            element["additional_array"] = arrayListOf(hashMapOf("name" to "Element1", "location" to "Region0"),
+                hashMapOf("name" to "Element2", "location" to "Region1"))
 
             val content = BluePrintJinjaTemplateService.generateContent(template, json, false, element)
             assertNotNull(content, "failed to generate content for velocity template")
@@ -67,42 +69,12 @@ class BluePrintTemplateServiceTest {
 
     }
 
-    @Test
-    fun testVelocityGeneratedContentFromFiles() {
-        runBlocking {
-            val bluePrintTemplateService = BluePrintTemplateService()
-            val templateFile = "templates/base-config-velocity-template.vtl"
-            val jsonFile = "templates/base-config-data-velocity.json"
-
-            val content = bluePrintTemplateService.generateContentFromFiles(
-                    templateFile, BluePrintConstants.ARTIFACT_VELOCITY_TYPE_NAME, jsonFile, false, mutableMapOf())
-            assertNotNull(content, "failed to generate content for velocity template")
-        }
-
-    }
-
-    @Test
-    fun testJinjaGeneratedContentFromFiles() {
-        runBlocking {
-            var element: MutableMap<String, Any> = mutableMapOf()
-            element["additional_array"] = arrayListOf(hashMapOf("name" to "Element1", "location" to "Region0"), hashMapOf("name" to "Element2", "location" to "Region1"))
-
-            val bluePrintTemplateService = BluePrintTemplateService()
-
-            val templateFile = "templates/base-config-jinja-template.jinja"
-            val jsonFile = "templates/base-config-data-jinja.json"
-
-            val content = bluePrintTemplateService.generateContentFromFiles(
-                    templateFile, BluePrintConstants.ARTIFACT_JINJA_TYPE_NAME,
-                    jsonFile, false, element)
-            assertNotNull(content, "failed to generate content for velocity template")
-        }
-    }
 
     @Test
     fun `no value variable should evaluate to default value - standalone template mesh test`() {
         runBlocking {
-            val template = JacksonUtils.getClassPathFileContent("templates/default-variable-value-velocity-template.vtl")
+            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)
@@ -113,24 +85,5 @@ class BluePrintTemplateServiceTest {
         }
     }
 
-    @Test
-    fun `no value variable should evaluate to default value - blueprint processing test`() {
-        runBlocking {
-            val bluePrintTemplateService = BluePrintTemplateService()
-
-            val templateFile = "templates/default-variable-value-velocity-template.vtl"
-            val jsonFile = "templates/default-variable-value-data.json"
-
-            val content = bluePrintTemplateService.generateContentFromFiles(templateFile,
-                    BluePrintConstants.ARTIFACT_VELOCITY_TYPE_NAME, jsonFile, false, mutableMapOf())
-
-            //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}"
-            assertEquals(expected, content, "No value variable should use default value")
-        }
-
-    }
-
 }
 
index bbfb38d..ab7abf3 100644 (file)
@@ -1,16 +1,3 @@
 {
-  "node_hostname": "sdnc-host",
-  "node_backup_router_address": "2001:1890:1253::192:168:100:1",
-  "node_backup_router_d_address": "2011:1090:1253::112:158:100:1",
-  "servers": [
-    "Server1",
-    "Server2",
-    "Server3"
-  ],
-  "classes": [
-    "superuser-class",
-    "tacacs-adv-class",
-    "tacacs-base-class"
-  ],
-  "system_password": "teamops-system-password"
+  "occurrence": 2
 }
\ No newline at end of file
diff --git a/ms/controllerblueprints/modules/blueprint-core/src/test/resources/templates/base-config-jinja-template.jinja b/ms/controllerblueprints/modules/blueprint-core/src/test/resources/templates/base-config-jinja-template.jinja
deleted file mode 100755 (executable)
index db900bc..0000000
+++ /dev/null
@@ -1,42 +0,0 @@
-<configuration xmlns="http://xml.juniper.net/xnm/1.1/xnm"
-xmlns:a="http://xml.juniper.net/junos/15.1X49/junos">
-       <version>15.1X49-D50.3</version>
-       <groups>
-               <name>node0</name>
-               <system>
-        {%- for server in servers %}
-            <server-host-name>{{ server }}</server-host-name>
-        {%- endfor %}
-        </system>
-               <system>
-                       <host-name>{{ node_hostname }}</host-name>
-                       <backup-router>
-                               <address>{{ node_backup_router_address }}</address>
-                               <destination>{{ node_backup_router_d_address }}</destination>
-                       </backup-router>
-                       <login>
-                               <message>ONAP information assets</message>
-                               {%- for class in classes %}
-                <class>
-                    {{ class }}
-                </class>
-                               {%- endfor %}
-                               <user>
-                                       <name>readwrite</name>
-                                       <full-name>Read - Write Account Access</full-name>
-                                       <uid>1002</uid>
-                                       <class>tacacs-adv-class</class>
-                                       <authentication>
-                                               <encrypted-password>{{ system_password }}</encrypted-password>
-                                       </authentication>
-                               </user>
-                       </login>
-                       {%- for element in additional_array %}
-                       <additionalArray>
-                <name>{{ element.name }}</name>
-                <location>{{ element.location }}</location>
-            </additionalArray>
-            {%- endfor %}
-               </system>
-       </groups>
-</configuration>
\ No newline at end of file
diff --git a/ms/controllerblueprints/modules/blueprint-core/src/test/resources/templates/interface.jinja b/ms/controllerblueprints/modules/blueprint-core/src/test/resources/templates/interface.jinja
new file mode 100755 (executable)
index 0000000..93114d9
--- /dev/null
@@ -0,0 +1,3 @@
+  <interface-configurations xmlns="http://cisco.com/ns/yang/Cisco-IOS-XR-ifmgr-cfg">
+blo
+  </interface-configurations>
\ No newline at end of file
diff --git a/ms/controllerblueprints/modules/blueprint-core/src/test/resources/templates/isis.jinja b/ms/controllerblueprints/modules/blueprint-core/src/test/resources/templates/isis.jinja
new file mode 100644 (file)
index 0000000..f46d913
--- /dev/null
@@ -0,0 +1,3 @@
+  <isis xmlns="http://cisco.com/ns/yang/Cisco-IOS-XR-clns-isis-cfg">
+blah
+  </isis>
\ No newline at end of file
diff --git a/ms/controllerblueprints/modules/blueprint-core/src/test/resources/templates/master.jinja b/ms/controllerblueprints/modules/blueprint-core/src/test/resources/templates/master.jinja
new file mode 100644 (file)
index 0000000..1137b25
--- /dev/null
@@ -0,0 +1,7 @@
+{%- for i in range(occurrence) %}
+<config>
+{% include "templates/isis.jinja" %}
+{% include "templates/interface.jinja" %}
+</config>
+{{ "]]>]]" if not loop.last }}
+{%- endfor  %}
\ No newline at end of file