Merge "Optimize queries for port operations" into stable/xena

This commit is contained in:
Zuul 2022-06-21 12:45:02 +00:00 committed by Gerrit Code Review
commit d4acd8f95f
4 changed files with 133 additions and 25 deletions

View File

@ -364,12 +364,17 @@ class Subnet(base.NeutronDbObject):
:raises: FixedIpsSubnetsNotOnSameSegment
"""
segment_ids = []
subnets = query.all()
for fixed_ip in fixed_ips:
subnet = None
if 'subnet_id' in fixed_ip:
try:
subnet = query.filter(
cls.db_model.id == fixed_ip['subnet_id']).all()[0]
subnet = [
sub
for sub in subnets
if sub['id'] == fixed_ip['subnet_id']
][0]
except IndexError:
# NOTE(hjensas): The subnet is invalid for the network,
# return all subnets. This will be detected in following
@ -378,7 +383,7 @@ class Subnet(base.NeutronDbObject):
elif 'ip_address' in fixed_ip:
ip = netaddr.IPNetwork(fixed_ip['ip_address'])
for s in query.all():
for s in subnets:
if ip in netaddr.IPNetwork(s.cidr):
subnet = s
break

View File

@ -237,27 +237,46 @@ class OVNClient(object):
parent_name = binding_prof.get('parent_name', [])
tag = binding_prof.get('tag', [])
address = port['mac_address']
for ip in port.get('fixed_ips', []):
try:
subnet = self._plugin.get_subnet(context, ip['subnet_id'])
except n_exc.SubnetNotFound:
continue
ip_addr = ip['ip_address']
address += ' ' + ip_addr
cidrs += ' {}/{}'.format(ip['ip_address'],
subnet['cidr'].split('/')[1])
# Check if the port being created is a virtual port
parents = utils.get_virtual_port_parents(
self._nb_idl, ip_addr, port['network_id'], port['id'])
if not parents:
continue
ip_subnets = port.get('fixed_ips', [])
subnet_ids = [
ip['subnet_id']
for ip in ip_subnets
if 'subnet_id' in ip
]
subnets = self._plugin.get_subnets(
context, filters={'id': subnet_ids})
if subnets:
for ip in ip_subnets:
ip_addr = ip['ip_address']
address += ' ' + ip_addr
subnet = None
port_type = ovn_const.LSP_TYPE_VIRTUAL
options[ovn_const.LSP_OPTIONS_VIRTUAL_IP_KEY] = ip_addr
options[ovn_const.LSP_OPTIONS_VIRTUAL_PARENTS_KEY] = (
','.join(parents))
break
try:
subnet = [
sub
for sub in subnets
if sub["id"] == ip["subnet_id"]
][0]
except IndexError:
LOG.debug('Subnet not found for ip address %s',
ip_addr)
continue
cidrs += ' {}/{}'.format(ip['ip_address'],
subnet['cidr'].split('/')[1])
# Check if the port being created is a virtual port
parents = utils.get_virtual_port_parents(
self._nb_idl, ip_addr, port['network_id'], port['id'])
if not parents:
continue
port_type = ovn_const.LSP_TYPE_VIRTUAL
options[ovn_const.LSP_OPTIONS_VIRTUAL_IP_KEY] = ip_addr
options[ovn_const.LSP_OPTIONS_VIRTUAL_PARENTS_KEY] = (
','.join(parents))
break
# Only adjust the OVN type if the port is not owned by Neutron
# DHCP agents.
@ -565,9 +584,14 @@ class OVNClient(object):
if self.is_metadata_port(port):
context = n_context.get_admin_context()
network = self._plugin.get_network(context, port['network_id'])
subnet_ids = set(_ip['subnet_id'] for _ip in port['fixed_ips'])
for subnet_id in subnet_ids:
subnet = self._plugin.get_subnet(context, subnet_id)
subnet_ids = [
_ip['subnet_id']
for _ip in port['fixed_ips']
if 'subnet_id' in _ip
]
for subnet in self._plugin.get_subnets(
context, filters={'id': subnet_ids}):
if not subnet['enable_dhcp']:
continue
self._update_subnet_dhcp_options(subnet, network, txn)

View File

@ -268,6 +268,26 @@ class SubnetDbObjectTestCase(obj_test_base.BaseDbObjectTestCase,
self.assertEqual([service_type_obj.service_type],
obj1.service_types)
def test_find_candidate_subnets(self):
network = self._create_test_network()
subnet_data = dict(self.obj_fields[0])
subnet_data['network_id'] = network['id']
subnet_net = self._make_object(subnet_data)
subnet2_data = dict(self.obj_fields[0])
subnet2_data['id'] = uuidutils.generate_uuid()
subnet2_data['network_id'] = network['id']
subnet2_net = self._make_object(subnet2_data)
subnet_net.create()
subnet2_net.create()
fixed_ips = [
{'subnet_id': subnet_data['id'], 'ip_address': '10.0.0.2'},
{'subnet_id': subnet2_data['id'], 'ip_address': '10.0.1.2'}]
candidate_subnet = subnet.Subnet.find_candidate_subnets(
self.context, network['id'], None, None, True, fixed_ips)
self.assertEqual(2, len(candidate_subnet))
self.assertNotEqual(
candidate_subnet[0]['id'], candidate_subnet[1]['id'])
class NetworkSubnetLockTestCase(obj_test_base.BaseObjectIfaceTestCase):

View File

@ -1727,6 +1727,65 @@ class TestOVNMechanismDriver(TestOVNMechanismDriverBase):
context.current, context.network.current, mock.ANY)
umd.assert_called_once_with(mock.ANY, 'id', subnet=subnet)
def test__get_port_options(self):
with mock.patch.object(self.mech_driver._plugin, 'get_subnets') as \
mock_get_subnets:
port = {'id': 'virt-port',
'mac_address': '00:00:00:00:00:00',
'device_owner': 'device_owner',
'network_id': 'foo',
'fixed_ips': [{'subnet_id': 'subnet-1',
'ip_address': '10.0.0.55'},
{'subnet_id': 'subnet-2',
'ip_address': '10.0.1.55'},
]}
subnet_ids = [
ip['subnet_id']
for ip in port.get('fixed_ips')
]
self.mech_driver._ovn_client._get_port_options(port)
mock_get_subnets.assert_called_once_with(
mock.ANY,
filters={'id': subnet_ids})
def test_update_port(self):
with mock.patch.object(
self.mech_driver._ovn_client, 'is_metadata_port') as \
mock_is_metadata_port, \
mock.patch.object(self.mech_driver._plugin, 'get_subnets') as \
mock_get_subnets, \
mock.patch.object(self.mech_driver._plugin, 'get_network') as \
mock_get_network:
net_attrs = {az_def.AZ_HINTS: ['az0', 'az1', 'az2']}
fake_net = (
fakes.FakeNetwork.create_one_network(attrs=net_attrs).info())
port = {'id': 'virt-port',
'mac_address': '00:00:00:00:00:00',
'name': 'port-foo',
'device_id': 'device_id-foo',
'project_id': 'project_id-foo',
'device_owner': 'device_owner',
'network_id': 'foo',
'admin_state_up': True,
'fixed_ips': [{'subnet_id': 'subnet-1',
'ip_address': '10.0.0.55'},
{'subnet_id': 'subnet-2',
'ip_address': '10.0.1.55'},
]}
subnet_ids = [
ip['subnet_id']
for ip in port.get('fixed_ips')
]
mock_is_metadata_port.return_value = [True]
mock_get_network.return_value = fake_net
self.mech_driver._ovn_client.update_port(
self.context, port)
self.assertEqual(mock_get_subnets.call_count, 2)
mock_get_subnets.assert_called_with(
mock.ANY,
filters={'id': subnet_ids})
def test_update_metadata_port_with_subnet(self):
ovn_conf.cfg.CONF.set_override('ovn_metadata_enabled', True,
group='ovn')