diff options
11 files changed, 308 insertions, 3 deletions
diff --git a/components/model-catalog/blueprint-model/test-blueprint/baseconfiguration/Definitions/activation-blueprint.json b/components/model-catalog/blueprint-model/test-blueprint/baseconfiguration/Definitions/activation-blueprint.json index 85a056c5e..c506ad05e 100644 --- a/components/model-catalog/blueprint-model/test-blueprint/baseconfiguration/Definitions/activation-blueprint.json +++ b/components/model-catalog/blueprint-model/test-blueprint/baseconfiguration/Definitions/activation-blueprint.json @@ -180,6 +180,14 @@ "type": "artifact-mapping-resource", "file": "Definitions/another-mapping.json" }, + "maxoccurrence-template": { + "type": "artifact-template-velocity", + "file": "Templates/maxoccurrence-template.vtl" + }, + "maxoccurrence-mapping": { + "type": "artifact-mapping-resource", + "file": "Definitions/maxoccurrence-mapping.json" + }, "notemplate-mapping": { "type": "artifact-mapping-resource", "file": "Definitions/notemplate-mapping.json" diff --git a/components/model-catalog/blueprint-model/test-blueprint/baseconfiguration/Definitions/data_types.json b/components/model-catalog/blueprint-model/test-blueprint/baseconfiguration/Definitions/data_types.json index 6d771cd68..94c587af7 100644 --- a/components/model-catalog/blueprint-model/test-blueprint/baseconfiguration/Definitions/data_types.json +++ b/components/model-catalog/blueprint-model/test-blueprint/baseconfiguration/Definitions/data_types.json @@ -51,6 +51,12 @@ "vnf_name": { "required": true, "type": "string" + }, + "firmware-version": { + "type" : "string" + }, + "ip-address": { + "type" : "string" } }, "derived_from": "tosca.datatypes.Dynamic" diff --git a/components/model-catalog/blueprint-model/test-blueprint/baseconfiguration/Definitions/maxoccurrence-mapping.json b/components/model-catalog/blueprint-model/test-blueprint/baseconfiguration/Definitions/maxoccurrence-mapping.json new file mode 100644 index 000000000..729488520 --- /dev/null +++ b/components/model-catalog/blueprint-model/test-blueprint/baseconfiguration/Definitions/maxoccurrence-mapping.json @@ -0,0 +1,23 @@ +[ + { + "name": "firmware-version", + "input-param": true, + "property": { + "type": "string" + }, + "dictionary-name": "input-source", + "dictionary-source": "input", + "dependencies": [] + }, + { + "name": "ip-address", + "input-param": true, + "property": { + "type": "string" + }, + "max-occurrence": 1, + "dictionary-name": "input-source", + "dictionary-source": "input", + "dependencies": [] + } +]
\ No newline at end of file diff --git a/components/model-catalog/blueprint-model/test-blueprint/baseconfiguration/Templates/maxoccurrence-template.vtl b/components/model-catalog/blueprint-model/test-blueprint/baseconfiguration/Templates/maxoccurrence-template.vtl new file mode 100644 index 000000000..9a9fc27eb --- /dev/null +++ b/components/model-catalog/blueprint-model/test-blueprint/baseconfiguration/Templates/maxoccurrence-template.vtl @@ -0,0 +1 @@ +This is maxoccurrence Velocity Template
\ No newline at end of file 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 a3c137807..427d48f3c 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 @@ -218,7 +218,18 @@ open class ResourceResolutionServiceImpl( 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. + // If resolution has already been performed previously then may need to update some assignments + val resourceAssignmentFilteredMap: Map<String, ResourceAssignment> = + resourceAssignments.filter { it.maxOccurrence != null && it.maxOccurrence!! in 1 until occurrence } + .associateBy { it.name } + if (occurrence > 1 && resourceAssignmentFilteredMap.isNotEmpty()) + updateResourceAssignmentByOccurrence( + bluePrintRuntimeService as ResourceAssignmentRuntimeService, + propertiesMutableMap, + artifactPrefix, + resourceAssignmentFilteredMap as MutableMap<String, ResourceAssignment> + ) + // we may be performing new resolution for some resources, simply pass an empty list. emptyList() } else { isNewResolution(bluePrintRuntimeService, properties, artifactPrefix) @@ -500,6 +511,92 @@ open class ResourceResolutionServiceImpl( } } + /** + * Utility to update the resourceAssignments with existing resolutions if maxOccurrence is defined on it. + */ + private suspend fun updateResourceAssignmentByOccurrence( + raRuntimeService: ResourceAssignmentRuntimeService, + properties: Map<String, Any>, + artifactPrefix: String, + resourceAssignmentFilteredMap: MutableMap<String, ResourceAssignment> + ) { + val resourceResolutionMap = + getResourceResolutionByLastOccurrence(raRuntimeService, properties, artifactPrefix).associateBy { it.name } + + resourceAssignmentFilteredMap + .filter { + resourceResolutionMap.containsKey(it.key) && compareOne( + resourceResolutionMap[it.key]!!, + it.value + ) + } + .forEach { raMapEntry -> + val resourceResolution = resourceResolutionMap[raMapEntry.key] + val resourceAssignment = raMapEntry.value + + resourceResolution?.value?.let { + val value = it.asJsonType(resourceAssignment.property!!.type) + resourceAssignment.property!!.value = value + ResourceAssignmentUtils.setResourceDataValue( + resourceAssignment, + raRuntimeService, + value + ) + } + resourceAssignment.status = resourceResolution?.status + resourceResolutionDBService.write( + properties, + raRuntimeService, + artifactPrefix, + resourceAssignment + ) + } + } + + /** + * Utility to find resource resolution based on occurrence. + */ + private suspend fun getResourceResolutionByLastOccurrence( + bluePrintRuntimeService: BluePrintRuntimeService<*>, + properties: Map<String, Any>, + artifactPrefix: String + ): List<ResourceResolution> { + + 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 last occurrence: " + + "Either provide a resolution-key OR combination of resource-id and resource-type" + ) + } + val metadata = bluePrintRuntimeService.bluePrintContext().metadata!! + val blueprintVersion = metadata[BluePrintConstants.METADATA_TEMPLATE_VERSION]!! + val blueprintName = metadata[BluePrintConstants.METADATA_TEMPLATE_NAME]!! + + return if (resolutionKey.isNotEmpty()) { + resourceResolutionDBService.findLastNOccurrences( + blueprintName, + blueprintVersion, + artifactPrefix, + resolutionKey, + 1 + ).takeIf { it.isNotEmpty() }?.values?.first() ?: emptyList() + } else { + resourceResolutionDBService.findLastNOccurrences( + blueprintName, + blueprintVersion, + artifactPrefix, + resourceId, + resourceType, + 1 + ).takeIf { it.isNotEmpty() }?.values?.first() ?: emptyList() + } + } + // Comparison between what we have in the database vs what we have to assign. private fun compareOne(resourceResolution: ResourceResolution, resourceAssignment: ResourceAssignment): Boolean { return ( 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 aa7b61f6a..bd8f9d27d 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 @@ -170,6 +170,35 @@ class ResourceResolutionDBService(private val resourceResolutionRepository: Reso } /** + * This returns the resolutions of last N 'occurrences'. + * + * @param blueprintName + * @param blueprintVersion + * @param artifactPrefix + * @param resourceId + * @param resourceType + * @param lastN + */ + suspend fun findLastNOccurrences( + blueprintName: String, + blueprintVersion: String, + artifactPrefix: String, + resourceId: String, + resourceType: String, + lastN: Int + ): Map<Int, List<ResourceResolution>> = withContext(Dispatchers.IO) { + + resourceResolutionRepository.findLastNOccurrences( + resourceId, + resourceType, + blueprintName, + blueprintVersion, + artifactPrefix, + lastN + ).groupBy(ResourceResolution::occurrence).toSortedMap(reverseOrder()) + } + + /** * This returns the resolutions with 'occurrence' value between begin and end. * * @param blueprintName 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 9317a71cd..5861cf8cb 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 @@ -77,6 +77,29 @@ interface ResourceResolutionRepository : JpaRepository<ResourceResolution, Strin @Query( value = """ + SELECT * FROM RESOURCE_RESOLUTION WHERE resource_id = :resourceId + AND resource_type =:resourceType AND blueprint_name = :blueprintName + AND blueprint_version = :blueprintVersion AND artifact_name = :artifactName + AND occurrence > ( + select max(occurrence) - :lastN from RESOURCE_RESOLUTION + WHERE resource_id = :resourceId + AND resource_type =:resourceType AND blueprint_name = :blueprintName + AND blueprint_version = :blueprintVersion AND artifact_name = :artifactName) + ORDER BY occurrence DESC, creation_date DESC + """, + nativeQuery = true + ) + fun findLastNOccurrences( + @Param("resourceId")resourceId: String, + @Param("resourceType")resourceType: 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 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 a801a7eb9..b39e709d0 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 @@ -249,6 +249,116 @@ class ResourceResolutionServiceTest { } /** + * Always perform new resolution even if resolution exists in the database. + */ + @Test + @Throws(Exception::class) + fun testResolveResourcesForMaxOccurrence() { + 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) + + // Run time for Request#1 + 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 + )!! + + // Prepare inputs from Request#1 + PayloadUtils.prepareInputsFromWorkflowPayload( + bluePrintRuntimeService, + executionServiceInput.payload, + "resource-assignment" + ) + + val resourceAssignmentRuntimeService = + ResourceAssignmentUtils.transformToRARuntimeService( + bluePrintRuntimeService, + "testResolveResource" + ) + + // Resolve resources as per Request#1 + resourceResolutionService.resolveResources( + resourceAssignmentRuntimeService, + "resource-assignment", + "maxoccurrence", + props + ) + + // Run time for Request#2 + val bluePrintRuntimeService2 = BluePrintMetadataUtils.getBluePrintRuntime( + "1234", + "./../../../../components/model-catalog/blueprint-model/test-blueprint/baseconfiguration" + ) + + // Request#2 + val executionServiceInput2 = + JacksonUtils.readValueFromClassPathFile( + "payload/requests/sample-resourceresolution-request2.json", + ExecutionServiceInput::class.java + )!! + + val resourceAssignmentRuntimeService2 = + ResourceAssignmentUtils.transformToRARuntimeService( + bluePrintRuntimeService2, + "testResolveResource" + ) + + // Prepare inputs from Request#2 + PayloadUtils.prepareInputsFromWorkflowPayload( + bluePrintRuntimeService2, + executionServiceInput2.payload, + "resource-assignment" + ) + + // Resolve resources as per Request#2 + resourceResolutionService.resolveResources( + resourceAssignmentRuntimeService2, + "resource-assignment", + "maxoccurrence", + props + ) + }.let { (template, assignmentList) -> + assertEquals("This is maxoccurrence Velocity Template", template) + + val assignmentListForRequest1 = mutableListOf( + "firmware-version" to "firmware-version-0", + "ip-address" to "192.0.0.1" + ) + val assignmentListForRequest2 = mutableListOf( + "firmware-version" to "firmware-version-1", + "ip-address" to "192.0.0.1" + ) + assertEquals(assignmentListForRequest1.size, assignmentList.size) + assertEquals(assignmentListForRequest2.size, assignmentList.size) + + // firmware-version has max-occurrence = 0 means perform new resolution all the time. + // ip-address has max-occurrence = 1 so its resolution should only be done once. + // + // AlwaysPerformNewResolution + max-occurrence feature use case - resolution request #2 should returns + // the resolution as per assignmentListForRequest2 since new resolution is only performed for + // firmware-version and not for ip-address. + 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 diff --git a/ms/blueprintsprocessor/functions/resource-resolution/src/test/resources/payload/requests/sample-resourceresolution-request.json b/ms/blueprintsprocessor/functions/resource-resolution/src/test/resources/payload/requests/sample-resourceresolution-request.json index 3ca754f87..e247ea248 100644 --- a/ms/blueprintsprocessor/functions/resource-resolution/src/test/resources/payload/requests/sample-resourceresolution-request.json +++ b/ms/blueprintsprocessor/functions/resource-resolution/src/test/resources/payload/requests/sample-resourceresolution-request.json @@ -25,7 +25,10 @@ "action-name": "assign-activate", "scope-type": "vnf-type", "hostname": "localhost", - "vnf_name": "temp_vnf" + "vnf_name": "temp_vnf", + "firmware-version": "firmware-version-0", + "ip-address": "192.0.0.1" + } } } 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 index 726477515..17f5aad52 100644 --- 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 @@ -24,7 +24,9 @@ "action-name": "assign-activate", "scope-type": "vnf-type", "hostname": "localhost", - "vnf_name": "temp_vnf_new_resolution" + "vnf_name": "temp_vnf_new_resolution", + "firmware-version": "firmware-version-1", + "ip-address": "192.0.0.2" } } } diff --git a/ms/blueprintsprocessor/modules/blueprints/resource-dict/src/main/kotlin/org/onap/ccsdk/cds/controllerblueprints/resource/dict/ResourceDefinition.kt b/ms/blueprintsprocessor/modules/blueprints/resource-dict/src/main/kotlin/org/onap/ccsdk/cds/controllerblueprints/resource/dict/ResourceDefinition.kt index 2e7e18258..f92548612 100644 --- a/ms/blueprintsprocessor/modules/blueprints/resource-dict/src/main/kotlin/org/onap/ccsdk/cds/controllerblueprints/resource/dict/ResourceDefinition.kt +++ b/ms/blueprintsprocessor/modules/blueprints/resource-dict/src/main/kotlin/org/onap/ccsdk/cds/controllerblueprints/resource/dict/ResourceDefinition.kt @@ -62,6 +62,9 @@ open class ResourceAssignment { @JsonProperty(value = "property") var property: PropertyDefinition? = null + @JsonProperty(value = "max-occurrence") + var maxOccurrence: Int? = null + @JsonProperty("input-param") var inputParameter: Boolean = false |