Renaming Files having BluePrint to have Blueprint
[ccsdk/cds.git] / ms / blueprintsprocessor / functions / resource-resolution / src / main / kotlin / org / onap / ccsdk / cds / blueprintsprocessor / functions / resource / resolution / ResourceResolutionService.kt
index 14e60bc..46410a8 100644 (file)
@@ -27,14 +27,17 @@ import org.onap.ccsdk.cds.blueprintsprocessor.functions.resource.resolution.db.T
 import org.onap.ccsdk.cds.blueprintsprocessor.functions.resource.resolution.processor.ResourceAssignmentProcessor
 import org.onap.ccsdk.cds.blueprintsprocessor.functions.resource.resolution.utils.ResourceAssignmentUtils
 import org.onap.ccsdk.cds.blueprintsprocessor.functions.resource.resolution.utils.ResourceDefinitionUtils.createResourceAssignments
-import org.onap.ccsdk.cds.controllerblueprints.core.BluePrintConstants
-import org.onap.ccsdk.cds.controllerblueprints.core.BluePrintProcessorException
+import org.onap.ccsdk.cds.controllerblueprints.core.BlueprintConstants
+import org.onap.ccsdk.cds.controllerblueprints.core.BlueprintProcessorException
+import org.onap.ccsdk.cds.controllerblueprints.core.asJsonNode
 import org.onap.ccsdk.cds.controllerblueprints.core.asJsonPrimitive
 import org.onap.ccsdk.cds.controllerblueprints.core.asJsonType
 import org.onap.ccsdk.cds.controllerblueprints.core.checkNotEmpty
-import org.onap.ccsdk.cds.controllerblueprints.core.service.BluePrintRuntimeService
-import org.onap.ccsdk.cds.controllerblueprints.core.service.BluePrintTemplateService
+import org.onap.ccsdk.cds.controllerblueprints.core.common.ApplicationConstants.LOG_REDACTED
+import org.onap.ccsdk.cds.controllerblueprints.core.service.BlueprintRuntimeService
+import org.onap.ccsdk.cds.controllerblueprints.core.service.BlueprintTemplateService
 import org.onap.ccsdk.cds.controllerblueprints.core.utils.JacksonUtils
+import org.onap.ccsdk.cds.controllerblueprints.core.utils.PropertyDefinitionUtils.Companion.hasLogProtect
 import org.onap.ccsdk.cds.controllerblueprints.resource.dict.ResourceAssignment
 import org.onap.ccsdk.cds.controllerblueprints.resource.dict.ResourceDefinition
 import org.onap.ccsdk.cds.controllerblueprints.resource.dict.utils.BulkResourceSequencingUtils
@@ -43,43 +46,48 @@ import org.springframework.context.ApplicationContext
 import org.springframework.stereotype.Service
 import java.util.UUID
 
+data class ResourceResolutionResult(
+    val templateMap: MutableMap<String, String>,
+    val assignmentMap: MutableMap<String, JsonNode>
+)
+
 interface ResourceResolutionService {
 
     fun registeredResourceSources(): List<String>
 
     suspend fun resolveFromDatabase(
-        bluePrintRuntimeService: BluePrintRuntimeService<*>,
+        bluePrintRuntimeService: BlueprintRuntimeService<*>,
         artifactTemplate: String,
         resolutionKey: String
     ): String
 
     suspend fun resolveResources(
-        bluePrintRuntimeService: BluePrintRuntimeService<*>,
+        bluePrintRuntimeService: BlueprintRuntimeService<*>,
         nodeTemplateName: String,
         artifactNames: List<String>,
         properties: Map<String, Any>
-    ): MutableMap<String, String>
+    ): ResourceResolutionResult
 
     suspend fun resolveResources(
-        bluePrintRuntimeService: BluePrintRuntimeService<*>,
+        bluePrintRuntimeService: BlueprintRuntimeService<*>,
         nodeTemplateName: String,
         artifactPrefix: String,
         properties: Map<String, Any>
-    ): String
+    ): Pair<String, MutableList<ResourceAssignment>>
 
     /** Resolve resources for all the sources defined in a particular resource Definition[resolveDefinition]
      * with other [resourceDefinitions] dependencies for the sources [sources]
      * Used to get the same resource values from multiple sources. **/
     suspend fun resolveResourceDefinition(
-        blueprintRuntimeService: BluePrintRuntimeService<*>,
+        blueprintRuntimeService: BlueprintRuntimeService<*>,
         resourceDefinitions: MutableMap<String, ResourceDefinition>,
         resolveDefinition: String,
         sources: List<String>
     ):
-            MutableMap<String, JsonNode>
+        MutableMap<String, JsonNode>
 
     suspend fun resolveResourceAssignments(
-        blueprintRuntimeService: BluePrintRuntimeService<*>,
+        blueprintRuntimeService: BlueprintRuntimeService<*>,
         resourceDefinitions: MutableMap<String, ResourceDefinition>,
         resourceAssignments: MutableList<ResourceAssignment>,
         artifactPrefix: String,
@@ -91,7 +99,7 @@ interface ResourceResolutionService {
 open class ResourceResolutionServiceImpl(
     private var applicationContext: ApplicationContext,
     private var templateResolutionDBService: TemplateResolutionService,
-    private var blueprintTemplateService: BluePrintTemplateService,
+    private var blueprintTemplateService: BlueprintTemplateService,
     private var resourceResolutionDBService: ResourceResolutionDBService
 ) :
     ResourceResolutionService {
@@ -105,7 +113,7 @@ open class ResourceResolutionServiceImpl(
     }
 
     override suspend fun resolveFromDatabase(
-        bluePrintRuntimeService: BluePrintRuntimeService<*>,
+        bluePrintRuntimeService: BlueprintRuntimeService<*>,
         artifactTemplate: String,
         resolutionKey: String
     ): String {
@@ -117,49 +125,62 @@ open class ResourceResolutionServiceImpl(
     }
 
     override suspend fun resolveResources(
-        bluePrintRuntimeService: BluePrintRuntimeService<*>,
+        bluePrintRuntimeService: BlueprintRuntimeService<*>,
         nodeTemplateName: String,
         artifactNames: List<String>,
         properties: Map<String, Any>
-    ): MutableMap<String, String> {
+    ): ResourceResolutionResult {
 
         val resourceAssignmentRuntimeService =
             ResourceAssignmentUtils.transformToRARuntimeService(bluePrintRuntimeService, artifactNames.toString())
 
-        val resolvedParams: MutableMap<String, String> = hashMapOf()
+        val templateMap: MutableMap<String, String> = hashMapOf()
+        val assignmentMap: MutableMap<String, JsonNode> = hashMapOf()
         artifactNames.forEach { artifactName ->
-            val resolvedContent = resolveResources(
+            val (resolvedStringContent, resourceAssignmentList) = resolveResources(
                 resourceAssignmentRuntimeService, nodeTemplateName,
                 artifactName, properties
             )
-
-            resolvedParams[artifactName] = resolvedContent
+            val resolvedJsonContent = resourceAssignmentList
+                .associateBy({ it.name }, { it.property?.value })
+                .asJsonNode()
+
+            templateMap[artifactName] = resolvedStringContent
+            assignmentMap[artifactName] = resolvedJsonContent
+
+            val failedResolution = resourceAssignmentList.filter { it.status != "success" && it.property?.required == true }.map { it.name }
+            if (failedResolution.isNotEmpty()) {
+                // The following error message is returned by default to handle a scenario when
+                // error message comes empty even when resolution has actually failed.
+                // Example: input-source type resolution seems to fail with no error code.
+                bluePrintRuntimeService.getBlueprintError().errors.add("Failed to resolve required resources($failedResolution)")
+                bluePrintRuntimeService.getBlueprintError().errors.addAll(resourceAssignmentRuntimeService.getBlueprintError().errors)
+            }
         }
-        return resolvedParams
+        return ResourceResolutionResult(templateMap, assignmentMap)
     }
 
     override suspend fun resolveResources(
-        bluePrintRuntimeService: BluePrintRuntimeService<*>,
+        bluePrintRuntimeService: BlueprintRuntimeService<*>,
         nodeTemplateName: String,
         artifactPrefix: String,
         properties: Map<String, Any>
-    ): String {
+    ): Pair<String, MutableList<ResourceAssignment>> {
 
-        // Velocity Artifact Definition Name
+        // Template Artifact Definition Name
         val artifactTemplate = "$artifactPrefix-template"
         // Resource Assignment Artifact Definition Name
         val artifactMapping = "$artifactPrefix-mapping"
 
-        val resolvedContent: String
-        log.info("Resolving resource for template artifact($artifactTemplate) with resource assignment artifact($artifactMapping)")
+        log.info("Resolving resource with resource assignment artifact($artifactMapping)")
 
         val resourceAssignmentContent =
             bluePrintRuntimeService.resolveNodeTemplateArtifact(nodeTemplateName, artifactMapping)
 
         val resourceAssignments: MutableList<ResourceAssignment> =
             JacksonUtils.getListFromJson(resourceAssignmentContent, ResourceAssignment::class.java)
-                    as? MutableList<ResourceAssignment>
-                ?: throw BluePrintProcessorException("couldn't get Dictionary Definitions")
+                as? MutableList<ResourceAssignment>
+                ?: throw BlueprintProcessorException("couldn't get Dictionary Definitions")
 
         if (isToStore(properties)) {
             val existingResourceResolution = isNewResolution(bluePrintRuntimeService, properties, artifactPrefix)
@@ -184,33 +205,50 @@ open class ResourceResolutionServiceImpl(
             properties
         )
 
+        val resolutionSummary = properties.getOrDefault(
+            ResourceResolutionConstants.RESOURCE_RESOLUTION_INPUT_RESOLUTION_SUMMARY,
+            false
+        ) as Boolean
+
         val resolvedParamJsonContent =
             ResourceAssignmentUtils.generateResourceDataForAssignments(resourceAssignments.toList())
-
-        resolvedContent = blueprintTemplateService.generateContent(
-            bluePrintRuntimeService, nodeTemplateName,
-            artifactTemplate, resolvedParamJsonContent, false,
-            mutableMapOf(
-                ResourceResolutionConstants.RESOURCE_RESOLUTION_INPUT_OCCURRENCE to
-                        properties[ResourceResolutionConstants.RESOURCE_RESOLUTION_INPUT_OCCURRENCE].asJsonPrimitive()
-            )
-        )
+        val artifactTemplateDefinition =
+            bluePrintRuntimeService.bluePrintContext().checkNodeTemplateArtifact(nodeTemplateName, artifactTemplate)
+
+        val resolvedContent = when {
+            artifactTemplateDefinition != null -> {
+                blueprintTemplateService.generateContent(
+                    bluePrintRuntimeService, nodeTemplateName,
+                    artifactTemplate, resolvedParamJsonContent, false,
+                    mutableMapOf(
+                        ResourceResolutionConstants.RESOURCE_RESOLUTION_INPUT_OCCURRENCE to
+                            properties[ResourceResolutionConstants.RESOURCE_RESOLUTION_INPUT_OCCURRENCE]
+                                .asJsonPrimitive()
+                    )
+                )
+            }
+            resolutionSummary -> {
+                ResourceAssignmentUtils.generateResolutionSummaryData(resourceAssignments, resourceDefinitions)
+            }
+            else -> {
+                resolvedParamJsonContent
+            }
+        }
 
         if (isToStore(properties)) {
             templateResolutionDBService.write(properties, resolvedContent, bluePrintRuntimeService, artifactPrefix)
             log.info("Template resolution saved into database successfully : ($properties)")
         }
 
-        return resolvedContent
+        return Pair(resolvedContent, resourceAssignments)
     }
 
     override suspend fun resolveResourceDefinition(
-        blueprintRuntimeService: BluePrintRuntimeService<*>,
+        blueprintRuntimeService: BlueprintRuntimeService<*>,
         resourceDefinitions: MutableMap<String, ResourceDefinition>,
         resolveDefinition: String,
         sources: List<String>
-    ):
-            MutableMap<String, JsonNode> {
+    ): MutableMap<String, JsonNode> {
 
         // Populate Dummy Resource Assignments
         val resourceAssignments = createResourceAssignments(resourceDefinitions, resolveDefinition, sources)
@@ -230,7 +268,7 @@ open class ResourceResolutionServiceImpl(
      * request.
      */
     override suspend fun resolveResourceAssignments(
-        blueprintRuntimeService: BluePrintRuntimeService<*>,
+        blueprintRuntimeService: BlueprintRuntimeService<*>,
         resourceDefinitions: MutableMap<String, ResourceDefinition>,
         resourceAssignments: MutableList<ResourceAssignment>,
         artifactPrefix: String,
@@ -253,7 +291,7 @@ open class ResourceResolutionServiceImpl(
                 // Execute Non Dependent Assignments in parallel ( ie asynchronously )
                 val deferred = batchResourceAssignments
                     .filter { it.name != "*" && it.name != "start" }
-                    .filter { it.status != BluePrintConstants.STATUS_SUCCESS }
+                    .filter { it.status != BlueprintConstants.STATUS_SUCCESS }
                     .map { resourceAssignment ->
                         async {
                             val dictionaryName = resourceAssignment.dictionaryName
@@ -263,15 +301,18 @@ open class ResourceResolutionServiceImpl(
 
                             val resourceAssignmentProcessor =
                                 applicationContext.getBean(processorName) as? ResourceAssignmentProcessor
-                                    ?: throw BluePrintProcessorException(
+                                    ?: throw BlueprintProcessorException(
                                         "failed to get resource processor ($processorName) " +
-                                                "for resource assignment(${resourceAssignment.name})"
+                                            "for resource assignment(${resourceAssignment.name})"
                                     )
                             try {
-                                // Set BluePrint Runtime Service
+                                // Set Blueprint Runtime Service
                                 resourceAssignmentProcessor.raRuntimeService = resourceAssignmentRuntimeService
                                 // Set Resource Dictionaries
                                 resourceAssignmentProcessor.resourceDictionaries = resourceDefinitions
+
+                                resourceAssignmentProcessor.resourceAssignments = resourceAssignments
+
                                 // Invoke Apply Method
                                 resourceAssignmentProcessor.applyNB(resourceAssignment)
 
@@ -286,10 +327,10 @@ open class ResourceResolutionServiceImpl(
                                 }
 
                                 // Set errors from RA
-                                blueprintRuntimeService.setBluePrintError(resourceAssignmentRuntimeService.getBluePrintError())
+                                blueprintRuntimeService.setBlueprintError(resourceAssignmentRuntimeService.getBlueprintError())
                             } catch (e: RuntimeException) {
                                 log.error("Fail in processing ${resourceAssignment.name}", e)
-                                throw BluePrintProcessorException(e)
+                                throw BlueprintProcessorException(e)
                             }
                         }
                     }
@@ -317,10 +358,10 @@ open class ResourceResolutionServiceImpl(
             }
             else -> {
                 val resourceDefinition = resourceDefinitions[dictionaryName]
-                    ?: throw BluePrintProcessorException("couldn't get resource dictionary definition for $dictionaryName")
+                    ?: throw BlueprintProcessorException("couldn't get resource dictionary definition for $dictionaryName")
 
                 val resourceSource = resourceDefinition.sources[dictionarySource]
-                    ?: throw BluePrintProcessorException("couldn't get resource definition $dictionaryName source($dictionarySource)")
+                    ?: throw BlueprintProcessorException("couldn't get resource definition $dictionaryName source($dictionarySource)")
 
                 ResourceResolutionConstants.PREFIX_RESOURCE_RESOLUTION_PROCESSOR.plus(resourceSource.type)
             }
@@ -335,12 +376,12 @@ open class ResourceResolutionServiceImpl(
     // Check whether to store or not the resolution of resource and template
     private fun isToStore(properties: Map<String, Any>): Boolean {
         return properties.containsKey(ResourceResolutionConstants.RESOURCE_RESOLUTION_INPUT_STORE_RESULT) &&
-                properties[ResourceResolutionConstants.RESOURCE_RESOLUTION_INPUT_STORE_RESULT] as Boolean
+            properties[ResourceResolutionConstants.RESOURCE_RESOLUTION_INPUT_STORE_RESULT] as Boolean
     }
 
     // Check whether resolution already exist in the database for the specified resolution-key or resourceId/resourceType
     private suspend fun isNewResolution(
-        bluePrintRuntimeService: BluePrintRuntimeService<*>,
+        bluePrintRuntimeService: BlueprintRuntimeService<*>,
         properties: Map<String, Any>,
         artifactPrefix: String
     ): List<ResourceResolution> {
@@ -376,8 +417,8 @@ open class ResourceResolutionServiceImpl(
                 )
             if (existingResourceAssignments.isNotEmpty()) {
                 log.info(
-                    "Resolution with resourceId=($resourceId) and resourceType=($resourceType) already exist - will resolve " +
-                            "all resources not already resolved."
+                    "Resolution with resourceId=($resourceId) and resourceType=($resourceType) already " +
+                        "exist - will resolve all resources not already resolved."
                 )
             }
             return existingResourceAssignments
@@ -392,10 +433,13 @@ open class ResourceResolutionServiceImpl(
         resourceAssignmentList: MutableList<ResourceAssignment>
     ) {
         resourceResolutionList.forEach { resourceResolution ->
-            if (resourceResolution.status == BluePrintConstants.STATUS_SUCCESS) {
+            if (resourceResolution.status == BlueprintConstants.STATUS_SUCCESS) {
                 resourceAssignmentList.forEach {
                     if (compareOne(resourceResolution, it)) {
-                        log.info("Resource ({}) already resolve: value=({})", it.name, resourceResolution.value)
+                        log.info(
+                            "Resource ({}) already resolved: value=({})", it.name,
+                            if (hasLogProtect(it.property)) LOG_REDACTED else resourceResolution.value
+                        )
 
                         // Make sure to recreate value as per the defined type.
                         val value = resourceResolution.value!!.asJsonType(it.property!!.type)
@@ -410,10 +454,12 @@ open class ResourceResolutionServiceImpl(
 
     // Comparision between what we have in the database vs what we have to assign.
     private fun compareOne(resourceResolution: ResourceResolution, resourceAssignment: ResourceAssignment): Boolean {
-        return (resourceResolution.name == resourceAssignment.name &&
+        return (
+            resourceResolution.name == resourceAssignment.name &&
                 resourceResolution.dictionaryName == resourceAssignment.dictionaryName &&
                 resourceResolution.dictionarySource == resourceAssignment.dictionarySource &&
-                resourceResolution.dictionaryVersion == resourceAssignment.version)
+                resourceResolution.dictionaryVersion == resourceAssignment.version
+            )
     }
 
     private fun exposeOccurrencePropertyInResourceAssignments(