Example #1
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()
Example #2
0
def _vif_attached(port_like_obj, vif_id):
    """Check if VIF is already attached to a port or portgroup.

    Raises an exception if a VIF with id=vif_id is attached to the port-like
    (Port or Portgroup) object. Otherwise, returns whether a VIF is attached.

    :param port_like_obj: port-like object to check.
    :param vif_id: identifier of the VIF to look for in port_like_obj.
    :returns: True if a VIF (but not vif_id) is attached to port_like_obj,
        False otherwise.
    :raises: VifAlreadyAttached, if vif_id is attached to port_like_obj.
    """
    attached_vif_id = port_like_obj.internal_info.get(TENANT_VIF_KEY)
    if attached_vif_id == vif_id:
        raise exception.VifAlreadyAttached(
            object_type=port_like_obj.__class__.__name__,
            vif=vif_id, object_uuid=port_like_obj.uuid)
    return attached_vif_id is not None