diff options
Diffstat (limited to 'ms/blueprintsprocessor/functions')
11 files changed, 847 insertions, 25 deletions
diff --git a/ms/blueprintsprocessor/functions/resource-resolution/src/main/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/functions/resource/resolution/ResourceResolutionComponent.kt b/ms/blueprintsprocessor/functions/resource-resolution/src/main/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/functions/resource/resolution/ResourceResolutionComponent.kt index 0435d1d2c..d46f75e41 100644 --- a/ms/blueprintsprocessor/functions/resource-resolution/src/main/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/functions/resource/resolution/ResourceResolutionComponent.kt +++ b/ms/blueprintsprocessor/functions/resource-resolution/src/main/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/functions/resource/resolution/ResourceResolutionComponent.kt @@ -63,6 +63,7 @@ open class ResourceResolutionComponent(private val resourceResolutionService: Re val resolutionKey = getOptionalOperationInput(ResourceResolutionConstants.RESOURCE_RESOLUTION_INPUT_RESOLUTION_KEY)?.returnNullIfMissing()?.textValue() ?: "" val storeResult = getOptionalOperationInput(ResourceResolutionConstants.RESOURCE_RESOLUTION_INPUT_STORE_RESULT)?.asBoolean() ?: false + val forceResolution = getOptionalOperationInput(ResourceResolutionConstants.RESOURCE_RESOLUTION_INPUT_FORCE_RESOLUTION)?.asBoolean() ?: false val resourceId = getOptionalOperationInput(ResourceResolutionConstants.RESOURCE_RESOLUTION_INPUT_RESOURCE_ID)?.returnNullIfMissing()?.textValue() ?: "" @@ -73,6 +74,7 @@ open class ResourceResolutionComponent(private val resourceResolutionService: Re val properties: MutableMap<String, Any> = mutableMapOf() properties[ResourceResolutionConstants.RESOURCE_RESOLUTION_INPUT_STORE_RESULT] = storeResult + properties[ResourceResolutionConstants.RESOURCE_RESOLUTION_INPUT_FORCE_RESOLUTION] = forceResolution properties[ResourceResolutionConstants.RESOURCE_RESOLUTION_INPUT_RESOLUTION_KEY] = resolutionKey properties[ResourceResolutionConstants.RESOURCE_RESOLUTION_INPUT_RESOURCE_ID] = resourceId properties[ResourceResolutionConstants.RESOURCE_RESOLUTION_INPUT_RESOURCE_TYPE] = resourceType @@ -107,9 +109,13 @@ open class ResourceResolutionComponent(private val resourceResolutionService: Re val artifactPrefixNamesNode = getOperationInput(ResourceResolutionConstants.INPUT_ARTIFACT_PREFIX_NAMES) val artifactPrefixNames = JacksonUtils.getListFromJsonNode(artifactPrefixNamesNode, String::class.java) + val alwaysPerformNewResolution = occurrence <= 0 + val resolutionsToPerform: Int = if (alwaysPerformNewResolution) 1 else occurrence + for (j in 1..resolutionsToPerform) { - for (j in 1..occurrence) { - properties[ResourceResolutionConstants.RESOURCE_RESOLUTION_INPUT_OCCURRENCE] = j + if (!alwaysPerformNewResolution) { + properties[ResourceResolutionConstants.RESOURCE_RESOLUTION_INPUT_OCCURRENCE] = j + } val result = resourceResolutionService.resolveResources( bluePrintRuntimeService, @@ -119,8 +125,8 @@ open class ResourceResolutionComponent(private val resourceResolutionService: Re stepName ) - // provide indexed result in output if we have multiple resolution - if (occurrence != 1) { + // provide indexed result in output if we have multiple resolution. + if (resolutionsToPerform != 1) { jsonResponse.set<JsonNode>(j.toString(), result.templateMap.asJsonNode()) assignmentMap.set<JsonNode>(j.toString(), result.assignmentMap.asJsonNode()) } else { diff --git a/ms/blueprintsprocessor/functions/resource-resolution/src/main/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/functions/resource/resolution/ResourceResolutionConstants.kt b/ms/blueprintsprocessor/functions/resource-resolution/src/main/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/functions/resource/resolution/ResourceResolutionConstants.kt index e2a8920f5..9f22b8134 100644 --- a/ms/blueprintsprocessor/functions/resource-resolution/src/main/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/functions/resource/resolution/ResourceResolutionConstants.kt +++ b/ms/blueprintsprocessor/functions/resource-resolution/src/main/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/functions/resource/resolution/ResourceResolutionConstants.kt @@ -27,6 +27,7 @@ object ResourceResolutionConstants { const val FILE_NAME_RESOURCE_DEFINITION_TYPES = "resources_definition_types.json" const val RESOURCE_RESOLUTION_INPUT_RESOLUTION_KEY = "resolution-key" const val RESOURCE_RESOLUTION_INPUT_STORE_RESULT = "store-result" + const val RESOURCE_RESOLUTION_INPUT_FORCE_RESOLUTION = "force-resolution" const val RESOURCE_RESOLUTION_INPUT_OCCURRENCE = "occurrence" const val RESOURCE_RESOLUTION_INPUT_RESOURCE_ID = "resource-id" const val RESOURCE_RESOLUTION_INPUT_RESOURCE_TYPE = "resource-type" 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 df07b8e03..a3c137807 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 @@ -199,7 +199,9 @@ open class ResourceResolutionServiceImpl( val artifactTemplate = "$artifactPrefix-template" // Resource Assignment Artifact Definition Name val artifactMapping = "$artifactPrefix-mapping" + val forceResolution = isForceResolution(properties) + val propertiesMutableMap = properties.toMutableMap() log.info("Resolving resource with resource assignment artifact($artifactMapping)") val resourceAssignmentContent = @@ -211,12 +213,27 @@ open class ResourceResolutionServiceImpl( ?: throw BluePrintProcessorException("couldn't get Dictionary Definitions") if (isToStore(properties)) { - val existingResourceResolution = isNewResolution(bluePrintRuntimeService, properties, artifactPrefix) + val alwaysPerformNewResolution = properties[ResourceResolutionConstants.RESOURCE_RESOLUTION_INPUT_OCCURRENCE] as Int <= 0 + val existingResourceResolution = if (alwaysPerformNewResolution) { + val occurrence = findNextOccurrence(bluePrintRuntimeService, properties, artifactPrefix) + log.info("Always perform new resolutions - next occurrence: $occurrence") + propertiesMutableMap[ResourceResolutionConstants.RESOURCE_RESOLUTION_INPUT_OCCURRENCE] = occurrence + // Since we are performing new resolution, simply pass empty list. + emptyList() + } else { + isNewResolution(bluePrintRuntimeService, properties, artifactPrefix) + } if (existingResourceResolution.isNotEmpty()) { - updateResourceAssignmentWithExisting( - bluePrintRuntimeService as ResourceAssignmentRuntimeService, - existingResourceResolution, resourceAssignments - ) + if (forceResolution) { + resourceResolutionDBService.deleteResourceResolutionList(existingResourceResolution) + log.info("Force resolution is enabled - will resolve all resources.") + } else { + updateResourceAssignmentWithExisting( + bluePrintRuntimeService as ResourceAssignmentRuntimeService, + existingResourceResolution, resourceAssignments + ) + log.info("Force resolution is disabled - will resolve all resources not already resolved.") + } } } @@ -230,7 +247,7 @@ open class ResourceResolutionServiceImpl( resourceDefinitions, resourceAssignments, artifactPrefix, - properties + propertiesMutableMap ) val resolutionSummary = properties.getOrDefault( @@ -264,7 +281,7 @@ open class ResourceResolutionServiceImpl( } if (isToStore(properties)) { - templateResolutionDBService.write(properties, resolvedContent, bluePrintRuntimeService, artifactPrefix) + templateResolutionDBService.write(propertiesMutableMap, resolvedContent, bluePrintRuntimeService, artifactPrefix) log.info("Template resolution saved into database successfully : ($properties)") } @@ -407,6 +424,10 @@ open class ResourceResolutionServiceImpl( properties[ResourceResolutionConstants.RESOURCE_RESOLUTION_INPUT_STORE_RESULT] as Boolean } + private fun isForceResolution(properties: Map<String, Any>): Boolean = + properties.containsKey(ResourceResolutionConstants.RESOURCE_RESOLUTION_INPUT_FORCE_RESOLUTION) && + properties[ResourceResolutionConstants.RESOURCE_RESOLUTION_INPUT_FORCE_RESOLUTION] as Boolean + // Check whether resolution already exist in the database for the specified resolution-key or resourceId/resourceType private suspend fun isNewResolution( bluePrintRuntimeService: BluePrintRuntimeService<*>, @@ -428,7 +449,7 @@ open class ResourceResolutionServiceImpl( ) if (existingResourceAssignments.isNotEmpty()) { log.info( - "Resolution with resolutionKey=($resolutionKey) already exist - will resolve all resources not already resolved.", + "Resolution with resolutionKey=($resolutionKey) already exist", resolutionKey ) } @@ -445,8 +466,7 @@ 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" ) } return existingResourceAssignments @@ -480,7 +500,7 @@ open class ResourceResolutionServiceImpl( } } - // Comparision between what we have in the database vs what we have to assign. + // Comparison 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 && @@ -499,4 +519,48 @@ open class ResourceResolutionServiceImpl( properties[ResourceResolutionConstants.RESOURCE_RESOLUTION_INPUT_OCCURRENCE].asJsonPrimitive() ) } + + /** + * This method returns 'occurrence' required to persist new resource resolution. + * + * @param bluePrintRuntimeService + * @param properties + * @param artifactPrefix + */ + private suspend fun findNextOccurrence( + bluePrintRuntimeService: BluePrintRuntimeService<*>, + properties: Map<String, Any>, + artifactPrefix: String + ): Int { + val metadata = bluePrintRuntimeService.bluePrintContext().metadata!! + val blueprintVersion = metadata[BluePrintConstants.METADATA_TEMPLATE_VERSION]!! + val blueprintName = metadata[BluePrintConstants.METADATA_TEMPLATE_NAME]!! + val resolutionKey = properties[ResourceResolutionConstants.RESOURCE_RESOLUTION_INPUT_RESOLUTION_KEY] as String + val resourceId = properties[ResourceResolutionConstants.RESOURCE_RESOLUTION_INPUT_RESOURCE_ID] as String + val resourceType = properties[ResourceResolutionConstants.RESOURCE_RESOLUTION_INPUT_RESOURCE_TYPE] as String + + // This should not happen since the request has already been validated but worth to check it here as well. + if (resourceType.isEmpty() && resourceId.isEmpty() && resolutionKey.isEmpty()) { + throw BluePrintProcessorException( + "Can't proceed to get next occurrence: " + + "Either provide a resolution-key OR combination of resource-id and resource-type" + ) + } + + if (resolutionKey.isNotEmpty()) { + return resourceResolutionDBService.findNextOccurrenceByResolutionKeyAndBlueprintNameAndBlueprintVersionAndArtifactName( + resolutionKey, + blueprintName, + blueprintVersion, + artifactPrefix + ) + } else { + return resourceResolutionDBService.findNextOccurrenceByBlueprintNameAndBlueprintVersionAndResourceIdAndResourceType( + blueprintName, + blueprintVersion, + resourceId, + resourceType + ) + } + } } diff --git a/ms/blueprintsprocessor/functions/resource-resolution/src/main/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/functions/resource/resolution/db/ResourceResolutionDBService.kt b/ms/blueprintsprocessor/functions/resource-resolution/src/main/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/functions/resource/resolution/db/ResourceResolutionDBService.kt index 5958c7899..ed9e6d1d6 100644 --- a/ms/blueprintsprocessor/functions/resource-resolution/src/main/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/functions/resource/resolution/db/ResourceResolutionDBService.kt +++ b/ms/blueprintsprocessor/functions/resource-resolution/src/main/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/functions/resource/resolution/db/ResourceResolutionDBService.kt @@ -90,7 +90,7 @@ class ResourceResolutionDBService(private val resourceResolutionRepository: Reso artifactPrefix: String, resolutionKey: String, name: String - ): ResourceResolution = withContext(Dispatchers.IO) { + ): ResourceResolution? = withContext(Dispatchers.IO) { resourceResolutionRepository.findByResolutionKeyAndBlueprintNameAndBlueprintVersionAndArtifactNameAndName( resolutionKey, @@ -116,6 +116,87 @@ class ResourceResolutionDBService(private val resourceResolutionRepository: Reso ) } + /** + * This returns the resolutions of first N 'occurrences'. + * + * @param blueprintName + * @param blueprintVersion + * @param artifactPrefix + * @param resolutionKey + * @param firstN + */ + suspend fun findFirstNOccurrences( + blueprintName: String, + blueprintVersion: String, + artifactPrefix: String, + resolutionKey: String, + firstN: Int + ): Map<Int, List<ResourceResolution>> = withContext(Dispatchers.IO) { + + resourceResolutionRepository.findFirstNOccurrences( + resolutionKey, + blueprintName, + blueprintVersion, + artifactPrefix, + firstN + ).groupBy(ResourceResolution::occurrence).toSortedMap(reverseOrder()) + } + + /** + * This returns the resolutions of last N 'occurrences'. + * + * @param blueprintName + * @param blueprintVersion + * @param artifactPrefix + * @param resolutionKey + * @param lastN + */ + suspend fun findLastNOccurrences( + blueprintName: String, + blueprintVersion: String, + artifactPrefix: String, + resolutionKey: String, + lastN: Int + ): Map<Int, List<ResourceResolution>> = withContext(Dispatchers.IO) { + + resourceResolutionRepository.findLastNOccurrences( + resolutionKey, + blueprintName, + blueprintVersion, + artifactPrefix, + lastN + ).groupBy(ResourceResolution::occurrence).toSortedMap(reverseOrder()) + } + + /** + * This returns the resolutions with 'occurrence' value between begin and end. + * + * @param blueprintName + * @param blueprintVersion + * @param artifactPrefix + * @param resolutionKey + * @param begin + * @param end + */ + suspend fun findOccurrencesWithinRange( + blueprintName: String, + blueprintVersion: String, + artifactPrefix: String, + resolutionKey: String, + begin: Int, + end: Int + ): Map<Int, List<ResourceResolution>> = withContext(Dispatchers.IO) { + + resourceResolutionRepository.findOccurrencesWithinRange( + resolutionKey, + blueprintName, + blueprintVersion, + artifactPrefix, + begin, + end + ).groupBy(ResourceResolution::occurrence).toSortedMap(reverseOrder()) + } + suspend fun readWithResourceIdAndResourceType( blueprintName: String, blueprintVersion: String, @@ -221,4 +302,60 @@ class ResourceResolutionDBService(private val resourceResolutionRepository: Reso resolutionKey ) } + + suspend fun deleteResourceResolutionList(listResourceResolution: List<ResourceResolution>) = withContext(Dispatchers.IO) { + try { + resourceResolutionRepository.deleteInBatch(listResourceResolution) + } catch (ex: Exception) { + throw BluePrintException("Failed to batch delete resource resolution", ex) + } + } + + /** + * This method returns the (highest occurrence + 1) of resource resolutions if present in DB, returns 1 otherwise. + * The 'occurrence' is used to persist new resource resolution in the DB. + * + * @param resolutionKey + * @param blueprintName + * @param blueprintVersion + * @param artifactPrefix + */ + suspend fun findNextOccurrenceByResolutionKeyAndBlueprintNameAndBlueprintVersionAndArtifactName( + resolutionKey: String, + blueprintName: String, + blueprintVersion: String, + artifactPrefix: String + ) = withContext(Dispatchers.IO) { + val maxOccurrence = resourceResolutionRepository.findMaxOccurrenceByResolutionKeyAndBlueprintNameAndBlueprintVersionAndArtifactName( + resolutionKey, + blueprintName, + blueprintVersion, + artifactPrefix + ) + maxOccurrence?.inc() ?: 1 + } + + /** + * This method returns the (highest occurrence + 1) of resource resolutions if present in DB, returns 1 otherwise. + * The 'occurrence' is used to persist new resource resolution in the DB. + * + * @param blueprintName + * @param blueprintVersion + * @param resourceId + * @param resourceType + */ + suspend fun findNextOccurrenceByBlueprintNameAndBlueprintVersionAndResourceIdAndResourceType( + blueprintName: String, + blueprintVersion: String, + resourceId: String, + resourceType: String + ) = withContext(Dispatchers.IO) { + val maxOccurrence = resourceResolutionRepository.findMaxOccurrenceByBlueprintNameAndBlueprintVersionAndResourceIdAndResourceType( + blueprintName, + blueprintVersion, + resourceId, + resourceType + ) + maxOccurrence?.inc() ?: 1 + } } diff --git a/ms/blueprintsprocessor/functions/resource-resolution/src/main/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/functions/resource/resolution/db/ResourceResolutionRepository.kt b/ms/blueprintsprocessor/functions/resource-resolution/src/main/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/functions/resource/resolution/db/ResourceResolutionRepository.kt index c2d630e5e..4b707b04e 100644 --- a/ms/blueprintsprocessor/functions/resource-resolution/src/main/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/functions/resource/resolution/db/ResourceResolutionRepository.kt +++ b/ms/blueprintsprocessor/functions/resource-resolution/src/main/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/functions/resource/resolution/db/ResourceResolutionRepository.kt @@ -16,19 +16,111 @@ package org.onap.ccsdk.cds.blueprintsprocessor.functions.resource.resolution.db import org.springframework.data.jpa.repository.JpaRepository +import org.springframework.data.jpa.repository.Query +import org.springframework.data.repository.query.Param import org.springframework.stereotype.Repository import javax.transaction.Transactional @Repository interface ResourceResolutionRepository : JpaRepository<ResourceResolution, String> { + @Query( + value = "SELECT * FROM RESOURCE_RESOLUTION WHERE resolution_key = :key AND blueprint_name = :blueprintName AND blueprint_version = :blueprintVersion AND artifact_name = :artifactName AND name = :name ORDER BY occurrence DESC, creation_date DESC LIMIT 1", + nativeQuery = true + ) fun findByResolutionKeyAndBlueprintNameAndBlueprintVersionAndArtifactNameAndName( - key: String, - blueprintName: String?, - blueprintVersion: String?, - artifactName: String, - name: String - ): ResourceResolution + @Param("key")key: String, + @Param("blueprintName")blueprintName: String, + @Param("blueprintVersion")blueprintVersion: String, + @Param("artifactName")artifactName: String, + @Param("name")name: String + ): ResourceResolution? + + @Query( + value = """ + SELECT * FROM RESOURCE_RESOLUTION WHERE resolution_key = :key + AND blueprint_name = :blueprintName AND blueprint_version = :blueprintVersion + AND artifact_name = :artifactName AND occurrence <= :firstN + """, + nativeQuery = true + ) + fun findFirstNOccurrences( + @Param("key")key: String, + @Param("blueprintName")blueprintName: String, + @Param("blueprintVersion")blueprintVersion: String, + @Param("artifactName")artifactName: String, + @Param("firstN")begin: Int + ): List<ResourceResolution> + + @Query( + value = """ + SELECT * FROM RESOURCE_RESOLUTION WHERE resolution_key = :key + AND blueprint_name = :blueprintName AND blueprint_version = :blueprintVersion + AND artifact_name = :artifactName + AND occurrence > ( + select max(occurrence) - :lastN from RESOURCE_RESOLUTION + WHERE resolution_key = :key AND blueprint_name = :blueprintName + AND blueprint_version = :blueprintVersion AND artifact_name = :artifactName + ) + ORDER BY occurrence DESC, creation_date DESC + """, + nativeQuery = true + ) + fun findLastNOccurrences( + @Param("key")key: String, + @Param("blueprintName")blueprintName: String, + @Param("blueprintVersion")blueprintVersion: String, + @Param("artifactName")artifactName: String, + @Param("lastN")begin: Int + ): List<ResourceResolution> + + @Query( + value = """ + SELECT * FROM RESOURCE_RESOLUTION WHERE resolution_key = :key + AND blueprint_name = :blueprintName AND blueprint_version = :blueprintVersion + AND artifact_name = :artifactName AND occurrence BETWEEN :begin AND :end + ORDER BY occurrence DESC, creation_date DESC + """, + nativeQuery = true + ) + fun findOccurrencesWithinRange( + @Param("key")key: String, + @Param("blueprintName")blueprintName: String, + @Param("blueprintVersion")blueprintVersion: String, + @Param("artifactName")artifactName: String, + @Param("begin")begin: Int, + @Param("end")end: Int + ): List<ResourceResolution> + + @Query( + value = """ + SELECT max(occurrence) FROM RESOURCE_RESOLUTION WHERE resolution_key = :key + AND blueprint_name = :blueprintName AND blueprint_version = :blueprintVersion + AND artifact_name = :artifactName + """, + nativeQuery = true + ) + fun findMaxOccurrenceByResolutionKeyAndBlueprintNameAndBlueprintVersionAndArtifactName( + @Param("key")key: String, + @Param("blueprintName")blueprintName: String, + @Param("blueprintVersion")blueprintVersion: String, + @Param("artifactName")artifactName: String + ): Int? + + @Query( + value = """ + SELECT max(occurrence) FROM RESOURCE_RESOLUTION WHERE blueprint_name = :blueprintName + AND blueprint_version = :blueprintVersion AND resource_id = :resourceId + AND resource_type = :resourceType + """, + nativeQuery = true + ) + fun findMaxOccurrenceByBlueprintNameAndBlueprintVersionAndResourceIdAndResourceType( + @Param("blueprintName")blueprintName: String, + @Param("blueprintVersion")blueprintVersion: String, + @Param("resourceId")resourceId: String, + @Param("resourceType")resourceType: String + ): Int? fun findByResolutionKeyAndBlueprintNameAndBlueprintVersionAndArtifactName( resolutionKey: String, diff --git a/ms/blueprintsprocessor/functions/resource-resolution/src/main/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/functions/resource/resolution/db/TemplateResolutionRepository.kt b/ms/blueprintsprocessor/functions/resource-resolution/src/main/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/functions/resource/resolution/db/TemplateResolutionRepository.kt index 3df613745..38d61e78d 100644 --- a/ms/blueprintsprocessor/functions/resource-resolution/src/main/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/functions/resource/resolution/db/TemplateResolutionRepository.kt +++ b/ms/blueprintsprocessor/functions/resource-resolution/src/main/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/functions/resource/resolution/db/TemplateResolutionRepository.kt @@ -42,6 +42,71 @@ interface TemplateResolutionRepository : JpaRepository<TemplateResolution, Strin ): TemplateResolution? @Query( + value = """ + SELECT * FROM TEMPLATE_RESOLUTION WHERE resolution_key = :key + AND blueprint_name = :blueprintName AND blueprint_version = :blueprintVersion + AND artifact_name = :artifactName + AND occurrence <= :firstN + """, + nativeQuery = true + ) + fun findFirstNOccurrences( + @Param("key")key: String, + @Param("blueprintName")blueprintName: String, + @Param("blueprintVersion")blueprintVersion: String, + @Param("artifactName")artifactName: String, + @Param("firstN")begin: Int + ): List<TemplateResolution> + + @Query( + value = """ + SELECT * FROM TEMPLATE_RESOLUTION WHERE resolution_key = :key + AND blueprint_name = :blueprintName AND blueprint_version = :blueprintVersion + AND artifact_name = :artifactName + AND occurrence > ( + select max(occurrence) - :lastN from RESOURCE_RESOLUTION + WHERE resolution_key = :key + AND blueprint_name = :blueprintName AND blueprint_version = :blueprintVersion + AND artifact_name = :artifactName) + ORDER BY occurrence DESC, creation_date DESC + """, + nativeQuery = true + ) + fun findLastNOccurrences( + @Param("key")key: String, + @Param("blueprintName")blueprintName: String, + @Param("blueprintVersion")blueprintVersion: String, + @Param("artifactName")artifactName: String, + @Param("lastN")begin: Int + ): List<TemplateResolution> + + @Query( + value = """ + SELECT * FROM TEMPLATE_RESOLUTION WHERE resolution_key = :key + AND blueprint_name = :blueprintName AND blueprint_version = :blueprintVersion + AND artifact_name = :artifactName + AND occurrence BETWEEN :begin AND :end + ORDER BY occurrence DESC, creation_date DESC + """, + nativeQuery = true + ) + fun findOccurrencesWithinRange( + @Param("key")key: String, + @Param("blueprintName")blueprintName: String, + @Param("blueprintVersion")blueprintVersion: String, + @Param("artifactName")artifactName: String, + @Param("begin")begin: Int, + @Param("end")end: Int + ): List<TemplateResolution> + + fun findByResolutionKeyAndBlueprintNameAndBlueprintVersionAndArtifactName( + resolutionKey: String, + blueprintName: String, + blueprintVersion: String, + artifactPrefix: String + ): List<TemplateResolution> + + @Query( "select tr.resolutionKey from TemplateResolution tr where tr.blueprintName = :blueprintName and tr.blueprintVersion = :blueprintVersion and tr.artifactName = :artifactName and tr.occurrence = :occurrence" ) fun findResolutionKeysByBlueprintNameAndBlueprintVersionAndArtifactNameAndOccurrence( diff --git a/ms/blueprintsprocessor/functions/resource-resolution/src/main/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/functions/resource/resolution/db/TemplateResolutionService.kt b/ms/blueprintsprocessor/functions/resource-resolution/src/main/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/functions/resource/resolution/db/TemplateResolutionService.kt index 8789ade99..906aedf09 100644 --- a/ms/blueprintsprocessor/functions/resource-resolution/src/main/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/functions/resource/resolution/db/TemplateResolutionService.kt +++ b/ms/blueprintsprocessor/functions/resource-resolution/src/main/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/functions/resource/resolution/db/TemplateResolutionService.kt @@ -241,4 +241,99 @@ class TemplateResolutionService(private val templateResolutionRepository: Templa throw BluePrintException("Failed to store resource api result.", ex) } } + /** + * This returns the templates of first N 'occurrences'. + * + * @param blueprintName + * @param blueprintVersion + * @param artifactPrefix + * @param resolutionKey + * @param firstN + */ + suspend fun findFirstNOccurrences( + blueprintName: String, + blueprintVersion: String, + artifactPrefix: String, + resolutionKey: String, + firstN: Int + ): Map<Int, List<TemplateResolution>> = withContext(Dispatchers.IO) { + + templateResolutionRepository.findFirstNOccurrences( + resolutionKey, + blueprintName, + blueprintVersion, + artifactPrefix, + firstN + ).groupBy(TemplateResolution::occurrence).toSortedMap(reverseOrder()) + } + + /** + * This returns the templates of last N 'occurrences'. + * + * @param blueprintName + * @param blueprintVersion + * @param artifactPrefix + * @param resolutionKey + * @param lastN + */ + suspend fun findLastNOccurrences( + blueprintName: String, + blueprintVersion: String, + artifactPrefix: String, + resolutionKey: String, + lastN: Int + ): Map<Int, List<TemplateResolution>> = withContext(Dispatchers.IO) { + + templateResolutionRepository.findLastNOccurrences( + resolutionKey, + blueprintName, + blueprintVersion, + artifactPrefix, + lastN + ).groupBy(TemplateResolution::occurrence).toSortedMap(reverseOrder()) + } + + /** + * This returns the templates with 'occurrence' value between begin and end. + * + * @param blueprintName + * @param blueprintVersion + * @param artifactPrefix + * @param resolutionKey + * @param begin + * @param end + */ + suspend fun findOccurrencesWithinRange( + blueprintName: String, + blueprintVersion: String, + artifactPrefix: String, + resolutionKey: String, + begin: Int, + end: Int + ): Map<Int, List<TemplateResolution>> = withContext(Dispatchers.IO) { + + templateResolutionRepository.findOccurrencesWithinRange( + resolutionKey, + blueprintName, + blueprintVersion, + artifactPrefix, + begin, + end + ).groupBy(TemplateResolution::occurrence).toSortedMap(reverseOrder()) + } + + suspend fun readWithResolutionKey( + blueprintName: String, + blueprintVersion: String, + artifactPrefix: String, + resolutionKey: String + ): List<TemplateResolution> = withContext(Dispatchers.IO) { + + templateResolutionRepository.findByResolutionKeyAndBlueprintNameAndBlueprintVersionAndArtifactName( + resolutionKey, + blueprintName, + blueprintVersion, + artifactPrefix + ) + } } diff --git a/ms/blueprintsprocessor/functions/resource-resolution/src/test/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/functions/resource/resolution/ResourceResolutionServiceTest.kt b/ms/blueprintsprocessor/functions/resource-resolution/src/test/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/functions/resource/resolution/ResourceResolutionServiceTest.kt index 3d2a9755c..a801a7eb9 100644 --- a/ms/blueprintsprocessor/functions/resource-resolution/src/test/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/functions/resource/resolution/ResourceResolutionServiceTest.kt +++ b/ms/blueprintsprocessor/functions/resource-resolution/src/test/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/functions/resource/resolution/ResourceResolutionServiceTest.kt @@ -153,6 +153,195 @@ class ResourceResolutionServiceTest { } } + /** + * Always perform new resolution even if resolution exists in the database. + */ + @Test + @Throws(Exception::class) + fun testResolveResourceAlwaysPerformNewResolution() { + runBlocking { + // Occurrence <= 0 indicates to perform new resolution even if resolution exists in the database. + props[ResourceResolutionConstants.RESOURCE_RESOLUTION_INPUT_OCCURRENCE] = -1 + Assert.assertNotNull("failed to create ResourceResolutionService", resourceResolutionService) + + val bluePrintRuntimeService = BluePrintMetadataUtils.getBluePrintRuntime( + "1234", + "./../../../../components/model-catalog/blueprint-model/test-blueprint/baseconfiguration" + ) + + // Request#1 + val executionServiceInput = + JacksonUtils.readValueFromClassPathFile( + "payload/requests/sample-resourceresolution-request.json", + ExecutionServiceInput::class.java + )!! + + val resourceAssignmentRuntimeService = + ResourceAssignmentUtils.transformToRARuntimeService( + bluePrintRuntimeService, + "testResolveResource" + ) + + // Prepare inputs from Request#1 + PayloadUtils.prepareInputsFromWorkflowPayload( + bluePrintRuntimeService, + executionServiceInput.payload, + "resource-assignment" + ) + + // Resolve resources as per Request#1 + resourceResolutionService.resolveResources( + resourceAssignmentRuntimeService, + "resource-assignment", + "baseconfig", + props + ) + + // Request#2 + val executionServiceInput2 = + JacksonUtils.readValueFromClassPathFile( + "payload/requests/sample-resourceresolution-request2.json", + ExecutionServiceInput::class.java + )!! + + // Prepare inputs from Request#2 + PayloadUtils.prepareInputsFromWorkflowPayload( + bluePrintRuntimeService, + executionServiceInput2.payload, + "resource-assignment" + ) + + // Resolve resources as per Request#2 + resourceResolutionService.resolveResources( + resourceAssignmentRuntimeService, + "resource-assignment", + "baseconfig", + props + ) + }.let { (templateMap, assignmentList) -> + assertEquals("This is Sample Velocity Template", templateMap) + + val assignmentListForRequest1 = mutableListOf( + "service-instance-id" to "siid_1234", + "vnf-id" to "vnf_1234", + "vnf_name" to "temp_vnf" + ) + val assignmentListForRequest2 = mutableListOf( + "service-instance-id" to "siid_new_resolution", + "vnf-id" to "vnf_new_resolution", + "vnf_name" to "temp_vnf_new_resolution" + ) + assertEquals(assignmentListForRequest1.size, assignmentList.size) + assertEquals(assignmentListForRequest2.size, assignmentList.size) + + // AlwaysPerformNewResolution use case - resolution request #2 should returns the resolution as per + // assignmentListForRequest2 since new resolution is performed. + var areEqual = assignmentListForRequest1.zip(assignmentList).all { (it1, it2) -> + it1.first == it2.name && it1.second == it2.property?.value?.asText() ?: null + } + assertEquals(false, areEqual) + + areEqual = assignmentListForRequest2.zip(assignmentList).all { (it1, it2) -> + it1.first == it2.name && it1.second == it2.property?.value?.asText() ?: null + } + assertEquals(true, areEqual) + } + } + + /** + * Don't perform new resolution in case resolution already exists in the database. + */ + @Test + @Throws(Exception::class) + fun testResolveResourceNoNewResolution() { + runBlocking { + // Occurrence > 0 indicates to not perform new resolution if resolution exists in the database. + props[ResourceResolutionConstants.RESOURCE_RESOLUTION_INPUT_OCCURRENCE] = 1 + Assert.assertNotNull("failed to create ResourceResolutionService", resourceResolutionService) + + val bluePrintRuntimeService = BluePrintMetadataUtils.getBluePrintRuntime( + "1234", + "./../../../../components/model-catalog/blueprint-model/test-blueprint/baseconfiguration" + ) + + // Request#1 + val executionServiceInput = + JacksonUtils.readValueFromClassPathFile( + "payload/requests/sample-resourceresolution-request.json", + ExecutionServiceInput::class.java + )!! + + val resourceAssignmentRuntimeService = + ResourceAssignmentUtils.transformToRARuntimeService( + bluePrintRuntimeService, + "testResolveResource" + ) + + // Prepare inputs from Request#1 + PayloadUtils.prepareInputsFromWorkflowPayload( + bluePrintRuntimeService, + executionServiceInput.payload, + "resource-assignment" + ) + // Resolve resources as per Request#1 + resourceResolutionService.resolveResources( + resourceAssignmentRuntimeService, + "resource-assignment", + "baseconfig", + props + ) + + // Request#2 + val executionServiceInput2 = + JacksonUtils.readValueFromClassPathFile( + "payload/requests/sample-resourceresolution-request2.json", + ExecutionServiceInput::class.java + )!! + + // Prepare inputs from Request#2 + PayloadUtils.prepareInputsFromWorkflowPayload( + bluePrintRuntimeService, + executionServiceInput2.payload, + "resource-assignment" + ) + + // Resolve resources as per Request#2 + resourceResolutionService.resolveResources( + resourceAssignmentRuntimeService, + "resource-assignment", + "baseconfig", + props + ) + }.let { (templateMap, assignmentList) -> + assertEquals("This is Sample Velocity Template", templateMap) + + val assignmentListForRequest1 = mutableListOf( + "service-instance-id" to "siid_1234", + "vnf-id" to "vnf_1234", + "vnf_name" to "temp_vnf" + ) + val assignmentListForRequest2 = mutableListOf( + "service-instance-id" to "siid_new_resolution", + "vnf-id" to "vnf_new_resolution", + "vnf_name" to "temp_vnf_new_resolution" + ) + assertEquals(assignmentListForRequest1.size, assignmentList.size) + assertEquals(assignmentListForRequest2.size, assignmentList.size) + + // NoNewResolution use case - resolution for request #2 returns the same resolution as + // assignmentListForRequest1 since no new resolution is/was actually performed. + var areEqual = assignmentListForRequest1.zip(assignmentList).all { (it1, it2) -> + it1.first == it2.name && it1.second == it2.property?.value?.asText() ?: null + } + assertEquals(true, areEqual) + + areEqual = assignmentListForRequest2.zip(assignmentList).all { (it1, it2) -> + it1.first == it2.name && it1.second == it2.property?.value?.asText() ?: null + } + assertEquals(false, areEqual) + } + } + @Test @Throws(Exception::class) fun testResolveResources() { diff --git a/ms/blueprintsprocessor/functions/resource-resolution/src/test/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/functions/resource/resolution/db/ResourceResolutionDBServiceTest.kt b/ms/blueprintsprocessor/functions/resource-resolution/src/test/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/functions/resource/resolution/db/ResourceResolutionDBServiceTest.kt index fa59876a9..8d4109fcf 100644 --- a/ms/blueprintsprocessor/functions/resource-resolution/src/test/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/functions/resource/resolution/db/ResourceResolutionDBServiceTest.kt +++ b/ms/blueprintsprocessor/functions/resource-resolution/src/test/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/functions/resource/resolution/db/ResourceResolutionDBServiceTest.kt @@ -30,6 +30,7 @@ import org.onap.ccsdk.cds.controllerblueprints.core.service.DefaultBluePrintRunt import org.onap.ccsdk.cds.controllerblueprints.resource.dict.ResourceAssignment import org.springframework.dao.EmptyResultDataAccessException import kotlin.test.assertEquals +import kotlin.test.assertNotEquals open class ResourceResolutionDBServiceTest { @@ -158,9 +159,11 @@ open class ResourceResolutionDBServiceTest { resourceResolutionDBService.readValue( blueprintName, blueprintVersion, artifactPrefix, resolutionKey, "bob" ) - - assertEquals(rr.name, res.name) - assertEquals(rr.value, res.value) + assertNotEquals(res, null, "resource resolution failed") + if (res != null) { + assertEquals(rr.name, res.name) + assertEquals(rr.value, res.value) + } } } @@ -184,6 +187,75 @@ open class ResourceResolutionDBServiceTest { } @Test + fun findFirstNOccurrencesTest() { + props[ResourceResolutionConstants.RESOURCE_RESOLUTION_INPUT_OCCURRENCE] = occurrence + val rr1 = ResourceResolution() + val rr2 = ResourceResolution() + val list = listOf(rr1, rr2) + every { + resourceResolutionRepository.findFirstNOccurrences( + any(), any(), any(), any(), 1 + ) + } returns list + runBlocking { + val res = + resourceResolutionDBService.findFirstNOccurrences( + blueprintName, blueprintVersion, artifactPrefix, resolutionKey, 1 + ) + assertEquals(false, res.isEmpty(), "find first N occurrences test failed") + assertEquals(1, res.size) + assertNotEquals(null, res[0]) + res[0]?.let { assertEquals(2, it.size) } + } + } + + @Test + fun findLastNOccurrencesTest() { + props[ResourceResolutionConstants.RESOURCE_RESOLUTION_INPUT_OCCURRENCE] = occurrence + val rr1 = ResourceResolution() + val rr2 = ResourceResolution() + val list = listOf(rr1, rr2) + every { + resourceResolutionRepository.findLastNOccurrences( + any(), any(), any(), any(), 1 + ) + } returns list + runBlocking { + val res = + resourceResolutionDBService.findLastNOccurrences( + blueprintName, blueprintVersion, artifactPrefix, resolutionKey, 1 + ) + assertEquals(false, res.isEmpty(), "find last N occurrences test failed") + assertEquals(1, res.size) + assertNotEquals(null, res[0]) + res[0]?.let { assertEquals(2, it.size) } + } + } + + @Test + fun findOccurrencesWithinRangeTest() { + props[ResourceResolutionConstants.RESOURCE_RESOLUTION_INPUT_OCCURRENCE] = occurrence + val rr1 = ResourceResolution() + val rr2 = ResourceResolution() + val list = listOf(rr1, rr2) + every { + resourceResolutionRepository.findOccurrencesWithinRange( + any(), any(), any(), any(), 0, 1 + ) + } returns list + runBlocking { + val res = + resourceResolutionDBService.findOccurrencesWithinRange( + blueprintName, blueprintVersion, artifactPrefix, resolutionKey, 0, 1 + ) + assertEquals(false, res.isEmpty(), "find occurrences within a range test failed") + assertEquals(1, res.size) + assertNotEquals(null, res[0]) + res[0]?.let { assertEquals(2, it.size) } + } + } + + @Test fun readWithResourceIdAndResourceTypeTest() { val rr1 = ResourceResolution() val rr2 = ResourceResolution() diff --git a/ms/blueprintsprocessor/functions/resource-resolution/src/test/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/functions/resource/resolution/db/TemplateResolutionServiceTest.kt b/ms/blueprintsprocessor/functions/resource-resolution/src/test/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/functions/resource/resolution/db/TemplateResolutionServiceTest.kt index 71d895574..a2550ed5f 100644 --- a/ms/blueprintsprocessor/functions/resource-resolution/src/test/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/functions/resource/resolution/db/TemplateResolutionServiceTest.kt +++ b/ms/blueprintsprocessor/functions/resource-resolution/src/test/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/functions/resource/resolution/db/TemplateResolutionServiceTest.kt @@ -12,6 +12,7 @@ import org.onap.ccsdk.cds.controllerblueprints.core.service.BluePrintContext import org.onap.ccsdk.cds.controllerblueprints.core.service.DefaultBluePrintRuntimeService import org.springframework.dao.EmptyResultDataAccessException import kotlin.test.assertEquals +import kotlin.test.assertNotEquals class TemplateResolutionServiceTest { @@ -96,6 +97,75 @@ class TemplateResolutionServiceTest { } @Test + fun findFirstNOccurrencesTest() { + props[ResourceResolutionConstants.RESOURCE_RESOLUTION_INPUT_OCCURRENCE] = occurrence + val tr1 = TemplateResolution() + val tr2 = TemplateResolution() + val list = listOf(tr1, tr2) + every { + templateResolutionRepository.findFirstNOccurrences( + any(), any(), any(), any(), 1 + ) + } returns list + runBlocking { + val res = + templateResolutionService.findFirstNOccurrences( + blueprintName, blueprintVersion, artifactPrefix, resolutionKey, 1 + ) + assertEquals(false, res.isEmpty(), "find first N occurrences test failed") + assertEquals(1, res.size) + assertNotEquals(null, res[1]) + res[1]?.let { assertEquals(2, it.size) } + } + } + + @Test + fun findLastNOccurrencesTest() { + props[ResourceResolutionConstants.RESOURCE_RESOLUTION_INPUT_OCCURRENCE] = occurrence + val tr1 = TemplateResolution() + val tr2 = TemplateResolution() + val list = listOf(tr1, tr2) + every { + templateResolutionRepository.findLastNOccurrences( + any(), any(), any(), any(), 1 + ) + } returns list + runBlocking { + val res = + templateResolutionService.findLastNOccurrences( + blueprintName, blueprintVersion, artifactPrefix, resolutionKey, 1 + ) + assertEquals(false, res.isEmpty(), "find last N occurrences test failed") + assertEquals(1, res.size) + assertNotEquals(null, res[1]) + res[1]?.let { assertEquals(2, it.size) } + } + } + + @Test + fun findOccurrencesWithinRangeTest() { + props[ResourceResolutionConstants.RESOURCE_RESOLUTION_INPUT_OCCURRENCE] = occurrence + val tr1 = TemplateResolution() + val tr2 = TemplateResolution() + val list = listOf(tr1, tr2) + every { + templateResolutionRepository.findOccurrencesWithinRange( + any(), any(), any(), any(), 0, 1 + ) + } returns list + runBlocking { + val res = + templateResolutionService.findOccurrencesWithinRange( + blueprintName, blueprintVersion, artifactPrefix, resolutionKey, 0, 1 + ) + assertEquals(false, res.isEmpty(), "find occurrences within a range test failed") + assertEquals(1, res.size) + assertNotEquals(null, res[1]) + res[1]?.let { assertEquals(2, it.size) } + } + } + + @Test fun writeWithResolutionKeyExistingTest() { val tr = TemplateResolution() runBlocking { diff --git a/ms/blueprintsprocessor/functions/resource-resolution/src/test/resources/payload/requests/sample-resourceresolution-request2.json b/ms/blueprintsprocessor/functions/resource-resolution/src/test/resources/payload/requests/sample-resourceresolution-request2.json new file mode 100644 index 000000000..726477515 --- /dev/null +++ b/ms/blueprintsprocessor/functions/resource-resolution/src/test/resources/payload/requests/sample-resourceresolution-request2.json @@ -0,0 +1,31 @@ +{ + "actionIdentifiers": { + "actionName": "sample-action", + "blueprintName": "sample-blueprint", + "blueprintVersion": "1.0.0", + "mode": "sync" + }, + "commonHeader": { + "flags": { + "isForce": true, + "ttl": 3600 + }, + "originatorId": "unit_tests", + "requestId": "123456-1001", + "subRequestId": "sub-123456-1001" + }, + "payload": { + "resource-assignment-request": { + "resource-assignment-properties": { + "request-id": "1234", + "profile_name": "1.0.0", + "service-instance-id": "siid_new_resolution", + "vnf-id": "vnf_new_resolution", + "action-name": "assign-activate", + "scope-type": "vnf-type", + "hostname": "localhost", + "vnf_name": "temp_vnf_new_resolution" + } + } + } +} |