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