Merge "Optimize the SG rule retrieval"

This commit is contained in:
Zuul 2024-10-14 16:26:18 +00:00 committed by Gerrit Code Review
commit 9ef180e524
2 changed files with 51 additions and 27 deletions

View File

@ -44,6 +44,7 @@ from neutron.extensions import security_groups_default_rules as \
from neutron.extensions import securitygroup as ext_sg from neutron.extensions import securitygroup as ext_sg
from neutron.objects import base as base_obj from neutron.objects import base as base_obj
from neutron.objects import ports as port_obj from neutron.objects import ports as port_obj
from neutron.objects import rbac_db as rbac_db_obj
from neutron.objects import securitygroup as sg_obj from neutron.objects import securitygroup as sg_obj
from neutron.objects import securitygroup_default_rules as sg_default_rules_obj from neutron.objects import securitygroup_default_rules as sg_default_rules_obj
from neutron import quota from neutron import quota
@ -131,8 +132,8 @@ class SecurityGroupDbMixin(
# be used here otherwise, SG will not be found and error 500 will # be used here otherwise, SG will not be found and error 500 will
# be returned through the API # be returned through the API
get_context = context.elevated() if default_sg else context get_context = context.elevated() if default_sg else context
sg = sg_obj.SecurityGroup.get_object(get_context, id=sg.id) sg = self._get_security_group(get_context, sg.id)
secgroup_dict = self._make_security_group_dict(sg) secgroup_dict = self._make_security_group_dict(context, sg)
self._registry_publish(resources.SECURITY_GROUP, self._registry_publish(resources.SECURITY_GROUP,
events.PRECOMMIT_CREATE, events.PRECOMMIT_CREATE,
exc_cls=ext_sg.SecurityGroupConflict, exc_cls=ext_sg.SecurityGroupConflict,
@ -174,9 +175,10 @@ class SecurityGroupDbMixin(
sg_objs = sg_obj.SecurityGroup.get_objects( sg_objs = sg_obj.SecurityGroup.get_objects(
context, _pager=pager, validate_filters=False, context, _pager=pager, validate_filters=False,
fields=fields, **filters) fields=fields, return_db_obj=True, **filters)
return [self._make_security_group_dict(obj, fields) for obj in sg_objs] return [self._make_security_group_dict(context, obj, fields)
for obj in sg_objs]
@db_api.retry_if_session_inactive() @db_api.retry_if_session_inactive()
def get_security_groups_count(self, context, filters=None): def get_security_groups_count(self, context, filters=None):
@ -195,8 +197,8 @@ class SecurityGroupDbMixin(
try: try:
with db_api.CONTEXT_READER.using(context): with db_api.CONTEXT_READER.using(context):
ret = self._make_security_group_dict(self._get_security_group( sg = self._get_security_group(context, id, fields=fields)
context, id, fields=fields), fields) ret = self._make_security_group_dict(context, sg, fields)
if (fields is None or len(fields) == 0 or if (fields is None or len(fields) == 0 or
'security_group_rules' in fields): 'security_group_rules' in fields):
rules = self.get_security_group_rules( rules = self.get_security_group_rules(
@ -209,12 +211,21 @@ class SecurityGroupDbMixin(
context.tenant_id = tmp_context_tenant_id context.tenant_id = tmp_context_tenant_id
return ret return ret
def _get_security_group(self, context, id, fields=None): @staticmethod
sg = sg_obj.SecurityGroup.get_object(context, fields=fields, id=id) def _get_security_group(context, _id, fields=None):
sg = sg_obj.SecurityGroup.get_object(context, fields=fields, id=_id)
if sg is None: if sg is None:
raise ext_sg.SecurityGroupNotFound(id=id) raise ext_sg.SecurityGroupNotFound(id=_id)
return sg return sg
@staticmethod
def _get_security_group_db(context, _id, fields=None):
sg_db = sg_obj.SecurityGroup.get_object(
context, fields=fields, id=_id, return_db_obj=True)
if sg_db is None:
raise ext_sg.SecurityGroupNotFound(id=_id)
return sg_db
def _check_security_group(self, context, id, tenant_id=None): def _check_security_group(self, context, id, tenant_id=None):
if tenant_id: if tenant_id:
tmp_context_tenant_id = context.tenant_id tmp_context_tenant_id = context.tenant_id
@ -258,7 +269,7 @@ class SecurityGroupDbMixin(
# consistency with deleted rules # consistency with deleted rules
sg = self._get_security_group(context, id) sg = self._get_security_group(context, id)
sgr_ids = [r['id'] for r in sg.rules] sgr_ids = [r['id'] for r in sg.rules]
sec_group = self._make_security_group_dict(sg) sec_group = self._make_security_group_dict(context, sg)
self._registry_publish(resources.SECURITY_GROUP, self._registry_publish(resources.SECURITY_GROUP,
events.PRECOMMIT_DELETE, events.PRECOMMIT_DELETE,
exc_cls=ext_sg.SecurityGroupInUse, exc_cls=ext_sg.SecurityGroupInUse,
@ -282,8 +293,8 @@ class SecurityGroupDbMixin(
if 'stateful' in s: if 'stateful' in s:
with db_api.CONTEXT_READER.using(context): with db_api.CONTEXT_READER.using(context):
sg = self._get_security_group(context, id) sg_db = self._get_security_group_db(context, id)
if s['stateful'] != sg['stateful']: if s['stateful'] != sg_db['stateful']:
filters = {'security_group_id': [id]} filters = {'security_group_id': [id]}
ports = self._get_port_security_group_bindings(context, ports = self._get_port_security_group_bindings(context,
filters) filters)
@ -299,11 +310,11 @@ class SecurityGroupDbMixin(
sg = self._get_security_group(context, id) sg = self._get_security_group(context, id)
if sg.name == 'default' and 'name' in s: if sg.name == 'default' and 'name' in s:
raise ext_sg.SecurityGroupCannotUpdateDefault() raise ext_sg.SecurityGroupCannotUpdateDefault()
sg_dict = self._make_security_group_dict(sg) sg_dict = self._make_security_group_dict(context, sg)
original_security_group = sg_dict original_security_group = sg_dict
sg.update_fields(s) sg.update_fields(s)
sg.update() sg.update()
sg_dict = self._make_security_group_dict(sg) sg_dict = self._make_security_group_dict(context, sg)
self._registry_publish( self._registry_publish(
resources.SECURITY_GROUP, resources.SECURITY_GROUP,
events.PRECOMMIT_UPDATE, events.PRECOMMIT_UPDATE,
@ -320,24 +331,33 @@ class SecurityGroupDbMixin(
return sg_dict return sg_dict
def _make_security_group_dict(self, security_group, fields=None): def _make_security_group_dict(self, context, security_group, fields=None):
"""Return the security group in a dictionary
:param context: Neutron API request context.
:param security_group: DB object or OVO of the security group.
:param fields: list of fields to filter the returned dictionary.
:return: a dictionary with the security group definition.
"""
rules = security_group.rules or []
if isinstance(security_group, sg_obj.SecurityGroup):
shared = security_group.shared
security_group = security_group.db_obj
else:
rbac_entries = security_group['rbac_entries']
shared = rbac_db_obj.RbacNeutronDbObjectMixin.is_network_shared(
context, rbac_entries)
res = {'id': security_group['id'], res = {'id': security_group['id'],
'name': security_group['name'], 'name': security_group['name'],
'stateful': security_group['stateful'], 'stateful': security_group['stateful'],
'tenant_id': security_group['tenant_id'], 'tenant_id': security_group['tenant_id'],
'description': security_group['description'], 'description': security_group['description'],
'standard_attr_id': security_group.db_obj.standard_attr_id, 'standard_attr_id': security_group.standard_attr_id,
'shared': security_group['shared'], 'shared': shared,
'security_group_rules': [self._make_security_group_rule_dict(r)
for r in rules],
} }
if security_group.rules: resource_extend.apply_funcs(ext_sg.SECURITYGROUPS, res, security_group)
res['security_group_rules'] = [
self._make_security_group_rule_dict(r)
for r in security_group.rules
]
else:
res['security_group_rules'] = []
resource_extend.apply_funcs(ext_sg.SECURITYGROUPS, res,
security_group.db_obj)
return db_utils.resource_fields(res, fields) return db_utils.resource_fields(res, fields)
@staticmethod @staticmethod

View File

@ -608,7 +608,7 @@ class NeutronDbObject(NeutronObject, metaclass=DeclarativeObject):
return db_api.CONTEXT_READER.using(context) return db_api.CONTEXT_READER.using(context)
@classmethod @classmethod
def get_object(cls, context, fields=None, **kwargs): def get_object(cls, context, fields=None, return_db_obj=False, **kwargs):
"""Fetch a single object """Fetch a single object
Return the first result of given context or None if the result doesn't Return the first result of given context or None if the result doesn't
@ -620,6 +620,8 @@ class NeutronDbObject(NeutronObject, metaclass=DeclarativeObject):
avoid loading synthetic fields when possible, and avoid loading synthetic fields when possible, and
does not affect db queries. Default is None, which does not affect db queries. Default is None, which
is the same as []. Example: ['id', 'name'] is the same as []. Example: ['id', 'name']
:param return_db_obj: return the DB model object instead of loading
the OVO; that could save some time.
:param kwargs: multiple keys defined by key=value pairs :param kwargs: multiple keys defined by key=value pairs
:return: single object of NeutronDbObject class or None :return: single object of NeutronDbObject class or None
""" """
@ -633,6 +635,8 @@ class NeutronDbObject(NeutronObject, metaclass=DeclarativeObject):
with cls.db_context_reader(context): with cls.db_context_reader(context):
db_obj = obj_db_api.get_object( db_obj = obj_db_api.get_object(
cls, context, **cls.modify_fields_to_db(kwargs)) cls, context, **cls.modify_fields_to_db(kwargs))
if return_db_obj:
return db_obj
if db_obj: if db_obj:
return cls._load_object(context, db_obj, fields=fields) return cls._load_object(context, db_obj, fields=fields)