]> review.fuel-infra Code Review - openstack-build/neutron-build.git/commitdiff
Avoid performing extra query for fetching port security binding
authorSalvatore Orlando <salv.orlando@gmail.com>
Sun, 14 Jul 2013 22:21:12 +0000 (00:21 +0200)
committerSalvatore Orlando <salv.orlando@gmail.com>
Wed, 31 Jul 2013 09:10:35 +0000 (02:10 -0700)
Bug 1201957

Add a relationship performing eager load in Port and Network
models, thus preventing the 'extend' function from performing
an extra database query.
Also fixes a comment in securitygroups_db.py

Change-Id: If0f0277191884aab4dcb1ee36826df7f7d66a8fa

neutron/api/v2/base.py
neutron/db/db_base_plugin_v2.py
neutron/db/portsecurity_db.py
neutron/db/securitygroups_db.py
neutron/plugins/nicira/NeutronPlugin.py
neutron/tests/unit/test_extension_portsecurity.py

index 0749d148b16bda4beb692f264e5306f5b09c40aa..f212d370321b97a4a11a6d755b354d96938501ff 100644 (file)
@@ -548,7 +548,6 @@ class Controller(object):
             raise webob.exc.HTTPBadRequest(msg)
 
         Controller._populate_tenant_id(context, res_dict, is_create)
-
         Controller._verify_attributes(res_dict, attr_info)
 
         if is_create:  # POST
index 932d5c08a94415573ea84299a663908d2bc2d13f..5b335244027b8e17750e28d4678a09574bce6a89 100644 (file)
@@ -995,7 +995,7 @@ class NeutronDbPluginV2(neutron_plugin_base_v2.NeutronPluginBaseV2,
                     'status': constants.NET_STATUS_ACTIVE}
             network = models_v2.Network(**args)
             context.session.add(network)
-        return self._make_network_dict(network)
+        return self._make_network_dict(network, process_extensions=False)
 
     def update_network(self, context, id, network):
         n = network['network']
index 0b16167505440fee7121f1acfe15ab13d00bde95..f2eff2aae1808477b5f1c4480ca783e7ac8e4aec 100644 (file)
 # @author: Aaron Rosen, Nicira, Inc
 
 import sqlalchemy as sa
+from sqlalchemy import orm
 from sqlalchemy.orm import exc
 
+from neutron.api.v2 import attributes as attrs
+from neutron.db import db_base_plugin_v2
 from neutron.db import model_base
+from neutron.db import models_v2
 from neutron.extensions import portsecurity as psec
 from neutron.openstack.common import log as logging
 
@@ -32,6 +36,13 @@ class PortSecurityBinding(model_base.BASEV2):
                         primary_key=True)
     port_security_enabled = sa.Column(sa.Boolean(), nullable=False)
 
+    # Add a relationship to the Port model in order to be to able to
+    # instruct SQLAlchemy to eagerly load port security binding
+    port = orm.relationship(
+        models_v2.Port,
+        backref=orm.backref("port_security", uselist=False,
+                            cascade='delete', lazy='joined'))
+
 
 class NetworkSecurityBinding(model_base.BASEV2):
     network_id = sa.Column(sa.String(36),
@@ -39,25 +50,43 @@ class NetworkSecurityBinding(model_base.BASEV2):
                            primary_key=True)
     port_security_enabled = sa.Column(sa.Boolean(), nullable=False)
 
+    # Add a relationship to the Port model in order to be able to instruct
+    # SQLAlchemy to eagerly load default port security setting for ports
+    # on this network
+    network = orm.relationship(
+        models_v2.Network,
+        backref=orm.backref("port_security", uselist=False,
+                            cascade='delete', lazy='joined'))
+
 
 class PortSecurityDbMixin(object):
     """Mixin class to add port security."""
 
-    def _process_network_create_port_security(self, context, network):
+    def _process_network_port_security_create(
+        self, context, network_req, network_res):
         with context.session.begin(subtransactions=True):
             db = NetworkSecurityBinding(
-                network_id=network['id'],
-                port_security_enabled=network[psec.PORTSECURITY])
+                network_id=network_res['id'],
+                port_security_enabled=network_req[psec.PORTSECURITY])
             context.session.add(db)
+        network_res[psec.PORTSECURITY] = network_req[psec.PORTSECURITY]
         return self._make_network_port_security_dict(db)
 
-    def _extend_network_port_security_dict(self, context, network):
-        network[psec.PORTSECURITY] = self._get_network_security_binding(
-            context, network['id'])
+    def _process_port_port_security_create(
+        self, context, port_req, port_res):
+        with context.session.begin(subtransactions=True):
+            db = PortSecurityBinding(
+                port_id=port_res['id'],
+                port_security_enabled=port_req[psec.PORTSECURITY])
+            context.session.add(db)
+        port_res[psec.PORTSECURITY] = port_req[psec.PORTSECURITY]
+        return self._make_port_security_dict(db)
 
-    def _extend_port_port_security_dict(self, context, port):
-        port[psec.PORTSECURITY] = self._get_port_security_binding(
-            context, port['id'])
+    def _extend_port_security_dict(self, response_data, db_data):
+        if ('port-security' in
+            getattr(self, 'supported_extension_aliases', [])):
+            psec_value = db_data['port_security'][psec.PORTSECURITY]
+            response_data[psec.PORTSECURITY] = psec_value
 
     def _get_network_security_binding(self, context, network_id):
         try:
@@ -77,25 +106,37 @@ class PortSecurityDbMixin(object):
             raise psec.PortSecurityBindingNotFound()
         return binding[psec.PORTSECURITY]
 
-    def _update_port_security_binding(self, context, port_id,
-                                      port_security_enabled):
+    def _process_port_port_security_update(
+        self, context, port_req, port_res):
+        if psec.PORTSECURITY in port_req:
+            port_security_enabled = port_req[psec.PORTSECURITY]
+        else:
+            return
         try:
             query = self._model_query(context, PortSecurityBinding)
+            port_id = port_res['id']
             binding = query.filter(
                 PortSecurityBinding.port_id == port_id).one()
 
-            binding.update({psec.PORTSECURITY: port_security_enabled})
+            binding.port_security_enabled = port_security_enabled
+            port_res[psec.PORTSECURITY] = port_security_enabled
         except exc.NoResultFound:
             raise psec.PortSecurityBindingNotFound()
 
-    def _update_network_security_binding(self, context, network_id,
-                                         port_security_enabled):
+    def _process_network_port_security_update(
+        self, context, network_req, network_res):
+        if psec.PORTSECURITY in network_req:
+            port_security_enabled = network_req[psec.PORTSECURITY]
+        else:
+            return
         try:
             query = self._model_query(context, NetworkSecurityBinding)
+            network_id = network_res['id']
             binding = query.filter(
                 NetworkSecurityBinding.network_id == network_id).one()
 
-            binding.update({psec.PORTSECURITY: port_security_enabled})
+            binding.port_security_enabled = port_security_enabled
+            network_res[psec.PORTSECURITY] = port_security_enabled
         except exc.NoResultFound:
             raise psec.PortSecurityBindingNotFound()
 
@@ -126,14 +167,6 @@ class PortSecurityDbMixin(object):
 
         return (port_security_enabled, has_ip)
 
-    def _process_port_security_create(self, context, port):
-        with context.session.begin(subtransactions=True):
-            port_security_binding = PortSecurityBinding(
-                port_id=port['id'],
-                port_security_enabled=port[psec.PORTSECURITY])
-            context.session.add(port_security_binding)
-        return self._make_port_security_dict(port_security_binding)
-
     def _make_port_security_dict(self, port, fields=None):
         res = {'port_id': port['port_id'],
                psec.PORTSECURITY: port[psec.PORTSECURITY]}
@@ -141,3 +174,9 @@ class PortSecurityDbMixin(object):
 
     def _ip_on_port(self, port):
         return bool(port.get('fixed_ips'))
+
+    # Register dict extend functions for ports and networks
+    db_base_plugin_v2.NeutronDbPluginV2.register_dict_extend_funcs(
+        attrs.NETWORKS, [_extend_port_security_dict])
+    db_base_plugin_v2.NeutronDbPluginV2.register_dict_extend_funcs(
+        attrs.PORTS, [_extend_port_security_dict])
index 198c231a8da1607c923198e2871283e69d8504bd..8e44ebec11dc2f5d271d8a43c83427d7c4e0bae5 100644 (file)
@@ -433,9 +433,9 @@ class SecurityGroupDbMixin(ext_sg.SecurityGroupPluginBase):
             context.session.delete(rule)
 
     def _extend_port_dict_security_group(self, port_res, port_db):
-        # If port_db is provided, security groups will be accessed via
-        # sqlalchemy models. As they're loaded together with ports this
-        # will not cause an extra query.
+        # Security group bindings will be retrieved from the sqlalchemy
+        # model. As they're loaded eagerly with ports because of the
+        # joined load they will not cause an extra query.
         security_group_ids = [sec_group_mapping['security_group_id'] for
                               sec_group_mapping in port_db.security_groups]
         port_res[ext_sg.SECURITYGROUPS] = security_group_ids
index 597c5aa7516f589220d8643b4c8e1797522370a1..b33c5fcb839b93e82783baebdfc40d4557f16139 100644 (file)
@@ -868,7 +868,8 @@ class NvpPluginV2(db_base_plugin_v2.NeutronDbPluginV2,
             # Ensure there's an id in net_data
             net_data['id'] = new_net['id']
             # Process port security extension
-            self._process_network_create_port_security(context, net_data)
+            self._process_network_port_security_create(
+                context, net_data, new_net)
             # DB Operations for setting the network as external
             self._process_l3_create(context, new_net, net_data)
             # Process QoS queue extension
@@ -887,7 +888,6 @@ class NvpPluginV2(db_base_plugin_v2.NeutronDbPluginV2,
                     net_data.get(pnet.SEGMENTATION_ID, 0))
                 self._extend_network_dict_provider(context, new_net,
                                                    net_binding)
-            self._extend_network_port_security_dict(context, new_net)
         self.schedule_network(context, new_net)
         return new_net
 
@@ -976,9 +976,8 @@ class NvpPluginV2(db_base_plugin_v2.NeutronDbPluginV2,
                     raise nvp_exc.NvpPluginException(err_msg=err_msg)
             # Don't do field selection here otherwise we won't be able
             # to add provider networks fields
-            net_result = self._make_network_dict(network, None)
+            net_result = self._make_network_dict(network)
             self._extend_network_dict_provider(context, net_result)
-            self._extend_network_port_security_dict(context, net_result)
             self._extend_network_qos_queue(context, net_result)
         return self._fields(net_result, fields)
 
@@ -990,7 +989,6 @@ class NvpPluginV2(db_base_plugin_v2.NeutronDbPluginV2,
                 super(NvpPluginV2, self).get_networks(context, filters))
             for net in neutron_lswitches:
                 self._extend_network_dict_provider(context, net)
-                self._extend_network_port_security_dict(context, net)
                 self._extend_network_qos_queue(context, net)
 
             tenant_ids = filters and filters.get('tenant_id') or None
@@ -1027,7 +1025,6 @@ class NvpPluginV2(db_base_plugin_v2.NeutronDbPluginV2,
             nvp_lswitches = dict(
                 (uuid, ls) for (uuid, ls) in nvp_lswitches.iteritems()
                 if uuid in set(filters['id']))
-
         for neutron_lswitch in neutron_lswitches:
             # Skip external networks as they do not exist in NVP
             if neutron_lswitch[l3.EXTERNAL]:
@@ -1063,7 +1060,6 @@ class NvpPluginV2(db_base_plugin_v2.NeutronDbPluginV2,
                     row[field] = neutron_lswitch[field]
                 ret_fields.append(row)
             return ret_fields
-
         return neutron_lswitches
 
     def update_network(self, context, id, network):
@@ -1076,13 +1072,12 @@ class NvpPluginV2(db_base_plugin_v2.NeutronDbPluginV2,
         with context.session.begin(subtransactions=True):
             net = super(NvpPluginV2, self).update_network(context, id, network)
             if psec.PORTSECURITY in network['network']:
-                self._update_network_security_binding(
-                    context, id, network['network'][psec.PORTSECURITY])
+                self._process_network_port_security_update(
+                    context, network['network'], net)
             if network['network'].get(ext_qos.QUEUE):
                 net[ext_qos.QUEUE] = network['network'][ext_qos.QUEUE]
                 self._delete_network_queue_mapping(context, id)
                 self._process_network_queue_mapping(context, net)
-            self._extend_network_port_security_dict(context, net)
             self._process_l3_update(context, net, network['network'])
             self._extend_network_dict_provider(context, net)
             self._extend_network_qos_queue(context, net)
@@ -1094,7 +1089,6 @@ class NvpPluginV2(db_base_plugin_v2.NeutronDbPluginV2,
             neutron_lports = super(NvpPluginV2, self).get_ports(
                 context, filters)
             for neutron_lport in neutron_lports:
-                self._extend_port_port_security_dict(context, neutron_lport)
                 self._extend_port_mac_learning_state(context, neutron_lport)
         if (filters.get('network_id') and len(filters.get('network_id')) and
             self._network_is_external(context, filters['network_id'][0])):
@@ -1218,7 +1212,8 @@ class NvpPluginV2(db_base_plugin_v2.NeutronDbPluginV2,
             (port_security, has_ip) = self._determine_port_security_and_has_ip(
                 context, port_data)
             port_data[psec.PORTSECURITY] = port_security
-            self._process_port_security_create(context, port_data)
+            self._process_port_port_security_create(
+                context, port_data, neutron_db)
             # security group extension checks
             if port_security and has_ip:
                 self._ensure_default_security_group_on_port(context, port)
@@ -1263,7 +1258,6 @@ class NvpPluginV2(db_base_plugin_v2.NeutronDbPluginV2,
 
             # remove since it will be added in extend based on policy
             del port_data[ext_qos.QUEUE]
-            self._extend_port_port_security_dict(context, port_data)
             self._extend_port_qos_queue(context, port_data)
             self._process_portbindings_create_and_update(context,
                                                          port, port_data)
@@ -1287,10 +1281,6 @@ class NvpPluginV2(db_base_plugin_v2.NeutronDbPluginV2,
             port['port'].pop('fixed_ips', None)
             ret_port.update(port['port'])
             tenant_id = self._get_tenant_id_for_create(context, ret_port)
-            # populate port_security setting
-            if psec.PORTSECURITY not in port['port']:
-                ret_port[psec.PORTSECURITY] = self._get_port_security_binding(
-                    context, id)
 
             has_ip = self._ip_on_port(ret_port)
             # checks if security groups were updated adding/modifying
@@ -1316,8 +1306,8 @@ class NvpPluginV2(db_base_plugin_v2.NeutronDbPluginV2,
                                                          sgids)
 
             if psec.PORTSECURITY in port['port']:
-                self._update_port_security_binding(
-                    context, id, ret_port[psec.PORTSECURITY])
+                self._process_port_port_security_update(
+                    context, port['port'], ret_port)
 
             ret_port[ext_qos.QUEUE] = self._check_for_queue_and_create(
                 context, ret_port)
@@ -1334,7 +1324,6 @@ class NvpPluginV2(db_base_plugin_v2.NeutronDbPluginV2,
                 ret_port[mac_ext.MAC_LEARNING] = old_mac_learning_state
             self._delete_port_queue_mapping(context, ret_port['id'])
             self._process_port_queue_mapping(context, ret_port)
-            self._extend_port_port_security_dict(context, ret_port)
             LOG.warn(_("Update port request: %s"), port)
             nvp_port_id = self._nvp_get_port_id(
                 context, self.cluster, ret_port)
@@ -1425,7 +1414,6 @@ class NvpPluginV2(db_base_plugin_v2.NeutronDbPluginV2,
         with context.session.begin(subtransactions=True):
             neutron_db_port = super(NvpPluginV2, self).get_port(context,
                                                                 id, fields)
-            self._extend_port_port_security_dict(context, neutron_db_port)
             self._extend_port_qos_queue(context, neutron_db_port)
             self._extend_port_mac_learning_state(context, neutron_db_port)
 
index 19335c6ce82dd0916731a1aea0297bad45cf540f..8ba50ff80d3952c5da8d5365dd52be64eefbaa62 100644 (file)
@@ -60,9 +60,8 @@ class PortSecurityTestPlugin(db_base_plugin_v2.NeutronDbPluginV2,
             neutron_db = super(PortSecurityTestPlugin, self).create_network(
                 context, network)
             neutron_db.update(network['network'])
-            self._process_network_create_port_security(
-                context, neutron_db)
-            self._extend_network_port_security_dict(context, neutron_db)
+            self._process_network_port_security_create(
+                context, network['network'], neutron_db)
         return neutron_db
 
     def update_network(self, context, id, network):
@@ -70,17 +69,14 @@ class PortSecurityTestPlugin(db_base_plugin_v2.NeutronDbPluginV2,
             neutron_db = super(PortSecurityTestPlugin, self).update_network(
                 context, id, network)
             if psec.PORTSECURITY in network['network']:
-                self._update_network_security_binding(
-                    context, id, network['network'][psec.PORTSECURITY])
-            self._extend_network_port_security_dict(
-                context, neutron_db)
+                self._process_network_port_security_update(
+                    context, network['network'], neutron_db)
         return neutron_db
 
     def get_network(self, context, id, fields=None):
         with context.session.begin(subtransactions=True):
             net = super(PortSecurityTestPlugin, self).get_network(
                 context, id)
-            self._extend_network_port_security_dict(context, net)
         return self._fields(net, fields)
 
     def create_port(self, context, port):
@@ -95,7 +91,7 @@ class PortSecurityTestPlugin(db_base_plugin_v2.NeutronDbPluginV2,
             (port_security, has_ip) = self._determine_port_security_and_has_ip(
                 context, p)
             p[psec.PORTSECURITY] = port_security
-            self._process_port_security_create(context, p)
+            self._process_port_port_security_create(context, p, neutron_db)
 
             if (attr.is_attr_set(p.get(ext_sg.SECURITYGROUPS)) and
                 not (port_security and has_ip)):
@@ -109,8 +105,6 @@ class PortSecurityTestPlugin(db_base_plugin_v2.NeutronDbPluginV2,
                 self._process_port_create_security_group(
                     context, p, p[ext_sg.SECURITYGROUPS])
 
-            self._extend_port_port_security_dict(context, p)
-
         return port['port']
 
     def update_port(self, context, id, port):
@@ -159,10 +153,8 @@ class PortSecurityTestPlugin(db_base_plugin_v2.NeutronDbPluginV2,
                                                          ret_port, sgids)
 
             if psec.PORTSECURITY in port['port']:
-                self._update_port_security_binding(
-                    context, id, ret_port[psec.PORTSECURITY])
-
-            self._extend_port_port_security_dict(context, ret_port)
+                self._process_port_port_security_update(
+                    context, port['port'], ret_port)
 
         return ret_port