[VVP-171] R-84123 and R-76160 test update 19/78719/7
authorstark, steven <steven.stark@att.com>
Tue, 19 Feb 2019 00:22:52 +0000 (16:22 -0800)
committerstark, steven <steven.stark@att.com>
Thu, 28 Feb 2019 00:41:43 +0000 (16:41 -0800)
R-84123 and R-76160
test_neutron_port_internal_fixed_ips
should only be checking incremental modules

Change-Id: I7ef3cd4aa2b01273c2592f0b17751c5cb79c002b
Issue-ID: VVP-171
Signed-off-by: stark, steven <steven.stark@att.com>
ice_validator/tests/fixtures/test_neutron_port_fixed_ips_subnet/fail/fail0.yaml [moved from ice_validator/tests/fixtures/test_neutron_port_fixed_ips/fail/fail0.yaml with 96% similarity]
ice_validator/tests/fixtures/test_neutron_port_fixed_ips_subnet/fail/fail1.yaml [moved from ice_validator/tests/fixtures/test_neutron_port_fixed_ips/fail/fail1.yaml with 93% similarity]
ice_validator/tests/fixtures/test_neutron_port_fixed_ips_subnet/pass/pass0.yaml [moved from ice_validator/tests/fixtures/test_neutron_port_fixed_ips/pass/pass0.yaml with 100% similarity]
ice_validator/tests/fixtures/test_neutron_port_fixed_ips_subnet/pass/pass0_base.yaml [moved from ice_validator/tests/fixtures/test_neutron_port_fixed_ips/pass/pass0_base.yaml with 100% similarity]
ice_validator/tests/helpers.py
ice_validator/tests/test_neutron_port_fixed_ips_subnet.py [moved from ice_validator/tests/test_neutron_port_fixed_ips.py with 58% similarity]
ice_validator/tests/test_neutron_port_internal_network.py

@@ -50,7 +50,7 @@ parameters:
   vm_typeX_bialy_guest_vlans:
     type: comma_delimited_list
   subnet_param:
   vm_typeX_bialy_guest_vlans:
     type: comma_delimited_list
   subnet_param:
-    type: string
+    type: comma_delimited_list
   subnet_id_param:
     type: comma_delimited_list
 
   subnet_id_param:
     type: comma_delimited_list
 
@@ -63,7 +63,6 @@ resources:
       fixed_ips:
         - ip_address: { get_param: lb_1_int_intranet_floating_ip }
           subnet: { get_param: subnet_param }
       fixed_ips:
         - ip_address: { get_param: lb_1_int_intranet_floating_ip }
           subnet: { get_param: subnet_param }
-          subnet_id: { get_param: subnet_id_param }
       binding:vnic_type: direct
       value_specs:
         vlan_filter: {get_param: vm_typeX_bialy_vlan_filter}
       binding:vnic_type: direct
       value_specs:
         vlan_filter: {get_param: vm_typeX_bialy_vlan_filter}
@@ -82,7 +81,6 @@ resources:
       fixed_ips:
         - ip_address: { get_param: lb_2_extnet_floating_v6_ip }
           subnet: { get_param: subnet_param }
       fixed_ips:
         - ip_address: { get_param: lb_2_extnet_floating_v6_ip }
           subnet: { get_param: subnet_param }
-          subnet_id: { get_param: subnet_id_param }
       binding:vnic_type: direct
       value_specs:
         vlan_filter: {get_param: vm_typeX_bialy_vlan_filter}
       binding:vnic_type: direct
       value_specs:
         vlan_filter: {get_param: vm_typeX_bialy_vlan_filter}
@@ -49,8 +49,8 @@ parameters:
     type: comma_delimited_list
   vm_typeX_bialy_guest_vlans:
     type: comma_delimited_list
     type: comma_delimited_list
   vm_typeX_bialy_guest_vlans:
     type: comma_delimited_list
-  bialy_subnet:
-    type: string
+  bialy_susbnet:
+    type: comma_delimited_list
   bialy_subnet_id:
     type: string
 
   bialy_subnet_id:
     type: string
 
@@ -62,8 +62,7 @@ resources:
       network: { get_param: int_intranet_net_name }
       fixed_ips:
         - ip_address: { get_param: lb_1_int_intranet_floating_ip }
       network: { get_param: int_intranet_net_name }
       fixed_ips:
         - ip_address: { get_param: lb_1_int_intranet_floating_ip }
-          subnet: { get_param: bialy_subnet }
-          subnet_id: { get_param: bialy_subnet_id }
+          subnet: { get_param: bialy_susbnet }
       binding:vnic_type: direct
       value_specs:
         vlan_filter: {get_param: vm_typeX_bialy_vlan_filter}
       binding:vnic_type: direct
       value_specs:
         vlan_filter: {get_param: vm_typeX_bialy_vlan_filter}
@@ -81,8 +80,7 @@ resources:
       network: { get_param: extnet_net_id }
       fixed_ips:
         - ip_address: { get_param: lb_2_extnet_floating_v6_ip }
       network: { get_param: extnet_net_id }
       fixed_ips:
         - ip_address: { get_param: lb_2_extnet_floating_v6_ip }
-          subnet: { get_param: bialy_subnet }
-          subnet_id: { get_param: bialy_subnet_id }
+          subnet: { get_param: bialy_susbnet }
       binding:vnic_type: direct
       value_specs:
         vlan_filter: {get_param: vm_typeX_bialy_vlan_filter}
       binding:vnic_type: direct
       value_specs:
         vlan_filter: {get_param: vm_typeX_bialy_vlan_filter}
index 69190d8..12a7a12 100644 (file)
@@ -41,6 +41,7 @@
 """
 
 import os
 """
 
 import os
+import re
 from collections import defaultdict
 
 from boltons import funcutils
 from collections import defaultdict
 
 from boltons import funcutils
@@ -259,3 +260,30 @@ def check_indices(pattern, values, value_type):
                 ).format(value_type, prefix, indices)
             )
     return invalid_params
                 ).format(value_type, prefix, indices)
             )
     return invalid_params
+
+
+RE_BASE = re.compile(r"(^base$)|(^base_)|(_base_)|(_base$)")
+
+
+def get_base_template_from_yaml_files(yaml_files):
+    """Return first filepath to match RE_BASE
+    """
+    for filepath in yaml_files:
+        basename = get_base_template_from_yaml_file(filepath)
+        if basename:
+            return basename
+    return None
+
+
+def get_base_template_from_yaml_file(yaml_file):
+    (dirname, filename) = os.path.split(yaml_file)
+    files = os.listdir(dirname)
+    for file in files:
+        basename, __ = os.path.splitext(os.path.basename(file))
+        if (
+            (__ == ".yaml" or __ == ".yml")
+            and RE_BASE.search(basename)
+            and basename.find("volume") == -1
+        ):
+            return os.path.join(dirname, "{}{}".format(basename, __))
+    return None
@@ -61,55 +61,40 @@ resources:
     port_type: SR-IOV_Mirrored_Trunk    #SR-IOV Trunk Port
                                         # Receiving Mirrored Traffic
 """
     port_type: SR-IOV_Mirrored_Trunk    #SR-IOV Trunk Port
                                         # Receiving Mirrored Traffic
 """
-
-import os
-import os.path
 import re
 
 import pytest
 
 from .structures import Heat
 import re
 
 import pytest
 
 from .structures import Heat
-from .helpers import validates
+from .helpers import validates, get_base_template_from_yaml_file
 
 VERSION = "1.3.0"
 
 RE_BASE = re.compile(r"(^base$)|(^base_)|(_base_)|(_base$)")  # search pattern
 
 
 VERSION = "1.3.0"
 
 RE_BASE = re.compile(r"(^base$)|(^base_)|(_base_)|(_base$)")  # search pattern
 
-RE_EXTERNAL_PARAM_SUBNET_ID = re.compile(  # match pattern
+RE_EXTERNAL_PARAM_SUBNET = re.compile(  # match pattern
     r"(?P<network_role>.+)(_v6)?_subnet_id$"
 )
     r"(?P<network_role>.+)(_v6)?_subnet_id$"
 )
-RE_EXTERNAL_PARAM_SUBNET = RE_EXTERNAL_PARAM_SUBNET_ID
-# RE_EXTERNAL_PARAM_SUBNET = re.compile( # match pattern
-#        r'(?P<network_role>.+)(_v6)?_subnet$')
 
 
-RE_INTERNAL_PARAM_SUBNET_ID = re.compile(  # match pattern
+RE_INTERNAL_PARAM_SUBNET = re.compile(  # match pattern
     r"int_(?P<network_role>.+)(_v6)?_subnet_id$"
 )
     r"int_(?P<network_role>.+)(_v6)?_subnet_id$"
 )
-RE_INTERNAL_PARAM_SUBNET = RE_INTERNAL_PARAM_SUBNET_ID
-# RE_INTERNAL_PARAM_SUBNET = re.compile( # match pattern
-#        r'int_(?P<network_role>.+)(_v6)?_subnet$')
 
 
 
 
-def get_network(base_template_filepath):
+def get_base(base_template_filepath):
     """Return the base template's Heat instance.
     """
     if base_template_filepath is None:
         pytest.skip("No base template found")
     base_template = Heat(filepath=base_template_filepath)
     """Return the base template's Heat instance.
     """
     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"
-            or base_template.nested_get(r, "type") == "OS::ContrailV2::VirtualNetwork"
-        ):
-            return base_template
-    return None
+    return base_template
 
 
 
 
-def run_test(heat_template, validate):
+def run_test(heat_template, validate, validator=None):
     """call validate for each fixed_ips
     """
     heat = Heat(filepath=heat_template)
     """call validate for each fixed_ips
     """
     heat = Heat(filepath=heat_template)
-    base_template = get_base_template(heat_template)
+    base_template = get_base_template_from_yaml_file(heat_template)
     if not heat.resources:
         pytest.skip("No resources found")
 
     if not heat.resources:
         pytest.skip("No resources found")
 
@@ -125,163 +110,109 @@ def run_test(heat_template, validate):
         if not isinstance(fixed_ips, list):
             bad[rid] = "properties.fixed_ips must be a list."
             continue
         if not isinstance(fixed_ips, list):
             bad[rid] = "properties.fixed_ips must be a list."
             continue
-        if not heat.parameters:
-            bad[rid] = "fixed_ips requires parameters"
-            continue
         for fixed_ip in fixed_ips:
         for fixed_ip in fixed_ips:
-            error = validate(heat, fixed_ip, base_template)
+            error = validate(heat, fixed_ip, base_template, validator)
             if error:
                 bad[rid] = error
                 break
     if bad:
         # raise RuntimeError(
         raise AssertionError(
             if error:
                 bad[rid] = error
                 break
     if bad:
         # raise RuntimeError(
         raise AssertionError(
-            "Bad OS::Neutron::Port: %s"
-            % (", ".join("%s: %s" % (rid, error) for rid, error in bad.items()))
+            "%s"
+            % (",   ".join("%s: %s" % (rid, error) for rid, error in bad.items()))
         )
 
 
         )
 
 
-def validate_external_fixed_ip(heat, fixed_ip, base_template):
-    """ensure fixed_ip subnet and subnet_id for external network
+def validate_external_fixed_ip_subnet(heat, fixed_ip, base_template, validator):
+    """ensure fixed_ip subnet for external network
     match the pattern.
     Returns error message string or None.
     """
     subnet = heat.nested_get(fixed_ip, "subnet", "get_param")
     match the pattern.
     Returns error message string or None.
     """
     subnet = heat.nested_get(fixed_ip, "subnet", "get_param")
-    subnet_id = heat.nested_get(fixed_ip, "subnet_id", "get_param")
-    if subnet and subnet_id:
-        error = 'fixed_ip %s has both "subnet" and "subnet_id"' % (fixed_ip)
-    elif subnet:
-        error = validate_external_subnet(subnet)
-    elif subnet_id:
-        error = validate_external_subnet_id(subnet_id)
+    if subnet:
+        error = validator(subnet, RE_EXTERNAL_PARAM_SUBNET)
     else:
         error = None
     return error
 
 
     else:
         error = None
     return error
 
 
-def validate_external_subnet(subnet):
+def validate_external_subnet_parameter_format(subnet, regx):
     """ensure subnet matches template.
     Returns error message string or None.
     """
     """ensure subnet matches template.
     Returns error message string or None.
     """
-    if (
-        subnet
-        and not subnet.startswith("int_")
-        and RE_EXTERNAL_PARAM_SUBNET.match(subnet) is None
-    ):
-        return 'fixed_ip subnet parameter "%s" does not match "%s"' % (
-            subnet,
-            RE_EXTERNAL_PARAM_SUBNET.pattern,
+    if subnet and not subnet.startswith("int_") and regx.match(subnet) is None:
+        return (
+            'fixed_ip subnet parameter "%s" does not match '
+            "{network-role}_subnet_id or {network-role}_v6_subnet_id" % (subnet)
         )
     return None
 
 
         )
     return None
 
 
-def validate_external_subnet_id(subnet_id):
-    """ensure subnet_id matches template.
-    Returns error message string or None.
-    """
-    if (
-        subnet_id
-        and not subnet_id.startswith("int_")
-        and RE_EXTERNAL_PARAM_SUBNET_ID.match(subnet_id) is None
-    ):
-        return 'fixed_ip subnet_id parameter "%s" does not match "%s"' % (
-            subnet_id,
-            RE_EXTERNAL_PARAM_SUBNET_ID.pattern,
-        )
-    return None
-
-
-def validate_internal_fixed_ip(heat, fixed_ip, base_template):
-    """ensure fixed_ip subnet and subnet_id for internal network
+def validate_internal_fixed_ip_subnet(heat, fixed_ip, base_template, validator):
+    """ensure fixed_ip subnet for internal network
     match the pattern.
     Returns error message string or None.
     """
     match the pattern.
     Returns error message string or None.
     """
-    base_module = get_network(base_template)
+    base_module = get_base(base_template)
     subnet = heat.nested_get(fixed_ip, "subnet", "get_param")
     subnet = heat.nested_get(fixed_ip, "subnet", "get_param")
-    subnet_id = heat.nested_get(fixed_ip, "subnet_id", "get_param")
-    if subnet and subnet_id:
-        error = 'fixed_ip %s has both "subnet" and "subnet_id"' % (fixed_ip)
-    elif subnet:
-        error = validate_internal_subnet(heat, base_module, subnet)
-    elif subnet_id:
-        error = validate_internal_subnet_id(heat, base_module, subnet_id)
+    if subnet:
+        error = validator(heat, base_module, subnet, RE_INTERNAL_PARAM_SUBNET)
     else:
         error = None
     return error
 
 
     else:
         error = None
     return error
 
 
-def validate_internal_subnet(heat, base_module, subnet):
+def validate_internal_subnet_parameter_format(heat, base_module, subnet, regx):
     """ensure if subnet matches template then its parameter exists.
     Returns error message string or None.
     """
     """ensure if subnet matches template then its parameter exists.
     Returns error message string or None.
     """
-    if (
-        subnet
-        and subnet.startswith("int_")
-        and RE_INTERNAL_PARAM_SUBNET.match(subnet)
-        and heat.nested_get(base_module.outputs, subnet) is None
-    ):
-        return 'fixed_ip subnet parameter "%s" not in base outputs"' % (subnet)
+    if subnet and subnet.startswith("int_") and regx.match(subnet) is None:
+        return (
+            'fixed_ip subnet parameter "%s" does not match '
+            "int_{network-role}_subnet_id or int_{network-role}_v6_subnet_id" % (subnet)
+        )
     return None
 
 
     return None
 
 
-def validate_internal_subnet_id(heat, base_module, subnet_id):
-    """ensure if subnet_id matches template then its parameter exists.
+def validate_internal_subnet_exists_in_base_output(heat, base_module, subnet, regx):
+    """ensure if subnet matches template then its parameter exists.
     Returns error message string or None.
     """
     if (
     Returns error message string or None.
     """
     if (
-        subnet_id
-        and subnet_id.startswith("int_")
-        and RE_INTERNAL_PARAM_SUBNET_ID.match(subnet_id)
-        and heat.nested_get(base_module.outputs, subnet_id) is None
+        subnet
+        and subnet.startswith("int_")
+        and regx.match(subnet)
+        and heat.nested_get(base_module.outputs, subnet) is None
     ):
     ):
-        return 'fixed_ip subnet_id parameter "%s" not in base outputs"' % (subnet_id)
+        return 'fixed_ip subnet(_id) parameter "%s" not in base outputs"' % (subnet)
     return None
 
 
     return None
 
 
-def validate_fixed_ip(heat, fixed_ip, base_template):
+def validate_fixed_ip_subnet(heat, fixed_ip, base_template, validator):
     """ensure fixed_ip has proper parameters
     Returns error message string or None.
     """
     subnet = heat.nested_get(fixed_ip, "subnet", "get_param")
     """ensure fixed_ip has proper parameters
     Returns error message string or None.
     """
     subnet = heat.nested_get(fixed_ip, "subnet", "get_param")
-    subnet_id = heat.nested_get(fixed_ip, "subnet_id", "get_param")
-    if subnet and subnet_id:
-        error = 'fixed_ip %s has both "subnet" and "subnet_id"' % (fixed_ip)
-    elif subnet and heat.nested_get(heat.parameters, subnet, "type") != "string":
+    if subnet and heat.nested_get(heat.parameters, subnet, "type") != "string":
         error = 'subnet parameter "%s" must be type "string"' % subnet
         error = 'subnet parameter "%s" must be type "string"' % subnet
-    elif subnet_id and heat.nested_get(heat.parameters, subnet_id, "type") != "string":
-        error = 'subnet_id parameter "%s" must be type "string"' % subnet_id
     else:
         error = None
     return error
 
 
     else:
         error = None
     return error
 
 
-def get_base_template(heat_template):
-    (dirname, filename) = os.path.split(heat_template)
-    files = os.listdir(dirname)
-    for file in files:
-        basename, __ = os.path.splitext(os.path.basename(file))
-        if (
-            __ == ".yaml"
-            and basename.find("base") != -1
-            and basename.find("volume") == -1
-        ):
-            return os.path.join(dirname, "{}{}".format(basename, __))
-    return None
-
-
 @validates("R-38236")
 @validates("R-38236")
-def test_neutron_port_fixed_ips(yaml_file):
+def test_neutron_port_fixed_ips_subnet(yaml_file):
     """
     The VNF's Heat Orchestration Template's
     resource ``OS::Neutron::Port`` property ``fixed_ips``
     map property ``subnet``/``subnet_id`` parameter
     **MUST** be declared type ``string``.
     """
     """
     The VNF's Heat Orchestration Template's
     resource ``OS::Neutron::Port`` property ``fixed_ips``
     map property ``subnet``/``subnet_id`` parameter
     **MUST** be declared type ``string``.
     """
-    run_test(yaml_file, validate_fixed_ip)
+    run_test(yaml_file, validate_fixed_ip_subnet)
 
 
 @validates("R-62802", "R-15287")
 
 
 @validates("R-62802", "R-15287")
-def test_neutron_port_external_fixed_ips(yaml_file):
+def test_neutron_port_external_fixed_ips_subnet(yaml_file):
     """
     When the VNF's Heat Orchestration Template's
     resource ``OS::Neutron::Port`` is attaching
     """
     When the VNF's Heat Orchestration Template's
     resource ``OS::Neutron::Port`` is attaching
@@ -296,12 +227,46 @@ def test_neutron_port_external_fixed_ips(yaml_file):
     and the external network IPv6 subnet is to be specified
       * ``{network-role}_v6_subnet_id``
     """
     and the external network IPv6 subnet is to be specified
       * ``{network-role}_v6_subnet_id``
     """
-    run_test(yaml_file, validate_external_fixed_ip)
+    run_test(
+        yaml_file,
+        validate_external_fixed_ip_subnet,
+        validate_external_subnet_parameter_format,
+    )
+
+
+@validates("R-84123", "R-76160")
+def test_neutron_port_internal_fixed_ips_subnet(yaml_file):
+    """
+    When
+
+      * the VNF's Heat Orchestration Template's
+        resource ``OS::Neutron::Port`` in an Incremental Module is attaching
+        to an internal network
+        that is created in the Base Module, AND
+      * an IPv4 address is being cloud assigned by OpenStack's DHCP Service AND
+      * the internal network IPv4 subnet is to be specified
+        using the property ``fixed_ips`` map property ``subnet``/``subnet_id``,
+
+    the parameter **MUST** follow the naming convention
+
+      * ``int_{network-role}_subnet_id``
+    an IPv6 address is being cloud assigned by OpenStack's DHCP Service AND
+      * ``int_{network-role}_v6_subnet_id``
+
+    """
+    run_test(
+        yaml_file,
+        validate_internal_fixed_ip_subnet,
+        validate_internal_subnet_parameter_format,
+    )
 
 
 @validates("R-84123", "R-76160")
 
 
 @validates("R-84123", "R-76160")
-def test_neutron_port_internal_fixed_ips(yaml_file):
+def test_neutron_port_internal_fixed_ips_subnet_in_base(heat_template):
     """
     """
+    Only check parent incremental modules, because nested file parameter
+    name may have been changed.
+
     When
 
       * the VNF's Heat Orchestration Template's
     When
 
       * the VNF's Heat Orchestration Template's
@@ -318,5 +283,11 @@ def test_neutron_port_internal_fixed_ips(yaml_file):
     an IPv6 address is being cloud assigned by OpenStack's DHCP Service AND
       * ``int_{network-role}_v6_subnet_id``
 
     an IPv6 address is being cloud assigned by OpenStack's DHCP Service AND
       * ``int_{network-role}_v6_subnet_id``
 
+    Note that the parameter MUST be defined as an output parameter in
+    the base module.
     """
     """
-    run_test(yaml_file, validate_internal_fixed_ip)
+    run_test(
+        heat_template,
+        validate_internal_fixed_ip_subnet,
+        validate_internal_subnet_exists_in_base_output,
+    )
index 00a3a93..e90f87c 100644 (file)
 # ============LICENSE_END============================================
 #
 
 # ============LICENSE_END============================================
 #
 
-import os.path
-import re
-
 from tests.parametrizers import get_nested_files
 from tests.utils.network_roles import get_network_type_from_port
 from .structures import Heat
 from tests.parametrizers import get_nested_files
 from tests.utils.network_roles import get_network_type_from_port
 from .structures import Heat
-from .helpers import validates, load_yaml
-
-
-RE_BASE = re.compile(r"(^base$)|(^base_)|(_base_)|(_base$)")
-
-
-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
+from .helpers import validates, load_yaml, get_base_template_from_yaml_files
 
 
 @validates("R-22688")
 def test_neutron_port_internal_network_v2(yaml_files):
 
 
 @validates("R-22688")
 def test_neutron_port_internal_network_v2(yaml_files):
-    base_path = get_base_template_filepath(yaml_files)
+    base_path = get_base_template_from_yaml_files(yaml_files)
     nested_template_paths = get_nested_files(yaml_files)
     errors = []
     for yaml_file in yaml_files:
         if yaml_file == base_path or yaml_file in nested_template_paths:
             continue  # Only applies to incremental modules
         heat = Heat(filepath=yaml_file)
     nested_template_paths = get_nested_files(yaml_files)
     errors = []
     for yaml_file in yaml_files:
         if yaml_file == base_path or yaml_file in nested_template_paths:
             continue  # Only applies to incremental modules
         heat = Heat(filepath=yaml_file)
-        internal_ports = {r_id: p for r_id, p in heat.neutron_port_resources.items()
-                          if get_network_type_from_port(p) == "internal"}
+        internal_ports = {
+            r_id: p
+            for r_id, p in heat.neutron_port_resources.items()
+            if get_network_type_from_port(p) == "internal"
+        }
         for r_id, port in internal_ports.items():
             props = port.get("properties") or {}
             network_value = props.get("network") or {}
         for r_id, port in internal_ports.items():
             props = port.get("properties") or {}
             network_value = props.get("network") or {}
@@ -80,15 +67,19 @@ def test_neutron_port_internal_network_v2(yaml_files):
             base_heat = load_yaml(base_path)
             base_outputs = base_heat.get("outputs") or {}
             if not param.endswith("_net_id"):
             base_heat = load_yaml(base_path)
             base_outputs = base_heat.get("outputs") or {}
             if not param.endswith("_net_id"):
-                errors.append((
-                    "Internal network {} is attached to port {}, but the "
-                    "network must be attached via UUID of the network not "
-                    "the name (ex: int_{{network-role}}_net_id)."
-                ).format(param, r_id))
+                errors.append(
+                    (
+                        "Internal network {} is attached to port {}, but the "
+                        "network must be attached via UUID of the network not "
+                        "the name (ex: int_{{network-role}}_net_id)."
+                    ).format(param, r_id)
+                )
             if param not in base_outputs:
             if param not in base_outputs:
-                errors.append((
-                    "Internal network {} is attached to port {}, but network "
-                    "is not defined as an output in the base module ({})."
-                ).format(param, r_id, base_path))
+                errors.append(
+                    (
+                        "Internal network {} is attached to port {}, but network "
+                        "is not defined as an output in the base module ({})."
+                    ).format(param, r_id, base_path)
+                )
 
     assert not errors, " ".join(errors)
 
     assert not errors, " ".join(errors)