From: Mitsuhiro Tanino Date: Fri, 13 Nov 2015 20:01:32 +0000 (-0500) Subject: Fix quotas issue during volume transfer X-Git-Url: https://review.fuel-infra.org/gitweb?a=commitdiff_plain;h=173fd8604c5fe1237330eca96efdc356906ced50;p=openstack-build%2Fcinder-build.git Fix quotas issue during volume transfer When admin transfers a volume with volume type from one tenant to another, it correctly updates the quota for the default values, but does not update for the volume type values. This patch fixes the problem to update quotas for the volume type values. Change-Id: If444639cea8e74a415220df43fccfb155ca89216 Closes-Bug: #1501855 --- diff --git a/cinder/tests/unit/test_volume_transfer.py b/cinder/tests/unit/test_volume_transfer.py index 46be3a9e7..af378bfcb 100644 --- a/cinder/tests/unit/test_volume_transfer.py +++ b/cinder/tests/unit/test_volume_transfer.py @@ -19,11 +19,15 @@ import mock from cinder import context from cinder import exception from cinder import objects +from cinder import quota from cinder import test from cinder.tests.unit import utils from cinder.transfer import api as transfer_api +QUOTAS = quota.QUOTAS + + class VolumeTransferTestCase(test.TestCase): """Test cases for volume transfer code.""" def setUp(self): @@ -64,8 +68,9 @@ class VolumeTransferTestCase(test.TestCase): self.assertEqual('in-use', volume['status'], 'Unexpected state') @mock.patch('cinder.volume.utils.notify_about_volume_usage') - def test_transfer_accept(self, mock_notify): + def test_transfer_accept_invalid_authkey(self, mock_notify): svc = self.start_service('volume', host='test_host') + self.addCleanup(svc.stop) tx_api = transfer_api.API() volume = utils.create_volume(self.ctxt, updated_at=self.updated_at) transfer = tx_api.create(self.ctxt, volume.id, 'Description') @@ -81,6 +86,17 @@ class VolumeTransferTestCase(test.TestCase): tx_api.accept, self.ctxt, transfer['id'], 'wrong') + @mock.patch('cinder.volume.utils.notify_about_volume_usage') + def test_transfer_accept_invalid_volume(self, mock_notify): + svc = self.start_service('volume', host='test_host') + self.addCleanup(svc.stop) + tx_api = transfer_api.API() + volume = utils.create_volume(self.ctxt, updated_at=self.updated_at) + transfer = tx_api.create(self.ctxt, volume.id, 'Description') + volume = objects.Volume.get_by_id(self.ctxt, volume.id) + self.assertEqual('awaiting-transfer', volume['status'], + 'Unexpected state') + calls = [mock.call(self.ctxt, mock.ANY, "transfer.create.start"), mock.call(self.ctxt, mock.ANY, "transfer.create.end")] mock_notify.assert_has_calls(calls) @@ -100,6 +116,18 @@ class VolumeTransferTestCase(test.TestCase): mock_notify.assert_has_calls(calls) self.assertEqual(3, mock_notify.call_count) + @mock.patch.object(QUOTAS, "reserve") + @mock.patch.object(QUOTAS, "add_volume_type_opts") + @mock.patch('cinder.volume.utils.notify_about_volume_usage') + def test_transfer_accept(self, mock_notify, mock_quota_voltype, + mock_quota_reserve): + svc = self.start_service('volume', host='test_host') + self.addCleanup(svc.stop) + tx_api = transfer_api.API() + volume = utils.create_volume(self.ctxt, volume_type_id='12345', + updated_at=self.updated_at) + transfer = tx_api.create(self.ctxt, volume.id, 'Description') + self.ctxt.user_id = 'new_user_id' self.ctxt.project_id = 'new_project_id' response = tx_api.accept(self.ctxt, @@ -117,9 +145,22 @@ class VolumeTransferTestCase(test.TestCase): calls = [mock.call(self.ctxt, mock.ANY, "transfer.accept.start"), mock.call(self.ctxt, mock.ANY, "transfer.accept.end")] mock_notify.assert_has_calls(calls) - self.assertEqual(5, mock_notify.call_count) + # The notify_about_volume_usage is called twice at create(), + # and twice at accept(). + self.assertEqual(4, mock_notify.call_count) - svc.stop() + # Check QUOTAS reservation calls + # QUOTAS.add_volume_type_opts + reserve_opt = {'volumes': 1, 'gigabytes': 1} + release_opt = {'volumes': -1, 'gigabytes': -1} + calls = [mock.call(self.ctxt, reserve_opt, '12345'), + mock.call(self.ctxt, release_opt, '12345')] + mock_quota_voltype.assert_has_calls(calls) + + # QUOTAS.reserve + calls = [mock.call(mock.ANY, **reserve_opt), + mock.call(mock.ANY, project_id='project_id', **release_opt)] + mock_quota_reserve.assert_has_calls(calls) def test_transfer_get(self): tx_api = transfer_api.API() diff --git a/cinder/transfer/api.py b/cinder/transfer/api.py index 04d48cadc..1bac73527 100644 --- a/cinder/transfer/api.py +++ b/cinder/transfer/api.py @@ -165,8 +165,11 @@ class API(base.Base): "transfer.accept.start") try: - reservations = QUOTAS.reserve(context, volumes=1, - gigabytes=vol_ref['size']) + reserve_opts = {'volumes': 1, 'gigabytes': vol_ref.size} + QUOTAS.add_volume_type_opts(context, + reserve_opts, + vol_ref.volume_type_id) + reservations = QUOTAS.reserve(context, **reserve_opts) except exception.OverQuota as e: overs = e.kwargs['overs'] usages = e.kwargs['usages'] @@ -196,10 +199,13 @@ class API(base.Base): raise exception.VolumeLimitExceeded(allowed=quotas['volumes']) try: donor_id = vol_ref['project_id'] + reserve_opts = {'volumes': -1, 'gigabytes': -vol_ref.size} + QUOTAS.add_volume_type_opts(context, + reserve_opts, + vol_ref.volume_type_id) donor_reservations = QUOTAS.reserve(context.elevated(), project_id=donor_id, - volumes=-1, - gigabytes=-vol_ref['size']) + **reserve_opts) except Exception: donor_reservations = None LOG.exception(_LE("Failed to update quota donating volume"