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)
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.
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)
# 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(':')
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
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
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)