937c00a4fcebac1e97e8273ed290f18b7f2a43df
[ccsdk/cds.git] / components / model-catalog / blueprint-model / service-blueprint / 5GC_Simulator_CNF_CDS / Scripts / kotlin / KotlinK8sUpdateConfig.kt
1 /*
2 *  Copyright © 2019 TechMahindra
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.services.execution.scripts
18
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
53
54 import com.google.gson.Gson
55 import com.google.gson.reflect.TypeToken
56
57 import org.onap.ccsdk.cds.blueprintsprocessor.functions.resource.resolution.storedContentFromResolvedArtifactNB
58 import org.onap.ccsdk.cds.blueprintsprocessor.rest.service.BasicAuthRestClientService
59
60 open class KotlinK8sUpdateConfig : AbstractScriptComponentFunction() {
61
62     private val log = LoggerFactory.getLogger(KotlinK8sUpdateConfig::class.java)!!
63
64     override fun getName(): String {
65         return "KotlinK8sUpdateConfig"
66     }
67
68     override suspend fun processNB(executionRequest: ExecutionServiceInput) {
69
70         println("Exeuting processNB")
71         log.info("Executing processNB from Kotlin script: KotlinK8sUpdateConfig ...")
72         val bluePrintPropertiesService: BluePrintPropertiesService =this.functionDependencyInstanceAsType("bluePrintPropertiesService")
73
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()
78
79         val prefix = "baseconfigput"
80
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()
84
85         log.info("AAI params $aaiApiUrl")
86
87         val resolution_key = getDynamicProperties("resolution-key").asText()
88
89         val payload = storedContentFromResolvedArtifactNB(resolution_key, prefix)
90
91         val payloadObject = JacksonUtils.jsonNode(payload) as ObjectNode
92
93         val serviceInstanceID: String = getResolvedParameter(payloadObject, "service-instance-id")
94         val vnfID: String = getResolvedParameter(payloadObject, "vnf-id")
95
96         log.info("Get serviceInstanceID $serviceInstanceID")
97         log.info("Get vnfID $vnfID")
98
99         val vnfUrl = aaiApiUrl + "/aai/v19/network/generic-vnfs/generic-vnf/" + vnfID + "/vf-modules";
100
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)
112         try {
113             val resultOfGet: BlueprintWebClientService.WebClientResponse<String> = basicAuthRestClientService.exchangeResource(HttpMethod.GET.name, "", "")
114
115             val aaiBody = resultOfGet.body
116             val aaiPayloadObject = JacksonUtils.jsonNode(aaiBody) as ObjectNode
117
118             log.info("aaiPayloadObject: $aaiPayloadObject")
119
120             for (item in aaiPayloadObject.get("vf-module")) {
121
122                 log.info("item payload Deatils : $item")
123
124                 val isItBaseVfModule = item.get("is-base-vf-module").asText()
125
126                 if(isItBaseVfModule.toBoolean())
127                     continue
128
129                 val vfModuleID: String = item.get("vf-module-id").asText()
130
131                 log.info("AAI Vf-module ID is : $vfModuleID")
132
133                 val vfModuleModelInvariantUuid: String = item.get("model-invariant-id").asText()
134
135                 log.info("AAI Vf-module Invariant ID is : $vfModuleModelInvariantUuid")
136
137                 val vfModuleModelUuid: String = item.get("model-customization-id").asText()
138
139                 log.info("AAI Vf-module UUID is : $vfModuleModelUuid")
140
141                 val vfModuleCustUuid: String = item.get("model-customization-id").asText()
142
143                 log.info("AAI Vf-module Customization UUID is : $vfModuleCustUuid")
144
145
146                 val vfModuleInstance: String = item.get("heat-stack-id").asText()
147
148                 log.info("AAI Vf-module Heat Stack ID : $vfModuleInstance")
149
150                 val profileName: String = "profile-"+ vfModuleID
151                 val templateName: String = "template_" + vfModuleCustUuid
152
153                 //val randomString = getRandomString(6)
154                 val configName: String = "config_"+ vfModuleID
155
156                 log.info("payloadObject: $payloadObject")
157
158                 var supportedNssai: String = getResolvedParameter(payloadObject, "supportedNssai")
159
160                 log.info("supportedNssai from SO -> "+ supportedNssai)
161                 log.info("configName ->"+ configName)
162                 log.info("profileName ->"+ profileName)
163                 log.info("templateName ->"+ templateName)
164
165
166                 executeK8sAPI(bluePrintPropertiesService,supportedNssai, k8sApiUsername, k8sApiPassword, baseK8sApiUrl, vfModuleModelInvariantUuid, vfModuleCustUuid, templateName, configName, profileName, vfModuleInstance)
167
168             }
169         }
170         catch (e: Exception) {
171             log.info("Caught exception trying to set config values!!")
172             throw BluePrintProcessorException("${e.message}")
173         }
174     }
175
176     fun getRandomString(length: Int) : String {
177         val charset = "0123456789"
178         return (1..length)
179                 .map { charset.random() }
180                 .joinToString("")
181     }
182
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){
184
185         println("Executing executeK8sAPI ...")
186
187         // read and convert supportedNssai parameters from string to json
188         val sNssaiAsJsonObj = parseSupportedNssai(supportedNssai)
189
190         // contruct config api
191         val api = K8sConfigApi(k8sApiUsername, k8sApiPassword, baseK8sApiUrl, vfModuleModelInvariantUuid, vfModuleCustUuid, instanceId, bluePrintPropertiesService)
192
193
194         // invoke config api
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()}
203
204         val dest = buildSNssaiArray(config.values.supportedNssai.snssaiInitial.snssaiSecond.snssaiFinalArray, sNssaiAsJsonObj)
205         api.createOrUpdateConfig(config, profileName, instanceId, configName, templateName)
206
207         log.info("K8s Configurations create or update Completed")
208
209     }
210
211     fun buildSNssaiArray(payloadSnssai: Array<SnssaiFinal>, requestSnssai: Array<SnssaiFinal>): Array<SnssaiFinal>{
212
213         System.arraycopy(requestSnssai, 0, payloadSnssai, 0, requestSnssai.size)
214
215         return payloadSnssai
216
217     }
218
219     fun parseSupportedNssai(supportedNssai: String): Array<SnssaiFinal>{
220
221         log.info("parsing supportedNssai string..")
222
223         log.info("sNssai value from input..  $supportedNssai")
224
225         val trimmed_supportedNssai = supportedNssai.replace("\\s".toRegex(), "").replace("\\r\\n","").replace("\\","")
226
227         val gson = Gson()
228
229         val startInd = trimmed_supportedNssai.indexOf('[')
230         val endInd = trimmed_supportedNssai.indexOf(']')
231
232         val subStr = trimmed_supportedNssai.substring(startInd, endInd+1)
233
234         val snType = object : TypeToken<Array<SnssaiFinal>>() {}.type
235
236         var snList: Array<SnssaiFinal> = gson.fromJson(subStr, snType)
237
238         log.info("parsing is done.")
239
240         return snList
241
242     }
243
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()
248             }
249         }
250         return ""
251     }
252
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())
257         return result
258     }
259
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!!)
265     }
266
267     inner class K8sConfigApi(
268             val username: String,
269             val password: String,
270             val baseUrl: String,
271             val definition: String,
272             val definitionVersion: String,
273             val instanceId: String,
274             val bluePrintPropertiesService: BluePrintPropertiesService
275
276     ) {
277         private val service: UploadFileConfigClientService // BasicAuthRestClientService
278
279         init {
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
290
291             this.service = UploadFileConfigClientService(basicAuthRestClientProperties)
292         }
293
294         fun createOrUpdateConfig(configJson: K8sConfigPayloadJson, profileName: String, instanceId: String, configName: String, templateName: String) {
295             val objectMapper = ObjectMapper()
296             var obj: Any? = null
297             val yamlReader = ObjectMapper(YAMLFactory())
298
299             for(snssai in configJson.values.supportedNssai.snssaiInitial.snssaiSecond.snssaiFinalArray){
300                 println("snssai->" +snssai.snssai)
301                 println("status->"+snssai.status)
302
303             }
304
305             val configJsonString: String = objectMapper.writeValueAsString(configJson.values)
306
307             log.info("payload generated -> "+ configJsonString)
308
309             val startInd = configJsonString.indexOf('[')
310             val endInd = configJsonString.indexOf(']')
311
312             val snssaiArray: String = configJsonString.substring(startInd, endInd+1).replace("\"","\\\"").replace("[","\"[").replace("]","]\"")
313
314             val finalPayload: String = configJsonString.replaceRange(startInd..endInd, snssaiArray)
315
316             log.info("payload restructured -> "+ finalPayload)
317             obj = yamlReader.readValue(finalPayload, Any::class.java)
318
319
320
321             val api = K8sPluginInstanceApi(K8sConnectionPluginConfiguration(bluePrintPropertiesService))
322
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)
329             } else {
330                 api.createConfigurationValues(configValueRequest, instanceId)
331             }
332         }
333
334     }
335 }
336
337 class UploadFileConfigClientService(
338         private val restClientProperties:
339         BasicAuthRestClientProperties
340 ) : BlueprintWebClientService {
341
342     override fun defaultHeaders(): Map<String, String> {
343
344         val encodedCredentials = setBasicAuth(
345                 restClientProperties.username,
346                 restClientProperties.password
347         )
348         return mapOf(
349                 HttpHeaders.CONTENT_TYPE to MediaType.APPLICATION_JSON_VALUE,
350                 HttpHeaders.ACCEPT to MediaType.APPLICATION_JSON_VALUE,
351                 HttpHeaders.AUTHORIZATION to "Basic $encodedCredentials"
352         )
353     }
354
355     override fun host(uri: String): String {
356         return restClientProperties.url + uri
357     }
358
359     override fun convertToBasicHeaders(headers: Map<String, String>):
360             Array<BasicHeader> {
361         val customHeaders: MutableMap<String, String> = headers.toMutableMap()
362         // inject additionalHeaders
363         customHeaders.putAll(verifyAdditionalHeaders(restClientProperties))
364
365         if (!headers.containsKey(HttpHeaders.AUTHORIZATION)) {
366             val encodedCredentials = setBasicAuth(
367                     restClientProperties.username,
368                     restClientProperties.password
369             )
370             customHeaders[HttpHeaders.AUTHORIZATION] =
371                     "Basic $encodedCredentials"
372         }
373         return super.convertToBasicHeaders(customHeaders)
374     }
375
376     private fun setBasicAuth(username: String, password: String): String {
377         val credentialsString = "$username:$password"
378         return Base64.getEncoder().encodeToString(
379                 credentialsString.toByteArray(Charset.defaultCharset())
380         )
381     }
382
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)
390         }
391     }
392
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)
401     }
402 }
403
404
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
412
413     override fun toString(): String {
414         return "$templateName:$configName:$values"
415     }
416
417     override fun equals(other: Any?): Boolean {
418         if (this === other) return true
419         if (javaClass != other?.javaClass) return false
420         return true
421     }
422
423     override fun hashCode(): Int {
424         return javaClass.hashCode()
425     }
426 }
427
428 class Config{
429     @get:JsonProperty("config")
430     lateinit var supportedNssai: SupportedNssai
431 }
432
433 class SupportedNssai{
434     @get:JsonProperty("supportedNssai")
435     lateinit var snssaiInitial: SnssaiInitial
436 }
437
438 class SnssaiInitial{
439
440     @get:JsonProperty("sNssai")
441     lateinit var snssaiSecond: SnssaiSecond
442 }
443
444 class SnssaiSecond{
445
446     @get:JsonProperty("snssai")
447     lateinit var snssaiFinalArray: Array<SnssaiFinal>
448 }
449
450
451 class SnssaiFinal{
452     @get:JsonProperty("snssai")
453     var snssai: String? = null
454
455     @get:JsonProperty("status")
456     var status: String? = null
457 }
458
459
460 fun main(args: Array<String>) {
461
462     val supportedNssai = """
463
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
465
466 """
467
468     val kotlin = KotlinK8sUpdateConfig()
469
470
471
472 }