2 # ============LICENSE_START====================================================
3 # org.onap.vvp/validation-scripts
4 # ===================================================================
5 # Copyright © 2017 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============================================
42 {vm-type}_{vm-type_index}_{network-role}_port_{port-index}:
43 type: OS::Neutron::Port
45 network: { get_param: ...}
46 fixed_ips: [ { "ipaddress": { get_param: ... } } ]
47 binding:vnic_type: direct #only SR-IOV ports, not OVS ports
49 vlan_filter: { get_param: ... }, #all NC ports
50 public_vlans: { get_param: ... }, #all NC ports
51 private_vlans: { get_param: ... },#all NC ports
52 guest_vlans: { get_param: ... }, #SR-IOV Trunk Port only
53 vlan_mirror: { get_param: ... }, #SRIOV Trunk Port
54 # Receiving Mirrored Traffic only
55 ATT_FABRIC_CONFIGURATION_REQUIRED: true #all NC ports
58 port_type: SR-IOV_Trunk #SR-IOV Trunk Port
59 port_type: SR-IOV_Non_Trunk #SR-IOV Non Trunk Port
60 port_type: OVS #OVS Port
61 port_type: SR-IOV_Mirrored_Trunk #SR-IOV Trunk Port
62 # Receiving Mirrored Traffic
68 from .structures import Heat
69 from .helpers import validates, get_base_template_from_yaml_file
73 RE_BASE = re.compile(r"(^base$)|(^base_)|(_base_)|(_base$)") # search pattern
75 RE_EXTERNAL_PARAM_SUBNET = re.compile( # match pattern
76 r"(?P<network_role>.+)(_v6)?_subnet_id$"
79 RE_INTERNAL_PARAM_SUBNET = re.compile( # match pattern
80 r"int_(?P<network_role>.+)(_v6)?_subnet_id$"
84 def get_base(base_template_filepath):
85 """Return the base template's Heat instance.
87 if base_template_filepath is None:
88 pytest.skip("No base template found")
89 base_template = Heat(filepath=base_template_filepath)
93 def run_test(heat_template, validate, validator=None):
94 """call validate for each fixed_ips
96 heat = Heat(filepath=heat_template)
97 base_template = get_base_template_from_yaml_file(heat_template)
98 if not heat.resources:
99 pytest.skip("No resources found")
101 neutron_ports = heat.neutron_port_resources
102 if not neutron_ports:
103 pytest.skip("No OS::Neutron::Port resources found")
106 for rid, resource in neutron_ports.items():
107 fixed_ips = heat.nested_get(resource, "properties", "fixed_ips")
108 if fixed_ips is None:
110 if not isinstance(fixed_ips, list):
111 bad[rid] = "properties.fixed_ips must be a list."
113 for fixed_ip in fixed_ips:
114 error = validate(heat, fixed_ip, base_template, validator)
119 # raise RuntimeError(
120 raise AssertionError(
122 % (", ".join("%s: %s" % (rid, error) for rid, error in bad.items()))
126 def validate_external_fixed_ip_subnet(heat, fixed_ip, base_template, validator):
127 """ensure fixed_ip subnet for external network
129 Returns error message string or None.
131 subnet = heat.nested_get(fixed_ip, "subnet", "get_param")
133 error = validator(subnet, RE_EXTERNAL_PARAM_SUBNET)
139 def validate_external_subnet_parameter_format(subnet, regx):
140 """ensure subnet matches template.
141 Returns error message string or None.
143 if subnet and not subnet.startswith("int_") and regx.match(subnet) is None:
145 'fixed_ip subnet parameter "%s" does not match '
146 "{network-role}_subnet_id or {network-role}_v6_subnet_id" % (subnet)
151 def validate_internal_fixed_ip_subnet(heat, fixed_ip, base_template, validator):
152 """ensure fixed_ip subnet for internal network
154 Returns error message string or None.
156 base_module = get_base(base_template)
157 subnet = heat.nested_get(fixed_ip, "subnet", "get_param")
159 error = validator(heat, base_module, subnet, RE_INTERNAL_PARAM_SUBNET)
165 def validate_internal_subnet_parameter_format(heat, base_module, subnet, regx):
166 """ensure if subnet matches template then its parameter exists.
167 Returns error message string or None.
169 if subnet and subnet.startswith("int_") and regx.match(subnet) is None:
171 'fixed_ip subnet parameter "%s" does not match '
172 "int_{network-role}_subnet_id or int_{network-role}_v6_subnet_id" % (subnet)
177 def validate_internal_subnet_exists_in_base_output(heat, base_module, subnet, regx):
178 """ensure if subnet matches template then its parameter exists.
179 Returns error message string or None.
183 and subnet.startswith("int_")
184 and regx.match(subnet)
185 and heat.nested_get(base_module.outputs, subnet) is None
187 return 'fixed_ip subnet(_id) parameter "%s" not in base outputs"' % (subnet)
191 def validate_fixed_ip_subnet(heat, fixed_ip, base_template, validator):
192 """ensure fixed_ip has proper parameters
193 Returns error message string or None.
195 subnet = heat.nested_get(fixed_ip, "subnet", "get_param")
196 if subnet and heat.nested_get(heat.parameters, subnet, "type") != "string":
197 error = 'subnet parameter "%s" must be type "string"' % subnet
203 @validates("R-38236")
204 def test_neutron_port_fixed_ips_subnet(yaml_file):
206 The VNF's Heat Orchestration Template's
207 resource ``OS::Neutron::Port`` property ``fixed_ips``
208 map property ``subnet``/``subnet_id`` parameter
209 **MUST** be declared type ``string``.
211 run_test(yaml_file, validate_fixed_ip_subnet)
214 @validates("R-62802", "R-15287")
215 def test_neutron_port_external_fixed_ips_subnet(yaml_file):
217 When the VNF's Heat Orchestration Template's
218 resource ``OS::Neutron::Port`` is attaching
219 to an external network,
220 and an IPv4 address is being cloud assigned by OpenStack's DHCP Service
221 and the external network IPv4 subnet is to be specified
222 using the property ``fixed_ips``
223 map property ``subnet``/``subnet_id``, the parameter
224 **MUST** follow the naming convention
226 * ``{network-role}_subnet_id``
227 and the external network IPv6 subnet is to be specified
228 * ``{network-role}_v6_subnet_id``
232 validate_external_fixed_ip_subnet,
233 validate_external_subnet_parameter_format,
237 @validates("R-84123", "R-76160")
238 def test_neutron_port_internal_fixed_ips_subnet(yaml_file):
242 * the VNF's Heat Orchestration Template's
243 resource ``OS::Neutron::Port`` in an Incremental Module is attaching
244 to an internal network
245 that is created in the Base Module, AND
246 * an IPv4 address is being cloud assigned by OpenStack's DHCP Service AND
247 * the internal network IPv4 subnet is to be specified
248 using the property ``fixed_ips`` map property ``subnet``/``subnet_id``,
250 the parameter **MUST** follow the naming convention
252 * ``int_{network-role}_subnet_id``
253 an IPv6 address is being cloud assigned by OpenStack's DHCP Service AND
254 * ``int_{network-role}_v6_subnet_id``
259 validate_internal_fixed_ip_subnet,
260 validate_internal_subnet_parameter_format,
264 @validates("R-84123", "R-76160")
265 def test_neutron_port_internal_fixed_ips_subnet_in_base(heat_template):
267 Only check parent incremental modules, because nested file parameter
268 name may have been changed.
272 * the VNF's Heat Orchestration Template's
273 resource ``OS::Neutron::Port`` in an Incremental Module is attaching
274 to an internal network
275 that is created in the Base Module, AND
276 * an IPv4 address is being cloud assigned by OpenStack's DHCP Service AND
277 * the internal network IPv4 subnet is to be specified
278 using the property ``fixed_ips`` map property ``subnet``/``subnet_id``,
280 the parameter **MUST** follow the naming convention
282 * ``int_{network-role}_subnet_id``
283 an IPv6 address is being cloud assigned by OpenStack's DHCP Service AND
284 * ``int_{network-role}_v6_subnet_id``
286 Note that the parameter MUST be defined as an output parameter in
291 validate_internal_fixed_ip_subnet,
292 validate_internal_subnet_exists_in_base_output,