Templating constants added to ResourceAssignment
[ccsdk/cds.git] / ms / blueprintsprocessor / functions / resource-resolution / src / main / kotlin / org / onap / ccsdk / cds / blueprintsprocessor / functions / resource / resolution / capabilities / NamingResolutionCapability.kt
1 /*
2  * Copyright © 2019 IBM.
3  *
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
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
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.
15  */
16
17 package org.onap.ccsdk.cds.blueprintsprocessor.functions.resource.resolution.capabilities
18
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
31
32 /**
33  * @author brindasanth
34  */
35
36 open class NamingResolutionCapability : ResourceAssignmentProcessor() {
37
38     val log = logger(NamingResolutionCapability::class)
39
40     override fun getName(): String {
41         return "${ResourceResolutionConstants.PREFIX_RESOURCE_RESOLUTION_PROCESSOR}naming-capability"
42     }
43
44     override suspend fun processNB(resourceAssignment: ResourceAssignment) {
45         try {
46             if (!setFromInput(resourceAssignment) && isTemplateKeyValueNull(resourceAssignment)) {
47                 val dName = resourceAssignment.dictionaryName!!
48                 val dSource = resourceAssignment.dictionarySource!!
49                 val resourceDefinition = resourceDefinition(dName)
50
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)")
55
56                 val resourceSourceProperties =
57                     checkNotNull(resourceSource.properties) { "failed to get source properties for $dName " }
58
59                 // Get all matching resources assignments to process
60                 val groupResourceAssignments =
61                     resourceAssignments.filter {
62                         it.dictionarySource == dSource
63                     }.toMutableList()
64
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)
70
71                 // Get the values from runtime store
72                 val resolvedInputKeyMapping = resolveInputKeyMappingVariables(
73                     inputKeyMapping,
74                     resourceAssignment.templatingConstants
75                 ).toMutableMap()
76                 log.info("\nResolved Input Key mappings: \n$resolvedInputKeyMapping")
77
78                 resolvedInputKeyMapping.map { KeyIdentifier(it.key, it.value) }.let {
79                     resourceAssignment.keyIdentifiers.addAll(it)
80                 }
81
82                 // Generate the payload using already resolved value
83                 val generatedPayload = generatePayload(resolvedInputKeyMapping, groupResourceAssignments)
84                 log.info("\nNaming mS Request Payload: \n{}", generatedPayload.asJsonType().toPrettyString())
85
86                 resourceSourceProperties["resolved-payload"] = JacksonUtils.jsonNode(generatedPayload)
87
88                 // Get the Rest Client service, selector will be included in application.properties
89                 val restClientService = BluePrintDependencyService.restClientService(
90                     "naming-ms"
91                 )
92
93                 // Get the Rest Response
94                 val response = restClientService.exchangeResource(
95                     HttpMethod.POST.name,
96                     "/web/service/v1/genNetworkElementName/cds", generatedPayload
97                 )
98
99                 val responseStatusCode = response.status
100                 val responseBody = response.body
101                 log.info("\nNaming mS Response : \n{}", responseBody.asJsonType().toPrettyString())
102                 if (responseStatusCode in 200..299 && !responseBody.isBlank()) {
103                     populateResource(groupResourceAssignments, responseBody)
104                 } else {
105                     val errMsg =
106                         "Failed to dictionary name ($dName), dictionary source($($dName) " +
107                             "response_code: ($responseStatusCode)"
108                     log.warn(errMsg)
109                     throw BluePrintProcessorException(errMsg)
110                 }
111                 // Parse the error Body and assign the property value
112             }
113             // Check the value has populated for mandatory case
114             ResourceAssignmentUtils.assertTemplateKeyValueNotNull(resourceAssignment)
115         } catch (e: Exception) {
116             ResourceAssignmentUtils.setFailedResourceDataValue(resourceAssignment, e.message)
117             throw BluePrintProcessorException(
118                 "Failed in template key ($resourceAssignment) assignments with: ${e.message}",
119                 e
120             )
121         }
122     }
123
124     override suspend fun recoverNB(runtimeException: RuntimeException, executionRequest: ResourceAssignment) {
125         addError(runtimeException.message!!)
126     }
127
128     /** Generates aggregated request payload for Naming mS. Parses the resourceassignments of
129      * sourceCapability "naming-ms". "naming-type" should be provides as property metadata for
130      * each resourceassigment of sourceCapability "naming-ms". It generates below sample payload
131      * {
132      "elements": [{
133      "vf-module-name": "${vf-module-name}",
134      "naming-type": "VF-MODULE",
135      "naming-code": "dbc",
136      "vf-module-label": "adsf",
137      "policy-instance-name": "SDNC_Policy.Config_Json.xml",
138      "vnf-name": "vnf-123",
139      "vf-module-type": "base"
140      }, {
141      "vnfc-name": "${vnfc-name}",
142      "naming-type": "VNFC",
143      "naming-code": "dbc",
144      "vf-module-label": "adsf",
145      "policy-instance-name": "SDNC_Policy.Config_Json.xml",
146      "vnf-name": "vnf-123",
147      "vf-module-type": "base"
148      }
149      ]
150      } */
151     private fun generatePayload(
152         input: Map<String, Any>,
153         groupResourceAssignments: MutableList<ResourceAssignment>
154     ): String {
155         data class NameAssignRequest(val elements: MutableList<Map<String, String>> = mutableListOf())
156
157         val nameAssignRequests = NameAssignRequest()
158         groupResourceAssignments.forEach {
159             val metadata = resourceDictionaries[it.dictionaryName]?.property?.metadata
160             val namingType = metadata?.get("naming-type")
161             val moduleName = namingType.plus("-name").toLowerCase()
162             val moduleValue = "\${".plus(moduleName.plus("}"))
163
164             val request: MutableMap<String, String> = input.mapValues {
165                 it.value.toString().removeSurrounding("\"")
166             } as MutableMap<String, String>
167             if (namingType != null) {
168                 request["naming-type"] = namingType
169             }
170             request[moduleName] = moduleValue
171             nameAssignRequests.elements.add(request)
172         }
173         return nameAssignRequests.asJsonType().toString()
174     }
175
176     private fun populateResource(
177         resourceAssignments: MutableList<ResourceAssignment>,
178         restResponse: String
179     ) {
180         /** Parse all the resource assignment fields and set the corresponding value */
181         resourceAssignments.forEach { resourceAssignment ->
182             // Set the List of Complex Values
183             val metadata =
184                 resourceDictionaries[resourceAssignment.dictionaryName]?.property?.metadata
185
186             /** Naming ms returns the keys with "${naming-type}-name" */
187             val responseKey = metadata?.get("naming-type")?.toLowerCase().plus("-name")
188
189             val parsedResourceAssignmentValue = checkNotNull(
190                 JacksonUtils.jsonNode(restResponse).path(responseKey).textValue()
191             ) {
192                 "Failed to find path ($responseKey) in response ($restResponse)"
193             }
194
195             ResourceAssignmentUtils.setResourceDataValue(
196                 resourceAssignment,
197                 raRuntimeService,
198                 parsedResourceAssignmentValue
199             )
200         }
201     }
202 }