2 * Copyright © 2019 TechMahindra
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.services.execution.scripts
19 import org.onap.ccsdk.cds.blueprintsprocessor.core.api.data.ExecutionServiceInput
20 import org.onap.ccsdk.cds.blueprintsprocessor.services.execution.AbstractScriptComponentFunction
21 import org.slf4j.LoggerFactory
22 import com.fasterxml.jackson.databind.node.ObjectNode
23 import org.onap.ccsdk.cds.controllerblueprints.core.utils.JacksonUtils
24 import com.fasterxml.jackson.databind.node.ArrayNode
25 import org.onap.ccsdk.cds.blueprintsprocessor.rest.service.BlueprintWebClientService
26 import org.onap.ccsdk.cds.controllerblueprints.core.BluePrintProcessorException
27 import java.nio.file.Path
28 import org.springframework.http.HttpMethod
29 import org.onap.ccsdk.cds.blueprintsprocessor.rest.BasicAuthRestClientProperties
30 import org.springframework.http.HttpHeaders
31 import org.springframework.http.MediaType
32 import org.apache.http.message.BasicHeader
33 import java.util.Base64
34 import java.nio.charset.Charset
35 import java.io.IOException
36 import org.apache.http.client.methods.HttpUriRequest
37 import com.fasterxml.jackson.annotation.JsonProperty
38 import org.apache.commons.io.IOUtils
39 import org.apache.http.client.methods.HttpPost
40 import org.apache.http.client.entity.EntityBuilder
41 import java.nio.file.Files
42 import org.onap.ccsdk.cds.blueprintsprocessor.rest.service.RestLoggerService
43 import org.apache.http.client.ClientProtocolException
44 import com.fasterxml.jackson.databind.ObjectMapper
45 import org.onap.ccsdk.cds.blueprintsprocessor.functions.k8s.definition.K8sPluginDefinitionApi
46 import org.onap.ccsdk.cds.blueprintsprocessor.functions.k8s.K8sConnectionPluginConfiguration
47 import org.onap.ccsdk.cds.blueprintsprocessor.functions.k8s.definition.K8sDefinitionRestClient
48 import org.onap.ccsdk.cds.blueprintsprocessor.functions.k8s.instance.K8sConfigValueRequest
49 import org.onap.ccsdk.cds.blueprintsprocessor.functions.k8s.instance.K8sPluginInstanceApi
50 import org.onap.ccsdk.cds.blueprintsprocessor.core.BluePrintPropertiesService
51 import com.fasterxml.jackson.dataformat.yaml.YAMLFactory
52 import com.fasterxml.jackson.module.kotlin.convertValue
54 import com.google.gson.Gson
55 import com.google.gson.reflect.TypeToken
57 import org.onap.ccsdk.cds.blueprintsprocessor.functions.resource.resolution.storedContentFromResolvedArtifactNB
58 import org.onap.ccsdk.cds.blueprintsprocessor.rest.service.BasicAuthRestClientService
60 open class KotlinK8sUpdateConfig : AbstractScriptComponentFunction() {
62 private val log = LoggerFactory.getLogger(KotlinK8sUpdateConfig::class.java)!!
64 override fun getName(): String {
65 return "KotlinK8sUpdateConfig"
68 override suspend fun processNB(executionRequest: ExecutionServiceInput) {
70 println("Exeuting processNB")
71 log.info("Executing processNB from Kotlin script: KotlinK8sUpdateConfig ...")
72 val bluePrintPropertiesService: BluePrintPropertiesService =this.functionDependencyInstanceAsType("bluePrintPropertiesService")
74 // read the config input
75 val baseK8sApiUrl = getDynamicProperties("api-access").get("url").asText()
76 val k8sApiUsername = getDynamicProperties("api-access").get("username").asText()
77 val k8sApiPassword = getDynamicProperties("api-access").get("password").asText()
79 val prefix = "baseconfigput"
81 val aaiApiUrl = getDynamicProperties("aai-access").get("url").asText()
82 val aaiApiUsername = getDynamicProperties("aai-access").get("username").asText()
83 val aaiApiPassword = getDynamicProperties("aai-access").get("password").asText()
85 log.info("AAI params $aaiApiUrl")
87 val resolution_key = getDynamicProperties("resolution-key").asText()
89 val payload = storedContentFromResolvedArtifactNB(resolution_key, prefix)
91 val payloadObject = JacksonUtils.jsonNode(payload) as ObjectNode
93 val serviceInstanceID: String = getResolvedParameter(payloadObject, "service-instance-id")
94 val vnfID: String = getResolvedParameter(payloadObject, "vnf-id")
96 log.info("Get serviceInstanceID $serviceInstanceID")
97 log.info("Get vnfID $vnfID")
99 val vnfUrl = aaiApiUrl + "/aai/v19/network/generic-vnfs/generic-vnf/" + vnfID + "/vf-modules";
101 val mapOfHeaders = hashMapOf<String, String>()
102 mapOfHeaders.put("Accept", "application/json")
103 mapOfHeaders.put("Content-Type", "application/json")
104 mapOfHeaders.put("x-FromAppId", "SO")
105 mapOfHeaders.put("X-TransactionId", "get_aai_subscr")
106 val basicAuthRestClientProperties: BasicAuthRestClientProperties = BasicAuthRestClientProperties()
107 basicAuthRestClientProperties.username = aaiApiUsername
108 basicAuthRestClientProperties.password = aaiApiPassword
109 basicAuthRestClientProperties.url = vnfUrl
110 basicAuthRestClientProperties.additionalHeaders =mapOfHeaders
111 val basicAuthRestClientService: BasicAuthRestClientService= BasicAuthRestClientService(basicAuthRestClientProperties)
113 val resultOfGet: BlueprintWebClientService.WebClientResponse<String> = basicAuthRestClientService.exchangeResource(HttpMethod.GET.name, "", "")
115 val aaiBody = resultOfGet.body
116 val aaiPayloadObject = JacksonUtils.jsonNode(aaiBody) as ObjectNode
118 log.info("aaiPayloadObject: $aaiPayloadObject")
120 for (item in aaiPayloadObject.get("vf-module")) {
122 log.info("item payload Deatils : $item")
124 val isItBaseVfModule = item.get("is-base-vf-module").asText()
126 if(isItBaseVfModule.toBoolean())
129 val vfModuleID: String = item.get("vf-module-id").asText()
131 log.info("AAI Vf-module ID is : $vfModuleID")
133 val vfModuleModelInvariantUuid: String = item.get("model-invariant-id").asText()
135 log.info("AAI Vf-module Invariant ID is : $vfModuleModelInvariantUuid")
137 val vfModuleModelUuid: String = item.get("model-customization-id").asText()
139 log.info("AAI Vf-module UUID is : $vfModuleModelUuid")
141 val vfModuleCustUuid: String = item.get("model-customization-id").asText()
143 log.info("AAI Vf-module Customization UUID is : $vfModuleCustUuid")
146 val vfModuleInstance: String = item.get("heat-stack-id").asText()
148 log.info("AAI Vf-module Heat Stack ID : $vfModuleInstance")
150 val profileName: String = "profile-"+ vfModuleID
151 val templateName: String = "template_" + vfModuleCustUuid
153 //val randomString = getRandomString(6)
154 val configName: String = "config_"+ vfModuleID
156 log.info("payloadObject: $payloadObject")
158 var supportedNssai: String = getResolvedParameter(payloadObject, "supportedNssai")
160 log.info("supportedNssai from SO -> "+ supportedNssai)
161 log.info("configName ->"+ configName)
162 log.info("profileName ->"+ profileName)
163 log.info("templateName ->"+ templateName)
166 executeK8sAPI(bluePrintPropertiesService,supportedNssai, k8sApiUsername, k8sApiPassword, baseK8sApiUrl, vfModuleModelInvariantUuid, vfModuleCustUuid, templateName, configName, profileName, vfModuleInstance)
170 catch (e: Exception) {
171 log.info("Caught exception trying to set config values!!")
172 throw BluePrintProcessorException("${e.message}")
176 fun getRandomString(length: Int) : String {
177 val charset = "0123456789"
179 .map { charset.random() }
183 fun executeK8sAPI(bluePrintPropertiesService: BluePrintPropertiesService,supportedNssai: String, k8sApiUsername:String, k8sApiPassword:String, baseK8sApiUrl:String, vfModuleModelInvariantUuid:String, vfModuleCustUuid: String, templateName: String, configName:String, profileName:String, instanceId: String){
185 println("Executing executeK8sAPI ...")
187 // read and convert supportedNssai parameters from string to json
188 val sNssaiAsJsonObj = parseSupportedNssai(supportedNssai)
190 // contruct config api
191 val api = K8sConfigApi(k8sApiUsername, k8sApiPassword, baseK8sApiUrl, vfModuleModelInvariantUuid, vfModuleCustUuid, instanceId, bluePrintPropertiesService)
195 var config = K8sConfigPayloadJson()
196 config.templateName = templateName
197 config.configName = configName
198 config.values = Config()
199 config.values.supportedNssai = SupportedNssai()
200 config.values.supportedNssai.snssaiInitial = SnssaiInitial()
201 config.values.supportedNssai.snssaiInitial.snssaiSecond = SnssaiSecond()
202 config.values.supportedNssai.snssaiInitial.snssaiSecond.snssaiFinalArray = Array<SnssaiFinal>(sNssaiAsJsonObj.size){i-> SnssaiFinal()}
204 val dest = buildSNssaiArray(config.values.supportedNssai.snssaiInitial.snssaiSecond.snssaiFinalArray, sNssaiAsJsonObj)
205 api.createOrUpdateConfig(config, profileName, instanceId, configName, templateName)
207 log.info("K8s Configurations create or update Completed")
211 fun buildSNssaiArray(payloadSnssai: Array<SnssaiFinal>, requestSnssai: Array<SnssaiFinal>): Array<SnssaiFinal>{
213 System.arraycopy(requestSnssai, 0, payloadSnssai, 0, requestSnssai.size)
219 fun parseSupportedNssai(supportedNssai: String): Array<SnssaiFinal>{
221 log.info("parsing supportedNssai string..")
223 log.info("sNssai value from input.. $supportedNssai")
225 val trimmed_supportedNssai = supportedNssai.replace("\\s".toRegex(), "").replace("\\r\\n","").replace("\\","")
229 val startInd = trimmed_supportedNssai.indexOf('[')
230 val endInd = trimmed_supportedNssai.indexOf(']')
232 val subStr = trimmed_supportedNssai.substring(startInd, endInd+1)
234 val snType = object : TypeToken<Array<SnssaiFinal>>() {}.type
236 var snList: Array<SnssaiFinal> = gson.fromJson(subStr, snType)
238 log.info("parsing is done.")
244 fun getResolvedParameter(payload: ObjectNode, keyName: String): String {
245 for (node in payload.get("resource-accumulator-resolved-data").elements()) {
246 if (node.get("param-name").asText().equals(keyName)) {
247 return node.get("param-value").asText()
253 fun getTemplatePrefixList(executionRequest: ExecutionServiceInput): ArrayList<String> {
254 val result = ArrayList<String>()
255 for (prefix in executionRequest.payload.get("resource-assignment-request").get("template-prefix").elements())
256 result.add(prefix.asText())
260 override suspend fun recoverNB(runtimeException: RuntimeException, executionRequest: ExecutionServiceInput) {
261 log.info("Recover function called!")
262 log.info("Execution request : $executionRequest")
263 log.error("Exception", runtimeException)
264 addError(runtimeException.message!!)
267 inner class K8sConfigApi(
268 val username: String,
269 val password: String,
271 val definition: String,
272 val definitionVersion: String,
273 val instanceId: String,
274 val bluePrintPropertiesService: BluePrintPropertiesService
277 private val service: UploadFileConfigClientService // BasicAuthRestClientService
280 var mapOfHeaders = hashMapOf<String, String>()
281 mapOfHeaders.put("Accept", "application/json")
282 mapOfHeaders.put("Content-Type", "application/json")
283 mapOfHeaders.put("cache-control", " no-cache")
284 mapOfHeaders.put("Accept", "application/json")
285 var basicAuthRestClientProperties: BasicAuthRestClientProperties = BasicAuthRestClientProperties()
286 basicAuthRestClientProperties.username = username
287 basicAuthRestClientProperties.password = password
288 basicAuthRestClientProperties.url = "$baseUrl/v1/instance"
289 basicAuthRestClientProperties.additionalHeaders = mapOfHeaders
291 this.service = UploadFileConfigClientService(basicAuthRestClientProperties)
294 fun createOrUpdateConfig(configJson: K8sConfigPayloadJson, profileName: String, instanceId: String, configName: String, templateName: String) {
295 val objectMapper = ObjectMapper()
297 val yamlReader = ObjectMapper(YAMLFactory())
299 for(snssai in configJson.values.supportedNssai.snssaiInitial.snssaiSecond.snssaiFinalArray){
300 println("snssai->" +snssai.snssai)
301 println("status->"+snssai.status)
305 val configJsonString: String = objectMapper.writeValueAsString(configJson.values)
307 log.info("payload generated -> "+ configJsonString)
309 val startInd = configJsonString.indexOf('[')
310 val endInd = configJsonString.indexOf(']')
312 val snssaiArray: String = configJsonString.substring(startInd, endInd+1).replace("\"","\\\"").replace("[","\"[").replace("]","]\"")
314 val finalPayload: String = configJsonString.replaceRange(startInd..endInd, snssaiArray)
316 log.info("payload restructured -> "+ finalPayload)
317 obj = yamlReader.readValue(finalPayload, Any::class.java)
321 val api = K8sPluginInstanceApi(K8sConnectionPluginConfiguration(bluePrintPropertiesService))
323 val configValueRequest = K8sConfigValueRequest()
324 configValueRequest.templateName = configJson.templateName
325 configValueRequest.configName = configJson.configName
326 configValueRequest.values = objectMapper.convertValue(obj)
327 if (api.hasConfigurationValues(instanceId, configName)) {
328 api.editConfigurationValues(configValueRequest, instanceId, configName)
330 api.createConfigurationValues(configValueRequest, instanceId)
337 class UploadFileConfigClientService(
338 private val restClientProperties:
339 BasicAuthRestClientProperties
340 ) : BlueprintWebClientService {
342 override fun defaultHeaders(): Map<String, String> {
344 val encodedCredentials = setBasicAuth(
345 restClientProperties.username,
346 restClientProperties.password
349 HttpHeaders.CONTENT_TYPE to MediaType.APPLICATION_JSON_VALUE,
350 HttpHeaders.ACCEPT to MediaType.APPLICATION_JSON_VALUE,
351 HttpHeaders.AUTHORIZATION to "Basic $encodedCredentials"
355 override fun host(uri: String): String {
356 return restClientProperties.url + uri
359 override fun convertToBasicHeaders(headers: Map<String, String>):
361 val customHeaders: MutableMap<String, String> = headers.toMutableMap()
362 // inject additionalHeaders
363 customHeaders.putAll(verifyAdditionalHeaders(restClientProperties))
365 if (!headers.containsKey(HttpHeaders.AUTHORIZATION)) {
366 val encodedCredentials = setBasicAuth(
367 restClientProperties.username,
368 restClientProperties.password
370 customHeaders[HttpHeaders.AUTHORIZATION] =
371 "Basic $encodedCredentials"
373 return super.convertToBasicHeaders(customHeaders)
376 private fun setBasicAuth(username: String, password: String): String {
377 val credentialsString = "$username:$password"
378 return Base64.getEncoder().encodeToString(
379 credentialsString.toByteArray(Charset.defaultCharset())
383 @Throws(IOException::class, ClientProtocolException::class)
384 private fun performHttpCall(httpUriRequest: HttpUriRequest): BlueprintWebClientService.WebClientResponse<String> {
385 val httpResponse = httpClient().execute(httpUriRequest)
386 val statusCode = httpResponse.statusLine.statusCode
387 httpResponse.entity.content.use {
388 val body = IOUtils.toString(it, Charset.defaultCharset())
389 return BlueprintWebClientService.WebClientResponse(statusCode, body)
393 fun uploadBinaryFile(path: String, filePath: Path): BlueprintWebClientService.WebClientResponse<String> {
394 val convertedHeaders: Array<BasicHeader> = convertToBasicHeaders(defaultHeaders())
395 val httpPost = HttpPost(host(path))
396 val entity = EntityBuilder.create().setBinary(Files.readAllBytes(filePath)).build()
397 httpPost.setEntity(entity)
398 RestLoggerService.httpInvoking(convertedHeaders)
399 httpPost.setHeaders(convertedHeaders)
400 return performHttpCall(httpPost)
405 class K8sConfigPayloadJson {
406 @get:JsonProperty("template-name")
407 var templateName: String? = null
408 @get:JsonProperty("config-name")
409 var configName: String? = null
410 @get:JsonProperty("values")
411 lateinit var values: Config
413 override fun toString(): String {
414 return "$templateName:$configName:$values"
417 override fun equals(other: Any?): Boolean {
418 if (this === other) return true
419 if (javaClass != other?.javaClass) return false
423 override fun hashCode(): Int {
424 return javaClass.hashCode()
429 @get:JsonProperty("config")
430 lateinit var supportedNssai: SupportedNssai
433 class SupportedNssai{
434 @get:JsonProperty("supportedNssai")
435 lateinit var snssaiInitial: SnssaiInitial
440 @get:JsonProperty("sNssai")
441 lateinit var snssaiSecond: SnssaiSecond
446 @get:JsonProperty("snssai")
447 lateinit var snssaiFinalArray: Array<SnssaiFinal>
452 @get:JsonProperty("snssai")
453 var snssai: String? = null
455 @get:JsonProperty("status")
456 var status: String? = null
460 fun main(args: Array<String>) {
462 val supportedNssai = """
464 {\r\n \"sNssai\":[\r\n {\r\n \"snssai\":\"001-100001\",\r\n \"status\":\"created-modified\"\r\n },\r\n {\r\n \"snssai\":\"002-100001\",\r\n \"status\":\"activated\"\r\n },\r\n {\r\n \"snssai\":\"003-100001\",\r\n \"status\":\"de-activated\"\r\n }\r\n ]\r\n }\r\n
468 val kotlin = KotlinK8sUpdateConfig()