def _trigger_return_to_pool(self): if not hasattr(self, '_recyclable_ports'): LOG.info("Kuryr-controller not yet ready to return ports to " "pools.") return neutron = clients.get_neutron_client() sg_current = {} if not config.CONF.kubernetes.port_debug: attrs = {'device_owner': ['trunk:subport', kl_const.DEVICE_OWNER]} tags = config.CONF.neutron_defaults.resource_tags if tags: attrs['tags'] = tags kuryr_subports = c_utils.get_ports_by_attrs(**attrs) for subport in kuryr_subports: if subport['id'] in self._recyclable_ports: sg_current[subport['id']] = tuple( sorted(subport['security_groups'])) for port_id, pool_key in self._recyclable_ports.copy().items(): if (not oslo_cfg.CONF.vif_pool.ports_pool_max or self._get_pool_size(pool_key) < oslo_cfg.CONF.vif_pool.ports_pool_max): port_name = (constants.KURYR_PORT_NAME if config.CONF.kubernetes.port_debug else '') if config.CONF.kubernetes.port_debug: try: neutron.update_port(port_id, {"port": { 'name': port_name, }}) except n_exc.NeutronClientException: LOG.warning( "Error changing name for port %s to be " "reused, put back on the cleanable " "pool.", port_id) continue self._available_ports_pools.setdefault( pool_key, {}).setdefault(sg_current.get(port_id), []).append(port_id) else: trunk_id = self._get_trunk_id(neutron, pool_key) try: self._drv_vif._remove_subport(neutron, trunk_id, port_id) self._drv_vif._release_vlan_id( self._existing_vifs[port_id].vlan_id) del self._existing_vifs[port_id] neutron.delete_port(port_id) except n_exc.PortNotFoundClient: LOG.debug( 'Unable to release port %s as it no longer ' 'exists.', port_id) except KeyError: LOG.debug('Port %s is not in the ports list.', port_id) except n_exc.NeutronClientException: LOG.warning('Error removing the subport %s', port_id) continue try: del self._recyclable_ports[port_id] except KeyError: LOG.debug('Port already recycled: %s', port_id)
def _recover_precreated_ports(self): attrs = {'device_owner': kl_const.DEVICE_OWNER} tags = config.CONF.neutron_defaults.resource_tags if tags: attrs['tags'] = tags if config.CONF.kubernetes.port_debug: attrs['name'] = constants.KURYR_PORT_NAME available_ports = c_utils.get_ports_by_attrs(**attrs) else: kuryr_ports = c_utils.get_ports_by_attrs(**attrs) in_use_ports = self._get_in_use_ports() available_ports = [port for port in kuryr_ports if port['id'] not in in_use_ports] _, available_subports, _ = self._get_trunks_info() for port in available_ports: # NOTE(ltomasbo): ensure subports are not considered for # recovering in the case of multi pools if available_subports.get(port['id']): continue vif_plugin = self._drv_vif._get_vif_plugin(port) port_host = port['binding:host_id'] if not vif_plugin or not port_host: # NOTE(ltomasbo): kuryr-controller is running without the # rights to get the needed information to recover the ports. # Thus, removing the port instead neutron = clients.get_neutron_client() neutron.delete_port(port['id']) continue subnet_id = port['fixed_ips'][0]['subnet_id'] subnet = { subnet_id: utils.get_subnet(subnet_id)} vif = ovu.neutron_to_osvif_vif(vif_plugin, port, subnet) net_obj = subnet[subnet_id] pool_key = self._get_pool_key(port_host, port['project_id'], net_obj.id, None) self._existing_vifs[port['id']] = vif self._available_ports_pools.setdefault( pool_key, {}).setdefault( tuple(sorted(port['security_groups'])), []).append( port['id']) LOG.info("PORTS POOL: pools updated with pre-created ports") self._create_healthcheck_file()
def _delete_namespace_network_resources(self, subnet_id, net_id): neutron = clients.get_neutron_client() if subnet_id: router_id = oslo_cfg.CONF.namespace_subnet.pod_router try: neutron.remove_interface_router(router_id, {"subnet_id": subnet_id}) except n_exc.NotFound: LOG.debug("Subnet %(subnet)s not attached to router " "%(router)s", {'subnet': subnet_id, 'router': router_id}) except n_exc.NeutronClientException: LOG.exception("Error deleting subnet %(subnet)s from router " "%(router)s.", {'subnet': subnet_id, 'router': router_id}) raise try: neutron.delete_network(net_id) except n_exc.NotFound: LOG.debug("Neutron Network not found: %s", net_id) except n_exc.NetworkInUseClient: LOG.exception("One or more ports in use on the network %s. " "Deleting leftovers ports before retrying", net_id) leftover_ports = c_utils.get_ports_by_attrs(status='DOWN', network_id=net_id) for leftover_port in leftover_ports: try: neutron.delete_port(leftover_port['id']) except n_exc.PortNotFoundClient: LOG.debug("Port already deleted.") except n_exc.NeutronClientException as e: if "currently a subport for trunk" in str(e): LOG.warning("Port %s is in DOWN status but still " "associated to a trunk. This should not " "happen. Trying to delete it from the " "trunk.", leftover_port['id']) # Get the trunk_id from the error message trunk_id = ( str(e).split('trunk')[1].split('.')[0].strip()) try: neutron.trunk_remove_subports( trunk_id, {'sub_ports': [ {'port_id': leftover_port['id']}]}) except n_exc.NotFound: LOG.debug("Port %s already removed from trunk %s", leftover_port['id'], trunk_id) else: LOG.exception("Unexpected error deleting leftover " "port %s. Skiping it and continue with " "the other rest.", leftover_port['id']) raise exceptions.ResourceNotReady(net_id) except n_exc.NeutronClientException: LOG.exception("Error deleting network %s.", net_id) raise
def _delete_namespace_network_resources(self, subnet_id, net_id): neutron = clients.get_neutron_client() if subnet_id: router_id = oslo_cfg.CONF.namespace_subnet.pod_router try: neutron.remove_interface_router(router_id, {"subnet_id": subnet_id}) except n_exc.NotFound: LOG.debug( "Subnet %(subnet)s not attached to router " "%(router)s", { 'subnet': subnet_id, 'router': router_id }) except n_exc.NeutronClientException: LOG.exception( "Error deleting subnet %(subnet)s from router " "%(router)s.", { 'subnet': subnet_id, 'router': router_id }) raise try: neutron.delete_network(net_id) except n_exc.NotFound: LOG.debug("Neutron Network not found: %s", net_id) except n_exc.NetworkInUseClient: LOG.exception( "One or more ports in use on the network %s. " "Deleting leftovers ports before retrying", net_id) leftover_ports = c_utils.get_ports_by_attrs(status='DOWN', network_id=net_id) for leftover_port in leftover_ports: try: neutron.delete_port(leftover_port['id']) except n_exc.PortNotFoundClient: LOG.debug("Port already deleted.") except n_exc.NeutronClientException: LOG.debug( "Unexpected error deleting leftover port %s. " "Skiping it and continue with the other rest.", leftover_port['id']) continue raise exceptions.ResourceNotReady(net_id) except n_exc.NeutronClientException: LOG.exception("Error deleting network %s.", net_id) raise
def _cleanup_leftover_ports(self): neutron = clients.get_neutron_client() attrs = {'device_owner': kl_const.DEVICE_OWNER, 'status': 'DOWN'} existing_ports = c_utils.get_ports_by_attrs(**attrs) tags = config.CONF.neutron_defaults.resource_tags if tags: nets = neutron.list_networks(tags=tags)['networks'] nets_ids = [n['id'] for n in nets] for port in existing_ports: net_id = port['network_id'] if net_id in nets_ids: if port.get('binding:host_id'): for tag in tags: if tag not in port.get('tags', []): # delete the port if it has binding details, it # belongs to the deployment subnet and it does # not have the right tags try: neutron.delete_port(port['id']) break except n_exc.NeutronClientException: LOG.debug( "Problem deleting leftover port " "%s. Skipping.", port['id']) continue else: # delete port if they have no binding but belong to the # deployment networks, regardless of their tagging try: neutron.delete_port(port['id']) except n_exc.NeutronClientException: LOG.debug( "Problem deleting leftover port %s. " "Skipping.", port['id']) continue else: for port in existing_ports: if not port.get('binding:host_id'): neutron.delete_port(port['id'])
def _get_trunks_info(self): """Returns information about trunks and their subports. This method searches for parent ports and subports among the active neutron ports. To find the parent ports it filters the ones that have trunk_details, i.e., the ones that are the parent port of a trunk. To find the subports to recover, it filters out the ports that are already in used by running kubernetes pods. It also filters out the ports whose device_owner is not related to subports, i.e., the ports that are not attached to trunks, such as active ports allocated to running VMs. At the same time it collects information about ports subnets to minimize the number of interaction with Neutron API. It returns three dictionaries with the needed information about the parent ports, subports and subnets :return: 3 dicts with the trunk details (Key: trunk_id; Value: dict containing ip and subports), subport details (Key: port_id; Value: port_object), and subnet details (Key: subnet_id; Value: subnet dict) """ # REVISIT(ltomasbo): there is no need to recover the subports # belonging to trunk ports whose parent port is DOWN as that means no # pods can be scheduled there. We may need to update this if we allow # lively extending the kubernetes cluster with VMs that already have # precreated subports. For instance by shutting down and up a # kubernetes Worker VM with subports already attached, and the # controller is restarted in between. parent_ports = {} subports = {} subnets = {} attrs = {'status': 'ACTIVE'} tags = config.CONF.neutron_defaults.resource_tags if tags: attrs['tags'] = tags all_active_ports = c_utils.get_ports_by_attrs(**attrs) in_use_ports = self._get_in_use_ports() for port in all_active_ports: trunk_details = port.get('trunk_details') # Parent port if trunk_details: parent_ports[trunk_details['trunk_id']] = { 'ip': port['fixed_ips'][0]['ip_address'], 'subports': trunk_details['sub_ports']} else: # Filter to only get subports that are not in use if (port['id'] not in in_use_ports and port['device_owner'] in ['trunk:subport', kl_const.DEVICE_OWNER]): subports[port['id']] = port # NOTE(ltomasbo): _get_subnet can be costly as it # needs to call neutron to get network and subnet # information. This ensures it is only called once # per subnet in use subnet_id = port['fixed_ips'][0]['subnet_id'] if not subnets.get(subnet_id): subnets[subnet_id] = {subnet_id: utils.get_subnet( subnet_id)} return parent_ports, subports, subnets