6 from tests.helpers import validates, get_base_template_from_yaml_files, get_param
7 from tests.utils.nested_files import get_nested_files
8 from tests.structures import Heat
11 INTERNAL_UUID_PATTERN = re.compile(r"^int_(?P<network_role>.+?)_net_id$")
12 INTERNAL_NAME_PATTERN = re.compile(r"^int_(?P<network_role>.+?)_net_name$")
13 INTERNAL_PORT = re.compile(
14 r"^(?P<vm_type>.+)_(?P<vm_type_index>\d+)_int_"
15 r"(?P<network_role>.+)_port_(?P<port_index>\d+)$"
18 EXTERNAL_PORT = re.compile(
19 r"^(?P<vm_type>.+)_(?P<vm_type_index>\d+)_(?!int_)"
20 r"(?P<network_role>.+)_port_(?P<port_index>\d+)$"
23 EXTERNAL_UUID_PATTERN = re.compile(r"^(?!int_)(?P<network_role>.+?)_net_id$")
24 EXTERNAL_NAME_PATTERN = re.compile(r"^(?!int_)(?P<network_role>.+?)_net_name$")
26 INTERNAL_NETWORK_PATTERN = re.compile(r"^int_(?P<network_role>.+?)" r"_(network|RVN)$")
29 def is_incremental_module(yaml_file, base_path, nested_paths):
30 return yaml_file != base_path and yaml_file not in nested_paths
33 @validates("R-86182", "R-22688")
34 def test_internal_network_parameters(yaml_files):
35 base_path = get_base_template_from_yaml_files(yaml_files)
37 pytest.skip("No base module found")
38 base_heat = Heat(filepath=base_path)
39 nested_paths = get_nested_files(yaml_files)
40 incremental_modules = [
41 f for f in yaml_files if is_incremental_module(f, base_path, nested_paths)
44 for module in incremental_modules:
45 heat = Heat(filepath=module)
46 for rid, port in heat.neutron_port_resources.items():
47 rid_match = INTERNAL_PORT.match(rid)
51 network = (port.get("properties") or {}).get("network") or {}
52 if isinstance(network, dict) and (
53 "get_resource" in network or "get_attr" in network
57 param = get_param(network)
61 "The internal port ({}) must either connect to a network "
62 "in the base module using get_param or to a network "
63 "created in this module ({})"
64 ).format(rid, os.path.split(module)[1])
68 param_match = INTERNAL_UUID_PATTERN.match(
70 ) or INTERNAL_NAME_PATTERN.match(param)
74 "The internal port ({}) network parameter ({}) does not "
75 "match one of the required naming conventions of "
76 "int_{{network-role}}_net_id or "
77 "int_{{network-role}}_net_name "
78 "for connecting to an internal network. "
79 "If this is not an internal port, then change the resource "
80 "ID to adhere to the external port naming convention."
85 if param not in base_heat.yml.get("outputs", {}):
86 base_module = os.path.split(base_path)[1]
89 "The internal network parameter ({}) attached to port ({}) "
90 "must be defined in the output section of the base module ({})."
91 ).format(param, rid, base_module)
95 param_network_role = param_match.groupdict().get("network_role")
96 rid_network_role = rid_match.groupdict().get("network_role")
97 if param_network_role.lower() != rid_network_role.lower():
100 "The network role ({}) extracted from the resource ID ({}) "
101 "does not match network role ({}) extracted from the "
102 "network parameter ({})"
103 ).format(rid_network_role, rid, param_network_role, param)
106 resources = base_heat.get_all_resources(os.path.split(base_path)[0])
109 for rid, resource in resources.items()
110 if resource.get("type")
111 in {"OS::Neutron::Net", "OS::ContrailV2::VirtualNetwork"}
113 matches = (INTERNAL_NETWORK_PATTERN.match(n) for n in networks)
114 roles = {m.groupdict()["network_role"].lower() for m in matches if m}
115 if param_network_role.lower() not in roles:
118 "No internal network with a network role of {} was "
119 "found in the base modules networks: {}"
120 ).format(param_network_role, ", ".join(networks))
123 assert not errors, ". ".join(errors)
126 @validates("R-62983")
127 def test_external_network_parameter(heat_template):
128 heat = Heat(filepath=heat_template)
130 for rid, port in heat.neutron_port_resources.items():
131 rid_match = EXTERNAL_PORT.match(rid)
133 continue # only test external ports
134 network = (port.get("properties") or {}).get("network") or {}
135 if not isinstance(network, dict) or "get_param" not in network:
138 "The external port ({}) must assign the network property "
139 "using get_param. If this port is for an internal network, "
140 "then change the resource ID format to the external format."
144 param = get_param(network)
148 "The get_param function on the network property of port ({}) "
149 "must only take a single, string parameter."
154 param_match = EXTERNAL_NAME_PATTERN.match(param) or EXTERNAL_UUID_PATTERN.match(
160 "The network parameter ({}) on port ({}) does not match one of "
161 "{{network-role}}_net_id or {{network-role}}_net_name."
165 rid_network_role = rid_match.groupdict()["network_role"]
166 param_network_role = param_match.groupdict()["network_role"]
167 if rid_network_role.lower() != param_network_role.lower():
170 "The network role ({}) extracted from the resource ID ({}) "
171 "does not match network role ({}) extracted from the "
172 "network parameter ({})"
173 ).format(rid_network_role, rid, param_network_role, param)
176 assert not errors, ". ".join(errors)