Blueprint Processor Python Script Components
[ccsdk/cds.git] / components / core / src / main / kotlin / org / onap / ccsdk / apps / controllerblueprints / core / validation / BluePrintNodeTemplateValidatorImpl.kt
1 /*
2  * Copyright © 2017-2018 AT&T Intellectual Property.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *     http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16
17 package org.onap.ccsdk.apps.controllerblueprints.core.validation
18
19 import com.att.eelf.configuration.EELFLogger
20 import com.att.eelf.configuration.EELFManager
21 import com.fasterxml.jackson.databind.JsonNode
22 import org.onap.ccsdk.apps.controllerblueprints.core.BluePrintException
23 import org.onap.ccsdk.apps.controllerblueprints.core.BluePrintTypes
24 import org.onap.ccsdk.apps.controllerblueprints.core.data.*
25 import org.onap.ccsdk.apps.controllerblueprints.core.format
26 import org.onap.ccsdk.apps.controllerblueprints.core.interfaces.BluePrintNodeTemplateValidator
27 import org.onap.ccsdk.apps.controllerblueprints.core.interfaces.BluePrintTypeValidatorService
28 import org.onap.ccsdk.apps.controllerblueprints.core.service.BluePrintContext
29 import org.onap.ccsdk.apps.controllerblueprints.core.service.BluePrintExpressionService
30 import org.onap.ccsdk.apps.controllerblueprints.core.service.BluePrintRuntimeService
31 import org.onap.ccsdk.apps.controllerblueprints.core.utils.JacksonUtils
32
33
34 open class BluePrintNodeTemplateValidatorImpl(private val bluePrintTypeValidatorService: BluePrintTypeValidatorService) : BluePrintNodeTemplateValidator {
35
36     private val log: EELFLogger = EELFManager.getInstance().getLogger(BluePrintNodeTemplateValidatorImpl::class.toString())
37
38     lateinit var bluePrintRuntimeService: BluePrintRuntimeService<*>
39     lateinit var bluePrintContext: BluePrintContext
40     var paths: MutableList<String> = arrayListOf()
41
42     override fun validate(bluePrintRuntimeService: BluePrintRuntimeService<*>, nodeTemplateName: String, nodeTemplate: NodeTemplate) {
43         log.info("Validating NodeTemplate($nodeTemplateName)")
44
45         this.bluePrintRuntimeService = bluePrintRuntimeService
46         this.bluePrintContext = bluePrintRuntimeService.bluePrintContext()
47
48         paths.add(nodeTemplateName)
49
50         val type: String = nodeTemplate.type
51
52         val nodeType: NodeType = bluePrintContext.serviceTemplate.nodeTypes?.get(type)
53                 ?: throw BluePrintException("Failed to get NodeType($type) definition for NodeTemplate($nodeTemplateName)")
54
55         nodeTemplate.properties?.let { validatePropertyAssignments(nodeType.properties!!, nodeTemplate.properties!!) }
56         nodeTemplate.capabilities?.let { validateCapabilityAssignments(nodeType, nodeTemplateName, nodeTemplate) }
57         nodeTemplate.requirements?.let { validateRequirementAssignments(nodeType, nodeTemplateName, nodeTemplate) }
58         nodeTemplate.interfaces?.let { validateInterfaceAssignments(nodeType, nodeTemplateName, nodeTemplate) }
59         nodeTemplate.artifacts?.let { validateArtifactDefinitions(nodeTemplate.artifacts!!) }
60
61         paths.removeAt(paths.lastIndex)
62     }
63
64     @Throws(BluePrintException::class)
65     open fun validateArtifactDefinitions(artifacts: MutableMap<String, ArtifactDefinition>) {
66         paths.add("artifacts")
67         artifacts.forEach { artifactDefinitionName, artifactDefinition ->
68             paths.add(artifactDefinitionName)
69             val type: String = artifactDefinition.type
70                     ?: throw BluePrintException("type is missing for ArtifactDefinition$artifactDefinitionName)")
71             // Check Artifact Type
72             checkValidArtifactType(artifactDefinitionName, type)
73
74             val file: String = artifactDefinition.file
75                     ?: throw BluePrintException("file is missing for ArtifactDefinition($artifactDefinitionName)")
76
77             paths.removeAt(paths.lastIndex)
78         }
79         paths.removeAt(paths.lastIndex)
80     }
81
82
83     @Throws(BluePrintException::class)
84     open fun validatePropertyAssignments(nodeTypeProperties: MutableMap<String, PropertyDefinition>,
85                                          properties: MutableMap<String, JsonNode>) {
86         properties.forEach { propertyName, propertyAssignment ->
87             val propertyDefinition: PropertyDefinition = nodeTypeProperties[propertyName]
88                     ?: throw BluePrintException("failed to get definition for the property ($propertyName)")
89
90             validatePropertyAssignment(propertyName, propertyDefinition, propertyAssignment)
91
92         }
93     }
94
95     @Throws(BluePrintException::class)
96     open fun validatePropertyAssignment(propertyName: String, propertyDefinition: PropertyDefinition,
97                                         propertyAssignment: JsonNode) {
98         // Check and Validate if Expression Node
99         val expressionData = BluePrintExpressionService.getExpressionData(propertyAssignment)
100         if (!expressionData.isExpression) {
101             checkPropertyValue(propertyName, propertyDefinition, propertyAssignment)
102         }
103     }
104
105     @Throws(BluePrintException::class)
106     open fun validateCapabilityAssignments(nodeType: NodeType, nodeTemplateName: String, nodeTemplate: NodeTemplate) {
107         val capabilities = nodeTemplate.capabilities
108         paths.add("capabilities")
109         capabilities?.forEach { capabilityName, capabilityAssignment ->
110             paths.add(capabilityName)
111
112             val capabilityDefinition = nodeType.capabilities?.get(capabilityName)
113                     ?: throw BluePrintException("Failed to get NodeTemplate($nodeTemplateName) capability definition ($capabilityName) " +
114                             "from NodeType(${nodeTemplate.type})")
115
116             validateCapabilityAssignment(nodeTemplateName, capabilityName, capabilityDefinition, capabilityAssignment)
117
118             paths.removeAt(paths.lastIndex)
119         }
120         paths.removeAt(paths.lastIndex)
121     }
122
123     @Throws(BluePrintException::class)
124     open fun validateCapabilityAssignment(nodeTemplateName: String, capabilityName: String,
125                                           capabilityDefinition: CapabilityDefinition, capabilityAssignment: CapabilityAssignment) {
126
127         capabilityAssignment.properties?.let { validatePropertyAssignments(capabilityDefinition.properties!!, capabilityAssignment.properties!!) }
128
129     }
130
131     @Throws(BluePrintException::class)
132     open fun validateRequirementAssignments(nodeType: NodeType, nodeTemplateName: String, nodeTemplate: NodeTemplate) {
133         val requirements = nodeTemplate.requirements
134         paths.add("requirements")
135         requirements?.forEach { requirementName, requirementAssignment ->
136             paths.add(requirementName)
137             val requirementDefinition = nodeType.requirements?.get(requirementName)
138                     ?: throw BluePrintException("Failed to get NodeTemplate($nodeTemplateName) requirement definition ($requirementName) from" +
139                             " NodeType(${nodeTemplate.type})")
140             // Validate Requirement Assignment
141             validateRequirementAssignment(nodeTemplateName, requirementName, requirementDefinition, requirementAssignment)
142             paths.removeAt(paths.lastIndex)
143         }
144         paths.removeAt(paths.lastIndex)
145
146     }
147
148     @Throws(BluePrintException::class)
149     open fun validateRequirementAssignment(nodeTemplateName: String, requirementAssignmentName: String,
150                                            requirementDefinition: RequirementDefinition, requirementAssignment: RequirementAssignment) {
151         log.info("Validating NodeTemplate({}) requirement assignment ({}) ", nodeTemplateName, requirementAssignmentName)
152         val requirementNodeTemplateName = requirementAssignment.node!!
153         val capabilityName = requirementAssignment.capability
154         val relationship = requirementAssignment.relationship!!
155
156         check(BluePrintTypes.validRelationShipDerivedFroms.contains(relationship)) {
157             throw BluePrintException("Failed to get relationship type ($relationship) for NodeTemplate($nodeTemplateName)'s requirement($requirementAssignmentName)")
158         }
159
160         val relationShipNodeTemplate = bluePrintContext.serviceTemplate.topologyTemplate?.nodeTemplates?.get(requirementNodeTemplateName)
161                 ?: throw BluePrintException("Failed to get requirement NodeTemplate($requirementNodeTemplateName)'s " +
162                         "for NodeTemplate($nodeTemplateName) requirement($requirementAssignmentName)")
163
164         relationShipNodeTemplate.capabilities?.get(capabilityName)
165                 ?: throw BluePrintException("Failed to get requirement NodeTemplate($requirementNodeTemplateName)'s " +
166                         "capability($capabilityName) for NodeTemplate ($nodeTemplateName)'s requirement($requirementAssignmentName)")
167
168
169     }
170
171     @Throws(BluePrintException::class)
172     open fun validateInterfaceAssignments(nodeType: NodeType, nodeTemplateName: String, nodeTemplate: NodeTemplate) {
173
174         val interfaces = nodeTemplate.interfaces
175         paths.add("interfaces")
176         interfaces?.forEach { interfaceAssignmentName, interfaceAssignment ->
177             paths.add(interfaceAssignmentName)
178             val interfaceDefinition = nodeType.interfaces?.get(interfaceAssignmentName)
179                     ?: throw BluePrintException("Failed to get NodeTemplate($nodeTemplateName) interface definition ($interfaceAssignmentName) from" +
180                             " NodeType(${nodeTemplate.type})")
181
182             validateInterfaceAssignment(nodeTemplateName, interfaceAssignmentName, interfaceDefinition,
183                     interfaceAssignment)
184             paths.removeAt(paths.lastIndex)
185         }
186         paths.removeAt(paths.lastIndex)
187
188
189     }
190
191     @Throws(BluePrintException::class)
192     open fun validateInterfaceAssignment(nodeTemplateName: String, interfaceAssignmentName: String,
193                                          interfaceDefinition: InterfaceDefinition,
194                                          interfaceAssignment: InterfaceAssignment) {
195
196         val operations = interfaceAssignment.operations
197         operations?.let {
198             validateInterfaceOperationsAssignment(nodeTemplateName, interfaceAssignmentName, interfaceDefinition,
199                     interfaceAssignment)
200         }
201
202     }
203
204     @Throws(BluePrintException::class)
205     open fun validateInterfaceOperationsAssignment(nodeTemplateName: String, interfaceAssignmentName: String,
206                                                    interfaceDefinition: InterfaceDefinition,
207                                                    interfaceAssignment: InterfaceAssignment) {
208
209         val operations = interfaceAssignment.operations
210         operations?.let {
211             it.forEach { operationAssignmentName, operationAssignments ->
212
213                 val operationDefinition = interfaceDefinition.operations?.get(operationAssignmentName)
214                         ?: throw BluePrintException("Failed to get NodeTemplate($nodeTemplateName) operation definition ($operationAssignmentName)")
215
216                 log.info("Validation NodeTemplate($nodeTemplateName) Interface($interfaceAssignmentName) Operation ($operationAssignmentName)")
217
218                 val inputs = operationAssignments.inputs
219                 val outputs = operationAssignments.outputs
220
221                 inputs?.forEach { propertyName, propertyAssignment ->
222                     val propertyDefinition = operationDefinition.inputs?.get(propertyName)
223                             ?: throw BluePrintException("Failed to get NodeTemplate($nodeTemplateName) operation " +
224                                     "definition ($operationAssignmentName) property definition($propertyName)")
225                     // Check the property values with property definition
226                     validatePropertyAssignment(propertyName, propertyDefinition, propertyAssignment)
227                 }
228
229                 outputs?.forEach { propertyName, propertyAssignment ->
230                     val propertyDefinition = operationDefinition.outputs?.get(propertyName)
231                             ?: throw BluePrintException("Failed to get NodeTemplate($nodeTemplateName) operation definition ($operationAssignmentName) " +
232                                     "output property definition($propertyName)")
233                     // Check the property values with property definition
234                     validatePropertyAssignment(propertyName, propertyDefinition, propertyAssignment)
235                 }
236
237             }
238         }
239
240     }
241
242     open fun checkValidArtifactType(artifactDefinitionName: String, artifactTypeName: String) {
243
244         val artifactType = bluePrintContext.serviceTemplate.artifactTypes?.get(artifactTypeName)
245                 ?: throw BluePrintException("failed to get artifactType($artifactTypeName) for ArtifactDefinition($artifactDefinitionName)")
246
247         checkValidArtifactTypeDerivedFrom(artifactTypeName, artifactType.derivedFrom)
248     }
249
250     @Throws(BluePrintException::class)
251     open fun checkValidArtifactTypeDerivedFrom(artifactTypeName: String, derivedFrom: String) {
252         check(BluePrintTypes.validArtifactTypeDerivedFroms.contains(derivedFrom)) {
253             throw BluePrintException("failed to get artifactType($artifactTypeName)'s derivedFrom($derivedFrom) definition")
254         }
255     }
256
257     open fun checkPropertyValue(propertyName: String, propertyDefinition: PropertyDefinition, propertyAssignment: JsonNode) {
258         val propertyType = propertyDefinition.type
259         val isValid: Boolean
260
261         if (BluePrintTypes.validPrimitiveTypes().contains(propertyType)) {
262             isValid = JacksonUtils.checkJsonNodeValueOfPrimitiveType(propertyType, propertyAssignment)
263
264         } else if (BluePrintTypes.validCollectionTypes().contains(propertyType)) {
265
266             val entrySchemaType = propertyDefinition.entrySchema?.type
267                     ?: throw BluePrintException(format("Failed to get EntrySchema type for the collection property ({})", propertyName))
268
269             if (!BluePrintTypes.validPropertyTypes().contains(entrySchemaType)) {
270                 checkPropertyDataType(entrySchemaType, propertyName)
271             }
272             isValid = JacksonUtils.checkJsonNodeValueOfCollectionType(propertyType, propertyAssignment)
273         } else {
274             checkPropertyDataType(propertyType, propertyName)
275             isValid = true
276         }
277
278         check(isValid) {
279             throw BluePrintException("property(propertyName) defined of type(propertyType) is not comptable with the value (propertyAssignment)")
280         }
281     }
282
283     private fun checkPropertyDataType(dataTypeName: String, propertyName: String) {
284
285         val dataType = bluePrintContext.serviceTemplate.dataTypes?.get(dataTypeName)
286                 ?: throw BluePrintException("DataType ($dataTypeName) for the property ($propertyName) not found")
287
288         checkValidDataTypeDerivedFrom(propertyName, dataType.derivedFrom)
289
290     }
291
292     private fun checkValidDataTypeDerivedFrom(dataTypeName: String, derivedFrom: String) {
293         check(BluePrintTypes.validDataTypeDerivedFroms.contains(derivedFrom)) {
294             throw BluePrintException("Failed to get DataType($dataTypeName)'s  derivedFrom($derivedFrom) definition ")
295         }
296     }
297
298 }