summaryrefslogtreecommitdiffstats
path: root/ms/blueprintsprocessor/functions/k8s-profile-upload
diff options
context:
space:
mode:
authorLukasz Rajewski <lukasz.rajewski@orange.com>2020-09-04 18:16:45 +0200
committerLukasz Rajewski <lukasz.rajewski@orange.com>2020-09-07 08:27:38 +0000
commitff8df16778818804d31b844b0df7b2f9a16f2cba (patch)
treec2204b548399f9d77fff9b426ecc62cd7733471f /ms/blueprintsprocessor/functions/k8s-profile-upload
parent836be777835eb05be1a62b98a9e1f5860623d7b2 (diff)
Add k8s-upload-profile templating and packaging
Issue-ID: CCSDK-2631 Signed-off-by: Lukasz Rajewski <lukasz.rajewski@orange.com> Change-Id: Id520338ffc2f43821d114b037467fbcc2f042b66
Diffstat (limited to 'ms/blueprintsprocessor/functions/k8s-profile-upload')
-rw-r--r--ms/blueprintsprocessor/functions/k8s-profile-upload/src/main/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/functions/k8s/profile/upload/K8sProfileUploadComponent.kt212
1 files changed, 186 insertions, 26 deletions
diff --git a/ms/blueprintsprocessor/functions/k8s-profile-upload/src/main/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/functions/k8s/profile/upload/K8sProfileUploadComponent.kt b/ms/blueprintsprocessor/functions/k8s-profile-upload/src/main/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/functions/k8s/profile/upload/K8sProfileUploadComponent.kt
index aa726a5e9..0ae76ea7e 100644
--- a/ms/blueprintsprocessor/functions/k8s-profile-upload/src/main/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/functions/k8s/profile/upload/K8sProfileUploadComponent.kt
+++ b/ms/blueprintsprocessor/functions/k8s-profile-upload/src/main/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/functions/k8s/profile/upload/K8sProfileUploadComponent.kt
@@ -19,26 +19,40 @@
package org.onap.ccsdk.cds.blueprintsprocessor.functions.k8s.profile.upload
+import com.fasterxml.jackson.databind.JsonNode
+import com.fasterxml.jackson.databind.node.ObjectNode
+import org.apache.commons.io.FileUtils
+import org.onap.ccsdk.cds.blueprintsprocessor.core.BluePrintPropertiesService
+import org.onap.ccsdk.cds.blueprintsprocessor.core.api.data.ExecutionServiceInput
+import org.onap.ccsdk.cds.blueprintsprocessor.functions.resource.resolution.ResourceResolutionConstants
+import org.onap.ccsdk.cds.blueprintsprocessor.functions.resource.resolution.ResourceResolutionService
import org.onap.ccsdk.cds.blueprintsprocessor.services.execution.AbstractComponentFunction
+import org.onap.ccsdk.cds.controllerblueprints.core.BluePrintConstants
+import org.onap.ccsdk.cds.controllerblueprints.core.BluePrintProcessorException
+import org.onap.ccsdk.cds.controllerblueprints.core.asJsonNode
+import org.onap.ccsdk.cds.controllerblueprints.core.data.ArtifactDefinition
+import org.onap.ccsdk.cds.controllerblueprints.core.returnNullIfMissing
+import org.onap.ccsdk.cds.controllerblueprints.core.service.BluePrintVelocityTemplateService
+import org.onap.ccsdk.cds.controllerblueprints.core.utils.ArchiveType
+import org.onap.ccsdk.cds.controllerblueprints.core.utils.BluePrintArchiveUtils
+import org.onap.ccsdk.cds.controllerblueprints.core.utils.JacksonUtils
+import org.slf4j.LoggerFactory
import org.springframework.beans.factory.config.ConfigurableBeanFactory
import org.springframework.context.annotation.Scope
import org.springframework.stereotype.Component
-import java.util.ArrayList
-import java.nio.file.Paths
+import org.yaml.snakeyaml.Yaml
import java.io.File
-import com.fasterxml.jackson.databind.JsonNode
-import org.onap.ccsdk.cds.controllerblueprints.core.asJsonNode
-import org.onap.ccsdk.cds.blueprintsprocessor.core.api.data.ExecutionServiceInput
-import org.onap.ccsdk.cds.blueprintsprocessor.core.BluePrintPropertiesService
-import org.slf4j.LoggerFactory
+import java.nio.file.Files
import java.nio.file.Path
-import org.onap.ccsdk.cds.controllerblueprints.core.returnNullIfMissing
-import com.fasterxml.jackson.databind.node.ObjectNode
-import org.onap.ccsdk.cds.controllerblueprints.core.utils.JacksonUtils
+import java.nio.file.Paths
+import kotlin.collections.ArrayList
@Component("component-k8s-profile-upload")
@Scope(value = ConfigurableBeanFactory.SCOPE_PROTOTYPE)
-open class K8sProfileUploadComponent(private var bluePrintPropertiesService: BluePrintPropertiesService) :
+open class K8sProfileUploadComponent(
+ private var bluePrintPropertiesService: BluePrintPropertiesService,
+ private val resourceResolutionService: ResourceResolutionService
+) :
AbstractComponentFunction() {
@@ -98,9 +112,9 @@ open class K8sProfileUploadComponent(private var bluePrintPropertiesService: Blu
}
// For clarity we pull out the required fields
- val profileName = prefixInputParamsMap[INPUT_K8S_PROFILE_NAME]?.returnNullIfMissing()?.textValue()
- val definitionName = prefixInputParamsMap[INPUT_K8S_DEFINITION_NAME]?.returnNullIfMissing()?.textValue()
- val definitionVersion = prefixInputParamsMap[INPUT_K8S_DEFINITION_VERSION]?.returnNullIfMissing()?.textValue()
+ val profileName: String? = prefixInputParamsMap[INPUT_K8S_PROFILE_NAME]?.returnNullIfMissing()?.asText()
+ val definitionName: String? = prefixInputParamsMap[INPUT_K8S_DEFINITION_NAME]?.returnNullIfMissing()?.asText()
+ val definitionVersion: String? = prefixInputParamsMap[INPUT_K8S_DEFINITION_VERSION]?.returnNullIfMissing()?.asText()
val k8sProfileUploadConfiguration = K8sProfileUploadConfiguration(bluePrintPropertiesService)
@@ -124,14 +138,26 @@ open class K8sProfileUploadComponent(private var bluePrintPropertiesService: Blu
} else {
log.info("Uploading K8s Profile..")
outputPrefixStatuses.put(prefix, OUTPUT_ERROR)
-
+ val profileNamespace: String? = prefixInputParamsMap[INPUT_K8S_PROFILE_NAMESPACE]?.returnNullIfMissing()?.asText()
+ var profileSource: String? = prefixInputParamsMap[INPUT_K8S_PROFILE_SOURCE]?.returnNullIfMissing()?.asText()
+ if (profileNamespace == null)
+ throw BluePrintProcessorException("Profile $profileName namespace is missing")
+ if (profileSource == null) {
+ profileSource = profileName
+ log.info("Profile name used instead of profile source")
+ }
+ val bluePrintContext = bluePrintRuntimeService.bluePrintContext()
+ val artifact: ArtifactDefinition = bluePrintContext.nodeTemplateArtifact(nodeTemplateName, profileSource)
+ if (artifact.type != BluePrintConstants.MODEL_TYPE_ARTIFACT_K8S_PROFILE)
+ throw BluePrintProcessorException("Unexpected profile artifact type for profile source " +
+ "$profileSource. Expecting: $artifact.type")
var profile = K8sProfile()
profile.profileName = profileName
profile.rbName = definitionName
profile.rbVersion = definitionVersion
- profile.namespace = prefixInputParamsMap[INPUT_K8S_PROFILE_NAMESPACE]?.textValue()
+ profile.namespace = profileNamespace
+ val profileFilePath: Path = prepareProfileFile(profileName, profileSource, artifact.file)
api.createProfile(profile)
- val profileFilePath: Path = prepareProfileFile(profileName)
api.uploadProfileContent(profile, profileFilePath)
log.info("K8s Profile Upload Completed")
@@ -156,16 +182,150 @@ open class K8sProfileUploadComponent(private var bluePrintPropertiesService: Blu
return result
}
- fun prepareProfileFile(k8sRbProfileName: String): Path {
+ private suspend fun prepareProfileFile(k8sRbProfileName: String, ks8ProfileSource: String, ks8ProfileLocation: String): Path {
val bluePrintContext = bluePrintRuntimeService.bluePrintContext()
val bluePrintBasePath: String = bluePrintContext.rootPath
- return Paths.get(
- bluePrintBasePath.plus(File.separator)
- .plus("Templates")
- .plus(File.separator)
- .plus("k8s-profiles")
- .plus(File.separator)
- .plus("$k8sRbProfileName.tar.gz")
- )
+ val profileSourceFileFolderPath: String = bluePrintBasePath.plus(File.separator)
+ .plus(ks8ProfileLocation)
+ val profileFilePathTarGz: String = profileSourceFileFolderPath.plus(".tar.gz")
+ val profileFilePathTgz: String = profileSourceFileFolderPath.plus(".tgz")
+
+ if (Paths.get(profileFilePathTarGz).toFile().exists())
+ return Paths.get(profileFilePathTarGz)
+ else if (Paths.get(profileFilePathTgz).toFile().exists())
+ return Paths.get(profileFilePathTgz)
+ else if (Paths.get(profileSourceFileFolderPath).toFile().exists()) {
+ log.info("Profile building started from source $ks8ProfileSource")
+ val properties: MutableMap<String, Any> = mutableMapOf()
+ properties[ResourceResolutionConstants.RESOURCE_RESOLUTION_INPUT_STORE_RESULT] = false
+ properties[ResourceResolutionConstants.RESOURCE_RESOLUTION_INPUT_RESOLUTION_KEY] = ""
+ properties[ResourceResolutionConstants.RESOURCE_RESOLUTION_INPUT_RESOURCE_ID] = ""
+ properties[ResourceResolutionConstants.RESOURCE_RESOLUTION_INPUT_RESOURCE_TYPE] = ""
+ properties[ResourceResolutionConstants.RESOURCE_RESOLUTION_INPUT_OCCURRENCE] = 1
+ properties[ResourceResolutionConstants.RESOURCE_RESOLUTION_INPUT_RESOLUTION_SUMMARY] = false
+ val resolutionResult: Pair<String, JsonNode> = resourceResolutionService.resolveResources(
+ bluePrintRuntimeService,
+ nodeTemplateName,
+ ks8ProfileSource,
+ properties)
+ val tempMainPath: File = createTempDir("k8s-profile-", "")
+ val tempProfilePath: File = createTempDir("content-", "", tempMainPath)
+
+ try {
+ val manifestFiles: ArrayList<File>? = readManifestFiles(Paths.get(profileSourceFileFolderPath).toFile(),
+ tempProfilePath)
+ if (manifestFiles != null) {
+ templateLocation(Paths.get(profileSourceFileFolderPath).toFile(), resolutionResult.second,
+ tempProfilePath, manifestFiles)
+ } else
+ throw BluePrintProcessorException("Manifest file is missing")
+ // Preparation of the final profile content
+ val finalProfileFilePath = Paths.get(tempMainPath.toString().plus(File.separator).plus(
+ "$k8sRbProfileName.tar.gz"))
+ if (!BluePrintArchiveUtils.compress(tempProfilePath, finalProfileFilePath.toFile(),
+ ArchiveType.TarGz)) {
+ throw BluePrintProcessorException("Profile compression has failed")
+ }
+ FileUtils.deleteDirectory(tempProfilePath)
+
+ return finalProfileFilePath
+ } catch (t: Throwable) {
+ FileUtils.deleteDirectory(tempMainPath)
+ throw t
+ }
+ } else
+ throw BluePrintProcessorException("Profile source $ks8ProfileSource is missing in CBA folder")
+ }
+
+ private fun readManifestFiles(profileSource: File, destinationFolder: File): ArrayList<File>? {
+ val directoryListing: Array<File>? = profileSource.listFiles()
+ var result: ArrayList<File>? = null
+ if (directoryListing != null) {
+ for (child in directoryListing) {
+ if (!child.isDirectory && child.name.toLowerCase() == "manifest.yaml") {
+ child.bufferedReader().use { inr ->
+ val manifestYaml = Yaml()
+ val manifestObject: Map<String, Any> = manifestYaml.load(inr)
+ val typeObject: MutableMap<String, Any>? = manifestObject["type"] as MutableMap<String, Any>?
+ if (typeObject != null) {
+ result = ArrayList<File>()
+ val valuesObject = typeObject["values"]
+ if (valuesObject != null) {
+ result!!.add(File(destinationFolder.toString().plus(File.separator).plus(valuesObject)))
+ result!!.add(File(destinationFolder.toString().plus(File.separator).plus(child.name)))
+ }
+ (typeObject["configresource"] as ArrayList<*>?)?.forEach { item ->
+ val fileInfo: Map<String, Any> = item as Map<String, Any>
+ val filePath = fileInfo["filepath"]
+ val chartPath = fileInfo["chartpath"]
+ if (filePath == null || chartPath == null)
+ log.error("One configresource in manifest was skipped because of the wrong format")
+ else {
+ result!!.add(File(destinationFolder.toString().plus(File.separator).plus(filePath)))
+ }
+ }
+ }
+ }
+ break
+ }
+ }
+ }
+ return result
+ }
+
+ private fun templateLocation(
+ location: File,
+ params: JsonNode,
+ destinationFolder: File,
+ manifestFiles: ArrayList<File>
+ ) {
+ val directoryListing: Array<File>? = location.listFiles()
+ if (directoryListing != null) {
+ for (child in directoryListing) {
+ var newDestinationFolder = destinationFolder.toPath()
+ if (child.isDirectory)
+ newDestinationFolder = Paths.get(destinationFolder.toString().plus(File.separator).plus(child.name))
+
+ templateLocation(child, params, newDestinationFolder.toFile(), manifestFiles)
+ }
+ } else if (!location.isDirectory) {
+ if (location.extension.toLowerCase() == "vtl") {
+ templateFile(location, params, destinationFolder, manifestFiles)
+ } else {
+ val finalFilePath = Paths.get(destinationFolder.path.plus(File.separator)
+ .plus(location.name)).toFile()
+ if (isFileInTheManifestFiles(finalFilePath, manifestFiles)) {
+ if (!destinationFolder.exists())
+ Files.createDirectories(destinationFolder.toPath())
+ FileUtils.copyFile(location, finalFilePath)
+ }
+ }
+ }
+ }
+
+ private fun isFileInTheManifestFiles(file: File, manifestFiles: ArrayList<File>): Boolean {
+ manifestFiles.forEach { fileFromManifest ->
+ if (fileFromManifest.toString().toLowerCase() == file.toString().toLowerCase())
+ return true
+ }
+ return false
+ }
+
+ private fun templateFile(
+ templatedFile: File,
+ params: JsonNode,
+ destinationFolder: File,
+ manifestFiles: ArrayList<File>
+ ) {
+ val finalFile = File(destinationFolder.path.plus(File.separator)
+ .plus(templatedFile.nameWithoutExtension))
+ if (!isFileInTheManifestFiles(finalFile, manifestFiles))
+ return
+ val fileContent = templatedFile.bufferedReader().readText()
+ val finalFileContent = BluePrintVelocityTemplateService.generateContent(fileContent,
+ params, true)
+ if (!destinationFolder.exists())
+ Files.createDirectories(destinationFolder.toPath())
+ finalFile.bufferedWriter().use { out -> out.write(finalFileContent) }
}
}