Not permitted to delete pools which are used by flavor

Pool will be used when creating a flavor, in this case
use is not permitted to delete the pool except after
removing the relationship either by patching the flavor
to change the pool it used or deleting the flavor.

DocsImpact
Pool deletion can now fail with 403 if the pool is used by flavor

Change-Id: I8db78a0f55602a865f98eecb0035b139f1ab18b1
Closes-Bug: #1362174
This commit is contained in:
pengfei wang 2014-08-29 14:56:25 +08:00
parent 517ffd8775
commit 97d05f229c
5 changed files with 61 additions and 2 deletions

View File

@ -395,10 +395,19 @@ class MongodbPoolsTests(base.PoolsControllerTest):
def setUp(self):
super(MongodbPoolsTests, self).setUp()
self.load_conf('wsgi_mongodb.conf')
self.flavors_controller = self.driver.flavors_controller
def tearDown(self):
super(MongodbPoolsTests, self).tearDown()
def test_delete_pool_used_by_flavor(self):
self.flavors_controller.create('durable', self.pool,
project=self.project,
capabilities={})
with testing.expect(errors.PoolInUseByFlavor):
self.pools_controller.delete(self.pool)
@testing.requires_mongodb
class MongodbCatalogueTests(base.CatalogueControllerTest):

View File

@ -163,3 +163,16 @@ class NoPoolFound(ExceptionBase):
def __init__(self):
super(NoPoolFound, self).__init__()
class PoolInUseByFlavor(NotPermitted):
msg_format = u'Pool {pid} is in use by flavor {fid}'
def __init__(self, pid, fid):
super(PoolInUseByFlavor, self).__init__(pid=pid, fid=fid)
self._flavor = fid
@property
def flavor(self):
return self._flavor

View File

@ -31,6 +31,10 @@ FLAVORS_INDEX = [
('n', 1),
]
FLAVORS_STORAGE_POOL_INDEX = [
('s', 1)
]
# NOTE(cpp-cabrera): used for get/list operations. There's no need to
# show the marker or the _id - they're implementation details.
OMIT_FIELDS = (('_id', False),)
@ -50,9 +54,21 @@ class FlavorsController(base.FlavorsBase):
background=True,
name='flavors_name',
unique=True)
self._col.ensure_index(FLAVORS_STORAGE_POOL_INDEX,
background=True,
name='flavors_storage_pool_name')
self._pools_ctrl = self.driver.pools_controller
@utils.raises_conn_error
def _list_by_pool(self, pool, limit=10, detailed=False):
query = {'s': pool}
cursor = self._col.find(query, fields=_field_spec(detailed),
limit=limit).sort('n', 1)
normalizer = functools.partial(_normalize, detailed=detailed)
return utils.HookedCursor(cursor, normalizer)
@utils.raises_conn_error
def list(self, project=None, marker=None, limit=10, detailed=False):
query = {'p': project}

View File

@ -100,6 +100,16 @@ class PoolsController(base.PoolsBase):
@utils.raises_conn_error
def delete(self, name):
# NOTE(wpf): Initializing the Flavors controller here instead of
# doing so in __init__ is required to avoid falling in a maximum
# recursion error.
flavor_ctl = self.driver.flavors_controller
res = list(flavor_ctl._list_by_pool(name))
if res:
flavors = ', '.join([x['name'] for x in res])
raise errors.PoolInUseByFlavor(name, flavors)
self._col.remove({'n': name}, w=0)
@utils.raises_conn_error

View File

@ -41,6 +41,7 @@ import jsonschema
from zaqar.common.schemas import pools as schema
from zaqar.common import utils as common_utils
from zaqar.i18n import _
from zaqar.openstack.common import log
from zaqar.queues.storage import errors
from zaqar.queues.storage import utils as storage_utils
@ -165,11 +166,21 @@ class Resource(object):
def on_delete(self, request, response, project_id, pool):
"""Deregisters a pool.
:returns: HTTP | 204
:returns: HTTP | [204, 403]
"""
LOG.debug(u'DELETE pool - name: %s', pool)
self._ctrl.delete(pool)
try:
self._ctrl.delete(pool)
except errors.PoolInUseByFlavor as ex:
LOG.exception(ex)
title = _(u'Unable to delete')
description = _(u'This pool is used by flavors {flavor}; '
u'It cannot be deleted.')
description = description.format(flavor=ex.flavor)
raise falcon.HTTPForbidden(title, description)
response.status = falcon.HTTP_204
def on_patch(self, request, response, project_id, pool):