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:
parent
517ffd8775
commit
97d05f229c
@ -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):
|
||||
|
@ -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
|
||||
|
@ -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}
|
||||
|
@ -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
|
||||
|
@ -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):
|
||||
|
Loading…
x
Reference in New Issue
Block a user