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)
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)
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)
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))
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)