df75b31eabea93880afd63bc7e9bd195b4c4ce7f
[oom.git] / kubernetes / pomba / charts / pomba-validation-service / resources / bundleconfig / etc / rules / poa-event / default-rules.groovy
1 /*
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
8  *
9  *        http://www.apache.org/licenses/LICENSE-2.0
10  *
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=====================================================
17  */
18
19 entity {
20     name 'POA-EVENT'
21     indexing {
22         indices 'default-rules'
23     }
24   validation {
25
26     // NDCB-AAI comparison: Context level
27     useRule {
28       name 'Attribute-comparison'
29       attributes 'context-list.ndcb', 'context-list.aai'
30     }
31
32     // NDCB-AAI comparison: Service entity
33     useRule {
34       name 'Attribute-comparison'
35       attributes 'context-list.ndcb.service', 'context-list.aai.service'
36     }
37
38     // NDCB-AAI comparison: Context level network list
39     useRule {
40       name 'Attribute-comparison'
41       attributes 'context-list.ndcb.networkList[*]', 'context-list.aai.networkList[*]'
42     }
43         
44     // NDCB-AAI comparison: VNF list
45     useRule {
46       name 'Attribute-comparison'
47       attributes 'context-list.ndcb.vnfList[*]', 'context-list.aai.vnfList[*]'
48     }
49
50     // NDCB-AAI comparison: VNF network list
51     useRule {
52       name 'Attribute-comparison'
53       attributes 'context-list.ndcb.vnfList[*].networkList[*]', 'context-list.aai.vnfList[*].networkList[*]'
54     }
55         
56     // NDCB-AAI comparison: VF-Module list
57     useRule {
58       name 'Attribute-comparison'
59       attributes 'context-list.ndcb.vnfList[*].vfModuleList[*]', 'context-list.aai.vnfList[*].vfModuleList[*]'
60     }
61
62     // NDCB-AAI comparison: VF-Module network list
63     useRule {
64       name 'Attribute-comparison'
65       attributes 'context-list.ndcb.vnfList[*].vfModuleList[*].networkList[*]', 'context-list.aai.vnfList[*].vfModuleList[*].networkList[*]'
66     }
67
68     // NDCB-AAI comparison: VNFC list
69     useRule {
70       name 'Attribute-comparison'
71       attributes 'context-list.ndcb.vnfList[*].vnfcList[*]', 'context-list.aai.vnfList[*].vnfcList[*]'
72     }
73
74     // NDCB-AAI comparison: VM list
75     useRule {
76       name 'Attribute-comparison'
77       attributes 'context-list.ndcb.vnfList[*].vfModuleList[*].vmList[*]', 'context-list.aai.vnfList[*].vfModuleList[*].vmList[*]'
78     }
79
80     // NDCB-AAI comparison: P-Interface list
81     useRule {
82       name 'Attribute-comparison'
83       attributes 'context-list.ndcb.pnfList[*].pInterfaceList[*]', 'context-list.aai.pnfList[*].pInterfaceList[*]'
84     }
85         
86         
87     // SDNC-AAI comparison: Context level
88     useRule {
89       name 'Attribute-comparison'
90       attributes 'context-list.sdnc', 'context-list.aai'
91     }
92
93     // SDNC-AAI comparison: Service entity
94     useRule {
95       name 'Attribute-comparison'
96       attributes 'context-list.sdnc.service', 'context-list.aai.service'
97     }
98
99     // SDNC-AAI comparison: Context level network list
100     useRule {
101       name 'Attribute-comparison'
102       attributes 'context-list.sdnc.networkList[*]', 'context-list.aai.networkList[*]'
103     }
104
105     // SDNC-AAI comparison: VNF list
106     useRule {
107       name 'Attribute-comparison'
108       attributes 'context-list.sdnc.vnfList[*]', 'context-list.aai.vnfList[*]'
109     }
110
111     // SDNC-AAI comparison: VNF network list
112     useRule {
113       name 'Attribute-comparison'
114       attributes 'context-list.sdnc.vnfList[*].networkList[*]', 'context-list.aai.vnfList[*].networkList[*]'
115     }
116
117     // SDNC-AAI comparison: VF-Module list
118     useRule {
119       name 'Attribute-comparison'
120       attributes 'context-list.sdnc.vnfList[*].vfModuleList[*]', 'context-list.aai.vnfList[*].vfModuleList[*]'
121     }
122
123     // SDNC-AAI comparison: VF-Module network list
124     useRule {
125       name 'Attribute-comparison'
126       attributes 'context-list.sdnc.vnfList[*].vfModuleList[*].networkList[*]', 'context-list.aai.vnfList[*].vfModuleList[*].networkList[*]'
127     }
128
129     // SDNC-AAI comparison: VNFC list
130     useRule {
131       name 'Attribute-comparison'
132       attributes 'context-list.sdnc.vnfList[*].vnfcList[*]', 'context-list.aai.vnfList[*].vnfcList[*]'
133     }
134
135     // SDNC-AAI comparison: VM list
136     useRule {
137       name 'Attribute-comparison'
138       attributes 'context-list.sdnc.vnfList[*].vfModuleList[*].vmList[*]', 'context-list.aai.vnfList[*].vfModuleList[*].vmList[*]'
139     }
140
141     // AAI-SDNC PNF name validation
142     useRule {
143       name 'AAI-SDNC-pnf-name-check'
144       attributes 'context-list.aai.pnfList[*].name', 'context-list.sdnc.pnfList[*].name'
145     }
146
147
148     // SDNC-NDCB comparison: Context level
149     useRule {
150       name 'Attribute-comparison'
151       attributes 'context-list.sdnc', 'context-list.ndcb'
152     }
153
154     // SDNC-NDCB comparison: Service entity
155     useRule {
156       name 'Attribute-comparison'
157       attributes 'context-list.sdnc.service', 'context-list.ndcb.service'
158     }
159
160     // SDNC-NDCB comparison: Context level network list
161     useRule {
162       name 'Attribute-comparison'
163       attributes 'context-list.sdnc.networkList[*]', 'context-list.ndcb.networkList[*]'
164     }
165
166     // SDNC-NDCB comparison: VNF list
167     useRule {
168       name 'Attribute-comparison'
169       attributes 'context-list.sdnc.vnfList[*]', 'context-list.ndcb.vnfList[*]'
170     }
171
172     // SDNC-NDCB comparison: VNF network list
173     useRule {
174       name 'Attribute-comparison'
175       attributes 'context-list.sdnc.vnfList[*].networkList[*]', 'context-list.ndcb.vnfList[*].networkList[*]'
176     }
177
178     // SDNC-NDCB comparison: VF-Module list
179     useRule {
180       name 'Attribute-comparison'
181       attributes 'context-list.sdnc.vnfList[*].vfModuleList[*]', 'context-list.ndcb.vnfList[*].vfModuleList[*]'
182     }
183
184     // SDNC-NDCB comparison: VF-Module network list
185     useRule {
186       name 'Attribute-comparison'
187       attributes 'context-list.sdnc.vnfList[*].vfModuleList[*].networkList[*]', 'context-list.ndcb.vnfList[*].vfModuleList[*].networkList[*]'
188     }
189
190     // SDNC-NDCB comparison: VNFC list
191     useRule {
192       name 'Attribute-comparison'
193       attributes 'context-list.sdnc.vnfList[*].vnfcList[*]', 'context-list.ndcb.vnfList[*].vnfcList[*]'
194     }
195
196     // SDNC-NDCB comparison: VM list
197     useRule {
198       name 'Attribute-comparison'
199       attributes 'context-list.sdnc.vnfList[*].vfModuleList[*].vmList[*]', 'context-list.ndcb.vnfList[*].vfModuleList[*].vmList[*]'
200     }
201
202         
203         
204     // SDC-AAI VNFC type
205     useRule {
206       name 'SDC-AAI-vnfc-type'
207       attributes 'context-list.sdc.vnfList[*].vnfcList[*]', 'context-list.aai.vnfList[*].vnfcList[*]'
208     }
209
210     // SDC-AAI VNFC node count
211     useRule {
212       name 'SDC-AAI-vnfc-node-count'
213       attributes 'context-list.sdc.vnfList[*].vnfcList[*]', 'context-list.aai.vnfList[*].vnfcList[*]'
214     }
215
216     // SDC-AAI VF-Module instance
217     useRule {
218       name 'SDC-AAI-vf-module-instance-check'
219       attributes 'context-list.sdc.vnfList[*].vfModuleList[*]', 'context-list.aai.vnfList[*].vfModuleList[*]'
220     }
221   }
222 }
223
224 rule {
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'
229   severity    'ERROR'
230   attributes  'sdcList', 'aaiList'
231   validate    '''
232         def getVnfcTypes = { parsedData ->
233           parsedData.collect{ it.findResult{ k, v -> if(k.equals("type")) {return "$v"}}}
234         }
235
236         def slurper = new groovy.json.JsonSlurper()
237         def sdcTypes = getVnfcTypes(slurper.parseText(sdcList.toString()))
238         def aaiTypes = getVnfcTypes(slurper.parseText(aaiList.toString()))
239
240         // each type in AAI must exist in SDC
241         return sdcTypes.containsAll(aaiTypes)
242                 '''
243 }
244
245 rule {
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'
250   severity    'WARNING'
251   attributes  'sdcList', 'aaiList'
252   validate    '''
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"}})
257           }
258         }
259
260         def slurper = new groovy.json.JsonSlurper()
261         def sdcNodes = getVnfcNodes(slurper.parseText(sdcList.toString()))
262         def aaiNodes = getVnfcNodes(slurper.parseText(aaiList.toString()))
263
264         // each node in AAI must exist in SDC
265         return aaiNodes.containsAll(sdcNodes)
266                 '''
267 }
268
269 rule {
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'
274   severity    'CRITICAL'
275   attributes  'sdcList', 'aaiList'
276   validate    '''
277         def getVfModules = { parsedData ->
278           parsedData.collect{ it.findResult{ k, v -> if(k.equals("name")) {return "$v"}}}
279         }
280
281         def slurper = new groovy.json.JsonSlurper()
282         def sdcVfModules = getVfModules(slurper.parseText(sdcList.toString()))
283         def aaiVfModules = getVfModules(slurper.parseText(aaiList.toString()))
284
285         // all VF modules in AAI must exist in SDC
286         return aaiVfModules.containsAll(sdcVfModules)
287                 '''
288 }
289
290 rule {
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}'
295   severity    'ERROR'
296   attributes  'lhsObject', 'rhsObject'
297   validate    '''
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()
303
304                         def isAttributeDataQualityOk = { attribute ->
305                                 attribute.findResult{ k, v -> if(k.equals("dataQuality") ) {return v.get("status")}}.equals("ok")
306                         }
307
308                         def addToMap = { attrKey, attrValue ->
309                                 java.util.Set values = attributeMap.get("$attrKey")
310                                 if(values == null) {
311                                         values = new java.util.HashSet()
312                                         attributeMap.put("$attrKey", values)
313                                 }
314                                 values.add("$attrValue")
315                         }
316
317                         def addAttributeToMap = { attribute ->
318                                 if(isAttributeDataQualityOk(attribute)) {
319                                         String key, value
320                                         attribute.each { k, v ->
321                                                 if(k.equals("name")) {key = "$v"}
322                                                 if(k.equals("value")) {value = "$v"}
323                                         }
324                                         addToMap("$key", "$value")
325                                 }
326                         }
327
328                         def processKeyValue = { key, value ->
329                                 if(value instanceof java.util.ArrayList) {
330                                         if(key.equals("attributeList")) {
331                                                 value.each {
332                                                         addAttributeToMap(it)
333                                                 }
334                                         }
335                                 } else if(!(value instanceof groovy.json.internal.LazyMap)) {
336                                         // only add key-value attributes, skip the rest
337                                         addToMap("$key", "$value")
338                                 }
339                         }
340
341                         if(parsedData instanceof java.util.ArrayList) {
342                                 parsedData.each {
343                                         it.each { key, value -> processKeyValue(key, value) }
344                                 }
345                         } else {
346                                 parsedData.each { key, value -> processKeyValue(key, value) }
347                         }
348                         return attributeMap
349                 }
350
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)
360                                                 if(existingValues) {
361                                                         existingValues.add("$rightValue")
362                                                 } else {
363                                                         java.util.Set newValues = new HashSet()
364                                                         newValues.add("$rightValue")
365                                                         violationMap.put("$leftKey", newValues)
366                                                 }
367                                         }
368                                 }
369                         }
370                         return violationMap
371                 }
372
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()) {
377                                 return [:]
378                         } else if(left.isEmpty()) {
379                                 return right
380                         } else if(right.isEmpty()) {
381                                 return left
382                         }
383                         java.util.Map merged = new java.util.HashMap()
384                         merged.putAll(left)
385                         right.each{ rightKey, rightValues ->
386                                 java.util.Set mergedValues = merged.get(rightKey)
387                                 if(mergedValues == null) {
388                                         merged.put(rightKey, rightValues)
389                                 } else {
390                                         mergedValues.addAll(rightValues)
391                                 }
392                         }
393                         return merged
394                 }
395
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()))
399
400                 def leftToRight = compareAttributes(lhsAttributes, rhsAttributes)
401                 def rightToLeft = compareAttributes(rhsAttributes, lhsAttributes)
402                 def mergedResults = mergeMaps(leftToRight, rightToLeft)
403
404                 boolean success = true
405                 List<String> details = new ArrayList<>()
406                 if(!mergedResults.isEmpty()) {
407                         success = false
408                         details.add(mergedResults.toString())
409                 }
410                 return new Tuple2(success, details)
411         '''
412 }
413
414 /*
415  * The data-dictionary rule below can be used with this useRule clause:
416  *   useRule {
417  *     name 'Data-Dictionary validate VF type'
418  *     attributes 'context-list.ndcb.vnfList[*].vfModuleList[*].networkList[*].type'
419  *   }
420  */
421 rule {
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}'
426     severity    'ERROR'
427     attributes  'typeList'
428     validate    '''
429         boolean success = true
430         List<String> details = new ArrayList<>()
431         typeList.any {
432             if(!success) {
433                 // break out of 'any' loop
434                 return false
435             }
436             def result = org.onap.aai.validation.ruledriven.rule.builtin.DataDictionary.validate("instance", "vfModuleNetworkType", "type", "$it")
437             if(!result.isEmpty()) {
438                 success = false
439                 details.add("$it")
440                 details.add("$result")
441             }
442         }
443         return new Tuple2(success, details)
444         '''
445 }
446
447 rule {
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}'
452   severity    'ERROR'
453   attributes  'aaiNames', 'sdncNames'
454   validate    '''
455         def addName = { values, key ->
456                 values.add("$key")
457         }
458
459         List<String> errorReasons = new ArrayList();
460
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)
464         }
465
466         // collect all the "name" values from AAI and SDNC into two Sets.
467         Set aaiNameSet = new java.util.HashSet()
468         aaiNames.each {
469            aValue -> addName(aaiNameSet, aValue)
470         }
471
472         Set sdncNameSet = new java.util.HashSet()
473         sdncNames.each {
474             aValue -> addName(sdncNameSet, aValue)
475         }
476
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)
481         }
482
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)
489         }
490
491         return true
492
493         '''
494 }