def request_vifs(self, pod, project_id, subnets, security_groups, num_ports, trunk_ip=None): """This method creates subports and returns a list with their vifs. It creates up to num_ports subports and attaches them to the trunk port. If not enough vlan ids are available for all the subports to create, it creates as much as available vlan ids. Note the neutron trunk_add_subports is an atomic operation that will either attach all or none of the subports. Therefore, if there is a vlan id collision, all the created ports will be deleted and the exception is raised. """ neutron = clients.get_neutron_client() if trunk_ip: parent_port = self._get_parent_port_by_host_ip(neutron, trunk_ip) else: parent_port = self._get_parent_port(neutron, pod) trunk_id = self._get_trunk_id(parent_port) port_rq, subports_info = self._create_subports_info( pod, project_id, subnets, security_groups, trunk_id, num_ports, unbound=True) if not subports_info: LOG.error("There are no vlan ids available to create subports") return [] bulk_port_rq = {'ports': [port_rq] * len(subports_info)} try: ports = neutron.create_port(bulk_port_rq).get('ports') except n_exc.NeutronClientException: LOG.exception("Error creating bulk ports: %s", bulk_port_rq) raise utils.tag_neutron_resources('ports', [port['id'] for port in ports]) for index, port in enumerate(ports): subports_info[index]['port_id'] = port['id'] try: try: neutron.trunk_add_subports(trunk_id, {'sub_ports': subports_info}) except n_exc.Conflict: LOG.error("vlan ids already in use on trunk") for port in ports: neutron.delete_port(port['id']) raise except n_exc.NeutronClientException: LOG.exception("Error happened during subport addition to trunk") raise vifs = [] for index, port in enumerate(ports): vlan_id = subports_info[index]['segmentation_id'] vif = ovu.neutron_to_osvif_vif_nested_vlan(port, subnets, vlan_id) vifs.append(vif) return vifs
def _recover_precreated_ports(self): neutron = clients.get_neutron_client() available_ports = self._get_ports_by_attrs( name='available-port', device_owner='trunk:subport') if not available_ports: return trunk_ports = neutron.list_trunks().get('trunks') for trunk in trunk_ports: try: host_addr = self._get_parent_port_ip(trunk['port_id']) except n_exc.PortNotFoundClient: LOG.debug('Unable to find parent port for trunk port %s.', trunk['port_id']) continue for subport in trunk.get('sub_ports'): kuryr_subport = None for port in available_ports: if port['id'] == subport['port_id']: kuryr_subport = port break if kuryr_subport: pool_key = (host_addr, kuryr_subport['project_id'], tuple(kuryr_subport['security_groups'])) subnet_id = kuryr_subport['fixed_ips'][0]['subnet_id'] subnet = {subnet_id: default_subnet._get_subnet(subnet_id)} vif = ovu.neutron_to_osvif_vif_nested_vlan( kuryr_subport, subnet, subport['segmentation_id']) self._existing_vifs[subport['port_id']] = vif self._available_ports_pools.setdefault( pool_key, []).append(subport['port_id'])
def request_vif(self, pod, project_id, subnets, security_groups): neutron = clients.get_neutron_client() parent_port = self._get_parent_port(neutron, pod) trunk_id = self._get_trunk_id(parent_port) rq = self._get_port_request(pod, project_id, subnets, security_groups) port = neutron.create_port(rq).get('port') vlan_id = self._add_subport(neutron, trunk_id, port['id']) return ovu.neutron_to_osvif_vif_nested_vlan(port, subnets, vlan_id)
def request_vif(self, pod, project_id, subnets, security_groups): os_net = clients.get_network_client() parent_port = self._get_parent_port(pod) trunk_id = self._get_trunk_id(parent_port) rq = self._get_port_request(pod, project_id, subnets, security_groups) port = os_net.create_port(**rq) utils.tag_neutron_resources([port]) vlan_id = self._add_subport(trunk_id, port.id) return ovu.neutron_to_osvif_vif_nested_vlan(port, subnets, vlan_id)
def test_neutron_to_osvif_nested_vlan(self, m_mk_vif, m_make_vif_network, m_is_port_active, m_get_vif_name): vif_plugin = const.K8S_OS_VIF_NOOP_PLUGIN port_id = mock.sentinel.port_id mac_address = mock.sentinel.mac_address port_filter = mock.sentinel.port_filter subnets = mock.sentinel.subnets network = mock.sentinel.network port_active = mock.sentinel.port_active vif_name = mock.sentinel.vif_name vif = mock.sentinel.vif vlan_id = mock.sentinel.vlan_id m_make_vif_network.return_value = network m_is_port_active.return_value = port_active m_get_vif_name.return_value = vif_name m_mk_vif.return_value = vif port = { 'id': port_id, 'mac_address': mac_address, 'binding:vif_details': { 'port_filter': port_filter }, } self.assertEqual( vif, ovu.neutron_to_osvif_vif_nested_vlan(port, subnets, vlan_id)) m_make_vif_network.assert_called_once_with(port, subnets) m_is_port_active.assert_called_once_with(port) m_get_vif_name.assert_called_once_with(port) m_mk_vif.assert_called_once_with(id=port_id, address=mac_address, network=network, has_traffic_filtering=port_filter, preserve_on_delete=False, active=port_active, plugin=vif_plugin, vif_name=vif_name, vlan_id=vlan_id)
def _precreated_ports(self, action, trunk_ips=None): """Removes or recovers pre-created subports at given pools This function handles the pre-created ports based on the given action: - If action is `free` it will remove all the subport from the given trunk ports, or from all the trunk ports if no trunk_ips are passed. - If action is `recover` it will discover the existing subports in the given trunk ports (or in all of them if none are passed) and will add them (and the needed information) to the respective pools. """ neutron = clients.get_neutron_client() # Note(ltomasbo): ML2/OVS changes the device_owner to trunk:subport # when a port is attached to a trunk. However, that is not the case # for other ML2 drivers, such as ODL. So we also need to look for # compute:kuryr parent_ports, available_subports, subnets = self._get_trunks_info() if not available_subports: return for trunk_id, parent_port in parent_ports.items(): host_addr = parent_port.get('ip') if trunk_ips and host_addr not in trunk_ips: continue for subport in parent_port.get('subports'): kuryr_subport = available_subports.get(subport['port_id']) if kuryr_subport: subnet_id = kuryr_subport['fixed_ips'][0]['subnet_id'] subnet = subnets[subnet_id] net_obj = subnet[subnet_id] pool_key = self._get_pool_key( host_addr, kuryr_subport['project_id'], kuryr_subport['security_groups'], net_obj.id, None) if action == 'recover': vif = ovu.neutron_to_osvif_vif_nested_vlan( kuryr_subport, subnet, subport['segmentation_id']) self._existing_vifs[kuryr_subport['id']] = vif self._available_ports_pools.setdefault( pool_key, []).append(kuryr_subport['id']) elif action == 'free': try: self._drv_vif._remove_subport( neutron, trunk_id, kuryr_subport['id']) neutron.delete_port(kuryr_subport['id']) self._drv_vif._release_vlan_id( subport['segmentation_id']) del self._existing_vifs[kuryr_subport['id']] self._available_ports_pools[pool_key].remove( kuryr_subport['id']) except n_exc.PortNotFoundClient: LOG.debug( 'Unable to release port %s as it no ' 'longer exists.', kuryr_subport['id']) except KeyError: LOG.debug('Port %s is not in the ports list.', kuryr_subport['id']) except n_exc.NeutronClientException: LOG.warning('Error removing the subport %s', kuryr_subport['id']) except ValueError: LOG.debug( 'Port %s is not in the available ports ' 'pool.', kuryr_subport['id'])
def _precreated_ports(self, action, trunk_ips=None): """Removes or recovers pre-created subports at given pools This function handles the pre-created ports based on the given action: - If action is `free` it will remove all the subport from the given trunk ports, or from all the trunk ports if no trunk_ips are passed. - If action is `recover` it will discover the existing subports in the given trunk ports (or in all of them if none are passed) and will add them (and the needed information) to the respective pools. """ os_net = clients.get_network_client() # Note(ltomasbo): ML2/OVS changes the device_owner to trunk:subport # when a port is attached to a trunk. However, that is not the case # for other ML2 drivers, such as ODL. So we also need to look for # compute:kuryr parent_ports, available_subports, subnets = self._get_trunks_info() if not available_subports: return # FIXME(ltomasbo): Workaround for ports already detached from trunks # whose status is ACTIVE trunks_subports = [ subport_id['port_id'] for p_port in parent_ports.values() for subport_id in p_port['subports'] ] port_ids_to_delete = [ p_id for p_id in available_subports if p_id not in trunks_subports ] for port_id in port_ids_to_delete: LOG.debug("Deleting port with wrong status: %s", port_id) try: os_net.delete_port(port_id) except os_exc.SDKException: LOG.exception('Error removing the port %s', port_id) for trunk_id, parent_port in parent_ports.items(): host_addr = parent_port.get('ip') if trunk_ips and host_addr not in trunk_ips: continue for subport in parent_port.get('subports'): kuryr_subport = available_subports.get(subport['port_id']) if not kuryr_subport: continue subnet_id = kuryr_subport.fixed_ips[0]['subnet_id'] subnet = subnets[subnet_id] net_obj = subnet[subnet_id] pool_key = self._get_pool_key(host_addr, kuryr_subport.project_id, net_obj.id, None) if action == 'recover': vif = ovu.neutron_to_osvif_vif_nested_vlan( kuryr_subport, subnet, subport['segmentation_id']) self._existing_vifs[kuryr_subport.id] = vif self._available_ports_pools.setdefault( pool_key, {}).setdefault( tuple(sorted(kuryr_subport.security_group_ids)), []).append(kuryr_subport.id) elif action == 'free': try: self._drv_vif._remove_subport(trunk_id, kuryr_subport.id) os_net.delete_port(kuryr_subport.id) self._drv_vif._release_vlan_id( subport['segmentation_id']) del self._existing_vifs[kuryr_subport.id] self._available_ports_pools[pool_key][tuple( sorted(kuryr_subport.security_group_ids))].remove( kuryr_subport.id) except KeyError: LOG.debug('Port %s is not in the ports list.', kuryr_subport.id) except (os_exc.SDKException, os_exc.HttpException): LOG.warning('Error removing the subport %s', kuryr_subport.id) except ValueError: LOG.debug( 'Port %s is not in the available ports ' 'pool.', kuryr_subport.id)
def request_vifs(self, pod, project_id, subnets, security_groups, num_ports, semaphore, trunk_ip=None): """This method creates subports and returns a list with their vifs. It creates up to num_ports subports and attaches them to the trunk port. If not enough vlan ids are available for all the subports to create, it creates as much as available vlan ids. Note the os_net add_trunk_subports is an atomic operation that will either attach all or none of the subports. Therefore, if there is a vlan id collision, all the created ports will be deleted and the exception is raised. """ os_net = clients.get_network_client() if trunk_ip: parent_port = self._get_parent_port_by_host_ip(trunk_ip) else: parent_port = self._get_parent_port(pod) trunk_id = self._get_trunk_id(parent_port) port_rq, subports_info = self._create_subports_info(pod, project_id, subnets, security_groups, trunk_id, num_ports, unbound=True) if not subports_info: LOG.error("There are no vlan ids available to create subports") return [] bulk_port_rq = {'ports': [port_rq] * len(subports_info)} # restrict amount of create Ports in bulk that might be running # in parallel. with semaphore: try: ports = list(os_net.create_ports(bulk_port_rq)) except os_exc.SDKException: for subport_info in subports_info: self._release_vlan_id(subport_info['segmentation_id']) LOG.exception("Error creating bulk ports: %s", bulk_port_rq) raise self._check_port_binding(ports) if not self._tag_on_creation: utils.tag_neutron_resources(ports) for index, port in enumerate(ports): subports_info[index]['port_id'] = port['id'] try: try: os_net.add_trunk_subports(trunk_id, subports_info) except os_exc.ConflictException: LOG.error("vlan ids already in use on trunk") utils.delete_ports(ports) for subport_info in subports_info: self._release_vlan_id(subport_info['segmentation_id']) return [] except os_exc.SDKException: LOG.exception("Error happened during subport addition to trunk") utils.delete_ports(ports) for subport_info in subports_info: self._release_vlan_id(subport_info['segmentation_id']) return [] vifs = [] for index, port in enumerate(ports): vlan_id = subports_info[index]['segmentation_id'] vif = ovu.neutron_to_osvif_vif_nested_vlan(port, subnets, vlan_id) vifs.append(vif) return vifs
def _precreated_ports(self, action, trunk_ips=None): """Removes or recovers pre-created subports at given pools This function handles the pre-created ports based on the given action: - If action is `free` it will remove all the subport from the given trunk ports, or from all the trunk ports if no trunk_ips are passed. - If action is `recover` it will discover the existing subports in the given trunk ports (or in all of them if none are passed) and will add them (and the needed information) to the respective pools. """ neutron = clients.get_neutron_client() # Note(ltomasbo): ML2/OVS changes the device_owner to trunk:subport # when a port is attached to a trunk. However, that is not the case # for other ML2 drivers, such as ODL. So we also need to look for # compute:kuryr if config.CONF.kubernetes.port_debug: available_ports = self._get_ports_by_attrs( name=constants.KURYR_PORT_NAME, device_owner=[ 'trunk:subport', kl_const.DEVICE_OWNER]) else: kuryr_subports = self._get_ports_by_attrs( device_owner=['trunk:subport', kl_const.DEVICE_OWNER]) in_use_ports = self._get_in_use_ports() available_ports = [subport for subport in kuryr_subports if subport['id'] not in in_use_ports] if not available_ports: return trunk_ports = neutron.list_trunks().get('trunks') for trunk in trunk_ports: try: host_addr = self._get_parent_port_ip(trunk['port_id']) except n_exc.PortNotFoundClient: LOG.debug('Unable to find parent port for trunk port %s.', trunk['port_id']) continue if trunk_ips and host_addr not in trunk_ips: continue for subport in trunk.get('sub_ports'): kuryr_subport = None for port in available_ports: if port['id'] == subport['port_id']: kuryr_subport = port break if kuryr_subport: pool_key = (host_addr, kuryr_subport['project_id'], tuple(kuryr_subport['security_groups'])) if action == 'recover': subnet_id = kuryr_subport['fixed_ips'][0]['subnet_id'] subnet = { subnet_id: default_subnet._get_subnet(subnet_id)} vif = ovu.neutron_to_osvif_vif_nested_vlan( kuryr_subport, subnet, subport['segmentation_id']) self._existing_vifs[subport['port_id']] = vif self._available_ports_pools.setdefault( pool_key, []).append(subport['port_id']) elif action == 'free': try: self._drv_vif._remove_subport(neutron, trunk['id'], subport['port_id']) neutron.delete_port(subport['port_id']) self._drv_vif._release_vlan_id( subport['segmentation_id']) del self._existing_vifs[subport['port_id']] self._available_ports_pools[pool_key].remove( subport['port_id']) except n_exc.PortNotFoundClient: LOG.debug('Unable to release port %s as it no ' 'longer exists.', subport['port_id']) except KeyError: LOG.debug('Port %s is not in the ports list.', subport['port_id']) except n_exc.NeutronClientException: LOG.warning('Error removing the subport %s', subport['port_id']) except ValueError: LOG.debug('Port %s is not in the available ports ' 'pool.', subport['port_id'])