Merge "Prevent share type deletion if linked to group types" into stable/rocky
This commit is contained in:
commit
cef5e7b034
|
@ -3975,18 +3975,25 @@ def share_type_destroy(context, id):
|
||||||
session = get_session()
|
session = get_session()
|
||||||
with session.begin():
|
with session.begin():
|
||||||
_share_type_get(context, id, session)
|
_share_type_get(context, id, session)
|
||||||
results = (model_query(context, models.ShareInstance, session=session,
|
shares_count = model_query(
|
||||||
read_deleted="no").
|
|
||||||
filter_by(share_type_id=id).count())
|
|
||||||
share_group_count = model_query(
|
|
||||||
context,
|
context,
|
||||||
models.ShareGroupShareTypeMapping,
|
models.ShareInstance,
|
||||||
read_deleted="no",
|
read_deleted="no",
|
||||||
session=session,
|
session=session,
|
||||||
).filter_by(share_type_id=id).count()
|
).filter_by(share_type_id=id).count()
|
||||||
if results or share_group_count:
|
share_group_types_count = model_query(
|
||||||
LOG.error('ShareType %s deletion failed, ShareType in use.',
|
context,
|
||||||
id)
|
models.ShareGroupTypeShareTypeMapping,
|
||||||
|
read_deleted="no",
|
||||||
|
session=session,
|
||||||
|
).filter_by(share_type_id=id).count()
|
||||||
|
if shares_count or share_group_types_count:
|
||||||
|
msg = ("Deletion of share type %(stype)s failed; it in use by "
|
||||||
|
"%(shares)d shares and %(gtypes)d share group types")
|
||||||
|
msg_args = {'stype': id,
|
||||||
|
'shares': shares_count,
|
||||||
|
'gtypes': share_group_types_count}
|
||||||
|
LOG.error(msg, msg_args)
|
||||||
raise exception.ShareTypeInUse(share_type_id=id)
|
raise exception.ShareTypeInUse(share_type_id=id)
|
||||||
(model_query(context, models.ShareTypeExtraSpecs, session=session).
|
(model_query(context, models.ShareTypeExtraSpecs, session=session).
|
||||||
filter_by(share_type_id=id).soft_delete())
|
filter_by(share_type_id=id).soft_delete())
|
||||||
|
@ -4847,6 +4854,11 @@ def share_group_type_destroy(context, type_id):
|
||||||
).filter_by(
|
).filter_by(
|
||||||
share_group_type_id=type_id,
|
share_group_type_id=type_id,
|
||||||
).soft_delete()
|
).soft_delete()
|
||||||
|
model_query(
|
||||||
|
context, models.ShareGroupTypeShareTypeMapping, session=session
|
||||||
|
).filter_by(
|
||||||
|
share_group_type_id=type_id,
|
||||||
|
).soft_delete()
|
||||||
model_query(
|
model_query(
|
||||||
context, models.ShareGroupTypes, session=session
|
context, models.ShareGroupTypes, session=session
|
||||||
).filter_by(
|
).filter_by(
|
||||||
|
|
|
@ -632,8 +632,8 @@ class ShareGroupTypeSpecsNotFound(NotFound):
|
||||||
|
|
||||||
|
|
||||||
class ShareTypeInUse(ManilaException):
|
class ShareTypeInUse(ManilaException):
|
||||||
message = _("Share Type %(share_type_id)s deletion is not allowed with "
|
message = _("Share Type %(share_type_id)s deletion is not allowed while "
|
||||||
"shares present with the type.")
|
"shares or share group types are associated with the type.")
|
||||||
|
|
||||||
|
|
||||||
class IPAddressInUse(InUse):
|
class IPAddressInUse(InUse):
|
||||||
|
|
|
@ -1194,6 +1194,57 @@ class ShareGroupDatabaseAPITestCase(test.TestCase):
|
||||||
self.assertEqual(constants.STATUS_AVAILABLE, member['status'])
|
self.assertEqual(constants.STATUS_AVAILABLE, member['status'])
|
||||||
|
|
||||||
|
|
||||||
|
@ddt.ddt
|
||||||
|
class ShareGroupTypeAPITestCase(test.TestCase):
|
||||||
|
|
||||||
|
def setUp(self):
|
||||||
|
super(ShareGroupTypeAPITestCase, self).setUp()
|
||||||
|
self.ctxt = context.RequestContext(
|
||||||
|
user_id='user_id', project_id='project_id', is_admin=True)
|
||||||
|
|
||||||
|
@ddt.data(True, False)
|
||||||
|
def test_share_type_destroy_in_use(self, used_by_groups):
|
||||||
|
share_type_1 = db_utils.create_share_type(name='fike')
|
||||||
|
share_type_2 = db_utils.create_share_type(name='bowman')
|
||||||
|
share_group_type_1 = db_utils.create_share_group_type(
|
||||||
|
name='orange', is_public=False, share_types=[share_type_1['id']],
|
||||||
|
group_specs={'dabo': 'allin', 'cadence': 'count'},
|
||||||
|
override_defaults=True)
|
||||||
|
share_group_type_2 = db_utils.create_share_group_type(
|
||||||
|
name='regalia', share_types=[share_type_2['id']])
|
||||||
|
if used_by_groups:
|
||||||
|
share_group_1 = db_utils.create_share_group(
|
||||||
|
share_group_type_id=share_group_type_1['id'],
|
||||||
|
share_types=[share_type_1['id']])
|
||||||
|
share_group_2 = db_utils.create_share_group(
|
||||||
|
share_group_type_id=share_group_type_2['id'],
|
||||||
|
share_types=[share_type_2['id']])
|
||||||
|
self.assertRaises(exception.ShareGroupTypeInUse,
|
||||||
|
db_api.share_group_type_destroy,
|
||||||
|
self.ctxt, share_group_type_1['id'])
|
||||||
|
self.assertRaises(exception.ShareGroupTypeInUse,
|
||||||
|
db_api.share_group_type_destroy,
|
||||||
|
self.ctxt, share_group_type_2['id'])
|
||||||
|
# Cleanup share groups
|
||||||
|
db_api.share_group_destroy(self.ctxt, share_group_1['id'])
|
||||||
|
db_api.share_group_destroy(self.ctxt, share_group_2['id'])
|
||||||
|
|
||||||
|
# Let's cleanup share_group_type_1 and verify it is gone
|
||||||
|
self.assertIsNone(db_api.share_group_type_destroy(
|
||||||
|
self.ctxt, share_group_type_1['id']))
|
||||||
|
self.assertDictMatch(
|
||||||
|
{}, db_api.share_group_type_specs_get(
|
||||||
|
self.ctxt, share_group_type_1['id']))
|
||||||
|
self.assertRaises(exception.ShareGroupTypeNotFound,
|
||||||
|
db_api.share_group_type_get,
|
||||||
|
self.ctxt, share_group_type_1['id'])
|
||||||
|
|
||||||
|
# share_group_type_2 must still be around
|
||||||
|
self.assertEqual(share_group_type_2['id'],
|
||||||
|
db_api.share_group_type_get(
|
||||||
|
self.ctxt, share_group_type_2['id'])['id'])
|
||||||
|
|
||||||
|
|
||||||
@ddt.ddt
|
@ddt.ddt
|
||||||
class ShareSnapshotDatabaseAPITestCase(test.TestCase):
|
class ShareSnapshotDatabaseAPITestCase(test.TestCase):
|
||||||
|
|
||||||
|
@ -2994,29 +3045,26 @@ class ShareTypeAPITestCase(test.TestCase):
|
||||||
self.ctxt = context.RequestContext(
|
self.ctxt = context.RequestContext(
|
||||||
user_id='user_id', project_id='project_id', is_admin=True)
|
user_id='user_id', project_id='project_id', is_admin=True)
|
||||||
|
|
||||||
@ddt.data({'used_by_shares': True, 'used_by_groups': False},
|
@ddt.data({'used_by_shares': True, 'used_by_group_types': False},
|
||||||
{'used_by_shares': False, 'used_by_groups': True},
|
{'used_by_shares': False, 'used_by_group_types': True},
|
||||||
{'used_by_shares': True, 'used_by_groups': True})
|
{'used_by_shares': True, 'used_by_group_types': True})
|
||||||
@ddt.unpack
|
@ddt.unpack
|
||||||
def test_share_type_destroy_in_use(self, used_by_shares,
|
def test_share_type_destroy_in_use(self, used_by_shares,
|
||||||
used_by_groups):
|
used_by_group_types):
|
||||||
share_type_1 = db_utils.create_share_type(
|
share_type_1 = db_utils.create_share_type(
|
||||||
name='orange', extra_specs={'somekey': 'someval'})
|
name='orange', extra_specs={'somekey': 'someval'})
|
||||||
share_type_2 = db_utils.create_share_type(name='regalia')
|
share_type_2 = db_utils.create_share_type(name='regalia')
|
||||||
if used_by_shares:
|
if used_by_shares:
|
||||||
share_1 = db_utils.create_share(share_type_id=share_type_1['id'])
|
share_1 = db_utils.create_share(share_type_id=share_type_1['id'])
|
||||||
db_utils.create_share(share_type_id=share_type_2['id'])
|
db_utils.create_share(share_type_id=share_type_2['id'])
|
||||||
if used_by_groups:
|
if used_by_group_types:
|
||||||
group_type_1 = db_utils.create_share_group_type(
|
group_type_1 = db_utils.create_share_group_type(
|
||||||
name='crimson', share_types=[share_type_1['id']])
|
name='crimson', share_types=[share_type_1['id']])
|
||||||
group_type_2 = db_utils.create_share_group_type(
|
db_utils.create_share_group_type(
|
||||||
name='tide', share_types=[share_type_2['id']])
|
name='tide', share_types=[share_type_2['id']])
|
||||||
share_group_1 = db_utils.create_share_group(
|
share_group_1 = db_utils.create_share_group(
|
||||||
share_group_type_id=group_type_1['id'],
|
share_group_type_id=group_type_1['id'],
|
||||||
share_types=[share_type_1['id']])
|
share_types=[share_type_1['id']])
|
||||||
db_utils.create_share_group(
|
|
||||||
share_group_type_id=group_type_2['id'],
|
|
||||||
share_types=[share_type_2['id']])
|
|
||||||
|
|
||||||
self.assertRaises(exception.ShareTypeInUse,
|
self.assertRaises(exception.ShareTypeInUse,
|
||||||
db_api.share_type_destroy,
|
db_api.share_type_destroy,
|
||||||
|
@ -3028,13 +3076,13 @@ class ShareTypeAPITestCase(test.TestCase):
|
||||||
# Let's cleanup share_type_1 and verify it is gone
|
# Let's cleanup share_type_1 and verify it is gone
|
||||||
if used_by_shares:
|
if used_by_shares:
|
||||||
db_api.share_instance_delete(self.ctxt, share_1.instance.id)
|
db_api.share_instance_delete(self.ctxt, share_1.instance.id)
|
||||||
if used_by_groups:
|
if used_by_group_types:
|
||||||
db_api.share_group_destroy(self.ctxt, share_group_1['id'])
|
db_api.share_group_destroy(self.ctxt, share_group_1['id'])
|
||||||
db_api.share_group_type_destroy(self.ctxt,
|
db_api.share_group_type_destroy(self.ctxt,
|
||||||
group_type_1['id'])
|
group_type_1['id'])
|
||||||
|
|
||||||
self.assertIsNone(db_api.share_type_destroy(
|
self.assertIsNone(
|
||||||
self.ctxt, share_type_1['id']))
|
db_api.share_type_destroy(self.ctxt, share_type_1['id']))
|
||||||
self.assertDictMatch(
|
self.assertDictMatch(
|
||||||
{}, db_api.share_type_extra_specs_get(
|
{}, db_api.share_type_extra_specs_get(
|
||||||
self.ctxt, share_type_1['id']))
|
self.ctxt, share_type_1['id']))
|
||||||
|
|
|
@ -0,0 +1,6 @@
|
||||||
|
---
|
||||||
|
fixes:
|
||||||
|
- |
|
||||||
|
Fixed `Launchpad bug 1699836 <https://launchpad.net/bugs/1699836>`_ by
|
||||||
|
preventing share type deletion when there are share group types
|
||||||
|
associated with them.
|
Loading…
Reference in New Issue