QUOTAS = quota.QUOTAS
-def get_volume_type_reservation(ctxt, volume, type_id):
+def get_volume_type_reservation(ctxt, volume, type_id,
+ reserve_vol_type_only=False):
# Reserve quotas for the given volume type
try:
reserve_opts = {'volumes': 1, 'gigabytes': volume['size']}
QUOTAS.add_volume_type_opts(ctxt,
reserve_opts,
type_id)
+ # If reserve_vol_type_only is True, just reserve volume_type quota,
+ # not volume quota.
+ if reserve_vol_type_only:
+ reserve_opts.pop('volumes')
+ reserve_opts.pop('gigabytes')
# Note that usually the project_id on the volume will be the same as
# the project_id in the context. But, if they are different then the
# reservations must be recorded against the project_id that owns the
project_id='vol_project_id',
gigabytes='1',
volumes=1)
+
+ @mock.patch.object(quota.QUOTAS, 'reserve')
+ def test_volume_type_reservation_with_type_only(self, mock_reserve):
+ my_context = FakeContext('MyProject', None)
+ volume = {'name': 'my_vol_name',
+ 'id': 'my_vol_id',
+ 'size': '1',
+ 'project_id': 'vol_project_id',
+ }
+ quota_utils.get_volume_type_reservation(my_context,
+ volume,
+ self.volume_type['id'],
+ reserve_vol_type_only=True)
+ vtype_volume_quota = "%s_%s" % ('volumes', self.volume_type['name'])
+ vtype_size_quota = "%s_%s" % ('gigabytes', self.volume_type['name'])
+ reserve_opts = {vtype_volume_quota: 1,
+ vtype_size_quota: volume['size']}
+ mock_reserve.assert_called_once_with(my_context,
+ project_id='vol_project_id',
+ **reserve_opts)
def _retype_volume_exec(self, driver, snap=False, policy='on-demand',
migrate_exc=False, exc=None, diff_equal=False,
- replica=False):
+ replica=False, reserve_vol_type_only=False):
elevated = context.get_admin_context()
project_id = self.context.project_id
QUOTAS.add_volume_type_opts(self.context,
reserve_opts,
vol_type['id'])
+ if reserve_vol_type_only:
+ reserve_opts.pop('volumes')
+ reserve_opts.pop('gigabytes')
+ try:
+ usage = db.quota_usage_get(elevated, project_id, 'volumes')
+ total_volumes_in_use = usage.in_use
+ usage = db.quota_usage_get(elevated, project_id, 'gigabytes')
+ total_gigabytes_in_use = usage.in_use
+ except exception.QuotaUsageNotFound:
+ total_volumes_in_use = 0
+ total_gigabytes_in_use = 0
reservations = QUOTAS.reserve(self.context,
project_id=project_id,
**reserve_opts)
except exception.QuotaUsageNotFound:
volumes_in_use = 0
+ # Get new in_use after retype, it should not be changed.
+ if reserve_vol_type_only:
+ try:
+ usage = db.quota_usage_get(elevated, project_id, 'volumes')
+ new_total_volumes_in_use = usage.in_use
+ usage = db.quota_usage_get(elevated, project_id, 'gigabytes')
+ new_total_gigabytes_in_use = usage.in_use
+ except exception.QuotaUsageNotFound:
+ new_total_volumes_in_use = 0
+ new_total_gigabytes_in_use = 0
+ self.assertEqual(total_volumes_in_use, new_total_volumes_in_use)
+ self.assertEqual(total_gigabytes_in_use,
+ new_total_gigabytes_in_use)
+
# check properties
if driver or diff_equal:
self.assertEqual(vol_type['id'], volume.volume_type_id)
def test_retype_volume_migration_equal_types(self):
self._retype_volume_exec(False, diff_equal=True)
+ def test_retype_volume_with_type_only(self):
+ self._retype_volume_exec(True, reserve_vol_type_only=True)
+
def test_migrate_driver_not_initialized(self):
volume = tests_utils.create_volume(self.context, size=0,
host=CONF.host)
# We're checking here in so that we can report any quota issues as
# early as possible, but won't commit until we change the type. We
# pass the reservations onward in case we need to roll back.
- reservations = quota_utils.get_volume_type_reservation(context, volume,
- vol_type_id)
+ reservations = quota_utils.get_volume_type_reservation(
+ context, volume, vol_type_id, reserve_vol_type_only=True)
# Get old reservations
try:
QUOTAS.add_volume_type_opts(context,
reserve_opts,
old_vol_type_id)
+ # NOTE(wanghao): We don't need to reserve volumes and gigabytes
+ # quota for retyping operation since they didn't changed, just
+ # reserve volume_type and type gigabytes is fine.
+ reserve_opts.pop('volumes')
+ reserve_opts.pop('gigabytes')
old_reservations = QUOTAS.reserve(context,
project_id=volume.project_id,
**reserve_opts)
QUOTAS.add_volume_type_opts(context,
reserve_opts,
volume.volume_type_id)
+ # NOTE(wanghao): We don't need to reserve volumes and gigabytes
+ # quota for retyping operation since they didn't changed, just
+ # reserve volume_type and type gigabytes is fine.
+ reserve_opts.pop('volumes')
+ reserve_opts.pop('gigabytes')
old_reservations = QUOTAS.reserve(context,
project_id=project_id,
**reserve_opts)