]> review.fuel-infra Code Review - openstack-build/neutron-build.git/commitdiff
Refactor db_base_plugin_v2 and to remove code duplication
authorEugene Nikanorov <enikanorov@mirantis.com>
Tue, 28 May 2013 07:45:25 +0000 (11:45 +0400)
committerEugene Nikanorov <enikanorov@mirantis.com>
Tue, 28 May 2013 08:13:57 +0000 (12:13 +0400)
fixes bug 1104379

Introduce CommonDbMixin which includes utility methods
to manipulate model queries.

Change-Id: Ib3602321328cbf945358e0581ecc649e3f69d196

quantum/db/db_base_plugin_v2.py
quantum/db/loadbalancer/loadbalancer_db.py

index 5a2f1525529328949595952e5ebfe8b85ca1b532..04d9029ec1ec54e0becd8734df114848a18f4533 100644 (file)
@@ -49,49 +49,39 @@ AGENT_OWNER_PREFIX = 'network:'
 AUTO_DELETE_PORT_OWNERS = ['network:dhcp']
 
 
-class QuantumDbPluginV2(quantum_plugin_base_v2.QuantumPluginBaseV2):
-    """V2 Quantum plugin interface implementation using SQLAlchemy models.
-
-    Whenever a non-read call happens the plugin will call an event handler
-    class method (e.g., network_created()).  The result is that this class
-    can be sub-classed by other classes that add custom behaviors on certain
-    events.
-    """
-
-    # This attribute specifies whether the plugin supports or not
-    # bulk/pagination/sorting operations. Name mangling is used in
-    # order to ensure it is qualified by class
-    __native_bulk_support = True
-    __native_pagination_support = True
-    __native_sorting_support = True
+class CommonDbMixin(object):
+    """Common methods used in core and service plugins."""
     # Plugins, mixin classes implementing extension will register
     # hooks into the dict below for "augmenting" the "core way" of
     # building a query for retrieving objects from a model class.
     # To this aim, the register_model_query_hook and unregister_query_hook
     # from this class should be invoked
     _model_query_hooks = {}
-    # This dictionary will store methods for extending attributes of
-    # api resources. Mixins can use this dict for adding their own methods
-    # TODO(salvatore-orlando): Avoid using class-level variables
-    _dict_extend_functions = {}
 
-    def __init__(self):
-        # NOTE(jkoelker) This is an incomlete implementation. Subclasses
-        #                must override __init__ and setup the database
-        #                and not call into this class's __init__.
-        #                This connection is setup as memory for the tests.
-        db.configure_db()
+    @classmethod
+    def register_model_query_hook(cls, model, name, query_hook, filter_hook,
+                                  result_filters=None):
+        """Register a hook to be invoked when a query is executed.
 
-    def _get_tenant_id_for_create(self, context, resource):
-        if context.is_admin and 'tenant_id' in resource:
-            tenant_id = resource['tenant_id']
-        elif ('tenant_id' in resource and
-              resource['tenant_id'] != context.tenant_id):
-            reason = _('Cannot create resource for another tenant')
-            raise q_exc.AdminRequired(reason=reason)
-        else:
-            tenant_id = context.tenant_id
-        return tenant_id
+        Add the hooks to the _model_query_hooks dict. Models are the keys
+        of this dict, whereas the value is another dict mapping hook names to
+        callables performing the hook.
+        Each hook has a "query" component, used to build the query expression
+        and a "filter" component, which is used to build the filter expression.
+
+        Query hooks take as input the query being built and return a
+        transformed query expression.
+
+        Filter hooks take as input the filter expression being built and return
+        a transformed filter expression
+        """
+        model_hooks = cls._model_query_hooks.get(model)
+        if not model_hooks:
+            # add key to dict
+            model_hooks = {}
+            cls._model_query_hooks[model] = model_hooks
+        model_hooks[name] = {'query': query_hook, 'filter': filter_hook,
+                             'result_filters': result_filters}
 
     def _model_query(self, context, model):
         query = context.session.query(model)
@@ -121,37 +111,104 @@ class QuantumDbPluginV2(quantum_plugin_base_v2.QuantumPluginBaseV2):
             query = query.filter(query_filter)
         return query
 
+    def _fields(self, resource, fields):
+        if fields:
+            return dict(((key, item) for key, item in resource.items()
+                         if key in fields))
+        return resource
+
+    def _get_tenant_id_for_create(self, context, resource):
+        if context.is_admin and 'tenant_id' in resource:
+            tenant_id = resource['tenant_id']
+        elif ('tenant_id' in resource and
+              resource['tenant_id'] != context.tenant_id):
+            reason = _('Cannot create resource for another tenant')
+            raise q_exc.AdminRequired(reason=reason)
+        else:
+            tenant_id = context.tenant_id
+        return tenant_id
+
+    def _get_by_id(self, context, model, id):
+        query = self._model_query(context, model)
+        return query.filter(model.id == id).one()
+
+    def _apply_filters_to_query(self, query, model, filters):
+        if filters:
+            for key, value in filters.iteritems():
+                column = getattr(model, key, None)
+                if column:
+                    query = query.filter(column.in_(value))
+            for _name, hooks in self._model_query_hooks.get(model,
+                                                            {}).iteritems():
+                result_filter = hooks.get('result_filters', None)
+                if result_filter:
+                    query = result_filter(self, query, filters)
+        return query
+
+    def _get_collection_query(self, context, model, filters=None,
+                              sorts=None, limit=None, marker_obj=None,
+                              page_reverse=False):
+        collection = self._model_query(context, model)
+        collection = self._apply_filters_to_query(collection, model, filters)
+        if limit and page_reverse and sorts:
+            sorts = [(s[0], not s[1]) for s in sorts]
+        collection = sqlalchemyutils.paginate_query(collection, model, limit,
+                                                    sorts,
+                                                    marker_obj=marker_obj)
+        return collection
+
+    def _get_collection(self, context, model, dict_func, filters=None,
+                        fields=None, sorts=None, limit=None, marker_obj=None,
+                        page_reverse=False):
+        query = self._get_collection_query(context, model, filters=filters,
+                                           sorts=sorts,
+                                           limit=limit,
+                                           marker_obj=marker_obj,
+                                           page_reverse=page_reverse)
+        items = [dict_func(c, fields) for c in query]
+        if limit and page_reverse:
+            items.reverse()
+        return items
+
+    def _get_collection_count(self, context, model, filters=None):
+        return self._get_collection_query(context, model, filters).count()
+
+
+class QuantumDbPluginV2(quantum_plugin_base_v2.QuantumPluginBaseV2,
+                        CommonDbMixin):
+    """V2 Quantum plugin interface implementation using SQLAlchemy models.
+
+    Whenever a non-read call happens the plugin will call an event handler
+    class method (e.g., network_created()).  The result is that this class
+    can be sub-classed by other classes that add custom behaviors on certain
+    events.
+    """
+
+    # This attribute specifies whether the plugin supports or not
+    # bulk/pagination/sorting operations. Name mangling is used in
+    # order to ensure it is qualified by class
+    __native_bulk_support = True
+    __native_pagination_support = True
+    __native_sorting_support = True
+
+    # This dictionary will store methods for extending attributes of
+    # api resources. Mixins can use this dict for adding their own methods
+    # TODO(salvatore-orlando): Avoid using class-level variables
+    _dict_extend_functions = {}
+
+    def __init__(self):
+        # NOTE(jkoelker) This is an incomlete implementation. Subclasses
+        #                must override __init__ and setup the database
+        #                and not call into this class's __init__.
+        #                This connection is setup as memory for the tests.
+        db.configure_db()
+
     @classmethod
     def register_dict_extend_funcs(cls, resource, funcs):
         cur_funcs = cls._dict_extend_functions.get(resource, [])
         cur_funcs.extend(funcs)
         cls._dict_extend_functions[resource] = cur_funcs
 
-    @classmethod
-    def register_model_query_hook(cls, model, name, query_hook, filter_hook,
-                                  result_filters=None):
-        """Register a hook to be invoked when a query is executed.
-
-        Add the hooks to the _model_query_hooks dict. Models are the keys
-        of this dict, whereas the value is another dict mapping hook names to
-        callables performing the hook.
-        Each hook has a "query" component, used to build the query expression
-        and a "filter" component, which is used to build the filter expression.
-
-        Query hooks take as input the query being built and return a
-        transformed query expression.
-
-        Filter hooks take as input the filter expression being built and return
-        a transformed filter expression
-        """
-        model_hooks = cls._model_query_hooks.get(model)
-        if not model_hooks:
-            # add key to dict
-            model_hooks = {}
-            cls._model_query_hooks[model] = model_hooks
-        model_hooks[name] = {'query': query_hook, 'filter': filter_hook,
-                             'result_filters': result_filters}
-
     def _filter_non_model_columns(self, data, model):
         """Remove all the attributes from data which are not columns of
         the model passed as second parameter.
@@ -160,10 +217,6 @@ class QuantumDbPluginV2(quantum_plugin_base_v2.QuantumPluginBaseV2):
         return dict((k, v) for (k, v) in
                     data.iteritems() if k in columns)
 
-    def _get_by_id(self, context, model, id):
-        query = self._model_query(context, model)
-        return query.filter(model.id == id).one()
-
     def _get_network(self, context, id):
         try:
             network = self._get_by_id(context, models_v2.Network, id)
@@ -213,53 +266,6 @@ class QuantumDbPluginV2(quantum_plugin_base_v2.QuantumPluginBaseV2):
         # a lot of stress on the db. Consider adding a cache layer
         return context.session.query(models_v2.Subnet).all()
 
-    def _fields(self, resource, fields):
-        if fields:
-            return dict(((key, item) for key, item in resource.iteritems()
-                         if key in fields))
-        return resource
-
-    def _apply_filters_to_query(self, query, model, filters):
-        if filters:
-            for key, value in filters.iteritems():
-                column = getattr(model, key, None)
-                if column:
-                    query = query.filter(column.in_(value))
-            for _name, hooks in self._model_query_hooks.get(model,
-                                                            {}).iteritems():
-                result_filter = hooks.get('result_filters', None)
-                if result_filter:
-                    query = result_filter(self, query, filters)
-        return query
-
-    def _get_collection_query(self, context, model, filters=None,
-                              sorts=None, limit=None, marker_obj=None,
-                              page_reverse=False):
-        collection = self._model_query(context, model)
-        collection = self._apply_filters_to_query(collection, model, filters)
-        if limit and page_reverse and sorts:
-            sorts = [(s[0], not s[1]) for s in sorts]
-        collection = sqlalchemyutils.paginate_query(collection, model, limit,
-                                                    sorts,
-                                                    marker_obj=marker_obj)
-        return collection
-
-    def _get_collection(self, context, model, dict_func, filters=None,
-                        fields=None, sorts=None, limit=None, marker_obj=None,
-                        page_reverse=False):
-        query = self._get_collection_query(context, model, filters=filters,
-                                           sorts=sorts,
-                                           limit=limit,
-                                           marker_obj=marker_obj,
-                                           page_reverse=page_reverse)
-        items = [dict_func(c, fields) for c in query]
-        if limit and page_reverse:
-            items.reverse()
-        return items
-
-    def _get_collection_count(self, context, model, filters=None):
-        return self._get_collection_query(context, model, filters).count()
-
     @staticmethod
     def _generate_mac(context, network_id):
         base_mac = cfg.CONF.base_mac.split(':')
index 4cc70d30aee808b9a0068ca241ccba8128d9574b..9a49ac355fa2c3ae167de2e24a2be8b55aa37732 100644 (file)
@@ -22,6 +22,7 @@ from sqlalchemy.orm import exc
 
 from quantum.api.v2 import attributes
 from quantum.common import exceptions as q_exc
+from quantum.db import db_base_plugin_v2 as base_db
 from quantum.db import model_base
 from quantum.db import models_v2
 from quantum.extensions import loadbalancer
@@ -151,7 +152,8 @@ class PoolMonitorAssociation(model_base.BASEV2):
                            primary_key=True)
 
 
-class LoadBalancerPluginDb(LoadBalancerPluginBase):
+class LoadBalancerPluginDb(LoadBalancerPluginBase,
+                           base_db.CommonDbMixin):
     """Wraps loadbalancer with SQLAlchemy models.
 
     A class that wraps the implementation of the Quantum loadbalancer
@@ -162,68 +164,6 @@ class LoadBalancerPluginDb(LoadBalancerPluginBase):
     def _core_plugin(self):
         return manager.QuantumManager.get_plugin()
 
-    # TODO(lcui):
-    # A set of internal facility methods are borrowed from QuantumDbPluginV2
-    # class and hence this is duplicate. We need to pull out those methods
-    # into a seperate class which can be used by both QuantumDbPluginV2 and
-    # this class (and others).
-    def _get_tenant_id_for_create(self, context, resource):
-        if context.is_admin and 'tenant_id' in resource:
-            tenant_id = resource['tenant_id']
-        elif ('tenant_id' in resource and
-              resource['tenant_id'] != context.tenant_id):
-            reason = _('Cannot create resource for another tenant')
-            raise q_exc.AdminRequired(reason=reason)
-        else:
-            tenant_id = context.tenant_id
-        return tenant_id
-
-    def _fields(self, resource, fields):
-        if fields:
-            return dict((key, item) for key, item in resource.iteritems()
-                        if key in fields)
-        return resource
-
-    def _apply_filters_to_query(self, query, model, filters):
-        if filters:
-            for key, value in filters.iteritems():
-                column = getattr(model, key, None)
-                if column:
-                    query = query.filter(column.in_(value))
-        return query
-
-    def _get_collection_query(self, context, model, filters=None):
-        collection = self._model_query(context, model)
-        collection = self._apply_filters_to_query(collection, model, filters)
-        return collection
-
-    def _get_collection(self, context, model, dict_func, filters=None,
-                        fields=None, sorts=None, limit=None, marker_obj=None,
-                        page_reverse=False):
-        query = self._get_collection_query(context, model, filters)
-        return [dict_func(c, fields) for c in query]
-
-    def _get_collection_count(self, context, model, filters=None):
-        return self._get_collection_query(context, model, filters).count()
-
-    def _model_query(self, context, model):
-        query = context.session.query(model)
-        query_filter = None
-        if not context.is_admin and hasattr(model, 'tenant_id'):
-            if hasattr(model, 'shared'):
-                query_filter = ((model.tenant_id == context.tenant_id) |
-                                (model.shared))
-            else:
-                query_filter = (model.tenant_id == context.tenant_id)
-
-        if query_filter is not None:
-            query = query.filter(query_filter)
-        return query
-
-    def _get_by_id(self, context, model, id):
-        query = self._model_query(context, model)
-        return query.filter(model.id == id).one()
-
     def update_status(self, context, model, id, status):
         with context.session.begin(subtransactions=True):
             v_db = self._get_resource(context, model, id)