Merge "Cinder consistency group returning generic error message"

This commit is contained in:
Jenkins 2016-12-21 13:34:40 +00:00 committed by Gerrit Code Review
commit 107ca25b99
7 changed files with 80 additions and 3 deletions

View File

@ -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)

View File

@ -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")

View File

@ -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)

View File

@ -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,

View File

@ -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()

View File

@ -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')

View File

@ -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}}