b158f5bbe6e13cec2c721a247188195ef9496cd3
[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                     "vm-type %s has class conflict %s"
102                     % (k, ", ".join(str(list(self.vm_classes[c])) for c in v))
103                 )
104                 classes = list(v)
105                 errors.append(
106                     "Differences %s"
107                     % ", ".join([str(key_diff(classes[0], c)) for c in classes[1:]])
108                 )
109         for k, v in self.vm_counts.items():
110             if len(v) > 1:
111                 errors.append(
112                     "Attachment count conflict %s"
113                     % ({rid: self.va_count.get(rid) for rid in self.vm_rids[k]})
114                 )
115         return errors
116
117
118 def key_diff(d1, d2, prefix=""):
119     """Return list of keys which differ between d1 and d2 (dicts)
120     """
121     diff = [prefix + k for k in d1 if k not in d2]
122     diff.extend(prefix + k for k in d2 if k not in d1)
123     if isinstance(d1, dict) and isinstance(d2, dict):
124         for k, v1 in d1.items():
125             if k in d2 and v1 != d2[k]:
126                 v2 = d2[k]
127                 if isinstance(v1, type(v2)) and isinstance(v1, (dict, frozenset)):
128                     diff.extend(key_diff(v1, v2, prefix=prefix + k + "."))
129                 else:
130                     diff.append(prefix + k)
131     return diff
132
133
134 @validates("R-01455")
135 def test_vm_class_has_unique_type(yaml_files):
136     """
137     When a VNF’s Heat Orchestration Template creates a Virtual
138     Machine (i.e., OS::Nova::Server), each “class” of VMs MUST be
139     assigned a VNF unique vm-type; where “class” defines VMs that
140     MUST have the following identical characteristics:
141
142     1.  OS::Nova::Server resource property flavor value
143     2.  OS::Nova::Server resource property image value
144     3.  Cinder Volume attachments
145         Each VM in the “class” MUST have the identical Cinder
146         Volume configuration
147     4.  Network attachments and IP address requirements
148         Each VM in the “class” MUST have the the identical number of
149         ports connecting to the identical networks and requiring the
150         identical IP address configuration
151     """
152     resources = get_all_resources(yaml_files)
153     errors = VmClassValidator()(resources)
154     assert not errors, "\n".join(errors)