示例#1
0
def get_free_port_like_object(task, vif_id, physnets):
    """Find free port-like object (portgroup or port) VIF will be attached to.

    Ensures that the VIF is not already attached to this node.  When selecting
    a port or portgroup to attach the virtual interface to, the following
    ordered criteria are applied:

    * Require ports or portgroups to have a physical network that is either
      None or one of the VIF's allowed physical networks.
    * Prefer ports or portgroups with a physical network field which is not
      None.
    * Prefer portgroups to ports.
    * Prefer ports with PXE enabled.

    :param task: a TaskManager instance.
    :param vif_id: Name or UUID of a VIF.
    :param physnets: Set of physical networks on which the VIF may be
        attached. This is governed by the segments of the VIF's network. An
        empty set indicates that the ports' physical networks should be
        ignored.
    :raises: VifAlreadyAttached, if VIF is already attached to the node.
    :raises: NoFreePhysicalPorts, if there is no port-like object VIF can be
        attached to.
    :raises: PortgroupPhysnetInconsistent if one of the node's portgroups
             has ports which are not all assigned the same physical network.
    :returns: port-like object VIF will be attached to.
    """
    free_port_like_objs = _get_free_portgroups_and_ports(
        task, vif_id, physnets)

    if not free_port_like_objs:
        raise exception.NoFreePhysicalPorts(vif=vif_id)

    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)

    sorted_free_plos = sorted(free_port_like_objs, key=sort_key, reverse=True)
    return sorted_free_plos[0]
示例#2
0
文件: common.py 项目: stackhpc/ironic
def get_free_port_like_object(task, vif_id):
    """Find free port-like object (portgroup or port) VIF will be attached to.

    Ensures that VIF is not already attached to this node. It will return the
    first free port group. If there are no free port groups, then the first
    available port (pxe_enabled preferably) is used.

    :param task: a TaskManager instance.
    :param vif_id: Name or UUID of a VIF.
    :raises: VifAlreadyAttached, if VIF is already attached to the node.
    :raises: NoFreePhysicalPorts, if there is no port-like object VIF can be
        attached to.
    :returns: port-like object VIF will be attached to.
    """

    free_portgroups, free_ports = _get_free_portgroups_and_ports(task, vif_id)

    if free_portgroups:
        # portgroups are higher priority
        return free_portgroups[0]

    if not free_ports:
        raise exception.NoFreePhysicalPorts(vif=vif_id)

    # Sort ports by pxe_enabled to ensure we always bind pxe_enabled ports
    # first
    sorted_free_ports = sorted(free_ports,
                               key=lambda p: p.pxe_enabled,
                               reverse=True)
    return sorted_free_ports[0]
示例#3
0
    def vif_attach(self, task, vif_info):
        """Attach a virtual network interface to a node

        :param task: A TaskManager instance.
        :param vif_info: a dictionary of information about a VIF.
             It must have an 'id' key, whose value is a unique
             identifier for that VIF.
        :raises: NetworkError, VifAlreadyAttached, NoFreePhysicalPorts
        """
        vif_id = vif_info['id']
        # Sort ports by pxe_enabled to ensure we always bind pxe_enabled ports
        # first
        sorted_ports = sorted(task.ports, key=lambda p: p.pxe_enabled,
                              reverse=True)
        free_ports = []
        # Check all ports to ensure this VIF isn't already attached
        for port in sorted_ports:
            port_id = port.internal_info.get(TENANT_VIF_KEY,
                                             port.extra.get('vif_port_id'))
            if port_id is None:
                free_ports.append(port)
            elif port_id == vif_id:
                raise exception.VifAlreadyAttached(
                    vif=vif_id, port_uuid=port.uuid)

        if not free_ports:
            raise exception.NoFreePhysicalPorts(vif=vif_id)

        # Get first free port
        port = free_ports.pop(0)

        # Check if the requested vif_id is a neutron port. If it is
        # then attempt to update the port's MAC address.
        try:
            client = neutron.get_client(task.context.auth_token)
            client.show_port(vif_id)
        except neutron_exceptions.NeutronClientException:
            # NOTE(sambetts): If a client error occurs this is because either
            # neutron doesn't exist because we're running in standalone
            # environment or we can't find a matching neutron port which means
            # a user might be requesting a non-neutron port. So skip trying to
            # update the neutron port MAC address in these cases.
            pass
        else:
            try:
                neutron.update_port_address(vif_id, port.address)
            except exception.FailedToUpdateMacOnPort:
                raise exception.NetworkError(_(
                    "Unable to attach VIF %(vif)s because Ironic can not "
                    "update Neutron port %(port)s MAC address to match "
                    "physical MAC address %(mac)s") % {
                        'vif': vif_id, 'port': vif_id, 'mac': port.address})

        int_info = port.internal_info
        int_info[TENANT_VIF_KEY] = vif_id
        port.internal_info = int_info
        port.save()