Merge "Add methods to populate/free subport pools"

This commit is contained in:
Jenkins 2017-09-08 08:17:54 +00:00 committed by Gerrit Code Review
commit e2adbc70cc
4 changed files with 137 additions and 23 deletions

View File

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

View File

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

View File

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

View File

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