]> review.fuel-infra Code Review - openstack-build/cinder-build.git/commitdiff
Fix quotas issue during volume transfer
authorMitsuhiro Tanino <mitsuhiro.tanino@hds.com>
Fri, 13 Nov 2015 20:01:32 +0000 (15:01 -0500)
committerMitsuhiro Tanino <mitsuhiro.tanino@hds.com>
Thu, 26 Nov 2015 04:52:01 +0000 (23:52 -0500)
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

cinder/tests/unit/test_volume_transfer.py
cinder/transfer/api.py

index 46be3a9e7a433c58962ca6d40de89430d53d5612..af378bfcb3f9045979b5a843df31b8fc2d14fc91 100644 (file)
@@ -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()
index 04d48cadcebdd8c93077bb26ca137a1f537bbafc..1bac7352734a9662147ae23dfd6e31b83661b4b9 100644 (file)
@@ -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"