2 * ============LICENSE_START===================================================
3 * Copyright (c) 2018 Amdocs
4 * ============================================================================
5 * Licensed under the Apache License, Version 2.0 (the "License");
6 * you may not use this file except in compliance with the License.
7 * You may obtain a copy of the License at
9 * http://www.apache.org/licenses/LICENSE-2.0
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
16 * ============LICENSE_END=====================================================
22 indices 'default-rules'
26 // NDCB-AAI comparison: Context level
28 name 'Attribute-comparison'
29 attributes 'context-list.ndcb', 'context-list.aai'
32 // NDCB-AAI comparison: Service entity
34 name 'Attribute-comparison'
35 attributes 'context-list.ndcb.service', 'context-list.aai.service'
38 // NDCB-AAI comparison: Context level network list
40 name 'Attribute-comparison'
41 attributes 'context-list.ndcb.networkList[*]', 'context-list.aai.networkList[*]'
44 // NDCB-AAI comparison: VNF list
46 name 'Attribute-comparison'
47 attributes 'context-list.ndcb.vnfList[*]', 'context-list.aai.vnfList[*]'
50 // NDCB-AAI comparison: VNF network list
52 name 'Attribute-comparison'
53 attributes 'context-list.ndcb.vnfList[*].networkList[*]', 'context-list.aai.vnfList[*].networkList[*]'
56 // NDCB-AAI comparison: VF-Module list
58 name 'Attribute-comparison'
59 attributes 'context-list.ndcb.vnfList[*].vfModuleList[*]', 'context-list.aai.vnfList[*].vfModuleList[*]'
62 // NDCB-AAI comparison: VF-Module network list
64 name 'Attribute-comparison'
65 attributes 'context-list.ndcb.vnfList[*].vfModuleList[*].networkList[*]', 'context-list.aai.vnfList[*].vfModuleList[*].networkList[*]'
68 // NDCB-AAI comparison: VNFC list
70 name 'Attribute-comparison'
71 attributes 'context-list.ndcb.vnfList[*].vnfcList[*]', 'context-list.aai.vnfList[*].vnfcList[*]'
74 // NDCB-AAI comparison: VM list
76 name 'Attribute-comparison'
77 attributes 'context-list.ndcb.vnfList[*].vfModuleList[*].vmList[*]', 'context-list.aai.vnfList[*].vfModuleList[*].vmList[*]'
80 // NDCB-AAI comparison: P-Interface list
82 name 'Attribute-comparison'
83 attributes 'context-list.ndcb.pnfList[*].pInterfaceList[*]', 'context-list.aai.pnfList[*].pInterfaceList[*]'
87 // SDNC-AAI comparison: Context level
89 name 'Attribute-comparison'
90 attributes 'context-list.sdnc', 'context-list.aai'
93 // SDNC-AAI comparison: Service entity
95 name 'Attribute-comparison'
96 attributes 'context-list.sdnc.service', 'context-list.aai.service'
99 // SDNC-AAI comparison: Context level network list
101 name 'Attribute-comparison'
102 attributes 'context-list.sdnc.networkList[*]', 'context-list.aai.networkList[*]'
105 // SDNC-AAI comparison: VNF list
107 name 'Attribute-comparison'
108 attributes 'context-list.sdnc.vnfList[*]', 'context-list.aai.vnfList[*]'
111 // SDNC-AAI comparison: VNF network list
113 name 'Attribute-comparison'
114 attributes 'context-list.sdnc.vnfList[*].networkList[*]', 'context-list.aai.vnfList[*].networkList[*]'
117 // SDNC-AAI comparison: VF-Module list
119 name 'Attribute-comparison'
120 attributes 'context-list.sdnc.vnfList[*].vfModuleList[*]', 'context-list.aai.vnfList[*].vfModuleList[*]'
123 // SDNC-AAI comparison: VF-Module network list
125 name 'Attribute-comparison'
126 attributes 'context-list.sdnc.vnfList[*].vfModuleList[*].networkList[*]', 'context-list.aai.vnfList[*].vfModuleList[*].networkList[*]'
129 // SDNC-AAI comparison: VNFC list
131 name 'Attribute-comparison'
132 attributes 'context-list.sdnc.vnfList[*].vnfcList[*]', 'context-list.aai.vnfList[*].vnfcList[*]'
135 // SDNC-AAI comparison: VM list
137 name 'Attribute-comparison'
138 attributes 'context-list.sdnc.vnfList[*].vfModuleList[*].vmList[*]', 'context-list.aai.vnfList[*].vfModuleList[*].vmList[*]'
141 // AAI-SDNC PNF name validation
143 name 'AAI-SDNC-pnf-name-check'
144 attributes 'context-list.aai.pnfList[*].name', 'context-list.sdnc.pnfList[*].name'
148 // SDNC-NDCB comparison: Context level
150 name 'Attribute-comparison'
151 attributes 'context-list.sdnc', 'context-list.ndcb'
154 // SDNC-NDCB comparison: Service entity
156 name 'Attribute-comparison'
157 attributes 'context-list.sdnc.service', 'context-list.ndcb.service'
160 // SDNC-NDCB comparison: Context level network list
162 name 'Attribute-comparison'
163 attributes 'context-list.sdnc.networkList[*]', 'context-list.ndcb.networkList[*]'
166 // SDNC-NDCB comparison: VNF list
168 name 'Attribute-comparison'
169 attributes 'context-list.sdnc.vnfList[*]', 'context-list.ndcb.vnfList[*]'
172 // SDNC-NDCB comparison: VNF network list
174 name 'Attribute-comparison'
175 attributes 'context-list.sdnc.vnfList[*].networkList[*]', 'context-list.ndcb.vnfList[*].networkList[*]'
178 // SDNC-NDCB comparison: VF-Module list
180 name 'Attribute-comparison'
181 attributes 'context-list.sdnc.vnfList[*].vfModuleList[*]', 'context-list.ndcb.vnfList[*].vfModuleList[*]'
184 // SDNC-NDCB comparison: VF-Module network list
186 name 'Attribute-comparison'
187 attributes 'context-list.sdnc.vnfList[*].vfModuleList[*].networkList[*]', 'context-list.ndcb.vnfList[*].vfModuleList[*].networkList[*]'
190 // SDNC-NDCB comparison: VNFC list
192 name 'Attribute-comparison'
193 attributes 'context-list.sdnc.vnfList[*].vnfcList[*]', 'context-list.ndcb.vnfList[*].vnfcList[*]'
196 // SDNC-NDCB comparison: VM list
198 name 'Attribute-comparison'
199 attributes 'context-list.sdnc.vnfList[*].vfModuleList[*].vmList[*]', 'context-list.ndcb.vnfList[*].vfModuleList[*].vmList[*]'
206 name 'SDC-AAI-vnfc-type'
207 attributes 'context-list.sdc.vnfList[*].vnfcList[*]', 'context-list.aai.vnfList[*].vnfcList[*]'
210 // SDC-AAI VNFC node count
212 name 'SDC-AAI-vnfc-node-count'
213 attributes 'context-list.sdc.vnfList[*].vnfcList[*]', 'context-list.aai.vnfList[*].vnfcList[*]'
216 // SDC-AAI VF-Module instance
218 name 'SDC-AAI-vf-module-instance-check'
219 attributes 'context-list.sdc.vnfList[*].vfModuleList[*]', 'context-list.aai.vnfList[*].vfModuleList[*]'
225 name 'SDC-AAI-vnfc-type'
226 category 'VNFC Consistency'
227 description 'Validate that each VNFC instance in AAI conforms to a VNFC type defined in SDC model'
228 errorText 'AAI VNFC instance includes non-specified type in design SDC model'
230 attributes 'sdcList', 'aaiList'
232 def getVnfcTypes = { parsedData ->
233 parsedData.collect{ it.findResult{ k, v -> if(k.equals("type")) {return "$v"}}}
236 def slurper = new groovy.json.JsonSlurper()
237 def sdcTypes = getVnfcTypes(slurper.parseText(sdcList.toString()))
238 def aaiTypes = getVnfcTypes(slurper.parseText(aaiList.toString()))
240 // each type in AAI must exist in SDC
241 return sdcTypes.containsAll(aaiTypes)
246 name 'SDC-AAI-vnfc-node-count'
247 category 'VNFC Consistency'
248 description 'Validate that for each VNFC node defined in SDC model, there is at least one VNFC instance in AAI'
249 errorText 'Design has specified types but not all of them exist in AAI'
251 attributes 'sdcList', 'aaiList'
253 def getVnfcNodes = { parsedData ->
254 parsedData.collect { new Tuple2(
255 it.findResult{ k, v -> if(k.equals("name")) {return "$v"}},
256 it.findResult{ k, v -> if(k.equals("type")) {return "$v"}})
260 def slurper = new groovy.json.JsonSlurper()
261 def sdcNodes = getVnfcNodes(slurper.parseText(sdcList.toString()))
262 def aaiNodes = getVnfcNodes(slurper.parseText(aaiList.toString()))
264 // each node in AAI must exist in SDC
265 return aaiNodes.containsAll(sdcNodes)
270 name 'SDC-AAI-vf-module-instance-check'
271 category 'VF Consistency'
272 description 'Validate that each VF module instance in AAI conforms to a VF module defined in SDC service model'
273 errorText 'One or more AAI VF module instance(s) not defined in SDC model'
275 attributes 'sdcList', 'aaiList'
277 def getVfModules = { parsedData ->
278 parsedData.collect{ it.findResult{ k, v -> if(k.equals("name")) {return "$v"}}}
281 def slurper = new groovy.json.JsonSlurper()
282 def sdcVfModules = getVfModules(slurper.parseText(sdcList.toString()))
283 def aaiVfModules = getVfModules(slurper.parseText(aaiList.toString()))
285 // all VF modules in AAI must exist in SDC
286 return aaiVfModules.containsAll(sdcVfModules)
291 name 'Attribute-comparison'
292 category 'Attribute Mismatch'
293 description 'Determine all discrepancies between values for attributes with matching names from each model'
294 errorText 'Error found with attribute(s) and values: {0}'
296 attributes 'lhsObject', 'rhsObject'
298 // This closure extracts the given object's root level attributes and contents of the attribute list.
299 // Complex items like lists are excluded.
300 // Returns a map containing attribute names as keys, mapping to a list of values for each attribute.
301 Closure<java.util.Map> getAttributes = { parsedData ->
302 java.util.Map attributeMap = new java.util.HashMap()
304 def isAttributeDataQualityOk = { attribute ->
305 attribute.findResult{ k, v -> if(k.equals("dataQuality") ) {return v.get("status")}}.equals("ok")
308 def addToMap = { attrKey, attrValue ->
309 java.util.Set values = attributeMap.get("$attrKey")
311 values = new java.util.HashSet()
312 attributeMap.put("$attrKey", values)
314 values.add("$attrValue")
317 def addAttributeToMap = { attribute ->
318 if(isAttributeDataQualityOk(attribute)) {
320 attribute.each { k, v ->
321 if(k.equals("name")) {key = "$v"}
322 if(k.equals("value")) {value = "$v"}
324 addToMap("$key", "$value")
328 def processKeyValue = { key, value ->
329 if(value instanceof java.util.ArrayList) {
330 if(key.equals("attributeList")) {
332 addAttributeToMap(it)
335 } else if(!(value instanceof groovy.json.internal.LazyMap)) {
336 // only add key-value attributes, skip the rest
337 addToMap("$key", "$value")
341 if(parsedData instanceof java.util.ArrayList) {
343 it.each { key, value -> processKeyValue(key, value) }
346 parsedData.each { key, value -> processKeyValue(key, value) }
351 // This closure compares all values for each key from the left map, to values of the same key from the right map.
352 // Returns a map of attributes with mismatched or missing values (i.e. attribute name mapped to list of failed values).
353 Closure<java.util.Map> compareAttributes = { java.util.Map left, java.util.Map right ->
354 java.util.Map violationMap = new java.util.HashMap()
355 left.each{ leftKey, leftValueList ->
356 def rightValueList = right.get("$leftKey")
357 rightValueList.each{ rightValue ->
358 if(!leftValueList.any{ it == "$rightValue" }) {
359 def existingValues = violationMap.get(leftKey)
361 existingValues.add("$rightValue")
363 java.util.Set newValues = new HashSet()
364 newValues.add("$rightValue")
365 violationMap.put("$leftKey", newValues)
373 // This closure merges the given maps into a new map.
374 // Returns a map containing all keys and their values from both maps.
375 Closure<java.util.Map> mergeMaps = { java.util.Map left, java.util.Map right ->
376 if(left.isEmpty() && right.isEmpty()) {
378 } else if(left.isEmpty()) {
380 } else if(right.isEmpty()) {
383 java.util.Map merged = new java.util.HashMap()
385 right.each{ rightKey, rightValues ->
386 java.util.Set mergedValues = merged.get(rightKey)
387 if(mergedValues == null) {
388 merged.put(rightKey, rightValues)
390 mergedValues.addAll(rightValues)
396 def slurper = new groovy.json.JsonSlurper()
397 java.util.Map lhsAttributes = getAttributes(slurper.parseText(lhsObject.toString()))
398 java.util.Map rhsAttributes = getAttributes(slurper.parseText(rhsObject.toString()))
400 def leftToRight = compareAttributes(lhsAttributes, rhsAttributes)
401 def rightToLeft = compareAttributes(rhsAttributes, lhsAttributes)
402 def mergedResults = mergeMaps(leftToRight, rightToLeft)
404 boolean success = true
405 List<String> details = new ArrayList<>()
406 if(!mergedResults.isEmpty()) {
408 details.add(mergedResults.toString())
410 return new Tuple2(success, details)
415 * The data-dictionary rule below can be used with this useRule clause:
417 * name 'Data-Dictionary validate VF type'
418 * attributes 'context-list.ndcb.vnfList[*].vfModuleList[*].networkList[*].type'
422 name 'Data-Dictionary validate VF type'
423 category 'INVALID_VALUE'
424 description 'Validate all VF type values against data-dictionary'
425 errorText 'VF type [{0}] failed data-dictionary validation: {1}'
427 attributes 'typeList'
429 boolean success = true
430 List<String> details = new ArrayList<>()
433 // break out of 'any' loop
436 def result = org.onap.aai.validation.ruledriven.rule.builtin.DataDictionary.validate("instance", "vfModuleNetworkType", "type", "$it")
437 if(!result.isEmpty()) {
440 details.add("$result")
443 return new Tuple2(success, details)
448 name 'AAI-SDNC-pnf-name-check'
449 category 'PNF Consistency'
450 description 'Validate that each PNF name in AAI matches a PNF name in the SDNC model'
451 errorText 'AAI PNF names do not match SDNC - {0}'
453 attributes 'aaiNames', 'sdncNames'
455 def addName = { values, key ->
459 List<String> errorReasons = new ArrayList();
461 if (aaiNames.size() != sdncNames.size()) {
462 errorReasons.add("Number of PNFs don't match; aai has ${aaiNames.size()}, sdnc has ${sdncNames.size()}")
463 return new Tuple2(false, errorReasons)
466 // collect all the "name" values from AAI and SDNC into two Sets.
467 Set aaiNameSet = new java.util.HashSet()
469 aValue -> addName(aaiNameSet, aValue)
472 Set sdncNameSet = new java.util.HashSet()
474 aValue -> addName(sdncNameSet, aValue)
477 // Validate that the names match by comparing the size of the two Sets.
478 if (aaiNameSet.size() != sdncNameSet.size()) {
479 errorReasons.add("Number of distinct PNF names don't match; aai: ${aaiNameSet}, sdnc: ${sdncNameSet}")
480 return new Tuple2(false, errorReasons)
483 Set combinedSet = new HashSet();
484 combinedSet.addAll(aaiNameSet);
485 combinedSet.addAll(sdncNameSet);
486 if (combinedSet.size() != aaiNameSet.size()) {
487 errorReasons.add("PNF names don't match; aai names: ${aaiNameSet}, sdnc names: ${sdncNameSet}")
488 return new Tuple2(false, errorReasons)