Merge "Implement `get_subnets_address_scopes` method"

This commit is contained in:
Zuul 2023-06-01 21:30:45 +00:00 committed by Gerrit Code Review
commit 5bce1ff51a
3 changed files with 105 additions and 20 deletions

View File

@ -857,6 +857,48 @@ def get_ovn_chassis_other_config(chassis):
return chassis.external_ids
def get_subnets_address_scopes(context, subnets, fixed_ips, ml2_plugin):
"""Returns the IPv4 and IPv6 address scopes of several subnets.
The subnets hosted on the same network must be allocated from the same
subnet pool (from ``NetworkSubnetPoolAffinityError`` exception). That
applies per IP version (it means it is possible to have two subnet pools,
one for IPv4 and one for IPv6).
:param context: neutron api request context
:param subnets: (list of dict) subnet dictionaries
:param fixed_ips: (list of dict) fixed IPs of several subnets (usually
belonging to a network but not mandatory)
:param ml2_plugin: (``Ml2Plugin``) ML2 plugin instance
:return: (tuple of 2 strings) IPv4 and IPv6 address scope IDs
"""
address4_scope_id, address6_scope_id = '', ''
if not subnets:
return address4_scope_id, address6_scope_id
subnets_by_id = {subnet['id']: subnet for subnet in subnets}
for fixed_ip in fixed_ips:
subnet_id = fixed_ip.get('subnet_id')
subnet = subnets_by_id.get(subnet_id)
if not subnet or not subnet['subnetpool_id']:
continue
try:
subnet_pool = ml2_plugin.get_subnetpool(context,
id=subnet['subnetpool_id'])
if subnet_pool['address_scope_id']:
if subnet_pool['ip_version'] == const.IP_VERSION_4:
address4_scope_id = subnet_pool['address_scope_id']
else:
address6_scope_id = subnet_pool['address_scope_id']
except n_exc.SubnetPoolNotFound:
# swallow the exception and just continue if the
# lookup failed
pass
return address4_scope_id, address6_scope_id
def sync_ha_chassis_group(context, network_id, nb_idl, sb_idl, txn):
"""Return the UUID of the HA Chassis Group or the HA Chassis Group cmd.

View File

@ -307,6 +307,9 @@ class OVNClient(object):
]
subnets = self._plugin.get_subnets(
context, filters={'id': subnet_ids})
address4_scope_id, address6_scope_id = (
utils.get_subnets_address_scopes(context, subnets, ip_subnets,
self._plugin))
if subnets:
for ip in ip_subnets:
ip_addr = ip['ip_address']
@ -324,26 +327,6 @@ class OVNClient(object):
ip_addr)
continue
if subnet["subnetpool_id"]:
try:
subnet_pool = self._plugin.get_subnetpool(
context, id=subnet["subnetpool_id"]
)
if subnet_pool["address_scope_id"]:
ip_version = subnet_pool["ip_version"]
if ip_version == const.IP_VERSION_4:
address4_scope_id = subnet_pool[
"address_scope_id"
]
elif ip_version == const.IP_VERSION_6:
address6_scope_id = subnet_pool[
"address_scope_id"
]
except n_exc.SubnetPoolNotFound:
# swallow the exception and just continue if the
# lookup failed
pass
cidrs += ' {}/{}'.format(ip['ip_address'],
subnet['cidr'].split('/')[1])

View File

@ -23,6 +23,7 @@ import neutron_lib
from neutron_lib.api.definitions import extra_dhcp_opt as edo_ext
from neutron_lib.api.definitions import portbindings
from neutron_lib import constants as n_const
from neutron_lib import exceptions as n_exc
from oslo_concurrency import processutils
from oslo_config import cfg
import testtools
@ -943,3 +944,62 @@ class TestOvsdbClientCommand(base.BaseTestCase):
def test_run_bad_schema(self):
with testtools.ExpectedException(KeyError):
self.OvsdbClientTestCommand.run(['foo'])
class GetSubnetsAddressScopeTestCase(base.BaseTestCase):
def setUp(self):
super().setUp()
self.ml2_plugin = mock.Mock()
def test_no_subnets(self):
subnets = []
fixed_ips = mock.ANY
address4, address6 = utils.get_subnets_address_scopes(
mock.ANY, subnets, fixed_ips, self.ml2_plugin)
self.assertEqual(('', ''), (address4, address6))
def test_no_subnetpool(self):
subnets = [
{'id': 'subnet1', 'subnetpool_id': None},
{'id': 'subnet2', 'subnetpool_id': None},
]
fixed_ips = [
{'subnet_id': 'subnet1'},
{'subnet_id': 'subnet2'},
]
address4, address6 = utils.get_subnets_address_scopes(
mock.ANY, subnets, fixed_ips, self.ml2_plugin)
self.assertEqual(('', ''), (address4, address6))
def test_no_address_scope(self):
subnets = [
{'id': 'subnet1', 'subnetpool_id': 'pool_ipv4'},
{'id': 'subnet2', 'subnetpool_id': 'pool_ipv6'},
]
fixed_ips = [
{'subnet_id': 'subnet1'},
{'subnet_id': 'subnet2'},
]
self.ml2_plugin.get_subnetpool.side_effect = n_exc.SubnetPoolNotFound(
subnetpool_id='snp')
address4, address6 = utils.get_subnets_address_scopes(
mock.ANY, subnets, fixed_ips, self.ml2_plugin)
self.assertEqual(('', ''), (address4, address6))
def test_address_scope(self):
subnets = [
{'id': 'subnet1', 'subnetpool_id': 'pool_ipv4'},
{'id': 'subnet2', 'subnetpool_id': 'pool_ipv6'},
]
fixed_ips = [
{'subnet_id': 'subnet1'},
{'subnet_id': 'subnet2'},
]
self.ml2_plugin.get_subnetpool.side_effect = [
{'address_scope_id': 'scope4', 'ip_version': n_const.IP_VERSION_4},
{'address_scope_id': 'scope6', 'ip_version': n_const.IP_VERSION_6},
]
address4, address6 = utils.get_subnets_address_scopes(
mock.ANY, subnets, fixed_ips, self.ml2_plugin)
self.assertEqual(('scope4', 'scope6'), (address4, address6))