Renaming Files having BluePrint to have Blueprint
[ccsdk/cds.git] / components / model-catalog / blueprint-model / service-blueprint / 5GC_Simulator_CNF_CDS / Scripts / kotlin / KotlinK8sUpdateConfig.kt
1 /*
2 *  Copyright © 2019 TechMahindra
3 *  Author: Vamshi Namilikonda <vn00480215@techmahindra.com>
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 org.onap.ccsdk.cds.blueprintsprocessor.rest.service.BlueprintWebClientService
25 import org.onap.ccsdk.cds.controllerblueprints.core.BlueprintProcessorException
26 import java.nio.file.Path
27 import org.springframework.http.HttpMethod
28 import org.onap.ccsdk.cds.blueprintsprocessor.rest.BasicAuthRestClientProperties
29 import org.springframework.http.HttpHeaders
30 import org.springframework.http.MediaType
31 import org.apache.http.message.BasicHeader
32 import java.util.Base64
33 import java.nio.charset.Charset
34 import java.io.IOException
35 import org.apache.http.client.methods.HttpUriRequest
36 import com.fasterxml.jackson.annotation.JsonProperty
37 import org.apache.commons.io.IOUtils
38 import org.apache.http.client.methods.HttpPost
39 import org.apache.http.client.entity.EntityBuilder
40 import java.nio.file.Files
41 import org.onap.ccsdk.cds.blueprintsprocessor.rest.service.RestLoggerService
42 import org.apache.http.client.ClientProtocolException
43 import com.fasterxml.jackson.databind.ObjectMapper
44
45 import com.google.gson.Gson
46 import com.google.gson.reflect.TypeToken
47
48 import org.onap.ccsdk.cds.blueprintsprocessor.functions.resource.resolution.storedContentFromResolvedArtifactNB
49 import org.onap.ccsdk.cds.blueprintsprocessor.rest.service.BasicAuthRestClientService
50
51 open class KotlinK8sUpdateConfig : AbstractScriptComponentFunction() {
52
53     private val log = LoggerFactory.getLogger(KotlinK8sUpdateConfig::class.java)!!
54
55     override fun getName(): String {
56         return "KotlinK8sUpdateConfig"
57     }
58
59     override suspend fun processNB(executionRequest: ExecutionServiceInput) {
60
61         println("Exeuting processNB")
62         log.info("Executing processNB from Kotlin script: KotlinK8sUpdateConfig ...")
63
64         // read the config  input
65         val baseK8sApiUrl = getDynamicProperties("api-access").get("url").asText()
66         val k8sApiUsername = getDynamicProperties("api-access").get("username").asText()
67         val k8sApiPassword = getDynamicProperties("api-access").get("password").asText()
68
69         val prefix = "baseconfigput"
70
71         val aaiApiUrl = getDynamicProperties("aai-access").get("url").asText()
72         val aaiApiUsername = getDynamicProperties("aai-access").get("username").asText()
73         val aaiApiPassword = getDynamicProperties("aai-access").get("password").asText()
74
75         log.info("AAI params $aaiApiUrl")
76
77         val resolution_key = getDynamicProperties("resolution-key").asText()
78
79         val payload = storedContentFromResolvedArtifactNB(resolution_key, prefix)
80
81         val payloadObject = JacksonUtils.jsonNode(payload) as ObjectNode
82
83         val serviceInstanceID: String = getResolvedParameter(payloadObject, "service-instance-id")
84         val vnfID: String = getResolvedParameter(payloadObject, "vnf-id")
85
86         log.info("Get serviceInstanceID $serviceInstanceID")
87         log.info("Get vnfID $vnfID")
88
89         val vnfUrl = aaiApiUrl + "/aai/v19/network/generic-vnfs/generic-vnf/" + vnfID + "/vf-modules";
90
91         val mapOfHeaders = hashMapOf<String, String>()
92         mapOfHeaders.put("Accept", "application/json")
93         mapOfHeaders.put("Content-Type", "application/json")
94         mapOfHeaders.put("x-FromAppId", "SO")
95         mapOfHeaders.put("X-TransactionId", "get_aai_subscr")
96         val basicAuthRestClientProperties: BasicAuthRestClientProperties = BasicAuthRestClientProperties()
97         basicAuthRestClientProperties.username = aaiApiUsername
98         basicAuthRestClientProperties.password = aaiApiPassword
99         basicAuthRestClientProperties.url = vnfUrl
100         basicAuthRestClientProperties.additionalHeaders =mapOfHeaders
101         val basicAuthRestClientService: BasicAuthRestClientService= BasicAuthRestClientService(basicAuthRestClientProperties)
102         try {
103             val resultOfGet: BlueprintWebClientService.WebClientResponse<String> = basicAuthRestClientService.exchangeResource(HttpMethod.GET.name, "", "")
104
105             val aaiBody = resultOfGet.body
106             val aaiPayloadObject = JacksonUtils.jsonNode(aaiBody) as ObjectNode
107
108             for (item in aaiPayloadObject.get("vf-module")) {
109
110                 log.info("item payload Deatils : $item")
111
112                 val isItBaseVfModule = item.get("is-base-vf-module").asText()
113
114                 if(isItBaseVfModule.toBoolean())
115                     continue
116
117                 val vfModuleID: String = item.get("vf-module-id").asText()
118
119                 log.info("AAI Vf-module ID is : $vfModuleID")
120
121                 val vfModuleModelInvariantUuid: String = item.get("model-invariant-id").asText()
122
123                 log.info("AAI Vf-module Invariant ID is : $vfModuleModelInvariantUuid")
124
125                 val vfModuleModelUuid: String = item.get("model-version-id").asText()
126
127                 log.info("AAI Vf-module UUID is : $vfModuleModelUuid")
128
129                 val vfModuleInstance: String = item.get("heat-stack-id").asText()
130
131                 log.info("AAI Vf-module Heat Stack ID : $vfModuleInstance")
132
133                 val profileName: String = "profile-"+ vfModuleID
134                 val templateName: String = "template_" + vfModuleID
135
136                 val randomString = getRandomString(6)
137                 val configName: String = "config_"+ randomString
138
139                 var supportedNssai: String = getResolvedParameter(payloadObject, "supportedNssai")
140
141                 log.info("supportedNssai from SO -> "+ supportedNssai)
142                 log.info("configName ->"+ configName)
143                 log.info("profileName ->"+ profileName)
144                 log.info("templateName ->"+ templateName)
145
146
147                 executeK8sAPI(supportedNssai, k8sApiUsername, k8sApiPassword, baseK8sApiUrl, vfModuleModelInvariantUuid, vfModuleModelUuid, templateName, configName, profileName)
148
149             }
150         }
151         catch (e: Exception) {
152             log.info("Caught exception trying to get the vnf Details!!")
153             throw BlueprintProcessorException("${e.message}")
154         }
155     }
156
157     fun getRandomString(length: Int) : String {
158         val charset = "0123456789"
159         return (1..length)
160                 .map { charset.random() }
161                 .joinToString("")
162     }
163
164     fun executeK8sAPI(supportedNssai: String, k8sApiUsername:String, k8sApiPassword:String, baseK8sApiUrl:String, vfModuleModelInvariantUuid:String, vfModuleModelUuid: String, templateName: String, configName:String, profileName:String){
165
166         println("Executing executeK8sAPI ...")
167
168         // read and convert supportedNssai parameters from string to json
169         val sNssaiAsJsonObj = parseSupportedNssai(supportedNssai)
170
171         // contruct config api
172         val api = K8sConfigApi(k8sApiUsername, k8sApiPassword, baseK8sApiUrl, vfModuleModelInvariantUuid, vfModuleModelUuid)
173
174
175         // invoke config api
176         var config = K8sConfigPayloadJson()
177         config.templateName = templateName
178         config.configName = configName
179         config.values = Config()
180         config.values.supportedNssai = SupportedNssai()
181         config.values.supportedNssai.snssaiInitial = SnssaiInitial()
182         config.values.supportedNssai.snssaiInitial.snssaiSecond = SnssaiSecond()
183         config.values.supportedNssai.snssaiInitial.snssaiSecond.snssaiFinalArray = Array<SnssaiFinal>(sNssaiAsJsonObj.size){i-> SnssaiFinal()}
184
185         val dest = buildSNssaiArray(config.values.supportedNssai.snssaiInitial.snssaiSecond.snssaiFinalArray, sNssaiAsJsonObj)
186         api.createOrUpdateConfig(config, profileName)
187
188         log.info("K8s Configurations create or update Completed")
189
190     }
191
192     fun buildSNssaiArray(payloadSnssai: Array<SnssaiFinal>, requestSnssai: Array<SnssaiFinal>): Array<SnssaiFinal>{
193
194         System.arraycopy(requestSnssai, 0, payloadSnssai, 0, requestSnssai.size)
195
196         return payloadSnssai
197
198     }
199
200     fun parseSupportedNssai(supportedNssai: String): Array<SnssaiFinal>{
201
202         log.info("parsing supportedNssai string..")
203
204         log.info("sNssai value from input..  $supportedNssai")
205
206         val trimmed_supportedNssai = supportedNssai.replace("\\s".toRegex(), "").replace("\\r\\n","").replace("\\","")
207
208         val gson = Gson()
209
210         val startInd = trimmed_supportedNssai.indexOf('[')
211         val endInd = trimmed_supportedNssai.indexOf(']')
212
213         val subStr = trimmed_supportedNssai.substring(startInd, endInd+1)
214
215         val snType = object : TypeToken<Array<SnssaiFinal>>() {}.type
216
217         var snList: Array<SnssaiFinal> = gson.fromJson(subStr, snType)
218
219         log.info("parsing is done.")
220
221         return snList
222
223     }
224
225     fun getResolvedParameter(payload: ObjectNode, keyName: String): String {
226         for (node in payload.get("resource-accumulator-resolved-data").elements()) {
227             if (node.get("param-name").asText().equals(keyName)) {
228                 return node.get("param-value").asText()
229             }
230         }
231         return ""
232     }
233
234     override suspend fun recoverNB(runtimeException: RuntimeException, executionRequest: ExecutionServiceInput) {
235         log.info("Executing Recovery")
236     }
237
238     inner class K8sConfigApi(
239             val username: String,
240             val password: String,
241             val baseUrl: String,
242             val definition: String,
243             val definitionVersion: String
244     ) {
245         private val service: UploadFileConfigClientService // BasicAuthRestClientService
246
247         init {
248             var mapOfHeaders = hashMapOf<String, String>()
249             mapOfHeaders.put("Accept", "application/json")
250             mapOfHeaders.put("Content-Type", "application/json")
251             mapOfHeaders.put("cache-control", " no-cache")
252             mapOfHeaders.put("Accept", "application/json")
253             var basicAuthRestClientProperties: BasicAuthRestClientProperties = BasicAuthRestClientProperties()
254             basicAuthRestClientProperties.username = username
255             basicAuthRestClientProperties.password = password
256             basicAuthRestClientProperties.url = "$baseUrl/v1/rb/definition/$definition/$definitionVersion"
257             basicAuthRestClientProperties.additionalHeaders = mapOfHeaders
258
259             this.service = UploadFileConfigClientService(basicAuthRestClientProperties)
260         }
261
262         fun createOrUpdateConfig(configJson: K8sConfigPayloadJson, profileName: String) {
263             val objectMapper = ObjectMapper()
264
265             for(snssai in configJson.values.supportedNssai.snssaiInitial.snssaiSecond.snssaiFinalArray){
266                 println("snssai->" +snssai.snssai)
267                 println("status->"+snssai.status)
268
269             }
270
271             val configJsonString: String = objectMapper.writeValueAsString(configJson)
272
273             log.info("payload generated -> "+ configJsonString)
274
275             val startInd = configJsonString.indexOf('[')
276             val endInd = configJsonString.indexOf(']')
277
278             val snssaiArray: String = configJsonString.substring(startInd, endInd+1).replace("\"","\\\"").replace("[","\"[").replace("]","]\"")
279
280             val finalPayload: String = configJsonString.replaceRange(startInd..endInd, snssaiArray)
281
282             log.info("payload restructured -> "+ finalPayload)
283
284             try {
285                 val result: BlueprintWebClientService.WebClientResponse<String> = service.exchangeResource(HttpMethod.POST.name,
286                         "/profile/${profileName}/config", finalPayload)
287                 if (result.status < 200 || result.status >= 300) {
288                     throw Exception(result.body)
289                 }
290             } catch (e: Exception) {
291                 log.info("Caught exception trying to create or update configuration ")
292                 throw BlueprintProcessorException("${e.message}")
293             }
294         }
295
296     }
297 }
298
299 class UploadFileConfigClientService(
300         private val restClientProperties:
301         BasicAuthRestClientProperties
302 ) : BlueprintWebClientService {
303
304     override fun defaultHeaders(): Map<String, String> {
305
306         val encodedCredentials = setBasicAuth(
307                 restClientProperties.username,
308                 restClientProperties.password
309         )
310         return mapOf(
311                 HttpHeaders.CONTENT_TYPE to MediaType.APPLICATION_JSON_VALUE,
312                 HttpHeaders.ACCEPT to MediaType.APPLICATION_JSON_VALUE,
313                 HttpHeaders.AUTHORIZATION to "Basic $encodedCredentials"
314         )
315     }
316
317     override fun host(uri: String): String {
318         return restClientProperties.url + uri
319     }
320
321     override fun convertToBasicHeaders(headers: Map<String, String>):
322             Array<BasicHeader> {
323         val customHeaders: MutableMap<String, String> = headers.toMutableMap()
324         // inject additionalHeaders
325         customHeaders.putAll(verifyAdditionalHeaders(restClientProperties))
326
327         if (!headers.containsKey(HttpHeaders.AUTHORIZATION)) {
328             val encodedCredentials = setBasicAuth(
329                     restClientProperties.username,
330                     restClientProperties.password
331             )
332             customHeaders[HttpHeaders.AUTHORIZATION] =
333                     "Basic $encodedCredentials"
334         }
335         return super.convertToBasicHeaders(customHeaders)
336     }
337
338     private fun setBasicAuth(username: String, password: String): String {
339         val credentialsString = "$username:$password"
340         return Base64.getEncoder().encodeToString(
341                 credentialsString.toByteArray(Charset.defaultCharset())
342         )
343     }
344
345     @Throws(IOException::class, ClientProtocolException::class)
346     private fun performHttpCall(httpUriRequest: HttpUriRequest): BlueprintWebClientService.WebClientResponse<String> {
347         val httpResponse = httpClient().execute(httpUriRequest)
348         val statusCode = httpResponse.statusLine.statusCode
349         httpResponse.entity.content.use {
350             val body = IOUtils.toString(it, Charset.defaultCharset())
351             return BlueprintWebClientService.WebClientResponse(statusCode, body)
352         }
353     }
354
355     fun uploadBinaryFile(path: String, filePath: Path): BlueprintWebClientService.WebClientResponse<String> {
356         val convertedHeaders: Array<BasicHeader> = convertToBasicHeaders(defaultHeaders())
357         val httpPost = HttpPost(host(path))
358         val entity = EntityBuilder.create().setBinary(Files.readAllBytes(filePath)).build()
359         httpPost.setEntity(entity)
360         RestLoggerService.httpInvoking(convertedHeaders)
361         httpPost.setHeaders(convertedHeaders)
362         return performHttpCall(httpPost)
363     }
364 }
365
366
367 class K8sConfigPayloadJson {
368     @get:JsonProperty("template-name")
369     var templateName: String? = null
370     @get:JsonProperty("config-name")
371     var configName: String? = null
372     @get:JsonProperty("values")
373     lateinit var values: Config
374
375     override fun toString(): String {
376         return "$templateName:$configName:$values"
377     }
378
379     override fun equals(other: Any?): Boolean {
380         if (this === other) return true
381         if (javaClass != other?.javaClass) return false
382         return true
383     }
384
385     override fun hashCode(): Int {
386         return javaClass.hashCode()
387     }
388 }
389
390 class Config{
391     @get:JsonProperty("config")
392     lateinit var supportedNssai: SupportedNssai
393 }
394
395 class SupportedNssai{
396     @get:JsonProperty("supportedNssai")
397     lateinit var snssaiInitial: SnssaiInitial
398 }
399
400 class SnssaiInitial{
401
402     @get:JsonProperty("sNssai")
403     lateinit var snssaiSecond: SnssaiSecond
404 }
405
406 class SnssaiSecond{
407
408     @get:JsonProperty("snssai")
409     lateinit var snssaiFinalArray: Array<SnssaiFinal>
410 }
411
412
413 class SnssaiFinal{
414     @get:JsonProperty("snssai")
415     var snssai: String? = null
416
417     @get:JsonProperty("status")
418     var status: String? = null
419 }
420
421
422 fun main(args: Array<String>) {
423
424     val supportedNssai = """
425
426         {\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
427
428 """
429
430     val kotlin = KotlinK8sUpdateConfig()
431
432     /* supportedNssai
433      k8sApiUsername
434      k8sApiPassword
435      baseK8sApiUrl
436      vfModuleModelInvariantUuid
437      vfModuleModelUuid
438      templateName
439      configName
440      profileName*/
441
442     kotlin.executeK8sAPI(supportedNssai, "admin", "admin", "http://0.0.0.0:9015", "rb_test", "1", "template_test", "config_test", "profile_test")
443
444 }