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 com.fasterxml.jackson.annotation.JsonIgnore
20 import com.fasterxml.jackson.annotation.JsonProperty
21 import com.fasterxml.jackson.databind.ObjectMapper
22 import com.fasterxml.jackson.databind.node.ObjectNode
23 import com.fasterxml.jackson.databind.JsonNode
24 import com.fasterxml.jackson.module.kotlin.jacksonObjectMapper
26 import java.nio.file.Path
27 import java.nio.file.Paths
28 import org.apache.commons.io.FilenameUtils
29 import org.apache.commons.io.IOUtils
30 import org.apache.http.client.ClientProtocolException
31 import org.apache.http.client.entity.EntityBuilder
32 import org.apache.http.client.methods.HttpPost
33 import org.apache.http.client.methods.HttpUriRequest
34 import org.apache.http.entity.ContentType
35 import org.apache.http.message.BasicHeader
36 import org.onap.ccsdk.cds.blueprintsprocessor.core.api.data.ExecutionServiceInput
37 import org.onap.ccsdk.cds.blueprintsprocessor.rest.BasicAuthRestClientProperties
38 import org.onap.ccsdk.cds.blueprintsprocessor.rest.RestClientProperties
39 import org.onap.ccsdk.cds.blueprintsprocessor.rest.service.BasicAuthRestClientService
40 import org.onap.ccsdk.cds.blueprintsprocessor.rest.service.BlueprintWebClientService
41 import org.onap.ccsdk.cds.blueprintsprocessor.core.BluePrintPropertiesService
42 import org.onap.ccsdk.cds.blueprintsprocessor.functions.k8s.definition.K8sPluginDefinitionApi
43 import org.onap.ccsdk.cds.blueprintsprocessor.functions.k8s.K8sConnectionPluginConfiguration
44 import org.onap.ccsdk.cds.blueprintsprocessor.functions.k8s.definition.K8sDefinitionRestClient
45 import org.onap.ccsdk.cds.blueprintsprocessor.rest.service.RestLoggerService
46 import org.onap.ccsdk.cds.blueprintsprocessor.services.execution.AbstractScriptComponentFunction
47 import org.onap.ccsdk.cds.blueprintsprocessor.functions.resource.resolution.contentFromResolvedArtifactNB
48 import org.onap.ccsdk.cds.controllerblueprints.core.BluePrintProcessorException
49 import org.onap.ccsdk.cds.controllerblueprints.core.utils.ArchiveType
50 import org.onap.ccsdk.cds.controllerblueprints.core.utils.BluePrintArchiveUtils
51 import org.onap.ccsdk.cds.controllerblueprints.core.utils.JacksonUtils
52 import org.onap.ccsdk.cds.blueprintsprocessor.functions.resource.resolution.storedContentFromResolvedArtifactNB
53 import org.slf4j.LoggerFactory
54 import org.springframework.http.HttpHeaders
55 import org.springframework.http.HttpMethod
56 import org.springframework.http.MediaType
57 import org.springframework.web.client.RestTemplate
58 import org.yaml.snakeyaml.Yaml
59 import java.util.ArrayList
60 import java.io.IOException
62 import java.util.Base64
63 import java.nio.charset.Charset
64 import java.nio.file.Files
65 import com.google.gson.Gson
66 import com.google.gson.reflect.TypeToken
68 open class DayOneConfig : AbstractScriptComponentFunction() {
70 private val log = LoggerFactory.getLogger(DayOneConfig::class.java)!!
72 override fun getName(): String {
76 override suspend fun processNB(executionRequest: ExecutionServiceInput) {
77 log.info("DAY-1 Script excution Started")
79 val prefix = "baseconfig"
81 val baseK8sApiUrl = getDynamicProperties("api-access").get("url").asText()
82 val k8sApiUsername = getDynamicProperties("api-access").get("username").asText()
83 val k8sApiPassword = getDynamicProperties("api-access").get("password").asText()
85 log.info("Multi-cloud params $baseK8sApiUrl")
87 val aaiApiUrl = getDynamicProperties("aai-access").get("url").asText()
88 val aaiApiUsername = getDynamicProperties("aai-access").get("username").asText()
89 val aaiApiPassword = getDynamicProperties("aai-access").get("password").asText()
93 log.info("AAI params $aaiApiUrl")
98 val resolution_key = getDynamicProperties("resolution-key").asText()
100 val sdnc_payload:String = contentFromResolvedArtifactNB("config-deploy-sdnc")
101 //log.info("SDNC payload $sdnc_payload")
102 val sdnc_payloadObject = JacksonUtils.jsonNode(sdnc_payload) as ObjectNode
105 val aai_payload:String = contentFromResolvedArtifactNB("config-deploy-aai")
106 //log.info("AAI payload $aai_payload")
107 val aai_payloadObject = JacksonUtils.jsonNode(aai_payload) as ObjectNode
116 for (item in sdnc_payloadObject.get("vf-modules")){
118 var instanceID:String =""
119 val modelTopology = item.get("vf-module-data").get("vf-module-topology")
123 val moduleParameters = modelTopology.get("vf-module-parameters").get("param")
125 val label: String? = getParamValueByName(moduleParameters, "vf-module-label")
126 val modelInfo = modelTopology.get("onap-model-information")
127 val vfModuleInvariantID = modelInfo.get("model-invariant-uuid").asText()
128 log.info("VF MOdule Inavriant ID $vfModuleInvariantID")
129 val vfModuleCustID=modelInfo.get("model-customization-uuid").asText()
130 val vfModuleUUID=modelInfo.get("model-uuid").asText()
131 val idInfo = modelTopology.get("vf-module-topology-identifier")
132 val vfModuleID = idInfo.get("vf-module-id").asText()
133 for (aai_item in aai_payloadObject.get("vf-modules"))
135 if (aai_item.get("vf-module-id").asText() == vfModuleID && aai_item.get("heat-stack-id") != null)
137 instanceID=aai_item.get("heat-stack-id").asText()
144 val k8sRbProfileName: String = "profile_" + vfModuleID
146 val k8sConfigTemplateName: String = "template_" + vfModuleCustID
148 val api = K8sConfigTemplateApi(k8sApiUsername, k8sApiPassword, baseK8sApiUrl, vfModuleInvariantID, vfModuleCustID, k8sConfigTemplateName)
150 // Check if definition exists
151 if (!api.hasDefinition()) {
152 throw BluePrintProcessorException("K8S Definition ($vfModuleInvariantID/$vfModuleCustID) not found ")
154 val bluePrintPropertiesService: BluePrintPropertiesService =this.functionDependencyInstanceAsType("bluePrintPropertiesService")
155 val k8sConfiguration = K8sConnectionPluginConfiguration(bluePrintPropertiesService)
156 val rbDefinitionService = K8sDefinitionRestClient(k8sConfiguration,vfModuleInvariantID, vfModuleCustID)
159 val def: BlueprintWebClientService.WebClientResponse<String> = rbDefinitionService.exchangeResource(HttpMethod.GET.name,"","")
160 log.info(def.body.toString())
161 val rbdef = JacksonUtils.jsonNode(def.body.toString()) as ObjectNode
162 val chartName = rbdef.get("chart-name").asText()
164 log.info("Config Template name: $k8sConfigTemplateName")
168 var configTemplate = K8sConfigTemplate()
169 configTemplate.templateName = k8sConfigTemplateName
170 configTemplate.description = " "
171 configTemplate.ChartName = chartName
172 log.info("Chart name: ${configTemplate.ChartName}")
176 if (!api.hasConfigTemplate(configTemplate)) {
179 val configTemplateFile: Path = prepareConfigTemplateJson(k8sConfigTemplateName, vfModuleID, label)
181 log.info("Config Template Upload Started")
182 api.createConfigTemplate(configTemplate)
183 api.uploadConfigTemplateContent(configTemplate, configTemplateFile)
184 log.info("Config Template Upload Completed")
187 log.info("DAY-1 Script excution completed")
191 catch (e: Exception) {
192 log.info("Caught exception during config template preparation!!")
193 throw BluePrintProcessorException("${e.message}")
196 private fun getParamValueByName(params: JsonNode, paramName: String): String? {
197 for (param in params) {
198 if (param.get("name").asText() == paramName && param.get("value").asText() != "null") {
199 return param.get("value").asText()
206 fun prepareConfigTemplateJson(configTemplateName: String, vfModuleID: String, label: String?): Path {
207 val bluePrintContext = bluePrintRuntimeService.bluePrintContext()
208 val bluePrintBasePath: String = bluePrintContext.rootPath
210 var profileFilePath: Path = Paths.get(bluePrintBasePath.plus(File.separator).plus("Templates").plus(File.separator).plus("k8s-profiles").plus(File.separator).plus(label +"-config-template.tar.gz"))
211 log.info("Reading K8s Config Template file: $profileFilePath")
213 val profileFile = profileFilePath.toFile()
215 if (!profileFile.exists())
216 throw BluePrintProcessorException("K8s Config template file $profileFilePath does not exists")
218 return profileFilePath
222 fun getResolvedParameter(payload: ObjectNode, keyName: String): String {
223 for (node in payload.get("resource-accumulator-resolved-data").elements()) {
224 if (node.get("param-name").asText().equals(keyName)) {
225 return node.get("param-value").asText()
230 override suspend fun recoverNB(runtimeException: RuntimeException, executionRequest: ExecutionServiceInput) {
231 log.info("Recover function called!")
232 log.info("Execution request : $executionRequest")
233 log.error("Exception", runtimeException)
234 addError(runtimeException.message!!)
239 inner class K8sConfigTemplateApi(
240 val username: String,
241 val password: String,
243 val definition: String,
244 val definitionVersion: String,
245 val configTemplateName: String
247 private val service: UploadConfigTemplateRestClientService // BasicAuthRestClientService
250 var mapOfHeaders = hashMapOf<String, String>()
251 mapOfHeaders.put("Accept", "application/json")
252 mapOfHeaders.put("Content-Type", "application/json")
253 mapOfHeaders.put("cache-control", " no-cache")
254 mapOfHeaders.put("Accept", "application/json")
255 var basicAuthRestClientProperties: BasicAuthRestClientProperties = BasicAuthRestClientProperties()
256 basicAuthRestClientProperties.username = username
257 basicAuthRestClientProperties.password = password
258 basicAuthRestClientProperties.url = "$baseUrl/v1/rb/definition/$definition/$definitionVersion"
259 basicAuthRestClientProperties.additionalHeaders = mapOfHeaders
261 this.service = UploadConfigTemplateRestClientService(basicAuthRestClientProperties)
264 fun hasDefinition(): Boolean {
266 val result: BlueprintWebClientService.WebClientResponse<String> = service.exchangeResource(HttpMethod.GET.name, "", "")
268 if (result.status >= 200 && result.status < 300)
272 } catch (e: Exception) {
273 log.info("Caught exception trying to get k8s config trmplate definition")
274 throw BluePrintProcessorException("${e.message}")
278 fun hasConfigTemplate(profile: K8sConfigTemplate): Boolean {
280 val result: BlueprintWebClientService.WebClientResponse<String> = service.exchangeResource(HttpMethod.GET.name, "/config-template/${profile.templateName}", "")
282 if (result.status >= 200 && result.status < 300) {
283 log.info("ConfigTemplate already exists")
287 } catch (e: Exception) {
288 log.info("Caught exception trying to get k8s config trmplate definition")
289 throw BluePrintProcessorException("${e.message}")
293 fun createConfigTemplate(profile: K8sConfigTemplate) {
294 val objectMapper = ObjectMapper()
295 val profileJsonString: String = objectMapper.writeValueAsString(profile)
297 val result: BlueprintWebClientService.WebClientResponse<String> = service.exchangeResource(
298 HttpMethod.POST.name,
303 if (result.status >= 200 && result.status < 300) {
304 log.info("Config template json info uploaded correctly")
305 } else if (result.status < 200 || result.status >= 300) {
306 log.info("Config template already exists")
308 } catch (e: Exception) {
309 log.info("Caught exception trying to create k8s config template ${profile.templateName} - updated")
310 // throw BluePrintProcessorException("${e.message}")
314 fun uploadConfigTemplateContent(profile: K8sConfigTemplate, filePath: Path) {
316 val result: BlueprintWebClientService.WebClientResponse<String> = service.uploadBinaryFile(
317 "/config-template/${profile.templateName}/content",
320 if (result.status < 200 || result.status >= 300) {
321 throw Exception(result.body)
323 } catch (e: Exception) {
324 log.info("Caught exception trying to upload k8s config template ${profile.templateName}")
325 throw BluePrintProcessorException("${e.message}")
331 class UploadConfigTemplateRestClientService(
332 private val restClientProperties:
333 BasicAuthRestClientProperties
334 ) : BlueprintWebClientService {
336 override fun defaultHeaders(): Map<String, String> {
338 val encodedCredentials = setBasicAuth(
339 restClientProperties.username,
340 restClientProperties.password
343 HttpHeaders.CONTENT_TYPE to MediaType.APPLICATION_JSON_VALUE,
344 HttpHeaders.ACCEPT to MediaType.APPLICATION_JSON_VALUE,
345 HttpHeaders.AUTHORIZATION to "Basic $encodedCredentials"
349 override fun host(uri: String): String {
350 return restClientProperties.url + uri
353 override fun convertToBasicHeaders(headers: Map<String, String>):
355 val customHeaders: MutableMap<String, String> = headers.toMutableMap()
356 // inject additionalHeaders
357 customHeaders.putAll(verifyAdditionalHeaders(restClientProperties))
359 if (!headers.containsKey(HttpHeaders.AUTHORIZATION)) {
360 val encodedCredentials = setBasicAuth(
361 restClientProperties.username,
362 restClientProperties.password
364 customHeaders[HttpHeaders.AUTHORIZATION] =
365 "Basic $encodedCredentials"
367 return super.convertToBasicHeaders(customHeaders)
370 private fun setBasicAuth(username: String, password: String): String {
371 val credentialsString = "$username:$password"
372 return Base64.getEncoder().encodeToString(
373 credentialsString.toByteArray(Charset.defaultCharset())
377 @Throws(IOException::class, ClientProtocolException::class)
378 private fun performHttpCall(httpUriRequest: HttpUriRequest): BlueprintWebClientService.WebClientResponse<String> {
379 val httpResponse = httpClient().execute(httpUriRequest)
380 val statusCode = httpResponse.statusLine.statusCode
381 httpResponse.entity.content.use {
382 val body = IOUtils.toString(it, Charset.defaultCharset())
383 return BlueprintWebClientService.WebClientResponse(statusCode, body)
387 fun uploadBinaryFile(path: String, filePath: Path): BlueprintWebClientService.WebClientResponse<String> {
388 val convertedHeaders: Array<BasicHeader> = convertToBasicHeaders(defaultHeaders())
389 val httpPost = HttpPost(host(path))
390 val entity = EntityBuilder.create().setBinary(Files.readAllBytes(filePath)).build()
391 httpPost.setEntity(entity)
392 RestLoggerService.httpInvoking(convertedHeaders)
393 httpPost.setHeaders(convertedHeaders)
394 return performHttpCall(httpPost)
398 class K8sConfigTemplate {
399 @get:JsonProperty("template-name")
400 var templateName: String? = null
401 @get:JsonProperty("description")
402 var description: String? = null
403 @get:JsonProperty("ChartName")
404 var ChartName: String? = null
406 override fun equals(other: Any?): Boolean {
407 if (this === other) return true
408 if (javaClass != other?.javaClass) return false
412 override fun hashCode(): Int {
413 return javaClass.hashCode()
420 lateinit var Name: String
426 var Group: String? = null
427 var Version: String? = null
428 var Kind: String? = null
432 fun main(args: Array<String>) {
434 val kotlin = DayOneConfig()