diff options
author | stark, steven <steven.stark@att.com> | 2018-12-17 12:43:02 -0800 |
---|---|---|
committer | stark, steven <steven.stark@att.com> | 2018-12-17 13:04:00 -0800 |
commit | 1f4df7c7ad27b23773ad9cdbe4db1632ce388cf1 (patch) | |
tree | 8092104f8be23051ff81c9f71ee34116df4d33ba /ice_validator/tests/test_neutron_port_internal_network.py | |
parent | ca9085f0f77d442d3741a8c754e65cc45b6a318d (diff) |
[VVP] updating validation scripts in dublin
- adding backlog of new validation scripts for dublin
- updating existing tests
- removing outdated tests
Issue-ID: VVP-123
Change-Id: Ib8260889ac957c1dd28d8ede450fc8edc6fb0ec0
Signed-off-by: stark, steven <steven.stark@att.com>
Diffstat (limited to 'ice_validator/tests/test_neutron_port_internal_network.py')
-rw-r--r-- | ice_validator/tests/test_neutron_port_internal_network.py | 241 |
1 files changed, 241 insertions, 0 deletions
diff --git a/ice_validator/tests/test_neutron_port_internal_network.py b/ice_validator/tests/test_neutron_port_internal_network.py new file mode 100644 index 0000000..b625be6 --- /dev/null +++ b/ice_validator/tests/test_neutron_port_internal_network.py @@ -0,0 +1,241 @@ +# -*- coding: utf8 -*- +# ============LICENSE_START==================================================== +# org.onap.vvp/validation-scripts +# =================================================================== +# Copyright © 2017 AT&T Intellectual Property. All rights reserved. +# =================================================================== +# +# Unless otherwise specified, all software contained herein is licensed +# under the Apache License, Version 2.0 (the "License"); +# you may not use this software except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +# +# +# Unless otherwise specified, all documentation contained herein is licensed +# under the Creative Commons License, Attribution 4.0 Intl. (the "License"); +# you may not use this documentation except in compliance with the License. +# You may obtain a copy of the License at +# +# https://creativecommons.org/licenses/by/4.0/ +# +# Unless required by applicable law or agreed to in writing, documentation +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +# ============LICENSE_END============================================ +# +# ECOMP is a trademark and service mark of AT&T Intellectual Property. +# + +""" +resources: +{vm-type}_{vm-type_index}_{network-role}_port_{port-index}: + type: OS::Neutron::Port + properties: + network: { get_param: ...} + fixed_ips: [ { "ipaddress": { get_param: ... } } ] + binding:vnic_type: direct #only SR-IOV ports, not OVS ports + value_specs: { + vlan_filter: { get_param: ... }, #all NC ports + public_vlans: { get_param: ... }, #all NC ports + private_vlans: { get_param: ... },#all NC ports + guest_vlans: { get_param: ... }, #SR-IOV Trunk Port only + vlan_mirror: { get_param: ... }, #SRIOV Trunk Port + # Receiving Mirrored Traffic only + ATT_FABRIC_CONFIGURATION_REQUIRED: true #all NC ports + } + metadata: + port_type: SR-IOV_Trunk #SR-IOV Trunk Port + port_type: SR-IOV_Non_Trunk #SR-IOV Non Trunk Port + port_type: OVS #OVS Port + port_type: SR-IOV_Mirrored_Trunk #SR-IOV Trunk Port + # Receiving Mirrored Traffic +""" + +import os.path +import re + +import pytest + +from .structures import Heat +from .helpers import validates + +VERSION = "1.1.0" + +RE_BASE = re.compile(r"(^base$)|(^base_)|(_base_)|(_base$)") # search pattern +RE_NEUTRON_PORT_RID = re.compile( # match pattern + r"(?P<vm_type>.+)" + r"_(?P<vm_type_index>\d+)" + r"_(?P<network_role>.+)" + r"_port_" + r"(?P<port_index>\d+)" + r"$" +) +RE_INTERNAL_NETWORK_PARAM = re.compile( # match pattern + r"int_(?P<network_role>.+)_net_(?P<value_type>id|name)$" +) +RE_INTERNAL_NETWORK_RID = re.compile( # match pattern + r"int_(?P<network_role>.+)_network$" +) + + +def get_base_template_filepath(yaml_files): + """Return first filepath to match RE_BASE + """ + for filepath in yaml_files: + basename, __ = os.path.splitext(os.path.basename(filepath)) + if RE_BASE.search(basename) and basename.find("volume") == -1: + return filepath + return None + + +def get_internal_network(yaml_files): + """Return the base template's Heat istance. + """ + base_template_filepath = get_base_template_filepath(yaml_files) + if base_template_filepath is None: + pytest.skip("No base template found") + base_template = Heat(filepath=base_template_filepath) + for r in base_template.resources.values(): + # if base_template.nested_get(r, 'type') == 'OS::Neutron::Net': + return base_template + + return None + + +def get_neutron_ports(heat): + """Return dict of resource_id: resource, whose type is + OS::Neutron::Port. + """ + return { + rid: resource + for rid, resource in heat.resources.items() + if heat.nested_get(resource, "type") == "OS::Neutron::Port" + } + + +# pylint: disable=invalid-name + + +@validates("R-86182", "R-22688") +def test_neutron_port_internal_network(yaml_files): + """ + When the VNF's Heat Orchestration Template's Resource + ``OS::Neutron::Port`` is attaching to an internal network (per the + ECOMP definition, see Requirements R-52425 and R-46461), + and the internal network is created in a + different Heat Orchestration Template than the ``OS::Neutron::Port``, + the ``network`` parameter name **MUST** + + * follow the naming convention ``int_{network-role}_net_id`` + if the Neutron + network UUID value is used to reference the network + * follow the naming convention ``int_{network-role}_net_name`` if the + OpenStack network name in is used to reference the network. + + where ``{network-role}`` is the network-role of the internal network and + a ``get_param`` **MUST** be used as the intrinsic function. + + In Requirement R-86182, the internal network is created in the VNF's + Base Module (Heat Orchestration Template) and the parameter name is + declared in the Base Module's ``outputs`` section. + When the parameter's value uses a "get_param" function, its name + must end in "_name", and when it uses a "get_resource" function, + its name must end in "_id". + + The output parameter name will be declared as a parameter in the + ``parameters`` section of the incremental module. + """ + internal_network = get_internal_network(yaml_files) + if not internal_network: + pytest.skip("internal_network template not found") + + if not internal_network.outputs: + pytest.skip('internal_network template has no "outputs"') + + for filepath in yaml_files: + if filepath != internal_network.filepath: + validate_neutron_port(filepath, internal_network) + + +def validate_neutron_port(filepath, internal_network): + """validate the neutron port + """ + heat = Heat(filepath=filepath) + if not heat.resources: + return + neutron_ports = get_neutron_ports(heat) + if not neutron_ports: + return + bad = {} + for rid, resource in neutron_ports.items(): + if not heat.parameters: + bad[rid] = 'missing "parameters"' + continue + network = heat.nested_get(resource, "properties", "network", "get_param") + if network is None: + bad[rid] = 'missing "network.get_param"' + continue + if not network.startswith("int_"): + continue # not an internal network port + error = validate_param(heat, network, internal_network) + if error: + bad[rid] = error + if bad: + raise RuntimeError( + "Bad OS::Neutron::Port: %s" + % (", ".join("%s: %s" % (rid, error) for rid, error in bad.items())) + ) + + +def validate_param(heat, network, internal_network): + """Ensure network (the parameter name) is defined in the base + template, and has the correct value function. Ensure its + network-role is found in the base template in some + OS::Neutron::Net resource. + Return error message string, or None if no no errors. + """ + match = RE_INTERNAL_NETWORK_PARAM.match(network) + if not match: + return 'network.get_param "%s" does not match "%s"' % ( + network, + RE_INTERNAL_NETWORK_PARAM.pattern, + ) + if heat.nested_get(heat.parameters, network) is None: + return "missing parameters.%s" % network + output = heat.nested_get(internal_network.outputs, network) + if not output: + return 'network.get_param "%s"' " not found in base template outputs" % network + param_dict = match.groupdict() + expect = {"name": "get_param", "id": "get_resource"}[param_dict["value_type"]] + value = heat.nested_get(output, "value") + if heat.nested_get(value, expect) is None: + return ( + 'network.get_param "%s" implies its base template' + ' output value function should be "%s" dict not "%s"' + % (network, expect, value) + ) + network_role = param_dict["network_role"] + for rid, resource in internal_network.resources.items(): + if ( + heat.nested_get(resource, "type") == "OS::Neutron::Net" + or heat.nested_get(resource, "type") == "OS::ContrailV2::VirtualNetwork" + ): + match = RE_INTERNAL_NETWORK_RID.match(rid) + if match and match.groupdict()["network_role"] == network_role: + return None + return ( + "OS::Neutron::Net with network-role" + ' "%s" not found in base template."' % network_role + ) |