1 package org.onap.ccsdk.cds.blueprintsprocessor.functions.k8s.definition.template
3 import com.fasterxml.jackson.databind.JsonNode
4 import com.fasterxml.jackson.databind.ObjectMapper
5 import com.fasterxml.jackson.databind.node.ArrayNode
6 import com.fasterxml.jackson.databind.node.ObjectNode
7 import com.fasterxml.jackson.dataformat.yaml.YAMLFactory
8 import com.fasterxml.jackson.module.kotlin.convertValue
9 import org.onap.ccsdk.cds.blueprintsprocessor.core.BlueprintPropertiesService
10 import org.onap.ccsdk.cds.blueprintsprocessor.core.api.data.ExecutionServiceInput
11 import org.onap.ccsdk.cds.blueprintsprocessor.functions.k8s.K8sConnectionPluginConfiguration
12 import org.onap.ccsdk.cds.blueprintsprocessor.functions.k8s.instance.K8sConfigValueRequest
13 import org.onap.ccsdk.cds.blueprintsprocessor.functions.k8s.instance.K8sPluginInstanceApi
14 import org.onap.ccsdk.cds.blueprintsprocessor.services.execution.AbstractComponentFunction
15 import org.onap.ccsdk.cds.controllerblueprints.core.BlueprintConstants
16 import org.onap.ccsdk.cds.controllerblueprints.core.BlueprintProcessorException
17 import org.onap.ccsdk.cds.controllerblueprints.core.data.ArtifactDefinition
18 import org.onap.ccsdk.cds.controllerblueprints.core.returnNullIfMissing
19 import org.onap.ccsdk.cds.controllerblueprints.core.utils.JacksonUtils
20 import org.slf4j.LoggerFactory
21 import org.springframework.beans.factory.config.ConfigurableBeanFactory
22 import org.springframework.context.annotation.Scope
23 import org.springframework.stereotype.Component
25 import java.nio.file.Path
26 import java.nio.file.Paths
28 @Component("component-k8s-config-value")
29 @Scope(value = ConfigurableBeanFactory.SCOPE_PROTOTYPE)
30 open class K8sConfigValueComponent(
31 private var bluePrintPropertiesService: BlueprintPropertiesService
32 ) : AbstractComponentFunction() {
34 private val log = LoggerFactory.getLogger(K8sConfigValueComponent::class.java)!!
37 const val INPUT_RESOURCE_ASSIGNMENT_MAP = "resource-assignment-map"
38 const val INPUT_ARTIFACT_PREFIX_NAMES = "artifact-prefix-names"
39 const val INPUT_K8S_TEMPLATE_NAME = "k8s-template-name"
40 const val INPUT_K8S_CONFIG_NAME = "k8s-config-name"
41 const val INPUT_K8S_INSTANCE_ID = "k8s-instance-id"
42 const val INPUT_K8S_TEMPLATE_VALUE_SOURCE = "k8s-rb-template-value-source"
43 const val INPUT_K8S_OPERATION_TYPE = "k8s-operation-type"
45 const val OUTPUT_STATUSES = "statuses"
46 const val OUTPUT_SKIPPED = "skipped"
47 const val OUTPUT_UPLOADED = "uploaded"
48 const val OUTPUT_ERROR = "error"
51 override suspend fun processNB(executionRequest: ExecutionServiceInput) {
52 log.info("Triggering K8s Config Value component logic.")
53 val inputParameterNames = arrayOf(
54 INPUT_K8S_TEMPLATE_NAME,
55 INPUT_K8S_CONFIG_NAME,
56 INPUT_K8S_INSTANCE_ID,
57 INPUT_K8S_OPERATION_TYPE,
58 INPUT_K8S_TEMPLATE_VALUE_SOURCE,
59 INPUT_ARTIFACT_PREFIX_NAMES
61 val outputPrefixStatuses = mutableMapOf<String, String>()
62 val inputParamsMap = mutableMapOf<String, JsonNode?>()
64 inputParameterNames.forEach {
65 inputParamsMap[it] = getOptionalOperationInput(it)?.returnNullIfMissing()
68 log.info("Getting the template prefixes")
69 val prefixList: ArrayList<String> = getTemplatePrefixList(inputParamsMap[INPUT_ARTIFACT_PREFIX_NAMES])
71 log.info("Iterating over prefixes in resource assignment map.")
72 for (prefix in prefixList) {
73 outputPrefixStatuses[prefix] = OUTPUT_SKIPPED
74 val prefixNode: JsonNode = operationInputs[INPUT_RESOURCE_ASSIGNMENT_MAP]?.get(prefix) ?: continue
75 val assignmentMapPrefix = JacksonUtils.jsonNode(prefixNode.toPrettyString()) as ObjectNode
76 val prefixInputParamsMap = inputParamsMap.toMutableMap()
77 prefixInputParamsMap.forEach { (inputParamName, value) ->
79 val mapValue = assignmentMapPrefix.get(inputParamName)
80 log.debug("$inputParamName value was $value so we fetch $mapValue")
81 prefixInputParamsMap[inputParamName] = mapValue
85 val templateName: String? = prefixInputParamsMap[INPUT_K8S_TEMPLATE_NAME]?.returnNullIfMissing()?.asText()
86 val configName: String? = prefixInputParamsMap[INPUT_K8S_CONFIG_NAME]?.returnNullIfMissing()?.asText()
87 val instanceId: String? = prefixInputParamsMap[INPUT_K8S_INSTANCE_ID]?.returnNullIfMissing()?.asText()
88 val valueSource: String? = prefixInputParamsMap[INPUT_K8S_TEMPLATE_VALUE_SOURCE]?.returnNullIfMissing()?.asText()
89 val operationType = prefixInputParamsMap[INPUT_K8S_TEMPLATE_VALUE_SOURCE]?.returnNullIfMissing()?.asText()?.toUpperCase()
91 if (operationType == null || operationType == OperationType.CREATE.toString())
92 createOperation(templateName, instanceId, valueSource, outputPrefixStatuses, prefix, configName)
93 else if (operationType == OperationType.UPDATE.toString())
94 updateOperation(templateName, instanceId, valueSource, outputPrefixStatuses, prefix, configName)
95 else if (operationType == OperationType.ROLLBACK.toString())
96 rollbackOperation(instanceId)
98 throw BlueprintProcessorException("Unknown operation type: $operationType")
102 private fun createOperation(templateName: String?, instanceId: String?, valueSource: String?, outputPrefixStatuses: MutableMap<String, String>, prefix: String, configName: String?) {
103 if (templateName == null || configName == null || instanceId == null || valueSource == null) {
104 log.warn("$INPUT_K8S_TEMPLATE_NAME or $INPUT_K8S_INSTANCE_ID or $INPUT_K8S_TEMPLATE_VALUE_SOURCE or $INPUT_K8S_CONFIG_NAME is null")
105 } else if (templateName.isEmpty()) {
106 log.warn("$INPUT_K8S_TEMPLATE_NAME is empty")
107 } else if (configName.isEmpty()) {
108 log.warn("$INPUT_K8S_CONFIG_NAME is empty")
110 log.info("Uploading K8s template value..")
111 outputPrefixStatuses[prefix] = OUTPUT_ERROR
112 val bluePrintContext = bluePrintRuntimeService.bluePrintContext()
113 val artifact: ArtifactDefinition = bluePrintContext.nodeTemplateArtifact(nodeTemplateName, valueSource)
114 if (artifact.type != BlueprintConstants.MODEL_TYPE_ARTIFACT_K8S_PROFILE)
115 throw BlueprintProcessorException(
116 "Unexpected profile artifact type for profile source $valueSource. Expecting: $artifact.type"
118 // Creating API connector
119 val api = K8sPluginInstanceApi(K8sConnectionPluginConfiguration(bluePrintPropertiesService))
120 val configValueRequest = K8sConfigValueRequest()
121 configValueRequest.templateName = templateName
122 configValueRequest.configName = configName
123 configValueRequest.description = valueSource
124 configValueRequest.values = parseResult(valueSource)
125 api.createConfigurationValues(configValueRequest, instanceId)
129 private fun updateOperation(templateName: String?, instanceId: String?, valueSource: String?, outputPrefixStatuses: MutableMap<String, String>, prefix: String, configName: String?) {
130 if (templateName == null || configName == null || instanceId == null || valueSource == null) {
131 log.warn("$INPUT_K8S_TEMPLATE_NAME or $INPUT_K8S_INSTANCE_ID or $INPUT_K8S_TEMPLATE_VALUE_SOURCE or $INPUT_K8S_CONFIG_NAME is null")
132 } else if (templateName.isEmpty()) {
133 log.warn("$INPUT_K8S_TEMPLATE_NAME is empty")
134 } else if (configName.isEmpty()) {
135 log.warn("$INPUT_K8S_CONFIG_NAME is empty")
137 log.info("Uploading K8s template value..")
138 outputPrefixStatuses[prefix] = OUTPUT_ERROR
139 val bluePrintContext = bluePrintRuntimeService.bluePrintContext()
140 val artifact: ArtifactDefinition = bluePrintContext.nodeTemplateArtifact(nodeTemplateName, valueSource)
141 if (artifact.type != BlueprintConstants.MODEL_TYPE_ARTIFACT_K8S_PROFILE)
142 throw BlueprintProcessorException(
143 "Unexpected profile artifact type for profile source $valueSource. Expecting: $artifact.type"
145 // Creating API connector
146 val api = K8sPluginInstanceApi(K8sConnectionPluginConfiguration(bluePrintPropertiesService))
147 if (api.hasConfigurationValues(instanceId, configName)) {
148 val configValueRequest = K8sConfigValueRequest()
149 configValueRequest.templateName = templateName
150 configValueRequest.configName = configName
151 configValueRequest.description = valueSource
152 configValueRequest.values = parseResult(valueSource)
153 api.editConfigurationValues(configValueRequest, instanceId, configName)
155 throw BlueprintProcessorException("Error while getting configuration value")
160 private fun rollbackOperation(instanceId: String?) {
161 if (instanceId != null) {
162 val api = K8sPluginInstanceApi(K8sConnectionPluginConfiguration(bluePrintPropertiesService))
163 api.rollbackConfigurationValues(instanceId)
165 throw BlueprintProcessorException("$INPUT_K8S_INSTANCE_ID is null")
169 private fun parseResult(templateValueSource: String): Any {
170 val ymlSourceFile = getYmlSourceFile(templateValueSource)
171 val yamlReader = ObjectMapper(YAMLFactory())
172 val obj: Any = yamlReader.readValue(ymlSourceFile, Any::class.java)
174 val jsonWriter = ObjectMapper()
175 return jsonWriter.convertValue(obj)
178 private fun getYmlSourceFile(templateValueSource: String): File {
179 val bluePrintBasePath: String = bluePrintRuntimeService.bluePrintContext().rootPath
180 val profileSourceFileFolderPath: Path = Paths.get(bluePrintBasePath.plus(File.separator).plus(templateValueSource))
182 if (profileSourceFileFolderPath.toFile().exists() && !profileSourceFileFolderPath.toFile().isDirectory)
183 return profileSourceFileFolderPath.toFile()
185 throw BlueprintProcessorException("Template value $profileSourceFileFolderPath is missing in CBA folder")
188 private fun getTemplatePrefixList(node: JsonNode?): ArrayList<String> {
189 val result = ArrayList<String>()
192 val arrayNode = node.toList()
193 for (prefixNode in arrayNode)
194 result.add(prefixNode.asText())
197 result.add(node.asText())
203 override suspend fun recoverNB(runtimeException: RuntimeException, executionRequest: ExecutionServiceInput) {
204 bluePrintRuntimeService.getBlueprintError().addError(runtimeException.message!!)
207 private enum class OperationType {
208 CREATE, UPDATE, ROLLBACK