diff options
author | Lovett, Trevor <trevor.lovett@att.com> | 2019-04-15 11:47:25 -0500 |
---|---|---|
committer | Lovett, Trevor (tl2972) <tl2972@att.com> | 2019-04-15 15:56:39 -0500 |
commit | e5d7862c7c6c02847b8b4f95d2af0c5e9a454828 (patch) | |
tree | ef3bb47eee8b72f6c30015dc5c33c14d357c3b0c /ice_validator/tests/test_neutron_port_network_attachment.py | |
parent | d0cb7757c638cbc60b80c4b645cfb7319ee2ba81 (diff) |
[VVP] Updated network param validations per reqts
Change-Id: Idb0e051d6063cd94b733ed68093989d527592c9f
Issue-ID: VVP-193
Signed-off-by: Lovett, Trevor <trevor.lovett@att.com>
Signed-off-by: Lovett, Trevor (tl2972) <tl2972@att.com>
Diffstat (limited to 'ice_validator/tests/test_neutron_port_network_attachment.py')
-rw-r--r-- | ice_validator/tests/test_neutron_port_network_attachment.py | 159 |
1 files changed, 159 insertions, 0 deletions
diff --git a/ice_validator/tests/test_neutron_port_network_attachment.py b/ice_validator/tests/test_neutron_port_network_attachment.py new file mode 100644 index 0000000..001d453 --- /dev/null +++ b/ice_validator/tests/test_neutron_port_network_attachment.py @@ -0,0 +1,159 @@ +import os +import re + +import pytest + +from tests.helpers import validates, get_base_template_from_yaml_files +from tests.parametrizers import get_nested_files +from tests.structures import Heat + +INTERNAL_UUID_PATTERN = re.compile(r"^int_(?P<network_role>.+?)_net_id$") +INTERNAL_NAME_PATTERN = re.compile(r"^int_(?P<network_role>.+?)_net_name$") +INTERNAL_PORT = re.compile(r"^(?P<vm_type>.+)_(?P<vm_type_index>\d+)_int_" + r"(?P<network_role>.+)_port_(?P<port_index>\d+)$") + +EXTERNAL_PORT = re.compile(r"^(?P<vm_type>.+)_(?P<vm_type_index>\d+)_(?!int_)" + r"(?P<network_role>.+)_port_(?P<port_index>\d+)$") + +EXTERNAL_UUID_PATTERN = re.compile(r"^(?!int_)(?P<network_role>.+?)_net_id$") +EXTERNAL_NAME_PATTERN = re.compile(r"^(?!int_)(?P<network_role>.+?)_net_name$") + +INTERNAL_NETWORK_PATTERN = re.compile(r"^int_(?P<network_role>.+?)" + r"_(network|RVN)$") + + +def is_incremental_module(yaml_file, base_path, nested_paths): + return yaml_file != base_path and yaml_file not in nested_paths + + +def get_param(prop_val): + if not isinstance(prop_val, dict): + return None + param = prop_val.get("get_param") + return param if isinstance(param, str) else None + + +@validates("R-86182", "R-22688") +def test_internal_network_parameters(yaml_files): + base_path = get_base_template_from_yaml_files(yaml_files) + if not base_path: + pytest.skip("No base module found") + base_heat = Heat(filepath=base_path) + nested_paths = get_nested_files(yaml_files) + incremental_modules = [f for f in yaml_files + if is_incremental_module(f, base_path, nested_paths)] + errors = [] + for module in incremental_modules: + heat = Heat(filepath=module) + for rid, port in heat.neutron_port_resources.items(): + rid_match = INTERNAL_PORT.match(rid) + if not rid_match: + continue + + network = (port.get("properties") or {}).get("network") or {} + if isinstance(network, dict) and ( + "get_resource" in network or "get_attr" in network): + continue + + param = get_param(network) + if not param: + errors.append(( + "The internal port ({}) must either connect to a network " + "in the base module using get_param or to a network " + "created in this module ({})" + ).format(rid, os.path.split(module)[1])) + continue + + param_match = ( + INTERNAL_UUID_PATTERN.match(param) + or INTERNAL_NAME_PATTERN.match(param) + ) + if not param_match: + errors.append(( + "The internal port ({}) network parameter ({}) does not " + "match one of the required naming conventions of " + "int_{{network-role}}_net_id or " + "int_{{network-role}}_net_name " + "for connecting to an internal network. " + "If this is not an internal port, then change the resource " + "ID to adhere to the external port naming convention." + ).format(rid, param)) + continue + + if param not in base_heat.yml.get("outputs", {}): + base_module = os.path.split(base_path)[1] + errors.append(( + "The internal network parameter ({}) attached to port ({}) " + "must be defined in the output section of the base module ({})." + ).format(param, rid, base_module)) + continue + + param_network_role = param_match.groupdict().get("network_role") + rid_network_role = rid_match.groupdict().get("network_role") + if param_network_role != rid_network_role: + errors.append(( + "The network role ({}) extracted from the resource ID ({}) " + "does not match network role ({}) extracted from the " + "network parameter ({})" + ).format(rid_network_role, rid, param_network_role, param)) + + resources = base_heat.get_all_resources(os.path.split(base_path)[0]) + networks = {rid: resource for rid, resource in resources.items() + if resource.get("type") + in {"OS::Neutron::Net", + "OS::ContrailV2::VirtualNetwork"}} + matches = (INTERNAL_NETWORK_PATTERN.match(n) for n in networks) + roles = {m.groupdict()["network_role"] for m in matches if m} + if param_network_role not in roles: + errors.append(( + "No internal network with a network role of {} was " + "found in the base modules networks: {}" + ).format(param_network_role, ", ".join(networks))) + + assert not errors, ". ".join(errors) + + +@validates("R-62983") +def test_external_network_parameter(heat_template): + heat = Heat(filepath=heat_template) + errors = [] + for rid, port in heat.neutron_port_resources.items(): + rid_match = EXTERNAL_PORT.match(rid) + if not rid_match: + continue # only test external ports + network = (port.get("properties") or {}).get("network") or {} + if not isinstance(network, dict) or "get_param" not in network: + errors.append(( + "The external port ({}) must assign the network property " + "using get_param. If this port is for an internal network, " + "then change the resource ID format to the external format." + ).format(rid)) + continue + param = get_param(network) + if not param: + errors.append(( + "The get_param function on the network property of port ({}) " + "must only take a single, string parameter." + ).format(rid)) + continue + + param_match = ( + EXTERNAL_NAME_PATTERN.match(param) + or EXTERNAL_UUID_PATTERN.match(param) + ) + if not param_match: + errors.append(( + "The network parameter ({}) on port ({}) does not match one of " + "{{network-role}}_net_id or {{network-role}}_net_name." + ).format(param, rid)) + continue + rid_network_role = rid_match.groupdict()["network_role"] + param_network_role = param_match.groupdict()["network_role"] + if rid_network_role != param_network_role: + errors.append(( + "The network role ({}) extracted from the resource ID ({}) " + "does not match network role ({}) extracted from the " + "network parameter ({})" + ).format(rid_network_role, rid, param_network_role, param)) + + assert not errors, ". ".join(errors) |