def validate_port_physnet(task, port_obj): """Validate the consistency of physical networks of ports in a portgroup. Validate the consistency of a port's physical network with other ports in the same portgroup. All ports in a portgroup should have the same value (which may be None) for their physical_network field. During creation or update of a port in a portgroup we apply the following validation criteria: - If the portgroup has existing ports with different physical networks, we raise PortgroupPhysnetInconsistent. This shouldn't ever happen. - If the port has a physical network that is inconsistent with other ports in the portgroup, we raise exception.Conflict. If a port's physical network is None, this indicates that ironic's VIF attachment mapping algorithm should operate in a legacy (physical network unaware) mode for this port or portgroup. This allows existing ironic nodes to continue to function after an upgrade to a release including physical network support. :param task: a TaskManager instance :param port_obj: a port object to be validated. :raises: Conflict if the port is a member of a portgroup which is on a different physical network. :raises: PortgroupPhysnetInconsistent if the port's portgroup has ports which are not all assigned the same physical network. """ if 'portgroup_id' not in port_obj or not port_obj.portgroup_id: return delta = port_obj.obj_what_changed() # We can skip this step if the port's portgroup membership or physical # network assignment is not being changed (during creation these will # appear changed). if not (delta & {'portgroup_id', 'physical_network'}): return # Determine the current physical network of the portgroup. pg_physnets = network.get_physnets_by_portgroup_id(task, port_obj.portgroup_id, exclude_port=port_obj) if not pg_physnets: return # Check that the port has the same physical network as any existing # member ports. pg_physnet = pg_physnets.pop() port_physnet = (port_obj.physical_network if 'physical_network' in port_obj else None) if port_physnet != pg_physnet: portgroup = network.get_portgroup_by_id(task, port_obj.portgroup_id) msg = _("Port with physical network %(physnet)s cannot become a " "member of port group %(portgroup)s which has ports in " "physical network %(pg_physnet)s.") raise exception.Conflict( msg % {'portgroup': portgroup.uuid, 'physnet': port_physnet, 'pg_physnet': pg_physnet})
def sort_key(port_like_obj): """Key function for sorting a combined list of ports and portgroups. We key the port-like objects using the following precedence: 1. Prefer objects with a physical network field which is in the physnets set. 2. Prefer portgroups to ports. 3. Prefer ports with PXE enabled. :param port_like_obj: The port or portgroup to key. :returns: A key value for sorting the object. """ is_pg = isinstance(port_like_obj, objects.Portgroup) if is_pg: pg_physnets = network.get_physnets_by_portgroup_id( task, port_like_obj.id) pg_physnet = pg_physnets.pop() physnet_matches = pg_physnet in physnets pxe_enabled = True else: physnet_matches = port_like_obj.physical_network in physnets pxe_enabled = port_like_obj.pxe_enabled return (physnet_matches, is_pg, pxe_enabled)
def _test(self, expected_result, exclude_port=None): with task_manager.acquire(self.context, self.node.uuid) as task: result = network.get_physnets_by_portgroup_id(task, self.portgroup.id, exclude_port) self.assertEqual(expected_result, result)