Merge "Cinder consistency group returning generic error message"
This commit is contained in:
commit
107ca25b99
@ -33,6 +33,7 @@ from cinder import objects
|
|||||||
from cinder.objects import fields as c_fields
|
from cinder.objects import fields as c_fields
|
||||||
import cinder.policy
|
import cinder.policy
|
||||||
from cinder import quota
|
from cinder import quota
|
||||||
|
from cinder import quota_utils
|
||||||
from cinder.scheduler import rpcapi as scheduler_rpcapi
|
from cinder.scheduler import rpcapi as scheduler_rpcapi
|
||||||
from cinder.volume import api as volume_api
|
from cinder.volume import api as volume_api
|
||||||
from cinder.volume import rpcapi as volume_rpcapi
|
from cinder.volume import rpcapi as volume_rpcapi
|
||||||
@ -405,10 +406,13 @@ class API(base.Base):
|
|||||||
**reserve_opts)
|
**reserve_opts)
|
||||||
if reservations:
|
if reservations:
|
||||||
CGQUOTAS.commit(context, reservations)
|
CGQUOTAS.commit(context, reservations)
|
||||||
except Exception:
|
except Exception as e:
|
||||||
with excutils.save_and_reraise_exception():
|
with excutils.save_and_reraise_exception():
|
||||||
try:
|
try:
|
||||||
group.destroy()
|
group.destroy()
|
||||||
|
if isinstance(e, exception.OverQuota):
|
||||||
|
quota_utils.process_reserve_over_quota(
|
||||||
|
context, e, resource='groups')
|
||||||
finally:
|
finally:
|
||||||
LOG.error(_LE("Failed to update quota for "
|
LOG.error(_LE("Failed to update quota for "
|
||||||
"consistency group %s."), group.id)
|
"consistency group %s."), group.id)
|
||||||
|
@ -659,6 +659,10 @@ class GroupTypeUpdateFailed(CinderException):
|
|||||||
message = _("Cannot update group_type %(id)s")
|
message = _("Cannot update group_type %(id)s")
|
||||||
|
|
||||||
|
|
||||||
|
class GroupLimitExceeded(QuotaError):
|
||||||
|
message = _("Maximum number of groups allowed (%(allowed)d) exceeded")
|
||||||
|
|
||||||
|
|
||||||
class UnknownCmd(VolumeDriverException):
|
class UnknownCmd(VolumeDriverException):
|
||||||
message = _("Unknown or unsupported command %(cmd)s")
|
message = _("Unknown or unsupported command %(cmd)s")
|
||||||
|
|
||||||
|
@ -35,6 +35,7 @@ from cinder.objects import base as objects_base
|
|||||||
from cinder.objects import fields as c_fields
|
from cinder.objects import fields as c_fields
|
||||||
import cinder.policy
|
import cinder.policy
|
||||||
from cinder import quota
|
from cinder import quota
|
||||||
|
from cinder import quota_utils
|
||||||
from cinder.scheduler import rpcapi as scheduler_rpcapi
|
from cinder.scheduler import rpcapi as scheduler_rpcapi
|
||||||
from cinder.volume import api as volume_api
|
from cinder.volume import api as volume_api
|
||||||
from cinder.volume import rpcapi as volume_rpcapi
|
from cinder.volume import rpcapi as volume_rpcapi
|
||||||
@ -469,10 +470,13 @@ class API(base.Base):
|
|||||||
**reserve_opts)
|
**reserve_opts)
|
||||||
if reservations:
|
if reservations:
|
||||||
GROUP_QUOTAS.commit(context, reservations)
|
GROUP_QUOTAS.commit(context, reservations)
|
||||||
except Exception:
|
except Exception as e:
|
||||||
with excutils.save_and_reraise_exception():
|
with excutils.save_and_reraise_exception():
|
||||||
try:
|
try:
|
||||||
group.destroy()
|
group.destroy()
|
||||||
|
if isinstance(e, exception.OverQuota):
|
||||||
|
quota_utils.process_reserve_over_quota(
|
||||||
|
context, e, resource='groups')
|
||||||
finally:
|
finally:
|
||||||
LOG.error(_LE("Failed to update quota for "
|
LOG.error(_LE("Failed to update quota for "
|
||||||
"group %s."), group.id)
|
"group %s."), group.id)
|
||||||
|
@ -238,7 +238,8 @@ def _keystone_client(context, version=(3, 0)):
|
|||||||
|
|
||||||
OVER_QUOTA_RESOURCE_EXCEPTIONS = {'snapshots': exception.SnapshotLimitExceeded,
|
OVER_QUOTA_RESOURCE_EXCEPTIONS = {'snapshots': exception.SnapshotLimitExceeded,
|
||||||
'backups': exception.BackupLimitExceeded,
|
'backups': exception.BackupLimitExceeded,
|
||||||
'volumes': exception.VolumeLimitExceeded, }
|
'volumes': exception.VolumeLimitExceeded,
|
||||||
|
'groups': exception.GroupLimitExceeded}
|
||||||
|
|
||||||
|
|
||||||
def process_reserve_over_quota(context, over_quota_exception,
|
def process_reserve_over_quota(context, over_quota_exception,
|
||||||
|
@ -491,6 +491,22 @@ class GroupsAPITestCase(test.TestCase):
|
|||||||
group.id)
|
group.id)
|
||||||
self.assertEqual(fields.GroupStatus.DELETED, group.status)
|
self.assertEqual(fields.GroupStatus.DELETED, group.status)
|
||||||
|
|
||||||
|
@mock.patch('cinder.group.api.API.create')
|
||||||
|
def test_create_group_failed_exceeded_quota(self, mock_group_create):
|
||||||
|
mock_group_create.side_effect = exception.GroupLimitExceeded(allowed=1)
|
||||||
|
name = 'group1'
|
||||||
|
body = {"group": {"group_type": fake.GROUP_TYPE_ID,
|
||||||
|
"volume_types": [fake.VOLUME_TYPE_ID],
|
||||||
|
"name": name,
|
||||||
|
"description":
|
||||||
|
"Group 1", }}
|
||||||
|
req = fakes.HTTPRequest.blank('/v3/%s/groups' % fake.PROJECT_ID,
|
||||||
|
version=GROUP_MICRO_VERSION)
|
||||||
|
ex = self.assertRaises(exception.GroupLimitExceeded,
|
||||||
|
self.controller.create,
|
||||||
|
req, body)
|
||||||
|
self.assertEqual(413, ex.code)
|
||||||
|
|
||||||
def test_delete_group_with_invalid_body(self):
|
def test_delete_group_with_invalid_body(self):
|
||||||
self.group1.status = fields.GroupStatus.AVAILABLE
|
self.group1.status = fields.GroupStatus.AVAILABLE
|
||||||
self.group1.save()
|
self.group1.save()
|
||||||
|
@ -22,14 +22,19 @@ import mock
|
|||||||
|
|
||||||
from cinder import context
|
from cinder import context
|
||||||
from cinder import db
|
from cinder import db
|
||||||
|
from cinder import exception
|
||||||
import cinder.group
|
import cinder.group
|
||||||
from cinder import objects
|
from cinder import objects
|
||||||
from cinder.objects import fields
|
from cinder.objects import fields
|
||||||
|
from cinder import quota
|
||||||
from cinder import test
|
from cinder import test
|
||||||
from cinder.tests.unit import fake_constants as fake
|
from cinder.tests.unit import fake_constants as fake
|
||||||
from cinder.tests.unit import utils
|
from cinder.tests.unit import utils
|
||||||
|
|
||||||
|
|
||||||
|
GROUP_QUOTAS = quota.GROUP_QUOTAS
|
||||||
|
|
||||||
|
|
||||||
@ddt.ddt
|
@ddt.ddt
|
||||||
class GroupAPITestCase(test.TestCase):
|
class GroupAPITestCase(test.TestCase):
|
||||||
"""Test Case for group API."""
|
"""Test Case for group API."""
|
||||||
@ -168,6 +173,40 @@ class GroupAPITestCase(test.TestCase):
|
|||||||
mock_volume_types_get.assert_called_once_with(mock.ANY,
|
mock_volume_types_get.assert_called_once_with(mock.ANY,
|
||||||
volume_type_names)
|
volume_type_names)
|
||||||
|
|
||||||
|
@mock.patch.object(GROUP_QUOTAS, "reserve")
|
||||||
|
@mock.patch('cinder.objects.Group')
|
||||||
|
@mock.patch('cinder.db.group_type_get_by_name')
|
||||||
|
@mock.patch('cinder.db.volume_types_get_by_name_or_id')
|
||||||
|
@mock.patch('cinder.group.api.check_policy')
|
||||||
|
def test_create_group_failed_update_quota(self, mock_policy,
|
||||||
|
mock_volume_types_get,
|
||||||
|
mock_group_type_get, mock_group,
|
||||||
|
mock_group_quota_reserve):
|
||||||
|
mock_volume_types_get.return_value = [{'id': fake.VOLUME_TYPE_ID}]
|
||||||
|
mock_group_type_get.return_value = {'id': fake.GROUP_TYPE_ID}
|
||||||
|
fake_overs = ['groups']
|
||||||
|
fake_quotas = {'groups': 1}
|
||||||
|
fake_usages = {'groups': {'reserved': 0, 'in_use': 1}}
|
||||||
|
mock_group_quota_reserve.side_effect = exception.OverQuota(
|
||||||
|
overs=fake_overs,
|
||||||
|
quotas=fake_quotas,
|
||||||
|
usages=fake_usages)
|
||||||
|
name = "test_group"
|
||||||
|
description = "this is a test group"
|
||||||
|
grp = utils.create_group(self.ctxt, group_type_id=fake.GROUP_TYPE_ID,
|
||||||
|
volume_type_ids=[fake.VOLUME_TYPE_ID],
|
||||||
|
availability_zone='nova', host=None,
|
||||||
|
name=name, description=description,
|
||||||
|
status=fields.GroupStatus.CREATING)
|
||||||
|
mock_group.return_value = grp
|
||||||
|
|
||||||
|
self.assertRaises(exception.GroupLimitExceeded,
|
||||||
|
self.group_api.create,
|
||||||
|
self.ctxt, name, description,
|
||||||
|
"fake-grouptype-name",
|
||||||
|
[fake.VOLUME_TYPE_ID],
|
||||||
|
availability_zone='nova')
|
||||||
|
|
||||||
@mock.patch('cinder.volume.rpcapi.VolumeAPI.update_group')
|
@mock.patch('cinder.volume.rpcapi.VolumeAPI.update_group')
|
||||||
@mock.patch('cinder.db.volume_get_all_by_generic_group')
|
@mock.patch('cinder.db.volume_get_all_by_generic_group')
|
||||||
@mock.patch('cinder.group.api.API._cast_create_group')
|
@mock.patch('cinder.group.api.API._cast_create_group')
|
||||||
|
@ -225,6 +225,15 @@ class QuotaUtilsTest(test.TestCase):
|
|||||||
overs, usages, quotas,
|
overs, usages, quotas,
|
||||||
exception.VolumeLimitExceeded)
|
exception.VolumeLimitExceeded)
|
||||||
|
|
||||||
|
def test_groups_limit_quota(self):
|
||||||
|
overs = ['groups']
|
||||||
|
usages = {'groups': {'reserved': 1, 'in_use': 9}}
|
||||||
|
quotas = {'groups': 9}
|
||||||
|
self._process_reserve_over_quota(
|
||||||
|
overs, usages, quotas,
|
||||||
|
exception.GroupLimitExceeded,
|
||||||
|
resource='groups')
|
||||||
|
|
||||||
def test_unknown_quota(self):
|
def test_unknown_quota(self):
|
||||||
overs = ['unknown']
|
overs = ['unknown']
|
||||||
usages = {'volumes': {'reserved': 1, 'in_use': 9}}
|
usages = {'volumes': {'reserved': 1, 'in_use': 9}}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user