2 * Copyright © 2019 IBM.
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
8 * http://www.apache.org/licenses/LICENSE-2.0
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
17 package org.onap.ccsdk.cds.blueprintsprocessor.functions.resource.resolution.capabilities
19 import org.onap.ccsdk.cds.blueprintsprocessor.functions.resource.resolution.ResourceResolutionConstants
20 import org.onap.ccsdk.cds.blueprintsprocessor.functions.resource.resolution.processor.ResourceAssignmentProcessor
21 import org.onap.ccsdk.cds.blueprintsprocessor.functions.resource.resolution.utils.ResourceAssignmentUtils
22 import org.onap.ccsdk.cds.blueprintsprocessor.rest.restClientService
23 import org.onap.ccsdk.cds.controllerblueprints.core.BlueprintProcessorException
24 import org.onap.ccsdk.cds.controllerblueprints.core.asJsonType
25 import org.onap.ccsdk.cds.controllerblueprints.core.logger
26 import org.onap.ccsdk.cds.controllerblueprints.core.service.BlueprintDependencyService
27 import org.onap.ccsdk.cds.controllerblueprints.core.utils.JacksonUtils
28 import org.onap.ccsdk.cds.controllerblueprints.resource.dict.KeyIdentifier
29 import org.onap.ccsdk.cds.controllerblueprints.resource.dict.ResourceAssignment
30 import org.springframework.http.HttpMethod
36 open class NamingResolutionCapability : ResourceAssignmentProcessor() {
38 val log = logger(NamingResolutionCapability::class)
40 override fun getName(): String {
41 return "${ResourceResolutionConstants.PREFIX_RESOURCE_RESOLUTION_PROCESSOR}naming-capability"
44 override suspend fun processNB(resourceAssignment: ResourceAssignment) {
46 if (!setFromInput(resourceAssignment) && isTemplateKeyValueNull(resourceAssignment)) {
47 val dName = resourceAssignment.dictionaryName!!
48 val dSource = resourceAssignment.dictionarySource!!
49 val resourceDefinition = resourceDefinition(dName)
51 /** Check Resource Assignment has the source definitions, If not get from Resource Definitions **/
52 val resourceSource = resourceAssignment.dictionarySourceDefinition
53 ?: resourceDefinition?.sources?.get(dSource)
54 ?: throw BlueprintProcessorException("couldn't get resource definition $dName source($dSource)")
56 val resourceSourceProperties =
57 checkNotNull(resourceSource.properties) { "failed to get source properties for $dName " }
59 // Get all matching resources assignments to process
60 val groupResourceAssignments =
61 resourceAssignments.filter {
62 it.dictionarySource == dSource
65 // inputKeyMapping is dynamic based on dependencies
66 val inputKeyMapping: MutableMap<String, String> =
67 resourceAssignment.dependencies?.map { it to it }?.toMap()
68 as MutableMap<String, String>
69 log.info("\nResolving Input Key mappings: \n{}", inputKeyMapping)
71 // Get the values from runtime store
72 val resolvedKeyValues = resolveInputKeyMappingVariables(inputKeyMapping)
73 log.info("\nResolved Input Key mappings: \n{}", resolvedKeyValues)
75 resolvedKeyValues?.map { KeyIdentifier(it.key, it.value) }
76 ?.let { resourceAssignment.keyIdentifiers.addAll(it) }
78 // Generate the payload using already resolved value
79 val generatedPayload = generatePayload(resolvedKeyValues, groupResourceAssignments)
80 log.info("\nNaming mS Request Payload: \n{}", generatedPayload.asJsonType().toPrettyString())
82 resourceSourceProperties["resolved-payload"] = JacksonUtils.jsonNode(generatedPayload)
84 // Get the Rest Client service, selector will be included in application.properties
85 val restClientService = BlueprintDependencyService.restClientService(
89 // Get the Rest Response
90 val response = restClientService.exchangeResource(
92 "/web/service/v1/genNetworkElementName/cds", generatedPayload
95 val responseStatusCode = response.status
96 val responseBody = response.body
97 log.info("\nNaming mS Response : \n{}", responseBody.asJsonType().toPrettyString())
98 if (responseStatusCode in 200..299 && !responseBody.isBlank()) {
99 populateResource(groupResourceAssignments, responseBody)
102 "Failed to dictionary name ($dName), dictionary source($($dName) " +
103 "response_code: ($responseStatusCode)"
105 throw BlueprintProcessorException(errMsg)
107 // Parse the error Body and assign the property value
109 // Check the value has populated for mandatory case
110 ResourceAssignmentUtils.assertTemplateKeyValueNotNull(resourceAssignment)
111 } catch (e: Exception) {
112 ResourceAssignmentUtils.setFailedResourceDataValue(resourceAssignment, e.message)
113 throw BlueprintProcessorException(
114 "Failed in template key ($resourceAssignment) assignments with: ${e.message}",
120 override suspend fun recoverNB(runtimeException: RuntimeException, executionRequest: ResourceAssignment) {
121 raRuntimeService.getBlueprintError().addError(runtimeException.message!!)
124 /** Generates aggregated request payload for Naming mS. Parses the resourceassignments of
125 * sourceCapability "naming-ms". "naming-type" should be provides as property metadata for
126 * each resourceassigment of sourceCapability "naming-ms". It generates below sample payload
129 "vf-module-name": "${vf-module-name}",
130 "naming-type": "VF-MODULE",
131 "naming-code": "dbc",
132 "vf-module-label": "adsf",
133 "policy-instance-name": "SDNC_Policy.Config_Json.xml",
134 "vnf-name": "vnf-123",
135 "vf-module-type": "base"
137 "vnfc-name": "${vnfc-name}",
138 "naming-type": "VNFC",
139 "naming-code": "dbc",
140 "vf-module-label": "adsf",
141 "policy-instance-name": "SDNC_Policy.Config_Json.xml",
142 "vnf-name": "vnf-123",
143 "vf-module-type": "base"
147 private fun generatePayload(
148 input: Map<String, Any>,
149 groupResourceAssignments: MutableList<ResourceAssignment>
151 data class NameAssignRequest(val elements: MutableList<Map<String, String>> = mutableListOf())
153 val nameAssignRequests = NameAssignRequest()
154 groupResourceAssignments.forEach {
155 val metadata = resourceDictionaries[it.dictionaryName]?.property?.metadata
156 val namingType = metadata?.get("naming-type")
157 val moduleName = namingType.plus("-name").toLowerCase()
158 val moduleValue = "\${".plus(moduleName.plus("}"))
160 val request: MutableMap<String, String> = input.mapValues {
161 it.value.toString().removeSurrounding("\"")
162 } as MutableMap<String, String>
163 if (namingType != null) {
164 request["naming-type"] = namingType
166 request[moduleName] = moduleValue
167 nameAssignRequests.elements.add(request)
169 return nameAssignRequests.asJsonType().toString()
172 private fun populateResource(
173 resourceAssignments: MutableList<ResourceAssignment>,
176 /** Parse all the resource assignment fields and set the corresponding value */
177 resourceAssignments.forEach { resourceAssignment ->
178 // Set the List of Complex Values
180 resourceDictionaries[resourceAssignment.dictionaryName]?.property?.metadata
182 /** Naming ms returns the keys with "${naming-type}-name" */
183 val responseKey = metadata?.get("naming-type")?.toLowerCase().plus("-name")
185 val parsedResourceAssignmentValue = checkNotNull(
186 JacksonUtils.jsonNode(restResponse).path(responseKey).textValue()
188 "Failed to find path ($responseKey) in response ($restResponse)"
191 ResourceAssignmentUtils.setResourceDataValue(
194 parsedResourceAssignmentValue