Merge "[VVP] Support pluggable data sources for preload data"
[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 #
39
40 """heat parameters
41 """
42
43 import collections
44
45 import pytest
46
47 from .structures import CinderVolumeAttachmentProcessor
48 from .structures import NovaServerProcessor
49 from .structures import get_all_resources
50 from .helpers import validates
51
52 VERSION = "2.0.0"
53
54
55 class VmClassValidator(object):
56     """validate VM class has unique type
57     """
58
59     def __init__(self):
60         self.vm_counts = None
61         self.vm_classes = None
62         self.vm_rids = None
63         self.vm_types = None
64         self.va_count = None
65
66     def __call__(self, resources):
67         """return (possibly empty) list of error message strings
68         """
69         if not resources:
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)
76         # if not va_config:
77         #     pytest.skip("No Cinder Volume Attachment configurations found")
78         for rid, resource in resources.items():
79             vm_class = NovaServerProcessor.get_vm_class(resource)
80             if vm_class:
81                 vm_class["cinder_volume_attachment"] = va_config.get(rid)
82                 match = NovaServerProcessor.get_rid_match_tuple(rid)[1]
83                 if match:
84                     vm_type = match.groupdict().get("vm_type")
85                     if 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()
93
94     def get_errors(self):
95         """return (possibly empty) list of error message strings
96         """
97         errors = []
98         for k, v in self.vm_types.items():
99             if len(v) > 1:
100                 errors.append(
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))
104                 )
105                 classes = list(v)
106                 errors.append(
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:]]))
110                 )
111         for k, v in self.vm_counts.items():
112             if len(v) > 1:
113                 errors.append(
114                     "Attachment count conflict %s"
115                     % ({rid: self.va_count.get(rid) for rid in self.vm_rids[k]})
116                 )
117         return errors
118
119
120 def key_diff(d1, d2, prefix=""):
121     """Return list of keys which differ between d1 and d2 (dicts)
122     """
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]:
128                 v2 = d2[k]
129                 if isinstance(v1, type(v2)) and isinstance(v1, (dict, frozenset)):
130                     diff.extend(key_diff(v1, v2, prefix=prefix + k + "."))
131                 else:
132                     diff.append(prefix + k)
133     return diff
134
135
136 @validates("R-01455")
137 def test_vm_class_has_unique_type(yaml_files):
138     """
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:
143
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
148         Volume configuration
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
153     """
154     resources = get_all_resources(yaml_files)
155     errors = VmClassValidator()(resources)
156     assert not errors, "\n".join(errors)