Improve the SG RPC callback `security_group_info_for_ports
`
This method populates the SG rules in a dictionary. Each SG rule inherits the "stateful" value of the SG. Prior to this patch, each SG rule was isuing a database call to retrieve the SG register. In this patch, the SG "stateful" retrieval is done in one database query for all SG. That improves the performance of this method reducing the database access to only one single call. This improvement, as commented in the LP bug, affects to ML2/LinuxBridge. ML2/OVS agent uses a cached RPC implementation that not requires to perform any RPC call/database query. Conflicts: neutron/objects/securitygroup.py Closes-Bug: #2045950 Change-Id: Iafd0419a1d1eeb25d5589edc2570ebf287450957 (cherry picked from commit6b6abb9698
) (cherry picked from commit7ac9edac80
)
This commit is contained in:
parent
0178671955
commit
6e26d9ed40
@ -431,6 +431,10 @@ class SecurityGroupServerAPIShim(sg_rpc_base.SecurityGroupInfoAPIMixin):
|
|||||||
for sg_id in p['security_group_ids']))
|
for sg_id in p['security_group_ids']))
|
||||||
return [(sg_id, ) for sg_id in sg_ids]
|
return [(sg_id, ) for sg_id in sg_ids]
|
||||||
|
|
||||||
def _is_security_group_stateful(self, context, sg_id):
|
def _get_sgs_stateful_flag(self, context, sg_ids):
|
||||||
|
sgs_stateful = {}
|
||||||
|
for sg_id in sg_ids:
|
||||||
sg = self.rcache.get_resource_by_id(resources.SECURITYGROUP, sg_id)
|
sg = self.rcache.get_resource_by_id(resources.SECURITYGROUP, sg_id)
|
||||||
return sg.stateful
|
sgs_stateful[sg_id] = sg.stateful
|
||||||
|
|
||||||
|
return sgs_stateful
|
||||||
|
@ -211,12 +211,10 @@ class SecurityGroupInfoAPIMixin(object):
|
|||||||
# this set will be serialized into a list by rpc code
|
# this set will be serialized into a list by rpc code
|
||||||
remote_address_group_info[remote_ag_id][ethertype] = set()
|
remote_address_group_info[remote_ag_id][ethertype] = set()
|
||||||
direction = rule_in_db['direction']
|
direction = rule_in_db['direction']
|
||||||
stateful = self._is_security_group_stateful(context,
|
|
||||||
security_group_id)
|
|
||||||
rule_dict = {
|
rule_dict = {
|
||||||
'direction': direction,
|
'direction': direction,
|
||||||
'ethertype': ethertype,
|
'ethertype': ethertype,
|
||||||
'stateful': stateful}
|
}
|
||||||
|
|
||||||
for key in ('protocol', 'port_range_min', 'port_range_max',
|
for key in ('protocol', 'port_range_min', 'port_range_max',
|
||||||
'remote_ip_prefix', 'remote_group_id',
|
'remote_ip_prefix', 'remote_group_id',
|
||||||
@ -234,6 +232,13 @@ class SecurityGroupInfoAPIMixin(object):
|
|||||||
if rule_dict not in sg_info['security_groups'][security_group_id]:
|
if rule_dict not in sg_info['security_groups'][security_group_id]:
|
||||||
sg_info['security_groups'][security_group_id].append(
|
sg_info['security_groups'][security_group_id].append(
|
||||||
rule_dict)
|
rule_dict)
|
||||||
|
|
||||||
|
# Populate the security group "stateful" flag in the SGs list of rules.
|
||||||
|
for sg_id, stateful in self._get_sgs_stateful_flag(
|
||||||
|
context, sg_info['security_groups'].keys()).items():
|
||||||
|
for rule in sg_info['security_groups'][sg_id]:
|
||||||
|
rule['stateful'] = stateful
|
||||||
|
|
||||||
# Update the security groups info if they don't have any rules
|
# Update the security groups info if they don't have any rules
|
||||||
sg_ids = self._select_sg_ids_for_ports(context, ports)
|
sg_ids = self._select_sg_ids_for_ports(context, ports)
|
||||||
for (sg_id, ) in sg_ids:
|
for (sg_id, ) in sg_ids:
|
||||||
@ -427,13 +432,13 @@ class SecurityGroupInfoAPIMixin(object):
|
|||||||
"""
|
"""
|
||||||
raise NotImplementedError()
|
raise NotImplementedError()
|
||||||
|
|
||||||
def _is_security_group_stateful(self, context, sg_id):
|
def _get_sgs_stateful_flag(self, context, sg_id):
|
||||||
"""Return whether the security group is stateful or not.
|
"""Return the security groups stateful flag.
|
||||||
|
|
||||||
Return True if the security group associated with the given ID
|
Returns a dictionary with the SG ID as key and the stateful flag:
|
||||||
is stateful, else False.
|
{sg_1: True, sg_2: False, ...}
|
||||||
"""
|
"""
|
||||||
return True
|
raise NotImplementedError()
|
||||||
|
|
||||||
|
|
||||||
class SecurityGroupServerRpcMixin(SecurityGroupInfoAPIMixin,
|
class SecurityGroupServerRpcMixin(SecurityGroupInfoAPIMixin,
|
||||||
@ -526,5 +531,5 @@ class SecurityGroupServerRpcMixin(SecurityGroupInfoAPIMixin,
|
|||||||
return ips_by_group
|
return ips_by_group
|
||||||
|
|
||||||
@db_api.retry_if_session_inactive()
|
@db_api.retry_if_session_inactive()
|
||||||
def _is_security_group_stateful(self, context, sg_id):
|
def _get_sgs_stateful_flag(self, context, sg_ids):
|
||||||
return sg_obj.SecurityGroup.get_sg_by_id(context, sg_id).stateful
|
return sg_obj.SecurityGroup.get_sgs_stateful_flag(context, sg_ids)
|
||||||
|
@ -11,6 +11,7 @@
|
|||||||
# under the License.
|
# under the License.
|
||||||
|
|
||||||
from neutron_lib import context as context_lib
|
from neutron_lib import context as context_lib
|
||||||
|
from neutron_lib.db import api as db_api
|
||||||
from neutron_lib.objects import common_types
|
from neutron_lib.objects import common_types
|
||||||
from neutron_lib.utils import net as net_utils
|
from neutron_lib.utils import net as net_utils
|
||||||
from oslo_utils import versionutils
|
from oslo_utils import versionutils
|
||||||
@ -130,6 +131,13 @@ class SecurityGroup(rbac_db.NeutronRbacObject):
|
|||||||
security_group_ids=[obj_id])
|
security_group_ids=[obj_id])
|
||||||
return {port.tenant_id for port in port_objs}
|
return {port.tenant_id for port in port_objs}
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
@db_api.CONTEXT_READER
|
||||||
|
def get_sgs_stateful_flag(cls, context, sg_ids):
|
||||||
|
query = context.session.query(cls.db_model.id, cls.db_model.stateful)
|
||||||
|
query = query.filter(cls.db_model.id.in_(sg_ids))
|
||||||
|
return dict(query.all())
|
||||||
|
|
||||||
|
|
||||||
@base.NeutronObjectRegistry.register
|
@base.NeutronObjectRegistry.register
|
||||||
class DefaultSecurityGroup(base.NeutronDbObject):
|
class DefaultSecurityGroup(base.NeutronDbObject):
|
||||||
|
@ -210,6 +210,22 @@ class SecurityGroupDbObjTestCase(test_base.BaseDbObjectTestCase,
|
|||||||
self.assertEqual(len(sg_obj.rules), 0)
|
self.assertEqual(len(sg_obj.rules), 0)
|
||||||
self.assertIsNone(listed_objs[0].rules)
|
self.assertIsNone(listed_objs[0].rules)
|
||||||
|
|
||||||
|
def test_get_sgs_stateful_flag(self):
|
||||||
|
for obj in self.objs:
|
||||||
|
obj.create()
|
||||||
|
|
||||||
|
sg_ids = tuple(sg.id for sg in self.objs)
|
||||||
|
sgs_stateful = securitygroup.SecurityGroup.get_sgs_stateful_flag(
|
||||||
|
self.context, sg_ids)
|
||||||
|
for sg_id, stateful in sgs_stateful.items():
|
||||||
|
for obj in (obj for obj in self.objs if obj.id == sg_id):
|
||||||
|
self.assertEqual(obj.stateful, stateful)
|
||||||
|
|
||||||
|
sg_ids = sg_ids + ('random_id_not_present', )
|
||||||
|
sgs_stateful = securitygroup.SecurityGroup.get_sgs_stateful_flag(
|
||||||
|
self.context, sg_ids)
|
||||||
|
self.assertEqual(len(self.objs), len(sgs_stateful))
|
||||||
|
|
||||||
|
|
||||||
class DefaultSecurityGroupIfaceObjTestCase(test_base.BaseObjectIfaceTestCase):
|
class DefaultSecurityGroupIfaceObjTestCase(test_base.BaseObjectIfaceTestCase):
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user