Exemplo n.º 1
0
    def unconfigure_tenant_networks(self, task):
        """Unconfigure tenant networks for a node.

        Nova takes care of port removal from tenant network, we unbind it
        here/now to avoid the possibility of the ironic port being bound to the
        tenant and cleaning networks at the same time.

        :param task: A TaskManager instance.
        :raises: NetworkError
        """
        node = task.node
        LOG.info('Unbinding instance ports from node %s', node.uuid)

        ports = [p for p in task.ports if not p.portgroup_id]
        portgroups = task.portgroups
        for port_like_obj in ports + portgroups:
            vif_port_id = (
                port_like_obj.internal_info.get(common.TENANT_VIF_KEY)
                or port_like_obj.extra.get('vif_port_id'))
            if not vif_port_id:
                continue

            is_smart_nic = neutron.is_smartnic_port(port_like_obj)
            if is_smart_nic:
                client = neutron.get_client(context=task.context)
                link_info = port_like_obj.local_link_connection
                neutron.wait_for_host_agent(client, link_info['hostname'])

            neutron.unbind_neutron_port(vif_port_id, context=task.context)
Exemplo n.º 2
0
def power_on_node_if_needed(task):
    """Powers on node if it is powered off and has a Smart NIC port

    :param task: A TaskManager object
    :returns: the previous power state or None if no changes were made
    """
    if not task.driver.network.need_power_on(task):
        return

    previous_power_state = task.driver.power.get_power_state(task)
    if previous_power_state == states.POWER_OFF:
        node_set_boot_device(task, boot_devices.BIOS, persistent=False)
        node_power_action(task, states.POWER_ON)

        # local import is necessary to avoid circular import
        from ironic.common import neutron

        host_id = None
        for port in task.ports:
            if neutron.is_smartnic_port(port):
                link_info = port.local_link_connection
                host_id = link_info['hostname']
                break

        if host_id:
            LOG.debug('Waiting for host %(host)s agent to be down',
                      {'host': host_id})

            client = neutron.get_client(context=task.context)
            neutron.wait_for_host_agent(client, host_id, target_state='down')
        return previous_power_state
Exemplo n.º 3
0
    def unconfigure_tenant_networks(self, task):
        """Unconfigure tenant networks for a node.

        Nova takes care of port removal from tenant network, we unbind it
        here/now to avoid the possibility of the ironic port being bound to the
        tenant and cleaning networks at the same time.

        :param task: A TaskManager instance.
        :raises: NetworkError
        """
        node = task.node
        LOG.info('Unbinding instance ports from node %s', node.uuid)

        ports = [p for p in task.ports if not p.portgroup_id]
        portgroups = task.portgroups
        for port_like_obj in ports + portgroups:
            vif_port_id = (
                port_like_obj.internal_info.get(common.TENANT_VIF_KEY)
                or port_like_obj.extra.get('vif_port_id'))
            if not vif_port_id:
                continue

            is_smart_nic = neutron.is_smartnic_port(port_like_obj)
            if is_smart_nic:
                client = neutron.get_client(context=task.context)
                link_info = port_like_obj.local_link_connection
                neutron.wait_for_host_agent(client, link_info['hostname'])

            neutron.unbind_neutron_port(vif_port_id, context=task.context)
Exemplo n.º 4
0
def power_on_node_if_needed(task):
    """Powers on node if it is powered off and has a Smart NIC port

    :param task: A TaskManager object
    :returns: the previous power state or None if no changes were made
    :raises: exception.NetworkError if agent status didn't match the required
        status after max retry attempts.
    """
    if not task.driver.network.need_power_on(task):
        return

    previous_power_state = task.driver.power.get_power_state(task)
    if previous_power_state == states.POWER_OFF:
        node_set_boot_device(
            task, boot_devices.BIOS, persistent=False)
        node_power_action(task, states.POWER_ON)

        # local import is necessary to avoid circular import
        from ironic.common import neutron

        host_id = None
        for port in task.ports:
            if neutron.is_smartnic_port(port):
                link_info = port.local_link_connection
                host_id = link_info['hostname']
                break

        if host_id:
            LOG.debug('Waiting for host %(host)s agent to be down',
                      {'host': host_id})

            client = neutron.get_client(context=task.context)
            neutron.wait_for_host_agent(
                client, host_id, target_state='down')
        return previous_power_state
Exemplo n.º 5
0
    def need_power_on(self, task):
        """Check if the node has any Smart NIC ports

        :param task: A TaskManager instance.
        :return: A boolean to indicate Smart NIC port presence
        """
        for port in task.ports:
            if neutron.is_smartnic_port(port):
                return True
        return False
Exemplo n.º 6
0
    def need_power_on(self, task):
        """Check if the node has any Smart NIC ports

        :param task: A TaskManager instance.
        :return: A boolean to indicate Smart NIC port presence
        """
        for port in task.ports:
            if neutron.is_smartnic_port(port):
                return True
        return False
Exemplo n.º 7
0
def plug_port_to_tenant_network(task, port_like_obj, client=None):
    """Plug port like object to tenant network.

    :param task: A TaskManager instance.
    :param port_like_obj: port-like object to plug.
    :param client: Neutron client instance.
    :raises: NetworkError if failed to update Neutron port.
    :raises: VifNotAttached if tenant VIF is not associated with port_like_obj.
    """

    node = task.node
    local_link_info = []
    local_group_info = None
    client_id_opt = None

    vif_id = (port_like_obj.internal_info.get(TENANT_VIF_KEY)
              or port_like_obj.extra.get('vif_port_id'))

    if not vif_id:
        obj_name = port_like_obj.__class__.__name__.lower()
        raise exception.VifNotAttached(
            _("Tenant VIF is not associated with %(obj_name)s "
              "%(obj_id)s") % {
                  'obj_name': obj_name,
                  'obj_id': port_like_obj.uuid
              })

    LOG.debug('Mapping tenant port %(vif_id)s to node '
              '%(node_id)s', {
                  'vif_id': vif_id,
                  'node_id': node.uuid
              })

    if isinstance(port_like_obj, objects.Portgroup):
        pg_ports = [
            p for p in task.ports if p.portgroup_id == port_like_obj.id
        ]
        for port in pg_ports:
            local_link_info.append(port.local_link_connection)
        local_group_info = neutron.get_local_group_information(
            task, port_like_obj)
    else:
        # We iterate only on ports or portgroups, no need to check
        # that it is a port
        local_link_info.append(port_like_obj.local_link_connection)
        client_id = port_like_obj.extra.get('client-id')
        if client_id:
            client_id_opt = ({
                'opt_name': DHCP_CLIENT_ID,
                'opt_value': client_id
            })

    # NOTE(sambetts) Only update required binding: attributes,
    # because other port attributes may have been set by the user or
    # nova.
    port_attrs = {
        'binding:vnic_type': neutron.VNIC_BAREMETAL,
        'binding:host_id': node.uuid
    }
    # NOTE(kaifeng) Only update mac address when it's available
    if port_like_obj.address:
        port_attrs['mac_address'] = port_like_obj.address
    binding_profile = {'local_link_information': local_link_info}
    if local_group_info:
        binding_profile['local_group_information'] = local_group_info
    port_attrs['binding:profile'] = binding_profile

    if client_id_opt:
        port_attrs['extra_dhcp_opts'] = [client_id_opt]

    is_smart_nic = neutron.is_smartnic_port(port_like_obj)
    if is_smart_nic:
        link_info = local_link_info[0]
        LOG.debug(
            'Setting hostname as host_id in case of Smart NIC, '
            'port %(port_id)s, hostname %(hostname)s', {
                'port_id': vif_id,
                'hostname': link_info['hostname']
            })
        port_attrs['binding:host_id'] = link_info['hostname']
        port_attrs['binding:vnic_type'] = neutron.VNIC_SMARTNIC

    if not client:
        client = neutron.get_client(context=task.context)

    if is_smart_nic:
        neutron.wait_for_host_agent(client, port_attrs['binding:host_id'])

    try:
        neutron.update_neutron_port(task.context, vif_id, port_attrs)
        if is_smart_nic:
            neutron.wait_for_port_status(client, vif_id, 'ACTIVE')
    except openstack_exc.OpenStackCloudException as e:
        msg = (_('Could not add public network VIF %(vif)s '
                 'to node %(node)s, possible network issue. %(exc)s') % {
                     'vif': vif_id,
                     'node': node.uuid,
                     'exc': e
                 })
        LOG.error(msg)
        raise exception.NetworkError(msg)
Exemplo n.º 8
0
def plug_port_to_tenant_network(task, port_like_obj, client=None):
    """Plug port like object to tenant network.

    :param task: A TaskManager instance.
    :param port_like_obj: port-like object to plug.
    :param client: Neutron client instance.
    :raises: NetworkError if failed to update Neutron port.
    :raises: VifNotAttached if tenant VIF is not associated with port_like_obj.
    """

    node = task.node
    local_link_info = []
    local_group_info = None
    client_id_opt = None

    vif_id = (
        port_like_obj.internal_info.get(TENANT_VIF_KEY)
        or port_like_obj.extra.get('vif_port_id'))

    if not vif_id:
        obj_name = port_like_obj.__class__.__name__.lower()
        raise exception.VifNotAttached(
            _("Tenant VIF is not associated with %(obj_name)s "
              "%(obj_id)s") % {'obj_name': obj_name,
                               'obj_id': port_like_obj.uuid})

    LOG.debug('Mapping tenant port %(vif_id)s to node '
              '%(node_id)s',
              {'vif_id': vif_id, 'node_id': node.uuid})

    if isinstance(port_like_obj, objects.Portgroup):
        pg_ports = [p for p in task.ports
                    if p.portgroup_id == port_like_obj.id]
        for port in pg_ports:
            local_link_info.append(port.local_link_connection)
        local_group_info = neutron.get_local_group_information(
            task, port_like_obj)
    else:
        # We iterate only on ports or portgroups, no need to check
        # that it is a port
        local_link_info.append(port_like_obj.local_link_connection)
        client_id = port_like_obj.extra.get('client-id')
        if client_id:
            client_id_opt = ({'opt_name': DHCP_CLIENT_ID,
                              'opt_value': client_id})

    # NOTE(sambetts) Only update required binding: attributes,
    # because other port attributes may have been set by the user or
    # nova.
    body = {
        'port': {
            'binding:vnic_type': neutron.VNIC_BAREMETAL,
            'binding:host_id': node.uuid,
            'mac_address': port_like_obj.address
        }
    }
    binding_profile = {'local_link_information': local_link_info}
    if local_group_info:
        binding_profile['local_group_information'] = local_group_info
    body['port']['binding:profile'] = binding_profile

    if client_id_opt:
        body['port']['extra_dhcp_opts'] = [client_id_opt]

    is_smart_nic = neutron.is_smartnic_port(port_like_obj)
    if is_smart_nic:
        link_info = local_link_info[0]
        LOG.debug('Setting hostname as host_id in case of Smart NIC, '
                  'port %(port_id)s, hostname %(hostname)s',
                  {'port_id': vif_id,
                   'hostname': link_info['hostname']})
        body['port']['binding:host_id'] = link_info['hostname']
        body['port']['binding:vnic_type'] = neutron.VNIC_SMARTNIC

    if not client:
        client = neutron.get_client(context=task.context)

    if is_smart_nic:
        neutron.wait_for_host_agent(client, body['port']['binding:host_id'])

    try:
        client.update_port(vif_id, body)
        if is_smart_nic:
            neutron.wait_for_port_status(client, vif_id, 'ACTIVE')
    except neutron_exceptions.ConnectionFailed as e:
        msg = (_('Could not add public network VIF %(vif)s '
                 'to node %(node)s, possible network issue. %(exc)s') %
               {'vif': vif_id,
                'node': node.uuid,
                'exc': e})
        LOG.error(msg)
        raise exception.NetworkError(msg)