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[*]'
81 // SDNC-AAI comparison: Context level
83 name 'Attribute-comparison'
84 attributes 'context-list.sdnc', 'context-list.aai'
87 // SDNC-AAI comparison: Service entity
89 name 'Attribute-comparison'
90 attributes 'context-list.sdnc.service', 'context-list.aai.service'
93 // SDNC-AAI comparison: Context level network list
95 name 'Attribute-comparison'
96 attributes 'context-list.sdnc.networkList[*]', 'context-list.aai.networkList[*]'
99 // SDNC-AAI comparison: VNF list
101 name 'Attribute-comparison'
102 attributes 'context-list.sdnc.vnfList[*]', 'context-list.aai.vnfList[*]'
105 // SDNC-AAI comparison: VNF network list
107 name 'Attribute-comparison'
108 attributes 'context-list.sdnc.vnfList[*].networkList[*]', 'context-list.aai.vnfList[*].networkList[*]'
111 // SDNC-AAI comparison: VF-Module list
113 name 'Attribute-comparison'
114 attributes 'context-list.sdnc.vnfList[*].vfModuleList[*]', 'context-list.aai.vnfList[*].vfModuleList[*]'
117 // SDNC-AAI comparison: VF-Module network list
119 name 'Attribute-comparison'
120 attributes 'context-list.sdnc.vnfList[*].vfModuleList[*].networkList[*]', 'context-list.aai.vnfList[*].vfModuleList[*].networkList[*]'
123 // SDNC-AAI comparison: VNFC list
125 name 'Attribute-comparison'
126 attributes 'context-list.sdnc.vnfList[*].vnfcList[*]', 'context-list.aai.vnfList[*].vnfcList[*]'
129 // SDNC-AAI comparison: VM list
131 name 'Attribute-comparison'
132 attributes 'context-list.sdnc.vnfList[*].vfModuleList[*].vmList[*]', 'context-list.aai.vnfList[*].vfModuleList[*].vmList[*]'
135 // AAI-SDNC PNF name validation
137 name 'AAI-SDNC-pnf-name-check'
138 attributes 'context-list.aai.pnfList[*].name', 'context-list.sdnc.pnfList[*].name'
142 // SDNC-NDCB comparison: Context level
144 name 'Attribute-comparison'
145 attributes 'context-list.sdnc', 'context-list.ndcb'
148 // SDNC-NDCB comparison: Service entity
150 name 'Attribute-comparison'
151 attributes 'context-list.sdnc.service', 'context-list.ndcb.service'
154 // SDNC-NDCB comparison: Context level network list
156 name 'Attribute-comparison'
157 attributes 'context-list.sdnc.networkList[*]', 'context-list.ndcb.networkList[*]'
160 // SDNC-NDCB comparison: VNF list
162 name 'Attribute-comparison'
163 attributes 'context-list.sdnc.vnfList[*]', 'context-list.ndcb.vnfList[*]'
166 // SDNC-NDCB comparison: VNF network list
168 name 'Attribute-comparison'
169 attributes 'context-list.sdnc.vnfList[*].networkList[*]', 'context-list.ndcb.vnfList[*].networkList[*]'
172 // SDNC-NDCB comparison: VF-Module list
174 name 'Attribute-comparison'
175 attributes 'context-list.sdnc.vnfList[*].vfModuleList[*]', 'context-list.ndcb.vnfList[*].vfModuleList[*]'
178 // SDNC-NDCB comparison: VF-Module network list
180 name 'Attribute-comparison'
181 attributes 'context-list.sdnc.vnfList[*].vfModuleList[*].networkList[*]', 'context-list.ndcb.vnfList[*].vfModuleList[*].networkList[*]'
184 // SDNC-NDCB comparison: VNFC list
186 name 'Attribute-comparison'
187 attributes 'context-list.sdnc.vnfList[*].vnfcList[*]', 'context-list.ndcb.vnfList[*].vnfcList[*]'
190 // SDNC-NDCB comparison: VM list
192 name 'Attribute-comparison'
193 attributes 'context-list.sdnc.vnfList[*].vfModuleList[*].vmList[*]', 'context-list.ndcb.vnfList[*].vfModuleList[*].vmList[*]'
200 name 'SDC-AAI-vnfc-type'
201 attributes 'context-list.sdc.vnfList[*].vnfcList[*]', 'context-list.aai.vnfList[*].vnfcList[*]'
204 // SDC-AAI VNFC node count
206 name 'SDC-AAI-vnfc-node-count'
207 attributes 'context-list.sdc.vnfList[*].vnfcList[*]', 'context-list.aai.vnfList[*].vnfcList[*]'
210 // SDC-AAI VF-Module instance
212 name 'SDC-AAI-vf-module-instance-check'
213 attributes 'context-list.sdc.vnfList[*].vfModuleList[*]', 'context-list.aai.vnfList[*].vfModuleList[*]'
219 name 'SDC-AAI-vnfc-type'
220 category 'VNFC Consistency'
221 description 'Validate that each VNFC instance in AAI conforms to a VNFC type defined in SDC model'
222 errorText 'AAI VNFC instance includes non-specified type in design SDC model'
224 attributes 'sdcList', 'aaiList'
226 def getVnfcTypes = { parsedData ->
227 parsedData.collect{ it.findResult{ k, v -> if(k.equals("type")) {return "$v"}}}
230 def slurper = new groovy.json.JsonSlurper()
231 def sdcTypes = getVnfcTypes(slurper.parseText(sdcList.toString()))
232 def aaiTypes = getVnfcTypes(slurper.parseText(aaiList.toString()))
234 // each type in AAI must exist in SDC
235 return sdcTypes.containsAll(aaiTypes)
240 name 'SDC-AAI-vnfc-node-count'
241 category 'VNFC Consistency'
242 description 'Validate that for each VNFC node defined in SDC model, there is at least one VNFC instance in AAI'
243 errorText 'Design has specified types but not all of them exist in AAI'
245 attributes 'sdcList', 'aaiList'
247 def getVnfcNodes = { parsedData ->
248 parsedData.collect { new Tuple2(
249 it.findResult{ k, v -> if(k.equals("name")) {return "$v"}},
250 it.findResult{ k, v -> if(k.equals("type")) {return "$v"}})
254 def slurper = new groovy.json.JsonSlurper()
255 def sdcNodes = getVnfcNodes(slurper.parseText(sdcList.toString()))
256 def aaiNodes = getVnfcNodes(slurper.parseText(aaiList.toString()))
258 // each node in AAI must exist in SDC
259 return aaiNodes.containsAll(sdcNodes)
264 name 'SDC-AAI-vf-module-instance-check'
265 category 'VF Consistency'
266 description 'Validate that each VF module instance in AAI conforms to a VF module defined in SDC service model'
267 errorText 'One or more AAI VF module instance(s) not defined in SDC model'
269 attributes 'sdcList', 'aaiList'
271 def getVfModules = { parsedData ->
272 parsedData.collect{ it.findResult{ k, v -> if(k.equals("name")) {return "$v"}}}
275 def slurper = new groovy.json.JsonSlurper()
276 def sdcVfModules = getVfModules(slurper.parseText(sdcList.toString()))
277 def aaiVfModules = getVfModules(slurper.parseText(aaiList.toString()))
279 // all VF modules in AAI must exist in SDC
280 return aaiVfModules.containsAll(sdcVfModules)
285 name 'Attribute-comparison'
286 category 'Attribute Mismatch'
287 description 'Determine all discrepancies between values for attributes with matching names from each model'
288 errorText 'Error found with attribute(s) and values: {0}'
290 attributes 'lhsObject', 'rhsObject'
292 // This closure extracts the given object's root level attributes and contents of the attribute list.
293 // Complex items like lists are excluded.
294 // Returns a map containing attribute names as keys, mapping to a list of values for each attribute.
295 Closure<java.util.Map> getAttributes = { parsedData ->
296 java.util.Map attributeMap = new java.util.HashMap()
298 def isAttributeDataQualityOk = { attribute ->
299 attribute.findResult{ k, v -> if(k.equals("dataQuality") ) {return v.get("status")}}.equals("ok")
302 def addToMap = { attrKey, attrValue ->
303 java.util.Set values = attributeMap.get("$attrKey")
305 values = new java.util.HashSet()
306 attributeMap.put("$attrKey", values)
308 values.add("$attrValue")
311 def addAttributeToMap = { attribute ->
312 if(isAttributeDataQualityOk(attribute)) {
314 attribute.each { k, v ->
315 if(k.equals("name")) {key = "$v"}
316 if(k.equals("value")) {value = "$v"}
318 addToMap("$key", "$value")
322 def processKeyValue = { key, value ->
323 if(value instanceof java.util.ArrayList) {
324 if(key.equals("attributeList")) {
326 addAttributeToMap(it)
329 } else if(!(value instanceof groovy.json.internal.LazyMap)) {
330 // only add key-value attributes, skip the rest
331 addToMap("$key", "$value")
335 if(parsedData instanceof java.util.ArrayList) {
337 it.each { key, value -> processKeyValue(key, value) }
340 parsedData.each { key, value -> processKeyValue(key, value) }
345 // This closure compares all values for each key from the left map, to values of the same key from the right map.
346 // Returns a map of attributes with mismatched or missing values (i.e. attribute name mapped to list of failed values).
347 Closure<java.util.Map> compareAttributes = { java.util.Map left, java.util.Map right ->
348 java.util.Map violationMap = new java.util.HashMap()
349 left.each{ leftKey, leftValueList ->
350 def rightValueList = right.get("$leftKey")
351 rightValueList.each{ rightValue ->
352 if(!leftValueList.any{ it == "$rightValue" }) {
353 def existingValues = violationMap.get(leftKey)
355 existingValues.add("$rightValue")
357 java.util.Set newValues = new HashSet()
358 newValues.add("$rightValue")
359 violationMap.put("$leftKey", newValues)
367 // This closure merges the given maps into a new map.
368 // Returns a map containing all keys and their values from both maps.
369 Closure<java.util.Map> mergeMaps = { java.util.Map left, java.util.Map right ->
370 if(left.isEmpty() && right.isEmpty()) {
372 } else if(left.isEmpty()) {
374 } else if(right.isEmpty()) {
377 java.util.Map merged = new java.util.HashMap()
379 right.each{ rightKey, rightValues ->
380 java.util.Set mergedValues = merged.get(rightKey)
381 if(mergedValues == null) {
382 merged.put(rightKey, rightValues)
384 mergedValues.addAll(rightValues)
390 def slurper = new groovy.json.JsonSlurper()
391 java.util.Map lhsAttributes = getAttributes(slurper.parseText(lhsObject.toString()))
392 java.util.Map rhsAttributes = getAttributes(slurper.parseText(rhsObject.toString()))
394 def leftToRight = compareAttributes(lhsAttributes, rhsAttributes)
395 def rightToLeft = compareAttributes(rhsAttributes, lhsAttributes)
396 def mergedResults = mergeMaps(leftToRight, rightToLeft)
398 boolean success = true
399 List<String> details = new ArrayList<>()
400 if(!mergedResults.isEmpty()) {
402 details.add(mergedResults.toString())
404 return new Tuple2(success, details)
409 * The data-dictionary rule below can be used with this useRule clause:
411 * name 'Data-Dictionary validate VF type'
412 * attributes 'context-list.ndcb.vnfList[*].vfModuleList[*].networkList[*].type'
416 name 'Data-Dictionary validate VF type'
417 category 'INVALID_VALUE'
418 description 'Validate all VF type values against data-dictionary'
419 errorText 'VF type [{0}] failed data-dictionary validation: {1}'
421 attributes 'typeList'
423 boolean success = true
424 List<String> details = new ArrayList<>()
427 // break out of 'any' loop
430 def result = org.onap.aai.validation.ruledriven.rule.builtin.DataDictionary.validate("instance", "vfModuleNetworkType", "type", "$it")
431 if(!result.isEmpty()) {
434 details.add("$result")
437 return new Tuple2(success, details)
442 name 'AAI-SDNC-pnf-name-check'
443 category 'PNF Consistency'
444 description 'Validate that each PNF name in AAI matches a PNF name in the SDNC model'
445 errorText 'AAI PNF names do not match SDNC - {0}'
447 attributes 'aaiNames', 'sdncNames'
449 def addName = { values, key ->
453 List<String> errorReasons = new ArrayList();
455 if (aaiNames.size() != sdncNames.size()) {
456 errorReasons.add("Number of PNFs don't match; aai has ${aaiNames.size()}, sdnc has ${sdncNames.size()}")
457 return new Tuple2(false, errorReasons)
460 // collect all the "name" values from AAI and SDNC into two Sets.
461 Set aaiNameSet = new java.util.HashSet()
463 aValue -> addName(aaiNameSet, aValue)
466 Set sdncNameSet = new java.util.HashSet()
468 aValue -> addName(sdncNameSet, aValue)
471 // Validate that the names match by comparing the size of the two Sets.
472 if (aaiNameSet.size() != sdncNameSet.size()) {
473 errorReasons.add("Number of distinct PNF names don't match; aai: ${aaiNameSet}, sdnc: ${sdncNameSet}")
474 return new Tuple2(false, errorReasons)
477 Set combinedSet = new HashSet();
478 combinedSet.addAll(aaiNameSet);
479 combinedSet.addAll(sdncNameSet);
480 if (combinedSet.size() != aaiNameSet.size()) {
481 errorReasons.add("PNF names don't match; aai names: ${aaiNameSet}, sdnc names: ${sdncNameSet}")
482 return new Tuple2(false, errorReasons)