diff options
author | Alexis de Talhouët <adetalhouet89@gmail.com> | 2019-06-29 00:28:40 -0400 |
---|---|---|
committer | Alexis de Talhouët <adetalhouet89@gmail.com> | 2019-07-04 15:53:42 -0400 |
commit | 5f0a5dde67bc0e7c99bd8f9e9b7c447e69ce62fa (patch) | |
tree | 0eb10b1fc86efa62c70114495b599d3701107bb1 /ms/blueprintsprocessor/functions/resource-resolution/src/main | |
parent | c48ca03872b11a54cf898c93d4a62ef220f3c55f (diff) |
Enforce resolutionKey or resourceId/resourceType
There are three existing ways to perform the resolution:
either we don't store the results at all, whether for resource or template
either we store using the resolution key. The combination of blueprintName,
blueprintVersion, artifactName and resolutionKey has to be unique. If it
is re-used, it is considered as a new attempt for that specific resolution
request, and process will only try to resolve resources not marked at SUCCESS
in the database.
either we store using the resourceId and resourceType. As previous point, the
combination of blueprintName, blueprintVersion, artifactName and resolutionKey
has to be unique. If it is re-used, it is considered as a new attempt for that
specific resolution request, and process will only try to resolve resources not
marked at SUCCESS in the database.
TBD: add uni tests
Issue-ID: CCSDK-1423
Change-Id: I6b7198453cf0002edfa7a0c9ea3179555211b5dc
Signed-off-by: Alexis de Talhouët <adetalhouet89@gmail.com>
Diffstat (limited to 'ms/blueprintsprocessor/functions/resource-resolution/src/main')
8 files changed, 393 insertions, 123 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 2039d2e5a..fd14cc8c1 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 @@ -21,11 +21,13 @@ import com.fasterxml.jackson.databind.node.JsonNodeFactory import org.onap.ccsdk.cds.blueprintsprocessor.core.api.data.ExecutionServiceInput import org.onap.ccsdk.cds.blueprintsprocessor.functions.resource.resolution.utils.ResourceAssignmentUtils import org.onap.ccsdk.cds.blueprintsprocessor.services.execution.AbstractComponentFunction +import org.onap.ccsdk.cds.controllerblueprints.core.BluePrintProcessorException import org.onap.ccsdk.cds.controllerblueprints.core.asJsonNode import org.onap.ccsdk.cds.controllerblueprints.core.asObjectNode import org.onap.ccsdk.cds.controllerblueprints.core.utils.JacksonUtils import org.springframework.beans.factory.config.ConfigurableBeanFactory import org.springframework.context.annotation.Scope +import org.springframework.http.ResponseEntity import org.springframework.stereotype.Component @Component("component-resource-resolution") @@ -35,41 +37,51 @@ open class ResourceResolutionComponent(private val resourceResolutionService: Re override suspend fun processNB(executionRequest: ExecutionServiceInput) { - val occurrence = getOperationInput(ResourceResolutionConstants.RESOURCE_RESOLUTION_INPUT_OCCURRENCE) - val resolutionKey = getOptionalOperationInput(ResourceResolutionConstants.RESOURCE_RESOLUTION_INPUT_KEY) - val storeResult = getOptionalOperationInput(ResourceResolutionConstants.RESOURCE_RESOLUTION_INPUT_STORE_RESULT) - val resourceId = getOptionalOperationInput(ResourceResolutionConstants.RESOURCE_RESOLUTION_INPUT_RESOURCE_ID) - val resourceType = getOptionalOperationInput(ResourceResolutionConstants.RESOURCE_RESOLUTION_INPUT_RESOURCE_TYPE) - + val occurrence = getOperationInput(ResourceResolutionConstants.RESOURCE_RESOLUTION_INPUT_OCCURRENCE).asInt() + val resolutionKey = getOptionalOperationInput(ResourceResolutionConstants.RESOURCE_RESOLUTION_INPUT_KEY)?.asText() ?: "" + val storeResult = getOptionalOperationInput(ResourceResolutionConstants.RESOURCE_RESOLUTION_INPUT_STORE_RESULT)?.asBoolean() ?: false + val resourceId = getOptionalOperationInput(ResourceResolutionConstants.RESOURCE_RESOLUTION_INPUT_RESOURCE_ID)?.asText() ?: "" + val resourceType = getOptionalOperationInput(ResourceResolutionConstants.RESOURCE_RESOLUTION_INPUT_RESOURCE_TYPE)?.asText() ?: "" val properties: MutableMap<String, Any> = mutableMapOf() - properties[ResourceResolutionConstants.RESOURCE_RESOLUTION_INPUT_STORE_RESULT] = storeResult?.asBoolean() ?: false - properties[ResourceResolutionConstants.RESOURCE_RESOLUTION_INPUT_KEY] = resolutionKey?.asText() ?: "" - properties[ResourceResolutionConstants.RESOURCE_RESOLUTION_INPUT_RESOURCE_ID] = resourceId?.asText() ?: "" - properties[ResourceResolutionConstants.RESOURCE_RESOLUTION_INPUT_RESOURCE_TYPE] = resourceType?.asText() ?: "" + properties[ResourceResolutionConstants.RESOURCE_RESOLUTION_INPUT_STORE_RESULT] = storeResult + properties[ResourceResolutionConstants.RESOURCE_RESOLUTION_INPUT_KEY] = resolutionKey + properties[ResourceResolutionConstants.RESOURCE_RESOLUTION_INPUT_RESOURCE_ID] = resourceId + properties[ResourceResolutionConstants.RESOURCE_RESOLUTION_INPUT_RESOURCE_TYPE] = resourceType + properties[ResourceResolutionConstants.RESOURCE_RESOLUTION_INPUT_OCCURRENCE] = occurrence + + val jsonResponse = JsonNodeFactory.instance.objectNode() + + // validate inputs if we need to store the resource and template resolution. + if (storeResult) { + if (resolutionKey.isNotEmpty() && (resourceId.isNotEmpty() || resourceType.isNotEmpty())) { + throw BluePrintProcessorException("Can't proceed with the resolution: either provide resolution-key OR combination of resource-id and resource-type.") + } else if ((resourceType.isNotEmpty() && resourceId.isEmpty()) || (resourceType.isEmpty() && resourceId.isNotEmpty())) { + throw BluePrintProcessorException("Can't proceed with the resolution: both resource-id and resource-type should be provided, one of them is missing.") + } else if (resourceType.isEmpty() && resourceId.isEmpty() && resolutionKey.isEmpty()) { + throw BluePrintProcessorException("Can't proceed with the resolution: can't persist resolution without a correlation key. " + + "Either provide a resolution-key OR combination of resource-id and resource-type OR set `storeResult` to false.") + } + } val artifactPrefixNamesNode = getOperationInput(ResourceResolutionConstants.INPUT_ARTIFACT_PREFIX_NAMES) val artifactPrefixNames = JacksonUtils.getListFromJsonNode(artifactPrefixNamesNode, String::class.java) - val resourceAssignmentRuntimeService = - ResourceAssignmentUtils.transformToRARuntimeService(bluePrintRuntimeService, artifactPrefixNames.toString()) - - val jsonResponse = JsonNodeFactory.instance.objectNode() - for (j in 1..occurrence.asInt()) { - val key = resolutionKey?.asText() + "-" + j - properties[ResourceResolutionConstants.RESOURCE_RESOLUTION_INPUT_KEY] = key + for (j in 1..occurrence) { + properties[ResourceResolutionConstants.RESOURCE_RESOLUTION_INPUT_OCCURRENCE] = j - val response = resourceResolutionService.resolveResources(resourceAssignmentRuntimeService, + val response = resourceResolutionService.resolveResources(bluePrintRuntimeService, nodeTemplateName, artifactPrefixNames, properties) // provide indexed result in output if we have multiple resolution - if (occurrence.asInt() != 1) { - jsonResponse.set(key, response.asJsonNode()) + if (occurrence != 1) { + jsonResponse.set(Integer.toString(j), response.asJsonNode()) } else { jsonResponse.setAll(response.asObjectNode()) } + } // Set Output Attributes 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 1270298a8..e08ac520a 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 @@ -20,13 +20,14 @@ package org.onap.ccsdk.cds.blueprintsprocessor.functions.resource.resolution import kotlinx.coroutines.async import kotlinx.coroutines.awaitAll import kotlinx.coroutines.coroutineScope +import org.onap.ccsdk.cds.blueprintsprocessor.functions.resource.resolution.db.ResourceResolution import org.onap.ccsdk.cds.blueprintsprocessor.functions.resource.resolution.db.ResourceResolutionDBService 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.BluePrintConstants import org.onap.ccsdk.cds.controllerblueprints.core.BluePrintProcessorException -import org.onap.ccsdk.cds.controllerblueprints.core.asJsonType +import org.onap.ccsdk.cds.controllerblueprints.core.asJsonPrimitive 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 @@ -60,7 +61,7 @@ interface ResourceResolutionService { @Service(ResourceResolutionConstants.SERVICE_RESOURCE_RESOLUTION) open class ResourceResolutionServiceImpl(private var applicationContext: ApplicationContext, - private var resolutionResultService: TemplateResolutionService, + private var templateResolutionDBService: TemplateResolutionService, private var blueprintTemplateService: BluePrintTemplateService, private var resourceResolutionDBService: ResourceResolutionDBService) : ResourceResolutionService { @@ -76,22 +77,30 @@ open class ResourceResolutionServiceImpl(private var applicationContext: Applica override suspend fun resolveFromDatabase(bluePrintRuntimeService: BluePrintRuntimeService<*>, artifactTemplate: String, resolutionKey: String): String { - return resolutionResultService.read(bluePrintRuntimeService, artifactTemplate, resolutionKey) + return templateResolutionDBService.findByResolutionKeyAndBlueprintNameAndBlueprintVersionAndArtifactName( + bluePrintRuntimeService, + artifactTemplate, + resolutionKey) } override suspend fun resolveResources(bluePrintRuntimeService: BluePrintRuntimeService<*>, nodeTemplateName: String, artifactNames: List<String>, properties: Map<String, Any>): MutableMap<String, String> { + + val resourceAssignmentRuntimeService = + ResourceAssignmentUtils.transformToRARuntimeService(bluePrintRuntimeService, artifactNames.toString()) + val resolvedParams: MutableMap<String, String> = hashMapOf() artifactNames.forEach { artifactName -> - val resolvedContent = resolveResources(bluePrintRuntimeService, nodeTemplateName, + val resolvedContent = resolveResources(resourceAssignmentRuntimeService, nodeTemplateName, artifactName, properties) resolvedParams[artifactName] = resolvedContent } return resolvedParams } + override suspend fun resolveResources(bluePrintRuntimeService: BluePrintRuntimeService<*>, nodeTemplateName: String, artifactPrefix: String, properties: Map<String, Any>): String { @@ -111,6 +120,13 @@ open class ResourceResolutionServiceImpl(private var applicationContext: Applica as? MutableList<ResourceAssignment> ?: throw BluePrintProcessorException("couldn't get Dictionary Definitions") + if (isToStore(properties)) { + val existingResourceResolution = isNewResolution(bluePrintRuntimeService, properties, artifactPrefix) + if (existingResourceResolution.isNotEmpty()) { + updateResourceAssignmentWithExisting(existingResourceResolution, resourceAssignments) + } + } + // Get the Resource Dictionary Name val resourceDefinitions: MutableMap<String, ResourceDefinition> = ResourceAssignmentUtils .resourceDefinitions(bluePrintRuntimeService.bluePrintContext().rootPath) @@ -128,10 +144,9 @@ open class ResourceResolutionServiceImpl(private var applicationContext: Applica resolvedContent = blueprintTemplateService.generateContent(bluePrintRuntimeService, nodeTemplateName, artifactTemplate, resolvedParamJsonContent) - if (properties.containsKey(ResourceResolutionConstants.RESOURCE_RESOLUTION_INPUT_STORE_RESULT) - && properties[ResourceResolutionConstants.RESOURCE_RESOLUTION_INPUT_STORE_RESULT] as Boolean) { - resolutionResultService.write(properties, resolvedContent, bluePrintRuntimeService, artifactPrefix) - log.info("template resolution saved into database successfully : ($properties)") + if (isToStore(properties)) { + templateResolutionDBService.write(properties, resolvedContent, bluePrintRuntimeService, artifactPrefix) + log.info("Template resolution saved into database successfully : ($properties)") } return resolvedContent @@ -154,7 +169,9 @@ open class ResourceResolutionServiceImpl(private var applicationContext: Applica coroutineScope { bulkSequenced.forEach { batchResourceAssignments -> // Execute Non Dependent Assignments in parallel ( ie asynchronously ) - val deferred = batchResourceAssignments.filter { it.name != "*" && it.name != "start" } + val deferred = batchResourceAssignments + .filter { it.name != "*" && it.name != "start" } + .filter { it.status != BluePrintConstants.STATUS_SUCCESS } .map { resourceAssignment -> async { val dictionaryName = resourceAssignment.dictionaryName @@ -197,12 +214,6 @@ open class ResourceResolutionServiceImpl(private var applicationContext: Applica } - 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 - } - - /** * If the Source instance is "input", then it is not mandatory to have source Resource Definition, So it can * derive the default input processor. @@ -233,4 +244,74 @@ 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<String, Any>): 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<String, Any>, + artifactPrefix: String): List<ResourceResolution> { + val occurrence = properties[ResourceResolutionConstants.RESOURCE_RESOLUTION_INPUT_OCCURRENCE] as Int + val resolutionKey = properties[ResourceResolutionConstants.RESOURCE_RESOLUTION_INPUT_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 + + if (resolutionKey.isNotEmpty()) { + val existingResourceAssignments = + resourceResolutionDBService.findByBlueprintNameAndBlueprintVersionAndArtifactNameAndResolutionKeyAndOccurrence( + bluePrintRuntimeService, + resolutionKey, + occurrence, + artifactPrefix) + if (existingResourceAssignments.isNotEmpty()) { + log.info("Resolution with resolutionKey=($resolutionKey) already exist - will resolve all resources not already resolved.", + resolutionKey) + } + return existingResourceAssignments + } else if (resourceId.isNotEmpty() && resourceType.isNotEmpty()) { + val existingResourceAssignments = + resourceResolutionDBService.findByBlueprintNameAndBlueprintVersionAndArtifactNameAndResourceIdAndResourceTypeAndOccurrence( + bluePrintRuntimeService, + resourceId, + resourceType, + + occurrence, + artifactPrefix) + if (existingResourceAssignments.isNotEmpty()) { + log.info("Resolution with resourceId=($resourceId) and resourceType=($resourceType) already exist - will resolve " + + "all resources not already resolved.") + } + return existingResourceAssignments + } + return emptyList() + } + + // Update the resource assignment list with the status of the resource that have already been resolved + private fun updateResourceAssignmentWithExisting(resourceResolutionList: List<ResourceResolution>, + resourceAssignmentList: MutableList<ResourceAssignment>) { + resourceResolutionList.forEach { resourceResolution -> + 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() + it.status = resourceResolution.status + } + } + } + } + } + + // 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) + } + } diff --git a/ms/blueprintsprocessor/functions/resource-resolution/src/main/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/functions/resource/resolution/db/ResourceResolution.kt b/ms/blueprintsprocessor/functions/resource-resolution/src/main/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/functions/resource/resolution/db/ResourceResolution.kt index fa922cde5..baabfd913 100644 --- a/ms/blueprintsprocessor/functions/resource-resolution/src/main/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/functions/resource/resolution/db/ResourceResolution.kt +++ b/ms/blueprintsprocessor/functions/resource-resolution/src/main/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/functions/resource/resolution/db/ResourceResolution.kt @@ -24,6 +24,7 @@ import org.springframework.data.jpa.domain.support.AuditingEntityListener import java.io.Serializable import java.util.* import javax.persistence.Column +import javax.persistence.ElementCollection import javax.persistence.Entity import javax.persistence.EntityListeners import javax.persistence.Id @@ -38,23 +39,6 @@ import javax.persistence.TemporalType @Proxy(lazy = false) class ResourceResolution : Serializable { - @Id - @Column(name = "resource_resolution_id") - var id: String? = null - - @get:ApiModelProperty(value = "Resolution Key uniquely identifying the resolution of a given artifact within a CBA.", - required = true) - @Column(name = "resolution_key", nullable = false) - var resolutionKey: String? = null - - @get:ApiModelProperty(value = "Resolution type.", required = true, example = "ServiceInstance, VfModule, VNF") - @Column(name = "resource_type", nullable = false) - var resourceType: String? = null - - @get:ApiModelProperty(value = "ID associated with the resolution type in the inventory system.", required = true) - @Column(name = "resource_id", nullable = false) - var resourceId: String? = null - @get:ApiModelProperty(value = "Name of the CBA.", required = true) @Column(name = "blueprint_name", nullable = false) var blueprintName: String? = null @@ -67,19 +51,43 @@ class ResourceResolution : Serializable { @Column(name = "artifact_name", nullable = false) var artifactName: String? = null + @get:ApiModelProperty(value = "Name of the resource.", required = true) + @Column(name = "name", nullable = false) + var name: String? = null + + @get:ApiModelProperty(value = "Value of the resolution.", required = true) + @Lob + @Column(name = "value", nullable = false) + var value: String? = null + @get:ApiModelProperty(value = "Whether success of failure.", required = true) @Column(name = "status", nullable = false) var status: String? = null - @get:ApiModelProperty(value = "Name of the resource.", required = true) - @Column(name = "name", nullable = false) - var name: String? = null + @get:ApiModelProperty(value = "Resolution Key uniquely identifying the resolution of a given artifact within a CBA.", + required = true) + @Column(name = "resolution_key", nullable = false) + var resolutionKey: String? = null + + @get:ApiModelProperty(value = "Resolution type.", required = true, example = "ServiceInstance, VfModule, VNF") + @Column(name = "resource_type", nullable = false) + var resourceType: String? = null + + @get:ApiModelProperty(value = "ID associated with the resolution type in the inventory system.", required = true) + @Column(name = "resource_id", nullable = false) + var resourceId: String? = null + + @get:ApiModelProperty(value = "If resolution occurred multiple time, this field provides the index.", + required = true) + @Column(name = "occurrence", nullable = false) + var occurrence: Int = 0 @get:ApiModelProperty(value = "Name of the data dictionary used for the resolution.", required = true) @Column(name = "dictionary_name", nullable = false) var dictionaryName: String? = null - @get:ApiModelProperty(value = "Source associated with the data dictionary used for the resolution.", required = true) + @get:ApiModelProperty(value = "Source associated with the data dictionary used for the resolution.", + required = true) @Column(name = "dictionary_status", nullable = false) var dictionarySource: String? = null @@ -87,10 +95,9 @@ class ResourceResolution : Serializable { @Column(name = "dictionary_version", nullable = false) var dictionaryVersion: Int = 0 - @get:ApiModelProperty(value = "Value of the resolution.", required = true) - @Lob - @Column(name = "value", nullable = false) - var value: String? = null + @Id + @Column(name = "resource_resolution_id") + var id: String? = null @get:ApiModelProperty(value = "Creation date of the resolution.", required = true) @JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd'T'HH:mm:ss.SSS'Z'") 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 c6ffde742..e9679eeba 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 @@ -25,6 +25,7 @@ import org.onap.ccsdk.cds.controllerblueprints.core.utils.JacksonUtils import org.onap.ccsdk.cds.controllerblueprints.resource.dict.ResourceAssignment import org.slf4j.LoggerFactory import org.springframework.dao.DataIntegrityViolationException +import org.springframework.dao.EmptyResultDataAccessException import org.springframework.stereotype.Service import java.util.* @@ -33,6 +34,49 @@ class ResourceResolutionDBService(private val resourceResolutionRepository: Reso private val log = LoggerFactory.getLogger(ResourceResolutionDBService::class.toString()) + suspend fun findByBlueprintNameAndBlueprintVersionAndArtifactNameAndResolutionKeyAndOccurrence( + bluePrintRuntimeService: BluePrintRuntimeService<*>, key: String, + occurrence: Int, artifactPrefix: String): List<ResourceResolution> { + return try { + val metadata = bluePrintRuntimeService.bluePrintContext().metadata!! + + val blueprintVersion = metadata[BluePrintConstants.METADATA_TEMPLATE_VERSION]!! + val blueprintName = metadata[BluePrintConstants.METADATA_TEMPLATE_NAME]!! + + resourceResolutionRepository.findByBlueprintNameAndBlueprintVersionAndArtifactNameAndResolutionKeyAndOccurrence( + blueprintName, + blueprintVersion, + artifactPrefix, + key, + occurrence) + } catch (e: EmptyResultDataAccessException) { + emptyList() + } + } + + suspend fun findByBlueprintNameAndBlueprintVersionAndArtifactNameAndResourceIdAndResourceTypeAndOccurrence( + bluePrintRuntimeService: BluePrintRuntimeService<*>, resourceId: String, + resourceType: String, occurrence: Int, + artifactPrefix: String): List<ResourceResolution> { + return try { + + val metadata = bluePrintRuntimeService.bluePrintContext().metadata!! + + val blueprintVersion = metadata[BluePrintConstants.METADATA_TEMPLATE_VERSION]!! + val blueprintName = metadata[BluePrintConstants.METADATA_TEMPLATE_NAME]!! + + resourceResolutionRepository.findByBlueprintNameAndBlueprintVersionAndArtifactNameAndResourceIdAndResourceTypeAndOccurrence( + blueprintName, + blueprintVersion, + artifactPrefix, + resourceId, + resourceType, + occurrence) + } catch (e: EmptyResultDataAccessException) { + emptyList() + } + } + suspend fun readValue(blueprintName: String, blueprintVersion: String, artifactPrefix: String, @@ -81,12 +125,11 @@ class ResourceResolutionDBService(private val resourceResolutionRepository: Reso val blueprintVersion = metadata[BluePrintConstants.METADATA_TEMPLATE_VERSION]!! val blueprintName = metadata[BluePrintConstants.METADATA_TEMPLATE_NAME]!! - val resolutionKey = - properties[ResourceResolutionConstants.RESOURCE_RESOLUTION_INPUT_KEY].toString() - val resourceType = - properties[ResourceResolutionConstants.RESOURCE_RESOLUTION_INPUT_RESOURCE_TYPE].toString() - val resourceId = - properties[ResourceResolutionConstants.RESOURCE_RESOLUTION_INPUT_RESOURCE_ID].toString() + + val resolutionKey = properties[ResourceResolutionConstants.RESOURCE_RESOLUTION_INPUT_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 + val occurrence = properties[ResourceResolutionConstants.RESOURCE_RESOLUTION_INPUT_OCCURRENCE] as Int write(blueprintName, blueprintVersion, @@ -94,7 +137,8 @@ class ResourceResolutionDBService(private val resourceResolutionRepository: Reso resourceId, resourceType, artifactPrefix, - resourceAssignment) + resourceAssignment, + occurrence) } suspend fun write(blueprintName: String, @@ -103,20 +147,22 @@ class ResourceResolutionDBService(private val resourceResolutionRepository: Reso resourceId: String, resourceType: String, artifactPrefix: String, - resourceAssignment: ResourceAssignment): ResourceResolution = withContext(Dispatchers.IO) { + resourceAssignment: ResourceAssignment, + occurrence: Int = 0): ResourceResolution = withContext(Dispatchers.IO) { val resourceResolution = ResourceResolution() resourceResolution.id = UUID.randomUUID().toString() resourceResolution.artifactName = artifactPrefix + resourceResolution.occurrence = occurrence resourceResolution.blueprintVersion = blueprintVersion resourceResolution.blueprintName = blueprintName resourceResolution.resolutionKey = resolutionKey resourceResolution.resourceType = resourceType resourceResolution.resourceId = resourceId - if (BluePrintConstants.STATUS_FAILURE == resourceAssignment.status) { - resourceResolution.value = "" - } else { + if (BluePrintConstants.STATUS_SUCCESS == resourceAssignment.status) { resourceResolution.value = JacksonUtils.getValue(resourceAssignment.property?.value!!).toString() + } else { + resourceResolution.value = "" } resourceResolution.name = resourceAssignment.name resourceResolution.dictionaryName = resourceAssignment.dictionaryName 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 d2cbf8411..429041e14 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 @@ -34,4 +34,19 @@ interface ResourceResolutionRepository : JpaRepository<ResourceResolution, Strin blueprintVersion: String, resourceId: String, resourceType: String): List<ResourceResolution> + + fun findByBlueprintNameAndBlueprintVersionAndArtifactNameAndResolutionKeyAndOccurrence( + blueprintName: String?, + blueprintVersion: String?, + artifactName: String, + resolutionKey: String, + occurrence: Int): List<ResourceResolution> + + fun findByBlueprintNameAndBlueprintVersionAndArtifactNameAndResourceIdAndResourceTypeAndOccurrence( + blueprintName: String?, + blueprintVersion: String?, + artifactName: String, + resourceId: String, + resourceType: String, + occurrence: Int): List<ResourceResolution> }
\ 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/db/TemplateResolution.kt b/ms/blueprintsprocessor/functions/resource-resolution/src/main/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/functions/resource/resolution/db/TemplateResolution.kt index ae24a9ac2..70aadb4b1 100755 --- a/ms/blueprintsprocessor/functions/resource-resolution/src/main/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/functions/resource/resolution/db/TemplateResolution.kt +++ b/ms/blueprintsprocessor/functions/resource-resolution/src/main/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/functions/resource/resolution/db/TemplateResolution.kt @@ -38,15 +38,6 @@ import javax.persistence.TemporalType @Proxy(lazy = false) class TemplateResolution : Serializable { - @Id - @Column(name = "template_resolution_id") - var id: String? = null - - @get:ApiModelProperty(value = "Resolution Key uniquely identifying the resolution of a given artifact within a CBA.", - required = true) - @Column(name = "resolution_key", nullable = false) - var resolutionKey: String? = null - @get:ApiModelProperty(value = "Name of the CBA.", required = true) @Column(name = "blueprint_name", nullable = false) var blueprintName: String? = null @@ -64,6 +55,28 @@ class TemplateResolution : Serializable { @Column(name = "result", nullable = false) var result: String? = null + @get:ApiModelProperty(value = "Resolution Key uniquely identifying the resolution of a given artifact within a CBA.", + required = true) + @Column(name = "resolution_key", nullable = false) + var resolutionKey: String? = null + + @get:ApiModelProperty(value = "Resolution type.", required = true, example = "ServiceInstance, VfModule, VNF") + @Column(name = "resource_type", nullable = false) + var resourceType: String? = null + + @get:ApiModelProperty(value = "ID associated with the resolution type in the inventory system.", required = true) + @Column(name = "resource_id", nullable = false) + var resourceId: String? = null + + @get:ApiModelProperty(value = "If resolution occurred multiple time, this field provides the index.", + required = true) + @Column(name = "occurrence", nullable = false) + var occurrence: Int = 0 + + @Id + @Column(name = "template_resolution_id") + var id: String? = null + @get:ApiModelProperty(value = "Creation date of the resolution.", required = true) @JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd'T'HH:mm:ss.SSS'Z'") @LastModifiedDate 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 136b5e952..440663f25 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 @@ -16,10 +16,39 @@ package org.onap.ccsdk.cds.blueprintsprocessor.functions.resource.resolution.db import org.springframework.data.jpa.repository.JpaRepository +import javax.transaction.Transactional interface TemplateResolutionRepository : JpaRepository<TemplateResolution, String> { - fun findByResolutionKeyAndBlueprintNameAndBlueprintVersionAndArtifactName(key: String, blueprintName: String?, - blueprintVersion: String?, - artifactName: String): TemplateResolution + fun findByResourceIdAndResourceTypeAndBlueprintNameAndBlueprintVersionAndArtifactNameAndOccurrence( + resourceId: String, + resourceType: String, + blueprintName: String?, + blueprintVersion: String?, + artifactName: String, + occurrence: Int): TemplateResolution ? + + fun findByResolutionKeyAndBlueprintNameAndBlueprintVersionAndArtifactNameAndOccurrence( + key: String, + blueprintName: String?, + blueprintVersion: String?, + artifactName: String, + occurrence: Int): TemplateResolution ? + + @Transactional + fun deleteByResourceIdAndResourceTypeAndBlueprintNameAndBlueprintVersionAndArtifactNameAndOccurrence( + resourceId: String, + resourceType: String, + blueprintName: String?, + blueprintVersion: String?, + artifactName: String, + occurrence: Int) + + @Transactional + fun deleteByResolutionKeyAndBlueprintNameAndBlueprintVersionAndArtifactNameAndOccurrence( + key: String, + blueprintName: String?, + blueprintVersion: String?, + artifactName: String, + occurrence: Int) } 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 c4e36401f..44662965d 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 @@ -21,36 +21,65 @@ import org.onap.ccsdk.cds.blueprintsprocessor.functions.resource.resolution.Reso import org.onap.ccsdk.cds.controllerblueprints.core.BluePrintConstants import org.onap.ccsdk.cds.controllerblueprints.core.BluePrintException import org.onap.ccsdk.cds.controllerblueprints.core.service.BluePrintRuntimeService +import org.slf4j.LoggerFactory import org.springframework.dao.DataIntegrityViolationException +import org.springframework.dao.EmptyResultDataAccessException import org.springframework.stereotype.Service import java.util.* @Service class TemplateResolutionService(private val templateResolutionRepository: TemplateResolutionRepository) { - suspend fun read(bluePrintRuntimeService: BluePrintRuntimeService<*>, - artifactPrefix: String, - resolutionKey: String): String = withContext(Dispatchers.IO) { + private val log = LoggerFactory.getLogger(TemplateResolutionService::class.toString()) - val metadata = bluePrintRuntimeService.bluePrintContext().metadata!! + suspend fun findByResolutionKeyAndBlueprintNameAndBlueprintVersionAndArtifactName( + bluePrintRuntimeService: BluePrintRuntimeService<*>, + artifactPrefix: String, + resolutionKey: String): String = + withContext(Dispatchers.IO) { - val blueprintVersion = metadata[BluePrintConstants.METADATA_TEMPLATE_VERSION]!! - val blueprintName = metadata[BluePrintConstants.METADATA_TEMPLATE_NAME]!! + val metadata = bluePrintRuntimeService.bluePrintContext().metadata!! - read(blueprintName, blueprintVersion, artifactPrefix, resolutionKey) - } + val blueprintVersion = metadata[BluePrintConstants.METADATA_TEMPLATE_VERSION]!! + val blueprintName = metadata[BluePrintConstants.METADATA_TEMPLATE_NAME]!! - suspend fun read(blueprintName: String, - blueprintVersion: String, - artifactPrefix: String, - resolutionKey: String): String = withContext(Dispatchers.IO) { + findByResolutionKeyAndBlueprintNameAndBlueprintVersionAndArtifactName(blueprintName, + blueprintVersion, + artifactPrefix, + resolutionKey) + } - templateResolutionRepository.findByResolutionKeyAndBlueprintNameAndBlueprintVersionAndArtifactName( - resolutionKey, - blueprintName, - blueprintVersion, - artifactPrefix).result!! - } + suspend fun findByResolutionKeyAndBlueprintNameAndBlueprintVersionAndArtifactName(blueprintName: String, + blueprintVersion: String, + artifactPrefix: String, + resolutionKey: String, + occurrence: Int = 0): String = + withContext(Dispatchers.IO) { + + templateResolutionRepository.findByResolutionKeyAndBlueprintNameAndBlueprintVersionAndArtifactNameAndOccurrence( + resolutionKey, + blueprintName, + blueprintVersion, + artifactPrefix, + occurrence)?.result ?: throw EmptyResultDataAccessException(1) + } + + suspend fun findByResoureIdAndResourceTypeAndBlueprintNameAndBlueprintVersionAndArtifactName(blueprintName: String, + blueprintVersion: String, + artifactPrefix: String, + resourceId: String, + resourceType: String, + occurrence: Int = 0): String = + withContext(Dispatchers.IO) { + + templateResolutionRepository.findByResourceIdAndResourceTypeAndBlueprintNameAndBlueprintVersionAndArtifactNameAndOccurrence( + resourceId, + resourceType, + blueprintName, + blueprintVersion, + artifactPrefix, + occurrence)?.result!! + } suspend fun write(properties: Map<String, Any>, result: String, bluePrintRuntimeService: BluePrintRuntimeService<*>, @@ -60,30 +89,68 @@ class TemplateResolutionService(private val templateResolutionRepository: Templa val blueprintVersion = metadata[BluePrintConstants.METADATA_TEMPLATE_VERSION]!! val blueprintName = metadata[BluePrintConstants.METADATA_TEMPLATE_NAME]!! - val resolutionKey = - properties[ResourceResolutionConstants.RESOURCE_RESOLUTION_INPUT_KEY].toString() + val resolutionKey = properties[ResourceResolutionConstants.RESOURCE_RESOLUTION_INPUT_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 + val occurrence = properties[ResourceResolutionConstants.RESOURCE_RESOLUTION_INPUT_OCCURRENCE] as Int - write(blueprintName, blueprintVersion, resolutionKey, artifactPrefix, result) + write(blueprintName, + blueprintVersion, + artifactPrefix, + result, + occurrence, + resolutionKey, + resourceId, + resourceType) } - suspend fun write(blueprintName: String, - blueprintVersion: String, - resolutionKey: String, - artifactPrefix: String, - template: String): TemplateResolution = withContext(Dispatchers.IO) { - - val resourceResolutionResult = TemplateResolution() - resourceResolutionResult.id = UUID.randomUUID().toString() - resourceResolutionResult.artifactName = artifactPrefix - resourceResolutionResult.blueprintVersion = blueprintVersion - resourceResolutionResult.blueprintName = blueprintName - resourceResolutionResult.resolutionKey = resolutionKey - resourceResolutionResult.result = template - - try { - templateResolutionRepository.saveAndFlush(resourceResolutionResult) - } catch (ex: DataIntegrityViolationException) { - throw BluePrintException("Failed to store resource api result.", ex) + suspend fun write(blueprintName: String, blueprintVersion: String, artifactPrefix: String, + template: String, occurrence: Int = 0, resolutionKey: String = "", resourceId: String = "", + resourceType: String = ""): TemplateResolution = + withContext(Dispatchers.IO) { + + val resourceResolutionResult = TemplateResolution() + resourceResolutionResult.id = UUID.randomUUID().toString() + resourceResolutionResult.artifactName = artifactPrefix + resourceResolutionResult.blueprintVersion = blueprintVersion + resourceResolutionResult.blueprintName = blueprintName + resourceResolutionResult.resolutionKey = resolutionKey + resourceResolutionResult.resourceId = resourceId + resourceResolutionResult.resourceType = resourceType + resourceResolutionResult.result = template + resourceResolutionResult.occurrence = occurrence + + // Overwrite template resolution-key of resourceId/resourceType already existant + if (resolutionKey.isNotEmpty()) { + templateResolutionRepository.findByResolutionKeyAndBlueprintNameAndBlueprintVersionAndArtifactNameAndOccurrence( + resolutionKey, blueprintName, blueprintVersion, artifactPrefix, occurrence)?.let { + log.info("Overwriting template resolution for blueprintName=($blueprintVersion), blueprintVersion=($blueprintName), " + + "artifactName=($artifactPrefix) and resolutionKey=($resolutionKey)") + templateResolutionRepository.deleteByResolutionKeyAndBlueprintNameAndBlueprintVersionAndArtifactNameAndOccurrence( + resolutionKey, + blueprintName, + blueprintVersion, + artifactPrefix, + occurrence) + } + } else if (resourceId.isNotEmpty() && resourceType.isNotEmpty()) { + templateResolutionRepository.findByResourceIdAndResourceTypeAndBlueprintNameAndBlueprintVersionAndArtifactNameAndOccurrence( + resourceId, resourceType, blueprintName, blueprintVersion, artifactPrefix, occurrence)?.let { + log.info("Overwriting template resolution for blueprintName=($blueprintVersion), blueprintVersion=($blueprintName), " + + "artifactName=($artifactPrefix), resourceId=($resourceId) and resourceType=($resourceType)") + templateResolutionRepository.deleteByResourceIdAndResourceTypeAndBlueprintNameAndBlueprintVersionAndArtifactNameAndOccurrence( + resourceId, + resourceType, + blueprintName, + blueprintVersion, + artifactPrefix, + occurrence) + } + } + try { + templateResolutionRepository.saveAndFlush(resourceResolutionResult) + } catch (ex: DataIntegrityViolationException) { + throw BluePrintException("Failed to store resource api result.", ex) + } } - } }
\ No newline at end of file |