34399fdd2965d068d8d7d8095d448a171150296f
[ccsdk/cds.git] /
1 /*\r
2  * Copyright © 2017-2018 AT&T Intellectual Property.\r
3  *\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
7  *\r
8  *     http://www.apache.org/licenses/LICENSE-2.0\r
9  *\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
15  */\r
16 \r
17 package org.onap.ccsdk.apps.controllerblueprints.core.service\r
18 \r
19 import com.fasterxml.jackson.databind.JsonNode\r
20 import com.google.common.base.Preconditions\r
21 import org.apache.commons.lang3.StringUtils\r
22 import org.onap.ccsdk.apps.controllerblueprints.core.*\r
23 import org.onap.ccsdk.apps.controllerblueprints.core.data.*\r
24 import com.att.eelf.configuration.EELFLogger\r
25 import com.att.eelf.configuration.EELFManager\r
26 import java.io.Serializable\r
27 \r
28 /**\r
29  *\r
30  *\r
31  * @author Brinda Santh\r
32  */\r
33 interface BluePrintValidatorService : Serializable {\r
34 \r
35     @Throws(BluePrintException::class)\r
36     fun validateBlueprint(bluePrintContext: BluePrintContext, properties: MutableMap<String, Any>)\r
37 \r
38     @Throws(BluePrintException::class)\r
39     fun validateBlueprint(serviceTemplate: ServiceTemplate, properties: MutableMap<String, Any>)\r
40 }\r
41 \r
42 open class BluePrintValidatorDefaultService : BluePrintValidatorService {\r
43 \r
44     val log: EELFLogger = EELFManager.getInstance().getLogger(BluePrintValidatorDefaultService::class.toString())\r
45 \r
46     lateinit var bluePrintContext: BluePrintContext\r
47     lateinit var serviceTemplate: ServiceTemplate\r
48     lateinit var properties: MutableMap<String, Any>\r
49     var message: StringBuilder = StringBuilder()\r
50     private val separator: String = BluePrintConstants.PATH_DIVIDER\r
51     var paths: MutableList<String> = arrayListOf()\r
52 \r
53     @Throws(BluePrintException::class)\r
54     override fun validateBlueprint(bluePrintContext: BluePrintContext, properties: MutableMap<String, Any>) {\r
55         validateBlueprint(bluePrintContext.serviceTemplate,properties)\r
56     }\r
57 \r
58     @Throws(BluePrintException::class)\r
59     override fun validateBlueprint(serviceTemplate: ServiceTemplate, properties: MutableMap<String, Any>) {\r
60         this.bluePrintContext = BluePrintContext(serviceTemplate)\r
61         this.serviceTemplate = serviceTemplate\r
62         this.properties = properties\r
63         try {\r
64             message.appendln("-> Config Blueprint")\r
65             serviceTemplate.metadata?.let { validateMetadata(serviceTemplate.metadata!!) }\r
66             serviceTemplate.artifactTypes?.let { validateArtifactTypes(serviceTemplate.artifactTypes!!) }\r
67             serviceTemplate.dataTypes?.let { validateDataTypes(serviceTemplate.dataTypes!!) }\r
68             serviceTemplate.nodeTypes?.let { validateNodeTypes(serviceTemplate.nodeTypes!!) }\r
69             serviceTemplate.topologyTemplate?.let { validateTopologyTemplate(serviceTemplate.topologyTemplate!!) }\r
70         } catch (e: Exception) {\r
71             log.error("validation failed in the path : {}", paths.joinToString(separator), e)\r
72             log.error("validation trace message :{} ", message)\r
73             throw BluePrintException(e,\r
74                     format("failed to validate blueprint on path ({}) with message {}"\r
75                             , paths.joinToString(separator), e.message))\r
76         }\r
77     }\r
78 \r
79     @Throws(BluePrintException::class)\r
80     open fun validateMetadata(metaDataMap: MutableMap<String, String>) {\r
81         paths.add("metadata")\r
82 \r
83         val templateName = metaDataMap[BluePrintConstants.METADATA_TEMPLATE_NAME]\r
84         val templateVersion = metaDataMap[BluePrintConstants.METADATA_TEMPLATE_VERSION]\r
85         val templateTags = metaDataMap[BluePrintConstants.METADATA_TEMPLATE_TAGS]\r
86         val templateAuthor = metaDataMap[BluePrintConstants.METADATA_TEMPLATE_AUTHOR]\r
87 \r
88         Preconditions.checkArgument(StringUtils.isNotBlank(templateName), "failed to get template name metadata")\r
89         Preconditions.checkArgument(StringUtils.isNotBlank(templateVersion), "failed to get template version metadata")\r
90         Preconditions.checkArgument(StringUtils.isNotBlank(templateTags), "failed to get template tags metadata")\r
91         Preconditions.checkArgument(StringUtils.isNotBlank(templateAuthor), "failed to get template author metadata")\r
92         paths.removeAt(paths.lastIndex)\r
93     }\r
94 \r
95     @Throws(BluePrintException::class)\r
96     open fun validateArtifactTypes(artifactTypes: MutableMap<String, ArtifactType>) {\r
97         paths.add("artifact_types")\r
98         artifactTypes.forEach { artifactName, artifactType ->\r
99             paths.add(artifactName)\r
100             message.appendln("--> Artifact Type :" + paths.joinToString(separator))\r
101             artifactType.properties?.let { validatePropertyDefinitions(artifactType.properties!!) }\r
102             paths.removeAt(paths.lastIndex)\r
103         }\r
104         paths.removeAt(paths.lastIndex)\r
105     }\r
106 \r
107     @Throws(BluePrintException::class)\r
108     open fun validateDataTypes(dataTypes: MutableMap<String, DataType>) {\r
109         paths.add("dataTypes")\r
110         dataTypes.forEach { dataTypeName, dataType ->\r
111             paths.add(dataTypeName)\r
112             message.appendln("--> Data Type :" + paths.joinToString(separator))\r
113             dataType.properties?.let { validatePropertyDefinitions(dataType.properties!!) }\r
114             paths.removeAt(paths.lastIndex)\r
115         }\r
116         paths.removeAt(paths.lastIndex)\r
117     }\r
118 \r
119     @Throws(BluePrintException::class)\r
120     open fun validateNodeTypes(nodeTypes: MutableMap<String, NodeType>) {\r
121         paths.add("nodeTypes")\r
122         nodeTypes.forEach { nodeTypeName, nodeType ->\r
123             // Validate Single Node Type\r
124             validateNodeType(nodeTypeName,nodeType)\r
125         }\r
126         paths.removeAt(paths.lastIndex)\r
127     }\r
128 \r
129     @Throws(BluePrintException::class)\r
130     open fun validateNodeType(nodeTypeName: String, nodeType: NodeType) {\r
131         paths.add(nodeTypeName)\r
132         message.appendln("--> Node Type :" + paths.joinToString(separator))\r
133         val derivedFrom: String = nodeType.derivedFrom\r
134         //Check Derived From\r
135         checkValidNodeTypesDerivedFrom(derivedFrom)\r
136 \r
137         nodeType.properties?.let { validatePropertyDefinitions(nodeType.properties!!) }\r
138         nodeType.interfaces?.let { validateInterfaceDefinitions(nodeType.interfaces!!) }\r
139         paths.removeAt(paths.lastIndex)\r
140     }\r
141 \r
142     @Throws(BluePrintException::class)\r
143     open fun validateTopologyTemplate(topologyTemplate: TopologyTemplate) {\r
144         paths.add("topology")\r
145         message.appendln("--> Topology Template")\r
146         topologyTemplate.inputs?.let { validateInputs(topologyTemplate.inputs!!) }\r
147         topologyTemplate.nodeTemplates?.let { validateNodeTemplates(topologyTemplate.nodeTemplates!!) }\r
148         topologyTemplate.workflows?.let { validateWorkFlows(topologyTemplate.workflows!!) }\r
149         paths.removeAt(paths.lastIndex)\r
150     }\r
151 \r
152     @Throws(BluePrintException::class)\r
153     open fun validateInputs(inputs: MutableMap<String, PropertyDefinition>) {\r
154         paths.add("inputs")\r
155         message.appendln("---> Input :" + paths.joinToString(separator))\r
156         validatePropertyDefinitions(inputs)\r
157         paths.removeAt(paths.lastIndex)\r
158     }\r
159 \r
160     @Throws(BluePrintException::class)\r
161     open fun validateNodeTemplates(nodeTemplates: MutableMap<String, NodeTemplate>) {\r
162         paths.add("nodeTemplates")\r
163         nodeTemplates.forEach { nodeTemplateName, nodeTemplate ->\r
164             validateNodeTemplate(nodeTemplateName, nodeTemplate)\r
165         }\r
166         paths.removeAt(paths.lastIndex)\r
167     }\r
168 \r
169     @Throws(BluePrintException::class)\r
170     open fun validateNodeTemplate(nodeTemplateName : String, nodeTemplate: NodeTemplate) {\r
171         paths.add(nodeTemplateName)\r
172         message.appendln("---> Node Template :" + paths.joinToString(separator))\r
173         val type: String = nodeTemplate.type\r
174 \r
175         val nodeType: NodeType = serviceTemplate.nodeTypes?.get(type)\r
176                 ?: throw BluePrintException(format("Failed to get node type definition  for node template : {}", nodeTemplateName))\r
177 \r
178         nodeTemplate.artifacts?.let { validateArtifactDefinitions(nodeTemplate.artifacts!!) }\r
179         nodeTemplate.properties?.let { validatePropertyAssignments(nodeType.properties!!, nodeTemplate.properties!!) }\r
180         nodeTemplate.capabilities?.let { validateCapabilityAssignments(nodeTemplate.capabilities!!) }\r
181         nodeTemplate.requirements?.let { validateRequirementAssignments(nodeTemplate.requirements!!) }\r
182         nodeTemplate.interfaces?.let { validateInterfaceAssignments(nodeTemplate.interfaces!!) }\r
183         paths.removeAt(paths.lastIndex)\r
184     }\r
185 \r
186     @Throws(BluePrintException::class)\r
187     open fun validateWorkFlows(workflows: MutableMap<String, Workflow>) {\r
188         paths.add("workflows")\r
189         workflows.forEach { workflowName, workflow ->\r
190 \r
191             // Validate Single workflow\r
192             validateWorkFlow(workflowName, workflow)\r
193         }\r
194         paths.removeAt(paths.lastIndex)\r
195     }\r
196 \r
197     @Throws(BluePrintException::class)\r
198     open fun validateWorkFlow(workflowName:String, workflow: Workflow) {\r
199         paths.add(workflowName)\r
200         message.appendln("---> Workflow :" + paths.joinToString(separator))\r
201         // Step Validation Start\r
202         paths.add("steps")\r
203         workflow.steps?.forEach { stepName, step ->\r
204             paths.add(stepName)\r
205             message.appendln("----> Steps :" + paths.joinToString(separator))\r
206             paths.removeAt(paths.lastIndex)\r
207         }\r
208         paths.removeAt(paths.lastIndex)\r
209         // Step Validation Ends\r
210         paths.removeAt(paths.lastIndex)\r
211     }\r
212 \r
213     @Throws(BluePrintException::class)\r
214     open fun validatePropertyDefinitions(properties: MutableMap<String, PropertyDefinition>) {\r
215         paths.add("properties")\r
216         properties.forEach { propertyName, propertyDefinition ->\r
217             paths.add(propertyName)\r
218             val dataType: String = propertyDefinition.type\r
219             when {\r
220                 BluePrintTypes.validPrimitiveTypes().contains(dataType) -> {\r
221                     // Do Nothing\r
222                 }\r
223                 BluePrintTypes.validCollectionTypes().contains(dataType) -> {\r
224                     val entrySchemaType: String = propertyDefinition.entrySchema?.type\r
225                             ?: throw BluePrintException(format("Entry schema for data type ({}) for the property ({}) not found", dataType, propertyName))\r
226                     checkPrimitiveOrComplex(entrySchemaType, propertyName)\r
227                 }\r
228                 else -> checkPropertyDataType(dataType, propertyName)\r
229             }\r
230             message.appendln("property " + paths.joinToString(separator) + " of type " + dataType)\r
231             paths.removeAt(paths.lastIndex)\r
232         }\r
233         paths.removeAt(paths.lastIndex)\r
234     }\r
235 \r
236     @Throws(BluePrintException::class)\r
237     open fun validatePropertyAssignments(nodeTypeProperties: MutableMap<String, PropertyDefinition>,\r
238                                          properties: MutableMap<String, JsonNode>) {\r
239         properties.forEach { propertyName, propertyAssignment ->\r
240             val propertyDefinition: PropertyDefinition = nodeTypeProperties[propertyName]\r
241                     ?: throw BluePrintException(format("failed to get definition for the property ({})", propertyName))\r
242             // Check and Validate if Expression Node\r
243             val expressionData = BluePrintExpressionService.getExpressionData(propertyAssignment)\r
244             if (!expressionData.isExpression) {\r
245                 checkPropertyValue(propertyDefinition, propertyAssignment)\r
246             }\r
247         }\r
248     }\r
249 \r
250     @Throws(BluePrintException::class)\r
251     open fun validateArtifactDefinitions(artifacts: MutableMap<String, ArtifactDefinition>) {\r
252         paths.add("artifacts")\r
253         artifacts.forEach { artifactName, artifactDefinition ->\r
254             paths.add(artifactName)\r
255             message.appendln("Validating artifact " + paths.joinToString(separator))\r
256             val type: String = artifactDefinition.type\r
257                     ?: throw BluePrintException("type is missing for artifact definition :" + artifactName)\r
258             // Check Artifact Type\r
259             checkValidArtifactType(type)\r
260 \r
261             val file: String = artifactDefinition.file\r
262                     ?: throw BluePrintException(format("file is missing for artifact definition : {}", artifactName))\r
263 \r
264             paths.removeAt(paths.lastIndex)\r
265         }\r
266         paths.removeAt(paths.lastIndex)\r
267     }\r
268 \r
269     @Throws(BluePrintException::class)\r
270     open fun validateCapabilityAssignments(capabilities: MutableMap<String, CapabilityAssignment>) {\r
271 \r
272     }\r
273 \r
274     @Throws(BluePrintException::class)\r
275     open fun validateRequirementAssignments(requirements: MutableMap<String, RequirementAssignment>) {\r
276 \r
277     }\r
278 \r
279     @Throws(BluePrintException::class)\r
280     open fun validateInterfaceAssignments(interfaces: MutableMap<String, InterfaceAssignment>) {\r
281 \r
282     }\r
283 \r
284     @Throws(BluePrintException::class)\r
285     open fun validateInterfaceDefinitions(interfaces: MutableMap<String, InterfaceDefinition>) {\r
286         paths.add("interfaces")\r
287         interfaces.forEach { interfaceName, interfaceDefinition ->\r
288             paths.add(interfaceName)\r
289             message.appendln("Validating : " + paths.joinToString(separator))\r
290             interfaceDefinition.operations?.let { validateOperationDefinitions(interfaceDefinition.operations!!) }\r
291             paths.removeAt(paths.lastIndex)\r
292         }\r
293         paths.removeAt(paths.lastIndex)\r
294     }\r
295 \r
296     @Throws(BluePrintException::class)\r
297     open fun validateOperationDefinitions(operations: MutableMap<String, OperationDefinition>) {\r
298         paths.add("operations")\r
299         operations.forEach { opertaionName, operationDefinition ->\r
300             paths.add(opertaionName)\r
301             message.appendln("Validating : " + paths.joinToString(separator))\r
302             operationDefinition.implementation?.let { validateImplementation(operationDefinition.implementation!!) }\r
303             operationDefinition.inputs?.let { validatePropertyDefinitions(operationDefinition.inputs!!) }\r
304             operationDefinition.outputs?.let { validatePropertyDefinitions(operationDefinition.outputs!!) }\r
305             paths.removeAt(paths.lastIndex)\r
306         }\r
307         paths.removeAt(paths.lastIndex)\r
308     }\r
309 \r
310     @Throws(BluePrintException::class)\r
311     open fun validateImplementation(implementation: Implementation) {\r
312         checkNotEmptyNThrow(implementation.primary)\r
313     }\r
314 \r
315     @Throws(BluePrintException::class)\r
316     open fun checkValidNodeType(nodeType : String) {\r
317 \r
318     }\r
319 \r
320     @Throws(BluePrintException::class)\r
321     open fun checkValidArtifactType(artifactType: String) {\r
322 \r
323         serviceTemplate.artifactTypes?.containsKey(artifactType)\r
324                 ?: throw BluePrintException(format("Failed to node type definition for artifact definition : {}", artifactType))\r
325     }\r
326 \r
327     @Throws(BluePrintException::class)\r
328     open fun checkValidNodeTypesDerivedFrom(derivedFrom: String) {\r
329 \r
330     }\r
331 \r
332     private fun checkPropertyValue(propertyDefinition: PropertyDefinition, jsonNode: JsonNode) {\r
333         //log.info("validating path ({}), Property {}, value ({})", paths, propertyDefinition, jsonNode)\r
334     }\r
335 \r
336     private fun checkPropertyDataType(dataType: String, propertyName: String): Boolean {\r
337         if (checkDataType(dataType)) {\r
338             return true\r
339         } else {\r
340             throw BluePrintException(format("Data type ({}) for the property ({}) not found", dataType, propertyName))\r
341         }\r
342     }\r
343 \r
344     private fun checkPrimitiveOrComplex(dataType: String, propertyName: String): Boolean {\r
345         if (BluePrintTypes.validPrimitiveTypes().contains(dataType) || checkDataType(dataType)) {\r
346             return true\r
347         } else {\r
348             throw BluePrintException(format("Data type ({}) for the property ({}) is not valid", dataType))\r
349         }\r
350     }\r
351 \r
352     private fun checkDataType(key: String): Boolean {\r
353         return serviceTemplate.dataTypes?.containsKey(key) ?: false\r
354     }\r
355 \r
356     private fun checkNodeType(key: String): Boolean {\r
357         return serviceTemplate.nodeTypes?.containsKey(key) ?: false\r
358     }\r
359 \r
360 }