[VVP] stand alone tool, script updates
[vvp/validation-scripts.git] / ice_validator / tests / test_vm_class_has_unique_type.py
1 # -*- coding: utf8 -*-
2 # ============LICENSE_START====================================================
3 # org.onap.vvp/validation-scripts
4 # ===================================================================
5 # Copyright © 2019 AT&T Intellectual Property. All rights reserved.
6 # ===================================================================
7 #
8 # Unless otherwise specified, all software contained herein is licensed
9 # under the Apache License, Version 2.0 (the "License");
10 # you may not use this software except in compliance with the License.
11 # You may obtain a copy of the License at
12 #
13 #             http://www.apache.org/licenses/LICENSE-2.0
14 #
15 # Unless required by applicable law or agreed to in writing, software
16 # distributed under the License is distributed on an "AS IS" BASIS,
17 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
18 # See the License for the specific language governing permissions and
19 # limitations under the License.
20 #
21 #
22 #
23 # Unless otherwise specified, all documentation contained herein is licensed
24 # under the Creative Commons License, Attribution 4.0 Intl. (the "License");
25 # you may not use this documentation except in compliance with the License.
26 # You may obtain a copy of the License at
27 #
28 #             https://creativecommons.org/licenses/by/4.0/
29 #
30 # Unless required by applicable law or agreed to in writing, documentation
31 # distributed under the License is distributed on an "AS IS" BASIS,
32 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
33 # See the License for the specific language governing permissions and
34 # limitations under the License.
35 #
36 # ============LICENSE_END============================================
37 #
38 # ECOMP is a trademark and service mark of AT&T Intellectual Property.
39 #
40
41 """heat parameters
42 """
43
44 import collections
45
46 import pytest
47
48 from .structures import CinderVolumeAttachmentProcessor
49 from .structures import NovaServerProcessor
50 from .structures import get_all_resources
51 from .helpers import validates
52
53 VERSION = "2.0.0"
54
55
56 class VmClassValidator(object):
57     """validate VM class has unique type
58     """
59
60     def __init__(self):
61         self.vm_counts = None
62         self.vm_classes = None
63         self.vm_rids = None
64         self.vm_types = None
65         self.va_count = None
66
67     def __call__(self, resources):
68         """return (possibly empty) list of error message strings
69         """
70         if not resources:
71             pytest.skip("No resources found")
72         self.vm_counts = collections.defaultdict(set)
73         self.vm_classes = collections.defaultdict(set)
74         self.vm_rids = collections.defaultdict(set)
75         self.vm_types = collections.defaultdict(set)
76         va_config, self.va_count = CinderVolumeAttachmentProcessor.get_config(resources)
77         if not va_config:
78             pytest.skip("No Cinder Volume Attachment configurations found")
79         for rid, resource in resources.items():
80             vm_class = NovaServerProcessor.get_vm_class(resource)
81             if vm_class:
82                 vm_class["cinder_volume_attachment"] = va_config.get(rid)
83                 match = NovaServerProcessor.get_rid_match_tuple(rid)[1]
84                 if match:
85                     vm_type = match.groupdict().get("vm_type")
86                     if vm_type:
87                         self.vm_classes[vm_class].add(rid)
88                         self.vm_types[vm_type].add(vm_class)
89                         self.vm_counts[vm_type].add(self.va_count.get(rid))
90                         self.vm_rids[vm_type].add(rid)
91         if not self.vm_classes:
92             pytest.skip("No vm_classes found")
93         return self.get_errors()
94
95     def get_errors(self):
96         """return (possibly empty) list of error message strings
97         """
98         errors = []
99         for k, v in self.vm_types.items():
100             if len(v) > 1:
101                 errors.append(
102                     "vm-type %s has class conflict %s"
103                     % (k, ", ".join(str(list(self.vm_classes[c])) for c in v))
104                 )
105                 classes = list(v)
106                 errors.append(
107                     "Differences %s"
108                     % ", ".join([str(key_diff(classes[0], c)) for c in classes[1:]])
109                 )
110         for k, v in self.vm_counts.items():
111             if len(v) > 1:
112                 errors.append(
113                     "Attachment count conflict %s"
114                     % ({rid: self.va_count.get(rid) for rid in self.vm_rids[k]})
115                 )
116         return errors
117
118
119 def key_diff(d1, d2, prefix=""):
120     """Return list of keys which differ between d1 and d2 (dicts)
121     """
122     diff = [prefix + k for k in d1 if k not in d2]
123     diff.extend(prefix + k for k in d2 if k not in d1)
124     if isinstance(d1, dict) and isinstance(d2, dict):
125         for k, v1 in d1.items():
126             if k in d2 and v1 != d2[k]:
127                 v2 = d2[k]
128                 if isinstance(v1, type(v2)) and isinstance(v1, (dict, frozenset)):
129                     diff.extend(key_diff(v1, v2, prefix=prefix + k + "."))
130                 else:
131                     diff.append(prefix + k)
132     return diff
133
134
135 @validates("R-01455")
136 def test_vm_class_has_unique_type(yaml_files):
137     """
138     When a VNF’s Heat Orchestration Template creates a Virtual
139     Machine (i.e., OS::Nova::Server), each “class” of VMs MUST be
140     assigned a VNF unique vm-type; where “class” defines VMs that
141     MUST have the following identical characteristics:
142
143     1.  OS::Nova::Server resource property flavor value
144     2.  OS::Nova::Server resource property image value
145     3.  Cinder Volume attachments
146         Each VM in the “class” MUST have the identical Cinder
147         Volume configuration
148     4.  Network attachments and IP address requirements
149         Each VM in the “class” MUST have the the identical number of
150         ports connecting to the identical networks and requiring the
151         identical IP address configuration
152     """
153     resources = get_all_resources(yaml_files)
154     errors = VmClassValidator()(resources)
155     assert not errors, "\n".join(errors)