Merge "Add methods to populate/free subport pools"
This commit is contained in:
commit
e2adbc70cc
|
@ -46,7 +46,7 @@ class NestedVlanPodVIFDriver(nested_vif.NestedPodVIFDriver):
|
|||
return ovu.neutron_to_osvif_vif_nested_vlan(port, subnets, vlan_id)
|
||||
|
||||
def request_vifs(self, pod, project_id, subnets, security_groups,
|
||||
num_ports):
|
||||
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
|
||||
|
@ -61,7 +61,10 @@ class NestedVlanPodVIFDriver(nested_vif.NestedPodVIFDriver):
|
|||
exception is raised.
|
||||
"""
|
||||
neutron = clients.get_neutron_client()
|
||||
parent_port = self._get_parent_port(neutron, pod)
|
||||
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(
|
||||
|
@ -116,7 +119,6 @@ class NestedVlanPodVIFDriver(nested_vif.NestedPodVIFDriver):
|
|||
def _get_port_request(self, pod, project_id, subnets, security_groups,
|
||||
unbound=False):
|
||||
port_req_body = {'project_id': project_id,
|
||||
'name': self._get_port_name(pod),
|
||||
'network_id': self._get_network_id(subnets),
|
||||
'fixed_ips': ovu.osvif_to_neutron_fixed_ips(subnets),
|
||||
'device_owner': kl_const.DEVICE_OWNER,
|
||||
|
@ -124,6 +126,8 @@ class NestedVlanPodVIFDriver(nested_vif.NestedPodVIFDriver):
|
|||
|
||||
if unbound:
|
||||
port_req_body['name'] = 'available-port'
|
||||
else:
|
||||
port_req_body['name'] = self._get_port_name(pod)
|
||||
|
||||
if security_groups:
|
||||
port_req_body['security_groups'] = security_groups
|
||||
|
|
|
@ -348,6 +348,21 @@ class NestedVIFPool(BaseVIFPool):
|
|||
return parent_port['fixed_ips'][0]['ip_address']
|
||||
|
||||
def _recover_precreated_ports(self):
|
||||
self._precreated_ports(action='recover')
|
||||
|
||||
def _remove_precreated_ports(self, trunk_ips=None):
|
||||
self._precreated_ports(action='free', trunk_ips=trunk_ips)
|
||||
|
||||
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
|
||||
|
@ -369,6 +384,9 @@ class NestedVIFPool(BaseVIFPool):
|
|||
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:
|
||||
|
@ -379,11 +397,67 @@ class NestedVIFPool(BaseVIFPool):
|
|||
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'])
|
||||
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'])
|
||||
|
||||
def force_populate_pool(self, trunk_ip, project_id, subnets,
|
||||
security_groups, num_ports):
|
||||
"""Create a given amount of subports at a given trunk port.
|
||||
|
||||
This function creates a given amount of subports and attaches them to
|
||||
the specified trunk, adding them to the related subports pool
|
||||
regardless of the amount of subports already available in the pool.
|
||||
"""
|
||||
vifs = self._drv_vif.request_vifs(
|
||||
pod=[],
|
||||
project_id=project_id,
|
||||
subnets=subnets,
|
||||
security_groups=security_groups,
|
||||
num_ports=num_ports,
|
||||
trunk_ip=trunk_ip)
|
||||
|
||||
pool_key = (trunk_ip, project_id, tuple(sorted(security_groups)))
|
||||
for vif in vifs:
|
||||
self._existing_vifs[vif.id] = vif
|
||||
self._available_ports_pools.setdefault(pool_key,
|
||||
[]).append(vif.id)
|
||||
|
||||
def free_pool(self, trunk_ips=None):
|
||||
"""Removes subports from the pool and deletes neutron port resource.
|
||||
|
||||
This function empties the pool of available subports and removes the
|
||||
neutron port resources of the specified trunk port (or all of them if
|
||||
no trunk is specified).
|
||||
"""
|
||||
self._remove_precreated_ports(trunk_ips)
|
||||
|
|
|
@ -356,7 +356,10 @@ class TestNestedVlanPodVIFDriver(test_base.TestCase):
|
|||
security_groups, unbound)
|
||||
|
||||
self.assertEqual(expected, ret)
|
||||
m_driver._get_port_name.assert_called_once_with(pod)
|
||||
if unbound:
|
||||
m_driver._get_port_name.assert_not_called()
|
||||
else:
|
||||
m_driver._get_port_name.assert_called_once_with(pod)
|
||||
m_driver._get_network_id.assert_called_once_with(subnets)
|
||||
m_to_fips.assert_called_once_with(subnets)
|
||||
|
||||
|
|
|
@ -957,7 +957,7 @@ class NestedVIFPool(test_base.TestCase):
|
|||
'neutron_to_osvif_vif_nested_vlan')
|
||||
@mock.patch('kuryr_kubernetes.controller.drivers.default_subnet.'
|
||||
'_get_subnet')
|
||||
def test__recover_precreated_ports(self, m_get_subnet, m_to_osvif):
|
||||
def test__precreated_ports_recover(self, m_get_subnet, m_to_osvif):
|
||||
cls = vif_pool.NestedVIFPool
|
||||
m_driver = mock.MagicMock(spec=cls)
|
||||
neutron = self.useFixture(k_fix.MockNeutronClient()).client
|
||||
|
@ -975,15 +975,45 @@ class NestedVIFPool(test_base.TestCase):
|
|||
m_get_subnet.return_value = mock.sentinel.subnet
|
||||
m_to_osvif.return_value = mock.sentinel.vif
|
||||
|
||||
cls._recover_precreated_ports(m_driver)
|
||||
cls._precreated_ports(m_driver, 'recover')
|
||||
neutron.list_trunks.assert_called_once()
|
||||
m_driver._get_parent_port_ip.assert_called_with(trunk_id)
|
||||
|
||||
def test__precreated_ports_free(self):
|
||||
cls = vif_pool.NestedVIFPool
|
||||
m_driver = mock.MagicMock(spec=cls)
|
||||
neutron = self.useFixture(k_fix.MockNeutronClient()).client
|
||||
cls_vif_driver = nested_vlan_vif.NestedVlanPodVIFDriver
|
||||
vif_driver = mock.MagicMock(spec=cls_vif_driver)
|
||||
m_driver._drv_vif = vif_driver
|
||||
|
||||
port_id = mock.sentinel.port_id
|
||||
host_addr = mock.sentinel.host_addr
|
||||
|
||||
subport_obj = get_port_obj(port_id=port_id,
|
||||
device_owner='trunk:subport')
|
||||
m_driver._get_ports_by_attrs.side_effect = [[subport_obj], []]
|
||||
trunk_id = mock.sentinel.trunk_id
|
||||
trunk_obj = self._get_trunk_obj(port_id=trunk_id, subport_id=port_id)
|
||||
pool_key = (host_addr, subport_obj['id'],
|
||||
tuple(subport_obj['security_groups']))
|
||||
m_driver._available_ports_pools = {pool_key: port_id}
|
||||
|
||||
neutron.list_trunks.return_value = {'trunks': [trunk_obj]}
|
||||
m_driver._get_parent_port_ip.return_value = host_addr
|
||||
|
||||
cls._precreated_ports(m_driver, 'free')
|
||||
neutron.list_trunks.assert_called_once()
|
||||
m_driver._get_parent_port_ip.assert_called_with(trunk_id)
|
||||
m_driver._drv_vif._remove_subport.assert_called_once()
|
||||
neutron.delete_port.assert_called_once()
|
||||
m_driver._drv_vif._release_vlan_id.assert_called_once()
|
||||
|
||||
@mock.patch('kuryr_kubernetes.os_vif_util.'
|
||||
'neutron_to_osvif_vif_nested_vlan')
|
||||
@mock.patch('kuryr_kubernetes.controller.drivers.default_subnet.'
|
||||
'_get_subnet')
|
||||
def test__recover_precreated_ports_several_trunks(self, m_get_subnet,
|
||||
def test__precreated_ports_recover_several_trunks(self, m_get_subnet,
|
||||
m_to_osvif):
|
||||
cls = vif_pool.NestedVIFPool
|
||||
m_driver = mock.MagicMock(spec=cls)
|
||||
|
@ -1013,7 +1043,7 @@ class NestedVIFPool(test_base.TestCase):
|
|||
m_get_subnet.return_value = subnet
|
||||
m_to_osvif.return_value = mock.sentinel.vif
|
||||
|
||||
cls._recover_precreated_ports(m_driver)
|
||||
cls._precreated_ports(m_driver, 'recover')
|
||||
neutron.list_trunks.asser_called_once()
|
||||
m_driver._get_parent_port_ip.assert_has_calls([mock.call(trunk_id1),
|
||||
mock.call(trunk_id2)])
|
||||
|
@ -1027,7 +1057,7 @@ class NestedVIFPool(test_base.TestCase):
|
|||
'neutron_to_osvif_vif_nested_vlan')
|
||||
@mock.patch('kuryr_kubernetes.controller.drivers.default_subnet.'
|
||||
'_get_subnet')
|
||||
def test__recover_precreated_ports_several_subports(self, m_get_subnet,
|
||||
def test__precreated_ports_recover_several_subports(self, m_get_subnet,
|
||||
m_to_osvif):
|
||||
cls = vif_pool.NestedVIFPool
|
||||
m_driver = mock.MagicMock(spec=cls)
|
||||
|
@ -1055,7 +1085,7 @@ class NestedVIFPool(test_base.TestCase):
|
|||
m_get_subnet.return_value = subnet
|
||||
m_to_osvif.return_value = mock.sentinel.vif
|
||||
|
||||
cls._recover_precreated_ports(m_driver)
|
||||
cls._precreated_ports(m_driver, 'recover')
|
||||
neutron.list_trunks.asser_called_once()
|
||||
m_driver._get_parent_port_ip.assert_called_once_with(trunk_id)
|
||||
calls = [mock.call(port1, {port1['fixed_ips'][0]['subnet_id']: subnet},
|
||||
|
@ -1064,17 +1094,19 @@ class NestedVIFPool(test_base.TestCase):
|
|||
trunk_obj['sub_ports'][1]['segmentation_id'])]
|
||||
m_to_osvif.assert_has_calls(calls)
|
||||
|
||||
def test__recover_precreated_ports_no_ports_to_recover(self):
|
||||
@ddt.data(('recover'), ('free'))
|
||||
def test__precreated_ports_no_ports(self, m_action):
|
||||
cls = vif_pool.NestedVIFPool
|
||||
m_driver = mock.MagicMock(spec=cls)
|
||||
neutron = self.useFixture(k_fix.MockNeutronClient()).client
|
||||
|
||||
m_driver._get_ports_by_attrs.return_value = []
|
||||
|
||||
cls._recover_precreated_ports(m_driver)
|
||||
cls._precreated_ports(m_driver, m_action)
|
||||
neutron.list_trunks.assert_not_called()
|
||||
|
||||
def test__recover_precreated_ports_no_trunks(self):
|
||||
@ddt.data(('recover'), ('free'))
|
||||
def test__precreated_ports_no_trunks(self, m_action):
|
||||
cls = vif_pool.NestedVIFPool
|
||||
m_driver = mock.MagicMock(spec=cls)
|
||||
neutron = self.useFixture(k_fix.MockNeutronClient()).client
|
||||
|
@ -1083,11 +1115,12 @@ class NestedVIFPool(test_base.TestCase):
|
|||
device_owner='trunk:subport')], []]
|
||||
neutron.list_trunks.return_value = {'trunks': []}
|
||||
|
||||
cls._recover_precreated_ports(m_driver)
|
||||
cls._precreated_ports(m_driver, m_action)
|
||||
neutron.list_trunks.assert_called()
|
||||
m_driver._get_parent_port_ip.assert_not_called()
|
||||
|
||||
def test__recover_precreated_ports_exception(self):
|
||||
@ddt.data(('recover'), ('free'))
|
||||
def test__precreated_ports_exception(self, m_action):
|
||||
cls = vif_pool.NestedVIFPool
|
||||
m_driver = mock.MagicMock(spec=cls)
|
||||
neutron = self.useFixture(k_fix.MockNeutronClient()).client
|
||||
|
@ -1100,6 +1133,6 @@ class NestedVIFPool(test_base.TestCase):
|
|||
neutron.list_trunks.return_value = {'trunks': [trunk_obj]}
|
||||
m_driver._get_parent_port_ip.side_effect = n_exc.PortNotFoundClient
|
||||
|
||||
self.assertIsNone(cls._recover_precreated_ports(m_driver))
|
||||
self.assertIsNone(cls._precreated_ports(m_driver, m_action))
|
||||
neutron.list_trunks.assert_called()
|
||||
m_driver._get_parent_port_ip.assert_called_with(trunk_id)
|
||||
|
|
Loading…
Reference in New Issue