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 / IpAssignResolutionCapability.kt
1 /*
2  * Copyright © 2019 AT&T.
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 saurav.paira
34  */
35
36 open class IpAssignResolutionCapability : ResourceAssignmentProcessor() {
37
38     val log = logger(IpAssignResolutionCapability::class)
39
40     override fun getName(): String {
41         return "${ResourceResolutionConstants.PREFIX_RESOURCE_RESOLUTION_PROCESSOR}ipassignment-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
70                 // Get the values from runtime store
71                 val resolvedInputKeyMapping = resolveInputKeyMappingVariables(
72                     inputKeyMapping,
73                     resourceAssignment.templatingConstants
74                 ).toMutableMap()
75                 log.info("\nResolved Input Key mappings: \n$resolvedInputKeyMapping")
76
77                 resolvedInputKeyMapping.map { KeyIdentifier(it.key, it.value) }.let {
78                     resourceAssignment.keyIdentifiers.addAll(it)
79                 }
80
81                 // Generate the payload using already resolved value
82                 val generatedPayload = generatePayload(resolvedInputKeyMapping, groupResourceAssignments)
83                 log.info("\nIP Assign mS Request Payload: \n{}", generatedPayload.asJsonType().toPrettyString())
84
85                 resourceSourceProperties["resolved-payload"] = JacksonUtils.jsonNode(generatedPayload)
86
87                 // Get the Rest Client service, selector will be included in application.properties
88                 val restClientService = BluePrintDependencyService.restClientService(
89                     "ipassign-ms"
90                 )
91
92                 // Get the Rest Response
93                 val response = restClientService.exchangeResource(
94                     HttpMethod.POST.name,
95                     "/web/service/v1/assign", generatedPayload
96                 )
97                 val responseStatusCode = response.status
98                 val responseBody = response.body
99                 log.info("\nIP Assign mS Response : \n{}", responseBody.asJsonType().toPrettyString())
100                 if (responseStatusCode in 200..299 && !responseBody.isBlank()) {
101                     populateResource(groupResourceAssignments, responseBody)
102                 } else {
103                     val errMsg =
104                         "Failed to dictionary name ($dName), dictionary source($($dName) " +
105                             "response_code: ($responseStatusCode)"
106                     log.warn(errMsg)
107                     throw BluePrintProcessorException(errMsg)
108                 }
109                 // Parse the error Body and assign the property value
110             }
111             // Check the value has populated for mandatory case
112             ResourceAssignmentUtils.assertTemplateKeyValueNotNull(resourceAssignment)
113         } catch (e: Exception) {
114             ResourceAssignmentUtils.setFailedResourceDataValue(resourceAssignment, e.message)
115             throw BluePrintProcessorException(
116                 "Failed in template key ($resourceAssignment) assignments with: ${e.message}",
117                 e
118             )
119         }
120     }
121
122     override suspend fun recoverNB(runtimeException: RuntimeException, executionRequest: ResourceAssignment) {
123         addError(runtimeException.message!!)
124     }
125
126     /** Generates aggregated request payload for Ip Assign mS. Parses the resourceassignments of
127      * sourceCapability "ipassign-ms". It generates below sample payload
128      * {
129      "requests": [{
130      "name": "fixed_ipv4_Address_01",
131      "property": {
132      "CloudRegionId": "abcd123",
133      "IpServiceName": "MobilityPlan",
134      }
135      }, {
136      "name": "fixed_ipv4_Address_02",
137      "property": {
138      "CloudRegionId": "abcd123",
139      "IpServiceName": "MobilityPlan",
140      }
141      }
142      ]
143      } */
144     private fun generatePayload(
145         input: Map<String, Any>,
146         groupResourceAssignments: MutableList<ResourceAssignment>
147     ): String {
148         data class IpRequest(val name: String = "", val property: Map<String, String> = mutableMapOf<String, String>())
149         data class IpAssignRequest(val requests: MutableList<IpRequest> = mutableListOf())
150
151         val ipAssignRequests = IpAssignRequest()
152         groupResourceAssignments.forEach {
153             val ipRequest = IpRequest(it.name, input.mapValues { it.value.toString().removeSurrounding("\"") })
154             ipAssignRequests.requests.add(ipRequest)
155         }
156         return ipAssignRequests.asJsonType().toString()
157     }
158
159     private fun populateResource(
160         resourceAssignments: MutableList<ResourceAssignment>,
161         restResponse: String
162     ) {
163         /** Parse all the resource assignment fields and set the corresponding value */
164         resourceAssignments.forEach { resourceAssignment ->
165             // Set the List of Complex Values
166             val parsedResourceAssignmentValue = checkNotNull(
167                 JacksonUtils.jsonNode(restResponse).path(resourceAssignment.name).textValue()
168             ) {
169                 "Failed to find path ($resourceAssignment.name) in response ($restResponse)"
170             }
171
172             ResourceAssignmentUtils.setResourceDataValue(
173                 resourceAssignment,
174                 raRuntimeService,
175                 parsedResourceAssignmentValue
176             )
177         }
178     }
179 }