Example #1
0
    def update_port_dhcp_opts(self, port_id, dhcp_options, token=None,
                              context=None):
        """Update a port's attributes.

        Update one or more DHCP options on the specified port.
        For the relevant API spec, see
        https://docs.openstack.org/api-ref/network/v2/index.html#update-port

        :param port_id: designate which port these attributes
                        will be applied to.
        :param dhcp_options: this will be a list of dicts, e.g.

                             ::

                              [{'opt_name': '67',
                                'opt_value': 'pxelinux.0'},
                               {'opt_name': '66',
                                'opt_value': '123.123.123.456'}]
        :param token: optional auth token. Deprecated, use context.
        :param context: request context
        :type context: ironic.common.context.RequestContext
        :raises: FailedToUpdateDHCPOptOnPort
        """
        super(NeutronDHCPApi, self).update_port_dhcp_opts(
            port_id, dhcp_options, token=token, context=context)
        port_req_body = {'port': {'extra_dhcp_opts': dhcp_options}}
        try:
            neutron.update_neutron_port(context, port_id, port_req_body)
        except neutron_client_exc.NeutronClientException:
            LOG.exception("Failed to update Neutron port %s.", port_id)
            raise exception.FailedToUpdateDHCPOptOnPort(port_id=port_id)
Example #2
0
    def update_port_dhcp_opts(self, port_id, dhcp_options, token=None,
                              context=None):
        """Update a port's attributes.

        Update one or more DHCP options on the specified port.
        For the relevant API spec, see
        https://docs.openstack.org/api-ref/network/v2/index.html#update-port

        :param port_id: designate which port these attributes
                        will be applied to.
        :param dhcp_options: this will be a list of dicts, e.g.

                             ::

                              [{'opt_name': '67',
                                'opt_value': 'pxelinux.0',
                                'ip_version': 4},
                               {'opt_name': '66',
                                'opt_value': '123.123.123.456'},
                                'ip_version': 4}]
        :param token: optional auth token. Deprecated, use context.
        :param context: request context
        :type context: ironic.common.context.RequestContext
        :raises: FailedToUpdateDHCPOptOnPort
        """
        super(NeutronDHCPApi, self).update_port_dhcp_opts(
            port_id, dhcp_options, token=token, context=context)
        try:
            neutron_client = neutron.get_client(token=token, context=context)

            fip = None
            port = neutron_client.get_port(port_id)
            try:
                if port:
                    # TODO(TheJulia): We need to retool this down the
                    # road so that we handle ports and allow preferences
                    # for multi-address ports with different IP versions
                    # and enable operators to possibly select preferences
                    # for provisionioning operations.
                    # This is compounded by v6 mainly only being available
                    # with UEFI machines, so the support matrix also gets
                    # a little "weird".
                    # Ideally, we should work on this in Victoria.
                    fip = port.get('fixed_ips')[0]
            except (TypeError, IndexError):
                fip = None
            update_opts = []
            if fip:
                ip_version = ipaddress.ip_address(fip['ip_address']).version
                for option in dhcp_options:
                    if option.get('ip_version', 4) == ip_version:
                        update_opts.append(option)
            else:
                LOG.error('Requested to update port for port %s, '
                          'however port lacks an IP address.', port_id)
            port_attrs = {'extra_dhcp_opts': update_opts}
            neutron.update_neutron_port(context, port_id, port_attrs)
        except openstack_exc.OpenStackCloudException:
            LOG.exception("Failed to update Neutron port %s.", port_id)
            raise exception.FailedToUpdateDHCPOptOnPort(port_id=port_id)
Example #3
0
 def _bind_flat_ports(self, task):
     LOG.debug("Binding flat network ports")
     for port_like_obj in task.ports + task.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
         body = {
             'port': {
                 'binding:host_id': task.node.uuid,
                 'binding:vnic_type': neutron.VNIC_BAREMETAL,
                 'mac_address': port_like_obj.address
             }
         }
         try:
             neutron.update_neutron_port(task.context, vif_port_id, body)
         except neutron_exceptions.NeutronClientException as e:
             msg = (_('Unable to set binding:host_id for '
                      'neutron port %(port_id)s. Error: '
                      '%(err)s') % {
                          'port_id': vif_port_id,
                          'err': e
                      })
             LOG.exception(msg)
             raise exception.NetworkError(msg)
Example #4
0
 def _bind_flat_ports(self, task):
     LOG.debug("Binding flat network ports")
     bound_ports = []
     for port_like_obj in task.ports + task.portgroups:
         vif_port_id = (
             port_like_obj.internal_info.get(common.TENANT_VIF_KEY)
         )
         if not vif_port_id:
             continue
         port_attrs = {'binding:host_id': task.node.uuid,
                       'binding:vnic_type': neutron.VNIC_BAREMETAL,
                       'mac_address': port_like_obj.address}
         try:
             neutron.update_neutron_port(task.context,
                                         vif_port_id, port_attrs)
             bound_ports.append(vif_port_id)
         except openstack_exc.OpenStackCloudException as e:
             msg = (_('Unable to set binding:host_id for '
                      'neutron port %(port_id)s. Error: '
                      '%(err)s') % {'port_id': vif_port_id, 'err': e})
             LOG.exception(msg)
             raise exception.NetworkError(msg)
     LOG.debug("Finished binding flat network ports, attached: %s",
               ' '.join(bound_ports))
Example #5
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)