Add a "GROUP BY" clause on queries with RBAC entries

As reported in the Neutron patch [1], this change introduce a
"GROUP BY" clause on the SQL queries with RBAC entries. With [1],
all resouces with RBAC entries ('network', 'qospolicy',
'securitygroup', 'addressscope', 'subnetpool', 'addressgroup') will
load the RBAC entries with "joined" strategy.

Because of the low cardinality of the RBAC query when all the RBAC
registers are in one single project, this patch groups the resource
queries by the resource ID. That will reduce the results returned by
the SQL engine to only the singular registers required.

[1]https://review.opendev.org/c/openstack/neutron/+/884877

Related-Bug: #1918145
Change-Id: I800e0356714d59ba93ab6252c77be0a82f024055
This commit is contained in:
Rodolfo Alonso Hernandez 2023-05-28 17:43:30 +02:00
parent 64cfdacdc1
commit 829e97024c

View File

@ -108,6 +108,7 @@ def query_with_hooks(context, model, field=None, lazy_fields=None):
:param lazy_fields: list of fields for lazy loading
:returns: The query with hooks applied to it.
"""
group_by = None
if field:
if hasattr(model, field):
field = getattr(model, field)
@ -129,6 +130,11 @@ def query_with_hooks(context, model, field=None, lazy_fields=None):
[constants.ACCESS_SHARED, constants.ACCESS_READONLY]) &
((rbac_model.target_project == context.tenant_id) |
(rbac_model.target_project == '*'))))
# This "group_by" clause will limit the number of registers
# returned by the query, avoiding the problem of the low SQL
# query cardinality when the RBAC registers are in the requested
# project ID.
group_by = model.id
elif hasattr(model, 'shared'):
query_filter = ((model.tenant_id == context.tenant_id) |
(model.shared == sql.true()))
@ -149,6 +155,9 @@ def query_with_hooks(context, model, field=None, lazy_fields=None):
if query_filter is not None:
query = query.filter(query_filter)
if group_by:
query = query.group_by(group_by)
if lazy_fields:
for field in lazy_fields:
query = query.options(lazyload(field))