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