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