X-Git-Url: https://gerrit.onap.org/r/gitweb?a=blobdiff_plain;f=ms%2Fblueprintsprocessor%2Ffunctions%2Fresource-resolution%2Fsrc%2Fmain%2Fkotlin%2Forg%2Fonap%2Fccsdk%2Fcds%2Fblueprintsprocessor%2Ffunctions%2Fresource%2Fresolution%2FResourceResolutionService.kt;h=46410a8597071ce948eadf161b778e330a9ebb72;hb=adcd4f2bc695840e9ecbc05003bc52c675f22fec;hp=938affc827da2fb385e96bccd5ba05a3f0daeeb6;hpb=fdbb1a7b9bf8159438f439bd0fae8a870a16c527;p=ccsdk%2Fcds.git diff --git a/ms/blueprintsprocessor/functions/resource-resolution/src/main/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/functions/resource/resolution/ResourceResolutionService.kt b/ms/blueprintsprocessor/functions/resource-resolution/src/main/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/functions/resource/resolution/ResourceResolutionService.kt index 938affc82..46410a859 100644 --- a/ms/blueprintsprocessor/functions/resource-resolution/src/main/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/functions/resource/resolution/ResourceResolutionService.kt +++ b/ms/blueprintsprocessor/functions/resource-resolution/src/main/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/functions/resource/resolution/ResourceResolutionService.kt @@ -26,42 +26,82 @@ import org.onap.ccsdk.cds.blueprintsprocessor.functions.resource.resolution.db.R import org.onap.ccsdk.cds.blueprintsprocessor.functions.resource.resolution.db.TemplateResolutionService 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.controllerblueprints.core.* -import org.onap.ccsdk.cds.controllerblueprints.core.service.BluePrintRuntimeService -import org.onap.ccsdk.cds.controllerblueprints.core.service.BluePrintTemplateService +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.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.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 import org.slf4j.LoggerFactory import org.springframework.context.ApplicationContext import org.springframework.stereotype.Service +import java.util.UUID + +data class ResourceResolutionResult( + val templateMap: MutableMap, + val assignmentMap: MutableMap +) interface ResourceResolutionService { fun registeredResourceSources(): List - suspend fun resolveFromDatabase(bluePrintRuntimeService: BluePrintRuntimeService<*>, artifactTemplate: String, - resolutionKey: String): String - - suspend fun resolveResources(bluePrintRuntimeService: BluePrintRuntimeService<*>, nodeTemplateName: String, - artifactNames: List, properties: Map): MutableMap - - suspend fun resolveResources(bluePrintRuntimeService: BluePrintRuntimeService<*>, nodeTemplateName: String, - artifactPrefix: String, properties: Map): String - - suspend fun resolveResourceAssignments(blueprintRuntimeService: BluePrintRuntimeService<*>, - resourceDefinitions: MutableMap, - resourceAssignments: MutableList, - artifactPrefix: String, - properties: Map) + suspend fun resolveFromDatabase( + bluePrintRuntimeService: BlueprintRuntimeService<*>, + artifactTemplate: String, + resolutionKey: String + ): String + + suspend fun resolveResources( + bluePrintRuntimeService: BlueprintRuntimeService<*>, + nodeTemplateName: String, + artifactNames: List, + properties: Map + ): ResourceResolutionResult + + suspend fun resolveResources( + bluePrintRuntimeService: BlueprintRuntimeService<*>, + nodeTemplateName: String, + artifactPrefix: String, + properties: Map + ): Pair> + + /** 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<*>, + resourceDefinitions: MutableMap, + resolveDefinition: String, + sources: List + ): + MutableMap + + suspend fun resolveResourceAssignments( + blueprintRuntimeService: BlueprintRuntimeService<*>, + resourceDefinitions: MutableMap, + resourceAssignments: MutableList, + artifactPrefix: String, + properties: Map + ) } @Service(ResourceResolutionConstants.SERVICE_RESOURCE_RESOLUTION) -open class ResourceResolutionServiceImpl(private var applicationContext: ApplicationContext, - private var templateResolutionDBService: TemplateResolutionService, - private var blueprintTemplateService: BluePrintTemplateService, - private var resourceResolutionDBService: ResourceResolutionDBService) : +open class ResourceResolutionServiceImpl( + private var applicationContext: ApplicationContext, + private var templateResolutionDBService: TemplateResolutionService, + private var blueprintTemplateService: BlueprintTemplateService, + private var resourceResolutionDBService: ResourceResolutionDBService +) : ResourceResolutionService { private val log = LoggerFactory.getLogger(ResourceResolutionService::class.java) @@ -72,58 +112,83 @@ open class ResourceResolutionServiceImpl(private var applicationContext: Applica .map { it.substringAfter(ResourceResolutionConstants.PREFIX_RESOURCE_RESOLUTION_PROCESSOR) } } - override suspend fun resolveFromDatabase(bluePrintRuntimeService: BluePrintRuntimeService<*>, - artifactTemplate: String, - resolutionKey: String): String { + override suspend fun resolveFromDatabase( + bluePrintRuntimeService: BlueprintRuntimeService<*>, + artifactTemplate: String, + resolutionKey: String + ): String { return templateResolutionDBService.findByResolutionKeyAndBlueprintNameAndBlueprintVersionAndArtifactName( bluePrintRuntimeService, artifactTemplate, - resolutionKey) + resolutionKey + ) } - override suspend fun resolveResources(bluePrintRuntimeService: BluePrintRuntimeService<*>, nodeTemplateName: String, - artifactNames: List, - properties: Map): MutableMap { - + override suspend fun resolveResources( + bluePrintRuntimeService: BlueprintRuntimeService<*>, + nodeTemplateName: String, + artifactNames: List, + properties: Map + ): ResourceResolutionResult { val resourceAssignmentRuntimeService = ResourceAssignmentUtils.transformToRARuntimeService(bluePrintRuntimeService, artifactNames.toString()) - val resolvedParams: MutableMap = hashMapOf() + val templateMap: MutableMap = hashMapOf() + val assignmentMap: MutableMap = hashMapOf() artifactNames.forEach { artifactName -> - val resolvedContent = resolveResources(resourceAssignmentRuntimeService, nodeTemplateName, - artifactName, properties) - - resolvedParams[artifactName] = resolvedContent.asJsonType() - + val (resolvedStringContent, resourceAssignmentList) = resolveResources( + resourceAssignmentRuntimeService, nodeTemplateName, + artifactName, properties + ) + 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<*>, + nodeTemplateName: String, + artifactPrefix: String, + properties: Map + ): Pair> { - override suspend fun resolveResources(bluePrintRuntimeService: BluePrintRuntimeService<*>, nodeTemplateName: String, - artifactPrefix: String, properties: Map): String { - - // 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 = JacksonUtils.getListFromJson(resourceAssignmentContent, ResourceAssignment::class.java) - as? MutableList - ?: throw BluePrintProcessorException("couldn't get Dictionary Definitions") + as? MutableList + ?: throw BlueprintProcessorException("couldn't get Dictionary Definitions") if (isToStore(properties)) { val existingResourceResolution = isNewResolution(bluePrintRuntimeService, properties, artifactPrefix) if (existingResourceResolution.isNotEmpty()) { - updateResourceAssignmentWithExisting(existingResourceResolution, resourceAssignments) + updateResourceAssignmentWithExisting( + bluePrintRuntimeService as ResourceAssignmentRuntimeService, + existingResourceResolution, resourceAssignments + ) } } @@ -132,24 +197,69 @@ open class ResourceResolutionServiceImpl(private var applicationContext: Applica .resourceDefinitions(bluePrintRuntimeService.bluePrintContext().rootPath) // Resolve resources - resolveResourceAssignments(bluePrintRuntimeService, + resolveResourceAssignments( + bluePrintRuntimeService, resourceDefinitions, resourceAssignments, artifactPrefix, - properties) + 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) + 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<*>, + resourceDefinitions: MutableMap, + resolveDefinition: String, + sources: List + ): MutableMap { + + // Populate Dummy Resource Assignments + val resourceAssignments = createResourceAssignments(resourceDefinitions, resolveDefinition, sources) + + resolveResourceAssignments( + blueprintRuntimeService, resourceDefinitions, resourceAssignments, + UUID.randomUUID().toString(), hashMapOf() + ) + + // Get the data from Resource Assignments + return ResourceAssignmentUtils.generateResourceForAssignments(resourceAssignments) } /** @@ -157,21 +267,31 @@ open class ResourceResolutionServiceImpl(private var applicationContext: Applica * name, then get the type of the Resource Definition, Get the instance for the Resource Type and process the * request. */ - override suspend fun resolveResourceAssignments(blueprintRuntimeService: BluePrintRuntimeService<*>, - resourceDefinitions: MutableMap, - resourceAssignments: MutableList, - artifactPrefix: String, - properties: Map) { + override suspend fun resolveResourceAssignments( + blueprintRuntimeService: BlueprintRuntimeService<*>, + resourceDefinitions: MutableMap, + resourceAssignments: MutableList, + artifactPrefix: String, + properties: Map + ) { val bulkSequenced = BulkResourceSequencingUtils.process(resourceAssignments) - val resourceAssignmentRuntimeService = blueprintRuntimeService as ResourceAssignmentRuntimeService + + // Check the BlueprintRuntime Service Should be ResourceAssignmentRuntimeService + val resourceAssignmentRuntimeService = if (blueprintRuntimeService !is ResourceAssignmentRuntimeService) { + ResourceAssignmentUtils.transformToRARuntimeService(blueprintRuntimeService, artifactPrefix) + } else { + blueprintRuntimeService + } + + exposeOccurrencePropertyInResourceAssignments(resourceAssignmentRuntimeService, properties) coroutineScope { bulkSequenced.forEach { batchResourceAssignments -> // 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 @@ -181,29 +301,36 @@ open class ResourceResolutionServiceImpl(private var applicationContext: Applica val resourceAssignmentProcessor = applicationContext.getBean(processorName) as? ResourceAssignmentProcessor - ?: throw BluePrintProcessorException("failed to get resource processor ($processorName) " + - "for resource assignment(${resourceAssignment.name})") + ?: throw BlueprintProcessorException( + "failed to get resource processor ($processorName) " + + "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) if (isToStore(properties)) { - resourceResolutionDBService.write(properties, + resourceResolutionDBService.write( + properties, blueprintRuntimeService, artifactPrefix, - resourceAssignment) - log.info("Resource resolution saved into database successfully : ($resourceAssignment)") + resourceAssignment + ) + log.info("Resource resolution saved into database successfully : (${resourceAssignment.name})") } // 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) } } } @@ -211,15 +338,17 @@ open class ResourceResolutionServiceImpl(private var applicationContext: Applica deferred.awaitAll() } } - } /** * If the Source instance is "input", then it is not mandatory to have source Resource Definition, So it can * derive the default input processor. */ - private fun processorName(dictionaryName: String, dictionarySource: String, - resourceDefinitions: MutableMap): String { + private fun processorName( + dictionaryName: String, + dictionarySource: String, + resourceDefinitions: MutableMap + ): String { val processorName: String = when (dictionarySource) { "input" -> { "${ResourceResolutionConstants.PREFIX_RESOURCE_RESOLUTION_PROCESSOR}source-input" @@ -229,10 +358,10 @@ open class ResourceResolutionServiceImpl(private var applicationContext: Applica } 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) } @@ -242,19 +371,20 @@ open class ResourceResolutionServiceImpl(private var applicationContext: Applica } return processorName - } // Check whether to store or not the resolution of resource and template private fun isToStore(properties: Map): Boolean { - return properties.containsKey(ResourceResolutionConstants.RESOURCE_RESOLUTION_INPUT_STORE_RESULT) - && properties[ResourceResolutionConstants.RESOURCE_RESOLUTION_INPUT_STORE_RESULT] as Boolean + return properties.containsKey(ResourceResolutionConstants.RESOURCE_RESOLUTION_INPUT_STORE_RESULT) && + 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<*>, - properties: Map, - artifactPrefix: String): List { + private suspend fun isNewResolution( + bluePrintRuntimeService: BlueprintRuntimeService<*>, + properties: Map, + artifactPrefix: String + ): List { val occurrence = properties[ResourceResolutionConstants.RESOURCE_RESOLUTION_INPUT_OCCURRENCE] as Int val resolutionKey = properties[ResourceResolutionConstants.RESOURCE_RESOLUTION_INPUT_RESOLUTION_KEY] as String val resourceId = properties[ResourceResolutionConstants.RESOURCE_RESOLUTION_INPUT_RESOURCE_ID] as String @@ -266,10 +396,13 @@ open class ResourceResolutionServiceImpl(private var applicationContext: Applica bluePrintRuntimeService, resolutionKey, occurrence, - artifactPrefix) + artifactPrefix + ) if (existingResourceAssignments.isNotEmpty()) { - log.info("Resolution with resolutionKey=($resolutionKey) already exist - will resolve all resources not already resolved.", - resolutionKey) + log.info( + "Resolution with resolutionKey=($resolutionKey) already exist - will resolve all resources not already resolved.", + resolutionKey + ) } return existingResourceAssignments } else if (resourceId.isNotEmpty() && resourceType.isNotEmpty()) { @@ -280,10 +413,13 @@ open class ResourceResolutionServiceImpl(private var applicationContext: Applica resourceType, occurrence, - artifactPrefix) + artifactPrefix + ) if (existingResourceAssignments.isNotEmpty()) { - log.info("Resolution with resourceId=($resourceId) and resourceType=($resourceType) already exist - will resolve " + - "all resources not already resolved.") + log.info( + "Resolution with resourceId=($resourceId) and resourceType=($resourceType) already " + + "exist - will resolve all resources not already resolved." + ) } return existingResourceAssignments } @@ -291,15 +427,25 @@ open class ResourceResolutionServiceImpl(private var applicationContext: Applica } // Update the resource assignment list with the status of the resource that have already been resolved - private fun updateResourceAssignmentWithExisting(resourceResolutionList: List, - resourceAssignmentList: MutableList) { + private fun updateResourceAssignmentWithExisting( + raRuntimeService: ResourceAssignmentRuntimeService, + resourceResolutionList: List, + resourceAssignmentList: MutableList + ) { 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) - it.property!!.value = resourceResolution.value!!.asJsonPrimitive() + 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) + it.property!!.value = value it.status = resourceResolution.status + ResourceAssignmentUtils.setResourceDataValue(it, raRuntimeService, value) } } } @@ -308,10 +454,21 @@ open class ResourceResolutionServiceImpl(private var applicationContext: Applica // 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 - && resourceResolution.dictionaryName == resourceAssignment.dictionaryName - && resourceResolution.dictionarySource == resourceAssignment.dictionarySource - && resourceResolution.dictionaryVersion == resourceAssignment.version) + return ( + resourceResolution.name == resourceAssignment.name && + resourceResolution.dictionaryName == resourceAssignment.dictionaryName && + resourceResolution.dictionarySource == resourceAssignment.dictionarySource && + resourceResolution.dictionaryVersion == resourceAssignment.version + ) } + private fun exposeOccurrencePropertyInResourceAssignments( + raRuntimeService: ResourceAssignmentRuntimeService, + properties: Map + ) { + raRuntimeService.putResolutionStore( + ResourceResolutionConstants.RESOURCE_RESOLUTION_INPUT_OCCURRENCE, + properties[ResourceResolutionConstants.RESOURCE_RESOLUTION_INPUT_OCCURRENCE].asJsonPrimitive() + ) + } }