From ab1d471d94c20d31dbdea60efa08d536e84903ed Mon Sep 17 00:00:00 2001 From: Flavio Percoco Date: Tue, 5 Aug 2014 13:44:30 +0200 Subject: [PATCH] Make the catalog flavor-aware This patch adds the knowledge of flavors to the catalog. When a new queue is registered, if a flavor is passed, it'll get the pool from the flavor record. If flavor is not passed, it'll preserve the previous behavior. Partially Implements blueprint: marconi-queue-flavors Change-Id: Idcf5a0215699269f29df793169ff21fc6435f3b2 --- .../unit/queues/storage/test_pool_catalog.py | 21 +++++++++++- zaqar/queues/storage/pooling.py | 34 +++++++++++++++---- 2 files changed, 48 insertions(+), 7 deletions(-) diff --git a/tests/unit/queues/storage/test_pool_catalog.py b/tests/unit/queues/storage/test_pool_catalog.py index 4366bc613..0de57e5c8 100644 --- a/tests/unit/queues/storage/test_pool_catalog.py +++ b/tests/unit/queues/storage/test_pool_catalog.py @@ -17,6 +17,7 @@ import uuid from oslo.config import cfg from zaqar.openstack.common.cache import cache as oslo_cache +from zaqar.queues.storage import errors from zaqar.queues.storage import pooling from zaqar.queues.storage import sqlalchemy from zaqar.queues.storage import utils @@ -40,16 +41,21 @@ class PoolCatalogTest(testing.TestBase): control = utils.load_storage_driver(self.conf, cache, control_mode=True) - self.catalogue_ctrl = control.catalogue_controller self.pools_ctrl = control.pools_controller + self.flavors_ctrl = control.flavors_controller + self.catalogue_ctrl = control.catalogue_controller # NOTE(cpp-cabrera): populate catalogue self.pool = str(uuid.uuid1()) self.queue = str(uuid.uuid1()) + self.flavor = str(uuid.uuid1()) self.project = str(uuid.uuid1()) + self.pools_ctrl.create(self.pool, 100, 'sqlite://:memory:') self.catalogue_ctrl.insert(self.project, self.queue, self.pool) self.catalog = pooling.Catalog(self.conf, cache, control) + self.flavors_ctrl.create(self.flavor, self.pool, + project=self.project) def tearDown(self): self.catalogue_ctrl.drop_all() @@ -71,3 +77,16 @@ class PoolCatalogTest(testing.TestBase): self.catalog.register('not_yet', 'mapped') storage = self.catalog.lookup('not_yet', 'mapped') self.assertIsInstance(storage, sqlalchemy.DataDriver) + + def test_register_with_flavor(self): + queue = 'test' + self.catalog.register(queue, project=self.project, + flavor=self.flavor) + storage = self.catalog.lookup(queue, self.project) + self.assertIsInstance(storage, sqlalchemy.DataDriver) + + def test_register_with_fake_flavor(self): + self.assertRaises(errors.FlavorDoesNotExist, + self.catalog.register, + 'test', project=self.project, + flavor='fake') diff --git a/zaqar/queues/storage/pooling.py b/zaqar/queues/storage/pooling.py index 35966e01a..512b98399 100644 --- a/zaqar/queues/storage/pooling.py +++ b/zaqar/queues/storage/pooling.py @@ -185,7 +185,8 @@ class QueueController(RoutingController): return {} def create(self, name, metadata=None, project=None): - self._pool_catalog.register(name, project) + flavor = metadata and metadata.get('_flavor', None) + self._pool_catalog.register(name, project=project, flavor=flavor) # NOTE(cpp-cabrera): This should always succeed since we just # registered the project/queue. There is a race condition, @@ -380,6 +381,7 @@ class Catalog(object): self._catalog_conf = self._conf[_CATALOG_GROUP] self._pools_ctrl = control.pools_controller + self._flavor_ctrl = control.flavors_controller self._catalogue_ctrl = control.catalogue_controller # FIXME(cpp-cabrera): https://bugs.launchpad.net/zaqar/+bug/1252791 @@ -408,7 +410,7 @@ class Catalog(object): """ return self._catalogue_ctrl.get(project, queue)['pool'] - def register(self, queue, project=None): + def register(self, queue, project=None, flavor=None): """Register a new queue in the pool catalog. This method should be called whenever a new queue is being @@ -425,19 +427,39 @@ class Catalog(object): :param project: Project to which the queue belongs, or None for the "global" or "generic" project. :type project: six.text_type + :param flavor: Flavor for the queue (OPTIONAL) + :type flavor: six.text_type + :raises: NoPoolFound + """ + # NOTE(cpp-cabrera): only register a queue if the entry # doesn't exist if not self._catalogue_ctrl.exists(project, queue): - # NOTE(cpp-cabrera): limit=0 implies unlimited - select from - # all pools - pool = select.weighted(self._pools_ctrl.list(limit=0)) + if flavor is not None: + # TODO(flaper87): If the flavor doesn't exist, this will + # raise a `FlavorDoesNotExist` making the transport to treat + # this failure as an internal error. However, this is actually + # an user error erro since a non valid flavor has been used. + # Make sure this error is caught in the queue creation endpoint + # and a proper message is logged. + flavor = self._flavor_ctrl.get(flavor, project=project) + pool = flavor['pool'] + else: + # NOTE(cpp-cabrera): limit=0 implies unlimited - select from + # all pools + pool = select.weighted(self._pools_ctrl.list(limit=0)) + pool = pool and pool['name'] or None + + # TODO(flaper87): If the pool is being registered by a + # queue creation, we shouldn't raise `NotFound` but a 500 + # and a proper error message should be logged.wq if not pool: raise errors.NoPoolFound() - self._catalogue_ctrl.insert(project, queue, pool['name']) + self._catalogue_ctrl.insert(project, queue, pool) @_pool_id.purges def deregister(self, queue, project=None):