Fix VRF subnets DB query

The patch in [0] created a DB query to support a new no-NAT CIDRs
extension. This DB query was incorrect, as it used unrelated joins.
This patch fixes the DB query to ensure related joins are used.

There also was an issue with the _query_vrf_subnets method before
the extension was added. It was possible that a single subnetpool
with multiple prefixes could have been used to allocate multiple
subnets. The current query would have returned the same subnetpool
ID for each prefix, leading to duplicates in the returned list. This
patch fixes that issue by ensuring that the returned values from
the query are distinct.

[0]: https://review.opendev.org/c/x/group-based-policy/+/875317

Change-Id: I7870ad58bc4d9098b4aa12a0cefbfe027d982564
This commit is contained in:
Thomas Bachman 2023-03-08 01:33:56 +00:00
parent 7d722bae8e
commit b7a5445e7b
1 changed files with 23 additions and 15 deletions

View File

@ -858,12 +858,12 @@ class ApicRpcHandlerMixin(object):
# address_scopes, and if so, return the subnetpool CIDRs
# associated with those address_scopes.
result = []
sub_ids = []
net_ids = []
sub_ids = []
subpool_ids = []
query = BAKERY(lambda s: s.query(
models_v2.SubnetPoolPrefix.cidr,
models_v2.Subnet.id,
models_v2.Network.id))
models_v2.SubnetPoolPrefix.subnetpool_id))
query += lambda q: q.join(
models_v2.SubnetPool,
models_v2.SubnetPool.id ==
@ -872,25 +872,33 @@ class ApicRpcHandlerMixin(object):
db.AddressScopeMapping,
db.AddressScopeMapping.scope_id ==
models_v2.SubnetPool.address_scope_id)
query += lambda q: q.join(
db.NetworkMapping,
db.NetworkMapping.network_id ==
models_v2.Network.id)
query += lambda q: q.filter(
db.AddressScopeMapping.vrf_name ==
sa.bindparam('vrf_name'),
db.AddressScopeMapping.vrf_tenant_name ==
sa.bindparam('vrf_tenant_name'),
db.NetworkMapping.vrf_name ==
sa.bindparam('vrf_name'),
db.NetworkMapping.vrf_tenant_name ==
sa.bindparam('vrf_tenant_name'))
for cidr, sub_id, net_id in query(session).params(vrf_name=vrf_name,
vrf_tenant_name=vrf_tenant_name).all():
query += lambda q: q.distinct()
for cidr, subpool_id in query(session).params(vrf_name=vrf_name,
vrf_tenant_name=vrf_tenant_name).all():
result.append(cidr)
sub_ids.append(sub_id)
net_ids.append(net_id)
subpool_ids.append(subpool_id)
if result:
# We need a list of subnets to query for the no-NAT CIDRs,
# and also a list of networks that might have this extension.
query = BAKERY(lambda s: s.query(
models_v2.Subnet.id,
models_v2.Subnet.network_id))
query += lambda q: q.join(
models_v2.SubnetPool,
models_v2.SubnetPool.id ==
models_v2.Subnet.subnetpool_id)
query += lambda q: q.filter(
models_v2.Subnet.subnetpool_id.in_(
sa.bindparam('subpool_ids', expanding=True)))
for sub_id, net_id in query(session).params(
subpool_ids=subpool_ids).all():
sub_ids.append(sub_id)
net_ids.append(net_id)
# query to fetch no nat cidrs extension from the networks
if not ext_net_info:
ext_net_info = self._query_endpoint_ext_net_info(