Add missing k8s-rb-instance-release-name.json
[ccsdk/cds.git] / ms / blueprintsprocessor / modules / blueprints / blueprint-core / src / main / kotlin / org / onap / ccsdk / cds / controllerblueprints / core / utils / BlueprintFileUtils.kt
1 /*
2  * Copyright © 2017-2018 AT&T Intellectual Property.
3  * Modifications Copyright © 2019 Bell Canada.
4  * Modifications Copyright © 2019 IBM.
5  *
6  * Licensed under the Apache License, Version 2.0 (the "License");
7  * you may not use this file except in compliance with the License.
8  * You may obtain a copy of the License at
9  *
10  *     http://www.apache.org/licenses/LICENSE-2.0
11  *
12  * Unless required by applicable law or agreed to in writing, software
13  * distributed under the License is distributed on an "AS IS" BASIS,
14  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15  * See the License for the specific language governing permissions and
16  * limitations under the License.
17  */
18
19 package org.onap.ccsdk.cds.controllerblueprints.core.utils
20
21 import kotlinx.coroutines.runBlocking
22 import org.apache.commons.io.FileUtils
23 import org.apache.commons.lang3.StringUtils
24 import org.onap.ccsdk.cds.controllerblueprints.core.BlueprintConstants
25 import org.onap.ccsdk.cds.controllerblueprints.core.BlueprintException
26 import org.onap.ccsdk.cds.controllerblueprints.core.data.ErrorCode
27 import org.onap.ccsdk.cds.controllerblueprints.core.data.ImportDefinition
28 import org.onap.ccsdk.cds.controllerblueprints.core.data.ServiceTemplate
29 import org.onap.ccsdk.cds.controllerblueprints.core.normalizedFile
30 import org.onap.ccsdk.cds.controllerblueprints.core.normalizedPathName
31 import org.onap.ccsdk.cds.controllerblueprints.core.service.BlueprintContext
32 import org.slf4j.LoggerFactory
33 import java.io.File
34 import java.io.FileFilter
35 import java.io.FileNotFoundException
36 import java.net.URL
37 import java.net.URLClassLoader
38 import java.nio.file.Files
39 import java.nio.file.NotDirectoryException
40 import java.nio.file.Path
41 import java.nio.file.Paths
42 import java.nio.file.StandardOpenOption
43
44 class BlueprintFileUtils {
45     companion object {
46
47         const val COMPILED_JAR_SUFFIX = "cba-kts.jar"
48
49         private val log = LoggerFactory.getLogger(this::class.toString())
50
51         fun createEmptyBlueprint(basePath: String) {
52
53             val blueprintDir = File(basePath)
54             FileUtils.deleteDirectory(blueprintDir)
55
56             Files.createDirectories(blueprintDir.toPath())
57
58             val metaDataDir = File(blueprintDir.absolutePath.plus(File.separator).plus(BlueprintConstants.TOSCA_METADATA_DIR))
59             Files.createDirectories(metaDataDir.toPath())
60
61             val metaFile = File(
62                 blueprintDir.absolutePath.plus(File.separator).plus(
63                     BlueprintConstants
64                         .TOSCA_METADATA_ENTRY_DEFINITION_FILE
65                 )
66             )
67             Files.write(metaFile.toPath(), getMetaDataContent().toByteArray(), StandardOpenOption.CREATE_NEW)
68
69             val definitionsDir = File(blueprintDir.absolutePath.plus(File.separator).plus(BlueprintConstants.TOSCA_DEFINITIONS_DIR))
70             Files.createDirectories(definitionsDir.toPath())
71
72             val scriptsDir = File(blueprintDir.absolutePath.plus(File.separator).plus(BlueprintConstants.TOSCA_SCRIPTS_DIR))
73             Files.createDirectories(scriptsDir.toPath())
74
75             val plansDir = File(blueprintDir.absolutePath.plus(File.separator).plus(BlueprintConstants.TOSCA_PLANS_DIR))
76             Files.createDirectories(plansDir.toPath())
77
78             val templatesDir = File(blueprintDir.absolutePath.plus(File.separator).plus(BlueprintConstants.TOSCA_TEMPLATES_DIR))
79             Files.createDirectories(templatesDir.toPath())
80         }
81
82         fun copyBlueprint(sourcePath: String, targetPath: String) {
83             val sourceFile = File(sourcePath)
84             val targetFile = File(targetPath)
85             sourceFile.copyRecursively(targetFile, true)
86         }
87
88         fun deleteBlueprintTypes(basePath: String) {
89             val definitionPath = basePath.plus(File.separator).plus(BlueprintConstants.TOSCA_DEFINITIONS_DIR)
90             log.info("deleting definition types under : $definitionPath")
91
92             val definitionDir = File(definitionPath)
93             // Find the Type Definitions
94             val fileFilter = FileFilter { pathname -> pathname.absolutePath.endsWith("_types.json") }
95             // Delete the Type Files
96             definitionDir.listFiles(fileFilter).forEach {
97                 Files.deleteIfExists(it.toPath())
98             }
99         }
100
101         fun writeEnhancedBlueprint(blueprintContext: BlueprintContext) {
102
103             // Write Blueprint Types
104             writeBlueprintTypes(blueprintContext)
105             // Re Populate the Imports
106             populateDefaultImports(blueprintContext)
107             // Rewrite the Entry Definition Files
108             writeEntryDefinitionFile(blueprintContext)
109         }
110
111         fun writeBlueprintTypes(blueprintContext: BlueprintContext) {
112
113             val basePath = blueprintContext.rootPath
114             val definitionPath = basePath.plus(File.separator).plus(BlueprintConstants.TOSCA_DEFINITIONS_DIR)
115             val definitionDir = File(definitionPath)
116
117             check(definitionDir.exists()) {
118                 throw BlueprintException(
119                     ErrorCode.BLUEPRINT_PATH_MISSING.value,
120                     "couldn't get definition file under " +
121                         "path(${definitionDir.absolutePath})"
122                 )
123             }
124
125             blueprintContext.serviceTemplate.dataTypes?.let {
126                 val dataTypesContent = JacksonUtils.getWrappedJson(BlueprintConstants.PATH_DATA_TYPES, it.toSortedMap(), true)
127                 writeTypeFile(definitionDir.absolutePath, BlueprintConstants.PATH_DATA_TYPES, dataTypesContent)
128             }
129
130             blueprintContext.serviceTemplate.relationshipTypes?.let {
131                 val nodeTypesContent = JacksonUtils.getWrappedJson(BlueprintConstants.PATH_RELATIONSHIP_TYPES, it.toSortedMap(), true)
132                 writeTypeFile(definitionDir.absolutePath, BlueprintConstants.PATH_RELATIONSHIP_TYPES, nodeTypesContent)
133             }
134
135             blueprintContext.serviceTemplate.artifactTypes?.let {
136                 val artifactTypesContent = JacksonUtils.getWrappedJson(BlueprintConstants.PATH_ARTIFACT_TYPES, it.toSortedMap(), true)
137                 writeTypeFile(definitionDir.absolutePath, BlueprintConstants.PATH_ARTIFACT_TYPES, artifactTypesContent)
138             }
139
140             blueprintContext.serviceTemplate.nodeTypes?.let {
141                 val nodeTypesContent = JacksonUtils.getWrappedJson(BlueprintConstants.PATH_NODE_TYPES, it.toSortedMap(), true)
142                 writeTypeFile(definitionDir.absolutePath, BlueprintConstants.PATH_NODE_TYPES, nodeTypesContent)
143             }
144
145             blueprintContext.serviceTemplate.policyTypes?.let {
146                 val nodeTypesContent = JacksonUtils.getWrappedJson(BlueprintConstants.PATH_POLICY_TYPES, it.toSortedMap(), true)
147                 writeTypeFile(definitionDir.absolutePath, BlueprintConstants.PATH_POLICY_TYPES, nodeTypesContent)
148             }
149         }
150
151         private fun populateDefaultImports(blueprintContext: BlueprintContext) {
152             // Get the Default Types
153             val types = arrayListOf(
154                 BlueprintConstants.PATH_DATA_TYPES, BlueprintConstants.PATH_RELATIONSHIP_TYPES,
155                 BlueprintConstants.PATH_ARTIFACT_TYPES, BlueprintConstants.PATH_NODE_TYPES,
156                 BlueprintConstants.PATH_POLICY_TYPES
157             )
158
159             // Clean Type Imports
160             cleanImportTypes(blueprintContext.serviceTemplate)
161
162             val imports = mutableListOf<ImportDefinition>()
163             types.forEach { typeName ->
164                 val import = ImportDefinition()
165                 import.file = BlueprintConstants.TOSCA_DEFINITIONS_DIR.plus("/$typeName.json")
166                 imports.add(import)
167             }
168
169             blueprintContext.serviceTemplate.imports = imports
170         }
171
172         fun cleanImportTypes(serviceTemplate: ServiceTemplate) {
173             // Clean the Type imports
174             val toDeleteTypes = serviceTemplate.imports?.filter {
175                 it.file.endsWith("_types.json")
176             }
177
178             if (toDeleteTypes != null && toDeleteTypes.isNotEmpty()) {
179                 serviceTemplate.imports?.removeAll(toDeleteTypes)
180             }
181         }
182
183         /**
184          * Re Generate the Blueprint Service Template Definition file based on Blueprint Context.
185          */
186         private fun writeEntryDefinitionFile(blueprintContext: BlueprintContext) {
187
188             val absoluteEntryDefinitionFile = blueprintContext.rootPath.plus(File.separator).plus(blueprintContext.entryDefinition)
189
190             val serviceTemplate = blueprintContext.serviceTemplate
191
192             // Clone the Service Template
193             val writeServiceTemplate = serviceTemplate.clone()
194             writeServiceTemplate.dataTypes = null
195             writeServiceTemplate.artifactTypes = null
196             writeServiceTemplate.policyTypes = null
197             writeServiceTemplate.relationshipTypes = null
198             writeServiceTemplate.nodeTypes = null
199
200             // Write the Service Template
201             writeDefinitionFile(absoluteEntryDefinitionFile, JacksonUtils.getJson(writeServiceTemplate, true))
202         }
203
204         fun writeDefinitionFile(definitionFileName: String, content: String) = runBlocking {
205             val definitionFile = File(definitionFileName)
206             // Delete the File If exists
207             Files.deleteIfExists(definitionFile.toPath())
208
209             Files.write(definitionFile.toPath(), content.toByteArray(), StandardOpenOption.CREATE_NEW)
210             check(definitionFile.exists()) {
211                 throw BlueprintException(
212                     ErrorCode.BLUEPRINT_WRITING_FAIL.value,
213                     "couldn't write definition file under " +
214                         "path(${definitionFile.absolutePath})"
215                 )
216             }
217         }
218
219         private fun writeTypeFile(definitionPath: String, type: String, content: String) = runBlocking {
220             val typeFile = File(definitionPath.plus(File.separator).plus("$type.json"))
221
222             Files.write(typeFile.toPath(), content.toByteArray(), StandardOpenOption.CREATE_NEW)
223             check(typeFile.exists()) {
224                 throw BlueprintException(
225                     ErrorCode.BLUEPRINT_WRITING_FAIL.value,
226                     "couldn't write $type.json file under " +
227                         "path(${typeFile.absolutePath})"
228                 )
229             }
230         }
231
232         private fun getMetaDataContent(): String {
233             return "TOSCA-Meta-File-Version: 1.0.0" +
234                 "\nCSAR-Version: <VERSION>" +
235                 "\nCreated-By: <AUTHOR NAME>" +
236                 "\nEntry-Definitions: Definitions/<BLUEPRINT_NAME>.json" +
237                 "\nTemplate-Name: <BLUEPRINT_NAME>" +
238                 "\nTemplate-Version: <BLUEPRINT_VERSION>" +
239                 "\nTemplate-Type: <BLUEPRINT_TYPE>" +
240                 "\nTemplate-Tags: <TAGS>"
241         }
242
243         fun getBlueprintFile(fileName: String, targetPath: Path): File {
244             val filePath = targetPath.resolve(fileName).toString()
245             val file = File(filePath)
246             check(file.exists()) {
247                 throw BlueprintException(
248                     ErrorCode.BLUEPRINT_PATH_MISSING.value,
249                     "couldn't get definition file under " +
250                         "path(${file.absolutePath})"
251                 )
252             }
253             return file
254         }
255
256         fun getCbaStorageDirectory(path: String): Path {
257             check(StringUtils.isNotBlank(path)) {
258                 throw BlueprintException(
259                     ErrorCode.BLUEPRINT_PATH_MISSING.value,
260                     "couldn't get " +
261                         "Blueprint folder under path($path)"
262                 )
263             }
264
265             val fileStorageLocation = Paths.get(path).toAbsolutePath().normalize()
266
267             if (!Files.exists(fileStorageLocation))
268                 Files.createDirectories(fileStorageLocation)
269
270             return fileStorageLocation
271         }
272
273         fun compileCacheKey(basePath: String): String {
274             return normalizedPathName(basePath)
275         }
276
277         private fun compileJarFileName(artifactName: String, artifactVersion: String): String {
278             return "$artifactName-$artifactVersion-$COMPILED_JAR_SUFFIX"
279         }
280
281         fun compileJarFilePathName(basePath: String, artifactName: String, artifactVersion: String): String {
282             return normalizedPathName(
283                 basePath, BlueprintConstants.TOSCA_SCRIPTS_KOTLIN_DIR,
284                 compileJarFileName(artifactName, artifactVersion)
285             )
286         }
287
288         fun compileJarFile(basePath: String, artifactName: String, artifactVersion: String): File {
289             return normalizedFile(
290                 compileJarFilePathName(
291                     basePath,
292                     artifactName, artifactVersion
293                 )
294             )
295         }
296
297         fun stripFileExtension(fileName: String): String {
298             val dotIndexe = fileName.lastIndexOf('.')
299
300             // In case dot is in first position, we are dealing with a hidden file rather than an extension
301             return if (dotIndexe > 0) fileName.substring(0, dotIndexe) else fileName
302         }
303
304         fun getURLClassLoaderFromDirectory(directory: File): URLClassLoader {
305             if (!directory.exists()) {
306                 throw FileNotFoundException(directory.absolutePath)
307             } else if (!directory.isDirectory) {
308                 throw NotDirectoryException(directory.absolutePath)
309             }
310
311             val urls = arrayListOf<URL>()
312             directory.walkTopDown()
313                 .filter { it.name.endsWith(COMPILED_JAR_SUFFIX) }
314                 .forEach {
315                     log.debug("Adding (${it.absolutePath}) to classLoader (${directory.absolutePath})")
316
317                     urls.add(it.toURI().toURL())
318                 }
319             return URLClassLoader(urls.toTypedArray(), this.javaClass.classLoader)
320         }
321
322         fun getURLClassLoaderFromDirectory(path: String): URLClassLoader {
323             val directory = normalizedFile(path)
324             return getURLClassLoaderFromDirectory(directory)
325         }
326     }
327 }