2 # ============LICENSE_START====================================================
3 # org.onap.vvp/validation-scripts
4 # ===================================================================
5 # Copyright © 2019 AT&T Intellectual Property. All rights reserved.
6 # ===================================================================
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
13 # http://www.apache.org/licenses/LICENSE-2.0
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.
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
28 # https://creativecommons.org/licenses/by/4.0/
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.
36 # ============LICENSE_END============================================
47 from .structures import CinderVolumeAttachmentProcessor
48 from .structures import NovaServerProcessor
49 from .structures import get_all_resources
50 from .helpers import validates
55 class VmClassValidator(object):
56 """validate VM class has unique type
61 self.vm_classes = None
66 def __call__(self, resources):
67 """return (possibly empty) list of error message strings
70 pytest.skip("No resources found")
71 self.vm_counts = collections.defaultdict(set)
72 self.vm_classes = collections.defaultdict(set)
73 self.vm_rids = collections.defaultdict(set)
74 self.vm_types = collections.defaultdict(set)
75 va_config, self.va_count = CinderVolumeAttachmentProcessor.get_config(resources)
77 # pytest.skip("No Cinder Volume Attachment configurations found")
78 for rid, resource in resources.items():
79 vm_class = NovaServerProcessor.get_vm_class(resource)
81 vm_class["cinder_volume_attachment"] = va_config.get(rid)
82 match = NovaServerProcessor.get_rid_match_tuple(rid)[1]
84 vm_type = match.groupdict().get("vm_type")
86 self.vm_classes[vm_class].add(rid)
87 self.vm_types[vm_type].add(vm_class)
88 self.vm_counts[vm_type].add(self.va_count.get(rid))
89 self.vm_rids[vm_type].add(rid)
90 if not self.vm_classes:
91 pytest.skip("No vm_classes found")
92 return self.get_errors()
95 """return (possibly empty) list of error message strings
98 for k, v in self.vm_types.items():
101 "OS::Nova::Server resources with the same vm_type must have identical configurations. "
102 "The following OS::Nova::Server resources for vm-type %s do not have identical configurations: %s"
103 % (k, ", ".join(str(list(self.vm_classes[c])) for c in v))
107 "The following attributes are detected differences between "
108 "OS::Nova::Server's with vm_type %s: %s"
109 % (k, ", ".join([str(key_diff(classes[0], c)) for c in classes[1:]]))
111 for k, v in self.vm_counts.items():
114 "Attachment count conflict %s"
115 % ({rid: self.va_count.get(rid) for rid in self.vm_rids[k]})
120 def key_diff(d1, d2, prefix=""):
121 """Return list of keys which differ between d1 and d2 (dicts)
123 diff = [prefix + k for k in d1 if k not in d2]
124 diff.extend(prefix + k for k in d2 if k not in d1)
125 if isinstance(d1, dict) and isinstance(d2, dict):
126 for k, v1 in d1.items():
127 if k in d2 and v1 != d2[k]:
129 if isinstance(v1, type(v2)) and isinstance(v1, (dict, frozenset)):
130 diff.extend(key_diff(v1, v2, prefix=prefix + k + "."))
132 diff.append(prefix + k)
136 @validates("R-01455")
137 def test_vm_class_has_unique_type(yaml_files):
139 When a VNF's Heat Orchestration Template creates a Virtual
140 Machine (i.e., OS::Nova::Server), each "class" of VMs MUST be
141 assigned a VNF unique vm-type; where "class" defines VMs that
142 MUST have the following identical characteristics:
144 1. OS::Nova::Server resource property flavor value
145 2. OS::Nova::Server resource property image value
146 3. Cinder Volume attachments
147 Each VM in the "class" MUST have the identical Cinder
149 4. Network attachments and IP address requirements
150 Each VM in the "class" MUST have the the identical number of
151 ports connecting to the identical networks and requiring the
152 identical IP address configuration
154 resources = get_all_resources(yaml_files)
155 errors = VmClassValidator()(resources)
156 assert not errors, "\n".join(errors)