Exemplo n.º 1
0
    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
Exemplo n.º 2
0
    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'])
Exemplo n.º 3
0
    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)
Exemplo n.º 4
0
    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)
Exemplo n.º 5
0
    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)
Exemplo n.º 6
0
    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'])
Exemplo n.º 7
0
    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)
Exemplo n.º 8
0
    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
Exemplo n.º 9
0
    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'])