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[*]'
224 attributes 'context-list.aai.pnfList', 'context-list.aai.vnfList', 'context-list.aai.networkList'
231 category 'VNFC Consistency'
232 description 'Check if AAI collected anything'
233 errorText 'AAI section is empty'
235 attributes 'pnfList', 'vnfList', 'networkList'
237 // expect at least one not empty list
238 return !pnfList.isEmpty() || !vnfList.isEmpty() || !networkList.isEmpty()
243 name 'SDC-AAI-vnfc-type'
244 category 'VNFC Consistency'
245 description 'Validate that each VNFC instance in AAI conforms to a VNFC type defined in SDC model'
246 errorText 'AAI VNFC instance includes non-specified type in design SDC model'
248 attributes 'sdcList', 'aaiList'
250 def getVnfcTypes = { parsedData ->
251 parsedData.collect{ it.findResult{ k, v -> if(k.equals("type")) {return "$v"}}}
254 def slurper = new groovy.json.JsonSlurper()
255 def sdcTypes = getVnfcTypes(slurper.parseText(sdcList.toString()))
256 def aaiTypes = getVnfcTypes(slurper.parseText(aaiList.toString()))
258 // each type in AAI must exist in SDC
259 return sdcTypes.containsAll(aaiTypes)
264 name 'SDC-AAI-vnfc-node-count'
265 category 'VNFC Consistency'
266 description 'Validate that for each VNFC node defined in SDC model, there is at least one VNFC instance in AAI'
267 errorText 'Design has specified types but not all of them exist in AAI'
269 attributes 'sdcList', 'aaiList'
271 def getVnfcNodes = { parsedData ->
272 parsedData.collect { new Tuple2(
273 it.findResult{ k, v -> if(k.equals("name")) {return "$v"}},
274 it.findResult{ k, v -> if(k.equals("type")) {return "$v"}})
278 def slurper = new groovy.json.JsonSlurper()
279 def sdcNodes = getVnfcNodes(slurper.parseText(sdcList.toString()))
280 def aaiNodes = getVnfcNodes(slurper.parseText(aaiList.toString()))
282 // each node in AAI must exist in SDC
283 return aaiNodes.containsAll(sdcNodes)
288 name 'SDC-AAI-vf-module-instance-check'
289 category 'VF Consistency'
290 description 'Validate that each VF module instance in AAI conforms to a VF module defined in SDC service model'
291 errorText 'One or more AAI VF module instance(s) not defined in SDC model'
293 attributes 'sdcList', 'aaiList'
295 def getVfModules = { parsedData ->
296 parsedData.collect{ it.findResult{ k, v -> if(k.equals("name")) {return "$v"}}}
299 def slurper = new groovy.json.JsonSlurper()
300 def sdcVfModules = getVfModules(slurper.parseText(sdcList.toString()))
301 def aaiVfModules = getVfModules(slurper.parseText(aaiList.toString()))
303 // all VF modules in AAI must exist in SDC
304 return aaiVfModules.containsAll(sdcVfModules)
309 name 'Attribute-comparison'
310 category 'Attribute Mismatch'
311 description 'Determine all discrepancies between values for attributes with matching names from each model'
312 errorText 'Error found with attribute(s) and values: {0}'
314 attributes 'lhsObject', 'rhsObject'
316 // This closure extracts the given object's root level attributes and contents of the attribute list.
317 // Complex items like lists are excluded.
318 // Returns a map containing attribute names as keys, mapping to a list of values for each attribute.
319 Closure<java.util.Map> getAttributes = { parsedData ->
320 java.util.Map attributeMap = new java.util.HashMap()
322 def isAttributeDataQualityOk = { attribute ->
323 attribute.findResult{ k, v -> if(k.equals("dataQuality") ) {return v.get("status")}}.equals("ok")
326 def addToMap = { attrKey, attrValue ->
327 java.util.Set values = attributeMap.get("$attrKey")
329 values = new java.util.HashSet()
330 attributeMap.put("$attrKey", values)
332 values.add("$attrValue")
335 def addAttributeToMap = { attribute ->
336 if(isAttributeDataQualityOk(attribute)) {
338 attribute.each { k, v ->
339 if(k.equals("name")) {key = "$v"}
340 if(k.equals("value")) {value = "$v"}
342 addToMap("$key", "$value")
346 def processKeyValue = { key, value ->
347 if(value instanceof java.util.ArrayList) {
348 if(key.equals("attributeList")) {
350 addAttributeToMap(it)
353 } else if(!(value instanceof groovy.json.internal.LazyMap)) {
354 // only add key-value attributes, skip the rest
355 addToMap("$key", "$value")
359 if(parsedData instanceof java.util.ArrayList) {
361 it.each { key, value -> processKeyValue(key, value) }
364 parsedData.each { key, value -> processKeyValue(key, value) }
369 // This closure compares all values for each key from the left map, to values of the same key from the right map.
370 // Returns a map of attributes with mismatched or missing values (i.e. attribute name mapped to list of failed values).
371 Closure<java.util.Map> compareAttributes = { java.util.Map left, java.util.Map right ->
372 java.util.Map violationMap = new java.util.HashMap()
373 left.each{ leftKey, leftValueList ->
374 def rightValueList = right.get("$leftKey")
375 rightValueList.each{ rightValue ->
376 if(!leftValueList.any{ it == "$rightValue" }) {
377 def existingValues = violationMap.get(leftKey)
379 existingValues.add("$rightValue")
381 java.util.Set newValues = new HashSet()
382 newValues.add("$rightValue")
383 violationMap.put("$leftKey", newValues)
391 // This closure merges the given maps into a new map.
392 // Returns a map containing all keys and their values from both maps.
393 Closure<java.util.Map> mergeMaps = { java.util.Map left, java.util.Map right ->
394 if(left.isEmpty() && right.isEmpty()) {
396 } else if(left.isEmpty()) {
398 } else if(right.isEmpty()) {
401 java.util.Map merged = new java.util.HashMap()
403 right.each{ rightKey, rightValues ->
404 java.util.Set mergedValues = merged.get(rightKey)
405 if(mergedValues == null) {
406 merged.put(rightKey, rightValues)
408 mergedValues.addAll(rightValues)
414 def slurper = new groovy.json.JsonSlurper()
415 java.util.Map lhsAttributes = getAttributes(slurper.parseText(lhsObject.toString()))
416 java.util.Map rhsAttributes = getAttributes(slurper.parseText(rhsObject.toString()))
418 def leftToRight = compareAttributes(lhsAttributes, rhsAttributes)
419 def rightToLeft = compareAttributes(rhsAttributes, lhsAttributes)
420 def mergedResults = mergeMaps(leftToRight, rightToLeft)
422 boolean success = true
423 List<String> details = new ArrayList<>()
424 if(!mergedResults.isEmpty()) {
426 details.add(mergedResults.toString())
428 return new Tuple2(success, details)
433 * The data-dictionary rule below can be used with this useRule clause:
435 * name 'Data-Dictionary validate VF type'
436 * attributes 'context-list.ndcb.vnfList[*].vfModuleList[*].networkList[*].type'
440 name 'Data-Dictionary validate VF type'
441 category 'INVALID_VALUE'
442 description 'Validate all VF type values against data-dictionary'
443 errorText 'VF type [{0}] failed data-dictionary validation: {1}'
445 attributes 'typeList'
447 boolean success = true
448 List<String> details = new ArrayList<>()
451 // break out of 'any' loop
454 def result = org.onap.aai.validation.ruledriven.rule.builtin.DataDictionary.validate("instance", "vfModuleNetworkType", "type", "$it")
455 if(!result.isEmpty()) {
458 details.add("$result")
461 return new Tuple2(success, details)
466 name 'AAI-SDNC-pnf-name-check'
467 category 'PNF Consistency'
468 description 'Validate that each PNF name in AAI matches a PNF name in the SDNC model'
469 errorText 'AAI PNF names do not match SDNC - {0}'
471 attributes 'aaiNames', 'sdncNames'
473 def addName = { values, key ->
477 List<String> errorReasons = new ArrayList();
479 if (aaiNames.size() != sdncNames.size()) {
480 errorReasons.add("Number of PNFs don't match; aai has ${aaiNames.size()}, sdnc has ${sdncNames.size()}")
481 return new Tuple2(false, errorReasons)
484 // collect all the "name" values from AAI and SDNC into two Sets.
485 Set aaiNameSet = new java.util.HashSet()
487 aValue -> addName(aaiNameSet, aValue)
490 Set sdncNameSet = new java.util.HashSet()
492 aValue -> addName(sdncNameSet, aValue)
495 // Validate that the names match by comparing the size of the two Sets.
496 if (aaiNameSet.size() != sdncNameSet.size()) {
497 errorReasons.add("Number of distinct PNF names don't match; aai: ${aaiNameSet}, sdnc: ${sdncNameSet}")
498 return new Tuple2(false, errorReasons)
501 Set combinedSet = new HashSet();
502 combinedSet.addAll(aaiNameSet);
503 combinedSet.addAll(sdncNameSet);
504 if (combinedSet.size() != aaiNameSet.size()) {
505 errorReasons.add("PNF names don't match; aai names: ${aaiNameSet}, sdnc names: ${sdncNameSet}")
506 return new Tuple2(false, errorReasons)